Skip to content

Commit d6a4a3e

Browse files
committed
System Touch
1 parent 2258d78 commit d6a4a3e

3 files changed

Lines changed: 341 additions & 8 deletions

File tree

source/connections/Connection.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package connections;
99

1010
import server.base.BaseServer;
11+
import server.hardened.experimental.m.NationalAwareHardService;
1112

1213
import java.io.BufferedReader;
1314
import java.io.BufferedWriter;
@@ -23,6 +24,8 @@ public class Connection implements AutoCloseable
2324

2425
public BaseServer SERVER;
2526

27+
public NationalAwareHardService NAHS;
28+
2629
public volatile Socket SOCKET;
2730

2831
public InputStream inputstream;
@@ -59,6 +62,14 @@ public Connection(final BaseServer SERVER)
5962
this.SERVER = SERVER;
6063
}
6164

65+
public Connection(final NationalAwareHardService NAHS)
66+
{
67+
if(NAHS==null) throw new commons.security.BodiSecurityException("//bodi/connect", Thread.currentThread().getStackTrace()[2]);
68+
69+
this.NAHS = NAHS;
70+
this.inception_date = new Date();
71+
}
72+
6273
@Override
6374
public void close()
6475
{

source/server/experimental/HardenedBaseServer.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import connections.*;
66
import exceptions.ExceptionHandler;
77
import heuristics.college.HeuristicClassifier;
8+
import server.base.BaseServer;
89

910
import java.io.BufferedReader;
1011
import java.io.BufferedWriter;
@@ -34,7 +35,7 @@
3435
* @author Max Rupplin
3536
* @date June 16 2026 EST
3637
*/
37-
public abstract class HardenedBaseServer extends Thread
38+
public abstract class HardenedBaseServer extends BaseServer
3839
{
3940
// ── Configuration ─────────────────────────────────────────────────────────
4041

@@ -59,13 +60,6 @@ public abstract class HardenedBaseServer extends Thread
5960

6061
// ── State ─────────────────────────────────────────────────────────────────
6162

62-
public String HOST = "localhost";
63-
public InetAddress ADDRESS;
64-
public Integer PORT;
65-
public ServerSocket SERVER_SOCKET;
66-
public volatile boolean RUNNING = true;
67-
68-
public CurrentConnections CURRENT_CONNECTIONS = new CurrentConnections();
6963
private final RecordedConnections RECORDED_CONNECTIONS = new RecordedConnections();
7064
private final InternationalConnections INTERNATIONAL_CONNECTIONS = new InternationalConnections();
7165
private final HeuristicClassifier HEURISTIC = new HeuristicClassifier();
@@ -80,6 +74,8 @@ public abstract class HardenedBaseServer extends Thread
8074

8175
public HardenedBaseServer(final String HOST, final Integer PORT)
8276
{
77+
super();
78+
8379
if (HOST == null || PORT == null)
8480
throw new commons.security.BodiSecurityException("//bodi/connect", Thread.currentThread().getStackTrace()[1]);
8581

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
package server.hardened.experimental.m;
2+
3+
import commons.CommonRails;
4+
import configuration.NitroWebExpressConfig;
5+
import connections.*;
6+
import exceptions.ExceptionHandler;
7+
import heuristics.college.HeuristicClassifier;
8+
9+
import java.io.BufferedReader;
10+
import java.io.BufferedWriter;
11+
import java.io.InputStreamReader;
12+
import java.io.OutputStreamWriter;
13+
import java.net.InetAddress;
14+
import java.net.ServerSocket;
15+
import java.net.Socket;
16+
import java.util.Set;
17+
import java.util.concurrent.ConcurrentHashMap;
18+
import java.util.concurrent.atomic.AtomicInteger;
19+
import java.util.concurrent.atomic.AtomicLong;
20+
21+
/**
22+
* NationalAwareHardService — hardened server with request-weight balancing.
23+
*
24+
* Design philosophy:
25+
* Every connection carries a "cost" proportional to the time and bytes it
26+
* consumes. A long-running request that occupies a slot for 10 minutes costs
27+
* more than a quick handshake. The server maintains a running weight budget
28+
* and rejects or deprioritises connections whose projected cost exceeds the
29+
* remaining capacity — protecting short, lightweight requests from starvation
30+
* by heavy consumers.
31+
*
32+
* Weight model:
33+
* spotValue = 1.0 (base value of any new connection attempt)
34+
* costPerSec = 0.02 (weight accrued per second the connection is alive)
35+
* costPerKB = 0.05 (weight accrued per KB received from the client)
36+
* budgetCap = MAX_CONNECTIONS * spotValue (total budget pool)
37+
*
38+
* When a connection's accumulated weight exceeds WEIGHT_EJECT_THRESHOLD it is
39+
* forcibly closed to free budget for waiting connections.
40+
*
41+
* Hardening (inherited + improved from HardenedBaseServer):
42+
* • MAX_CONNECTIONS = 5040
43+
* • MAX_PER_IP = 1
44+
* • Socket timeout = 58 minutes
45+
* • Port whitelist enforced at bind
46+
* • Backlog 128, SO_REUSEADDR, TcpNoDelay, KeepAlive
47+
* • Accept-loop resilient to individual failures
48+
* • Graceful shutdown via volatile flag + socket close
49+
* • releaseConnection decrements counters and reclaims weight budget
50+
*
51+
* @author Max Rupplin
52+
* @date June 16 2026 EST
53+
*/
54+
public abstract class NationalAwareHardService extends Thread
55+
{
56+
// ── Limits ────────────────────────────────────────────────────────────────
57+
58+
private static final int MAX_CONNECTIONS = 5040;
59+
private static final int MAX_PER_IP = 1;
60+
private static final int CONNECTION_TIMEOUT_MS = 58 * 60 * 1000;
61+
private static final int BACKLOG = 128;
62+
63+
// ── Weight model ──────────────────────────────────────────────────────────
64+
65+
/** Base spot-value of any new connection attempt. */
66+
private static final double SPOT_VALUE = 1.0;
67+
/** Weight accrued per second the connection is held open. */
68+
private static final double COST_PER_SEC = 0.02;
69+
/** Weight accrued per KB received from the client. */
70+
private static final double COST_PER_KB = 0.05;
71+
/** Maximum accumulated weight before forced ejection. */
72+
private static final double WEIGHT_EJECT_THRESHOLD = 120.0;
73+
/** Total weight budget pool. */
74+
private static final double WEIGHT_BUDGET = MAX_CONNECTIONS * SPOT_VALUE;
75+
76+
// ── Port whitelist ────────────────────────────────────────────────────────
77+
78+
private static final Set<Integer> ALLOWED_PORTS = Set.of(
79+
49152, 5512, 6682, 7743, 7744,
80+
49111, 49122, 49133, 49144, 49155,
81+
49166, 49177, 49188, 49199, 49200
82+
);
83+
84+
// ── State ─────────────────────────────────────────────────────────────────
85+
86+
public String HOST = "localhost";
87+
public InetAddress ADDRESS;
88+
public Integer PORT;
89+
public ServerSocket SERVER_SOCKET;
90+
public volatile boolean RUNNING = true;
91+
92+
public CurrentConnections CURRENT_CONNECTIONS = new CurrentConnections();
93+
private final RecordedConnections RECORDED_CONNECTIONS = new RecordedConnections();
94+
private final InternationalConnections INTERNATIONAL_CONNECTIONS = new InternationalConnections();
95+
private final HeuristicClassifier HEURISTIC = new HeuristicClassifier();
96+
97+
private final ConcurrentHashMap<String, AtomicInteger> ipConnectionCount = new ConcurrentHashMap<>();
98+
private final AtomicInteger activeConnections = new AtomicInteger(0);
99+
100+
/** Current consumed weight across all live connections. */
101+
private final AtomicLong consumedWeightMillis = new AtomicLong(0); // stored as weight * 1000
102+
103+
/** Per-connection weight ledger: connectionHashCode -> WeightEntry */
104+
private final ConcurrentHashMap<Integer, WeightEntry> weightLedger = new ConcurrentHashMap<>();
105+
106+
// ── Constructor ───────────────────────────────────────────────────────────
107+
108+
public NationalAwareHardService(final String HOST, final Integer PORT)
109+
{
110+
if (HOST == null || PORT == null)
111+
throw new commons.security.BodiSecurityException("//bodi/connect", Thread.currentThread().getStackTrace()[1]);
112+
if (!ALLOWED_PORTS.contains(PORT))
113+
throw new commons.security.BodiSecurityException("//bodi/port-not-allowed:" + PORT, Thread.currentThread().getStackTrace()[1]);
114+
115+
this.HOST = HOST;
116+
this.PORT = PORT;
117+
this.setName("NationalAwareHard-" + PORT);
118+
119+
try
120+
{
121+
this.ADDRESS = InetAddress.getByName(HOST);
122+
this.SERVER_SOCKET = new ServerSocket(this.PORT, BACKLOG, this.ADDRESS);
123+
this.SERVER_SOCKET.setReuseAddress(true);
124+
this.SERVER_SOCKET.setPerformancePreferences(0, 1, 2);
125+
}
126+
catch (Exception e)
127+
{
128+
ExceptionHandler.dispatch(e);
129+
this.RUNNING = false;
130+
return;
131+
}
132+
133+
CommonRails.printSystemComponent(this, this.hashCode(),
134+
". NationalAwareHardService bound port=" + PORT
135+
+ " max=" + MAX_CONNECTIONS + " perIP=" + MAX_PER_IP
136+
+ " weightBudget=" + WEIGHT_BUDGET + " .");
137+
}
138+
139+
// ── Accept loop ───────────────────────────────────────────────────────────
140+
141+
@Override
142+
public void run()
143+
{
144+
if (SERVER_SOCKET == null || !RUNNING) return;
145+
146+
while (RUNNING)
147+
{
148+
Socket socket = null;
149+
try
150+
{
151+
socket = SERVER_SOCKET.accept();
152+
String remoteIp = socket.getInetAddress().getHostAddress();
153+
154+
// ── 1. Global connection cap ──────────────────────────────────
155+
if (activeConnections.get() >= MAX_CONNECTIONS)
156+
{
157+
reject(socket, remoteIp, "server at capacity (" + MAX_CONNECTIONS + ")");
158+
continue;
159+
}
160+
161+
// ── 2. Per-IP limit ───────────────────────────────────────────
162+
AtomicInteger ipCount = ipConnectionCount.computeIfAbsent(remoteIp, k -> new AtomicInteger(0));
163+
if (ipCount.get() >= MAX_PER_IP)
164+
{
165+
reject(socket, remoteIp, "per-IP limit (" + MAX_PER_IP + ")");
166+
continue;
167+
}
168+
169+
// ── 3. Weight budget check ────────────────────────────────────
170+
double currentWeight = consumedWeightMillis.get() / 1000.0;
171+
if (currentWeight + SPOT_VALUE > WEIGHT_BUDGET)
172+
{
173+
reject(socket, remoteIp, "weight budget exhausted (consumed=" + String.format("%.1f", currentWeight) + ")");
174+
continue;
175+
}
176+
177+
// ── 4. Heuristic classification ───────────────────────────────
178+
if (NitroWebExpressConfig.isEnabled("HEURISTIC_CLASSIFIER"))
179+
{
180+
HeuristicClassifier.ConnectionEvent event =
181+
new HeuristicClassifier.ConnectionEvent.Builder()
182+
.ip(remoteIp).port(this.PORT).build();
183+
HeuristicClassifier.Classification result = HEURISTIC.classify(event);
184+
if (result.threat)
185+
{
186+
reject(socket, remoteIp, "threat: " + result.summary());
187+
continue;
188+
}
189+
}
190+
191+
// ── 5. Socket hardening ───────────────────────────────────────
192+
socket.setSoTimeout(CONNECTION_TIMEOUT_MS);
193+
socket.setTcpNoDelay(true);
194+
socket.setKeepAlive(true);
195+
196+
// ── 6. Build connection ───────────────────────────────────────
197+
Connection connection = new Connection(this);
198+
connection.SOCKET = socket;
199+
connection.remote_address = socket.getRemoteSocketAddress().toString();
200+
connection.internet_address = socket.getInetAddress();
201+
connection.inputstream = socket.getInputStream();
202+
connection.reader = new BufferedReader(new InputStreamReader(connection.inputstream));
203+
connection.outputstream = socket.getOutputStream();
204+
connection.writer = new BufferedWriter(new OutputStreamWriter(connection.outputstream));
205+
206+
// ── 7. Track ──────────────────────────────────────────────────
207+
CURRENT_CONNECTIONS.add(connection);
208+
RECORDED_CONNECTIONS.add(connection);
209+
INTERNATIONAL_CONNECTIONS.add(connection);
210+
activeConnections.incrementAndGet();
211+
ipCount.incrementAndGet();
212+
213+
// Charge spot value
214+
long spotMillis = (long)(SPOT_VALUE * 1000);
215+
consumedWeightMillis.addAndGet(spotMillis);
216+
weightLedger.put(System.identityHashCode(connection), new WeightEntry(remoteIp, spotMillis, System.currentTimeMillis()));
217+
218+
database.N21Store.storeConnection(connection, this.PORT);
219+
220+
CommonRails.printSystemComponent(this, this.hashCode(),
221+
". ACCEPTED " + remoteIp + " port=" + PORT
222+
+ " active=" + activeConnections.get()
223+
+ " weight=" + String.format("%.1f", consumedWeightMillis.get() / 1000.0)
224+
+ "/" + String.format("%.0f", WEIGHT_BUDGET) + " .");
225+
}
226+
catch (Exception e)
227+
{
228+
if (RUNNING)
229+
{
230+
ExceptionHandler.dispatch(e);
231+
try { if (socket != null && !socket.isClosed()) socket.close(); } catch (Exception ignored) {}
232+
}
233+
}
234+
}
235+
}
236+
237+
// ── Weight accounting ─────────────────────────────────────────────────────
238+
239+
/**
240+
* Call periodically (e.g. from ConnectionPoller) to accrue time-based weight
241+
* for a live connection. Returns true if the connection should be ejected.
242+
*/
243+
public boolean accrueWeight(final Connection C, final long bytesReceivedSinceLastCall)
244+
{
245+
int key = System.identityHashCode(C);
246+
WeightEntry entry = weightLedger.get(key);
247+
if (entry == null) return false;
248+
249+
long now = System.currentTimeMillis();
250+
double elapsedSec = (now - entry.lastAccrualMs) / 1000.0;
251+
double timeCost = elapsedSec * COST_PER_SEC;
252+
double dataCost = (bytesReceivedSinceLastCall / 1024.0) * COST_PER_KB;
253+
long deltaMillis = (long)((timeCost + dataCost) * 1000);
254+
255+
entry.accruedMillis += deltaMillis;
256+
entry.lastAccrualMs = now;
257+
consumedWeightMillis.addAndGet(deltaMillis);
258+
259+
double totalWeight = entry.accruedMillis / 1000.0;
260+
if (totalWeight >= WEIGHT_EJECT_THRESHOLD)
261+
{
262+
CommonRails.printSystemComponent(this, this.hashCode(),
263+
". EJECT " + entry.ip + " — weight " + String.format("%.1f", totalWeight)
264+
+ " exceeds threshold " + WEIGHT_EJECT_THRESHOLD + " .");
265+
return true;
266+
}
267+
return false;
268+
}
269+
270+
// ── Release ───────────────────────────────────────────────────────────────
271+
272+
public void releaseConnection(final Connection C)
273+
{
274+
activeConnections.decrementAndGet();
275+
276+
int key = System.identityHashCode(C);
277+
WeightEntry entry = weightLedger.remove(key);
278+
if (entry != null)
279+
{
280+
consumedWeightMillis.addAndGet(-entry.accruedMillis);
281+
AtomicInteger ipCount = ipConnectionCount.get(entry.ip);
282+
if (ipCount != null) ipCount.decrementAndGet();
283+
}
284+
else if (C != null && C.internet_address != null)
285+
{
286+
String ip = C.internet_address.getHostAddress();
287+
AtomicInteger count = ipConnectionCount.get(ip);
288+
if (count != null) count.decrementAndGet();
289+
}
290+
}
291+
292+
// ── Shutdown ──────────────────────────────────────────────────────────────
293+
294+
public void shutdown()
295+
{
296+
RUNNING = false;
297+
try { if (SERVER_SOCKET != null && !SERVER_SOCKET.isClosed()) SERVER_SOCKET.close(); }
298+
catch (Exception ignored) {}
299+
CommonRails.printSystemComponent(this, this.hashCode(),
300+
". NationalAwareHardService shutdown port=" + PORT + " .");
301+
}
302+
303+
// ── Internals ─────────────────────────────────────────────────────────────
304+
305+
private void reject(final Socket S, final String IP, final String REASON)
306+
{
307+
CommonRails.printSystemComponent(this, this.hashCode(),
308+
". REJECTED " + IP + " — " + REASON + " .");
309+
try { S.close(); } catch (Exception ignored) {}
310+
}
311+
312+
/** Per-connection weight tracking record. */
313+
private static class WeightEntry
314+
{
315+
final String ip;
316+
long accruedMillis;
317+
long lastAccrualMs;
318+
319+
WeightEntry(final String IP, final long INITIAL_MILLIS, final long NOW)
320+
{
321+
this.ip = IP;
322+
this.accruedMillis = INITIAL_MILLIS;
323+
this.lastAccrualMs = NOW;
324+
}
325+
}
326+
}

0 commit comments

Comments
 (0)