@earendil-works/gondolin 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,658 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.NetworkStack = void 0;
4
- const events_1 = require("events");
5
- // Protocol Constants
6
- const ETH_P_IP = 0x0800;
7
- const ETH_P_ARP = 0x0806;
8
- const IP_PROTO_TCP = 6;
9
- const IP_PROTO_UDP = 17;
10
- const IP_PROTO_ICMP = 1;
11
- const HTTP_METHODS = [
12
- "GET",
13
- "POST",
14
- "PUT",
15
- "PATCH",
16
- "DELETE",
17
- "HEAD",
18
- "OPTIONS",
19
- "CONNECT",
20
- "TRACE",
21
- ];
22
- // DHCP Constants
23
- const DHCP_SERVER_PORT = 67;
24
- const DHCP_CLIENT_PORT = 68;
25
- const DHCP_MAGIC_COOKIE = 0x63825363;
26
- // DHCP Message Types
27
- const DHCP_DISCOVER = 1;
28
- const DHCP_OFFER = 2;
29
- const DHCP_REQUEST = 3;
30
- const DHCP_ACK = 5;
31
- // DHCP Options
32
- const DHCP_OPT_SUBNET_MASK = 1;
33
- const DHCP_OPT_ROUTER = 3;
34
- const DHCP_OPT_DNS = 6;
35
- const DHCP_OPT_REQUESTED_IP = 50;
36
- const DHCP_OPT_LEASE_TIME = 51;
37
- const DHCP_OPT_MSG_TYPE = 53;
38
- const DHCP_OPT_SERVER_ID = 54;
39
- const DHCP_OPT_END = 255;
40
- class NetworkStack extends events_1.EventEmitter {
41
- constructor(options) {
42
- super();
43
- this.natTable = new Map();
44
- this.MAX_FLOW_SNIFF = 8 * 1024;
45
- this.rxBuffer = Buffer.alloc(0);
46
- this.txBuffer = Buffer.alloc(0);
47
- this.TX_BUFFER_HIGH_WATER = 16 * 1024;
48
- this.TX_BUFFER_LOW_WATER = 4 * 1024;
49
- this.txPaused = new Set();
50
- this.gatewayIP = options.gatewayIP ?? "192.168.127.1";
51
- this.vmIP = options.vmIP ?? "192.168.127.3";
52
- this.gatewayMac =
53
- options.gatewayMac ?? Buffer.from([0x5a, 0x94, 0xef, 0xe4, 0x0c, 0xdd]);
54
- this.vmMac =
55
- options.vmMac ?? Buffer.from([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]);
56
- this.callbacks = options.callbacks;
57
- this.allowTcpFlow = options.allowTcpFlow ?? (() => true);
58
- }
59
- reset() {
60
- this.natTable.clear();
61
- this.rxBuffer = Buffer.alloc(0);
62
- this.txBuffer = Buffer.alloc(0);
63
- this.txPaused.clear();
64
- }
65
- hasPendingData() {
66
- return this.txBuffer.length > 0;
67
- }
68
- // Called when QEMU writes data to the network interface
69
- writeToNetwork(data) {
70
- this.rxBuffer = Buffer.concat([this.rxBuffer, data]);
71
- while (this.rxBuffer.length >= 4) {
72
- const frameLen = this.rxBuffer.readUInt32BE(0);
73
- if (this.rxBuffer.length < 4 + frameLen)
74
- break;
75
- const frame = this.rxBuffer.subarray(4, 4 + frameLen);
76
- this.receive(frame);
77
- this.rxBuffer = this.rxBuffer.subarray(4 + frameLen);
78
- }
79
- }
80
- // Called when QEMU wants to read data from the network interface
81
- readFromNetwork(maxLen) {
82
- if (this.txBuffer.length === 0)
83
- return null;
84
- const chunk = this.txBuffer.subarray(0, maxLen);
85
- this.txBuffer = this.txBuffer.subarray(chunk.length);
86
- if (this.txBuffer.length < this.TX_BUFFER_LOW_WATER && this.txPaused.size > 0) {
87
- for (const key of this.txPaused) {
88
- this.callbacks.onTcpResume({ key });
89
- }
90
- this.txPaused.clear();
91
- }
92
- return chunk;
93
- }
94
- send(payload, proto) {
95
- if (!this.vmMac)
96
- return;
97
- const frame = Buffer.alloc(14 + payload.length);
98
- this.vmMac.copy(frame, 0);
99
- this.gatewayMac.copy(frame, 6);
100
- frame.writeUInt16BE(proto, 12);
101
- payload.copy(frame, 14);
102
- const header = Buffer.alloc(4);
103
- header.writeUInt32BE(frame.length, 0);
104
- this.txBuffer = Buffer.concat([this.txBuffer, header, frame]);
105
- this.emit("network-activity");
106
- }
107
- sendBroadcast(payload, proto) {
108
- const broadcastMac = Buffer.from([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
109
- const frame = Buffer.alloc(14 + payload.length);
110
- broadcastMac.copy(frame, 0);
111
- this.gatewayMac.copy(frame, 6);
112
- frame.writeUInt16BE(proto, 12);
113
- payload.copy(frame, 14);
114
- const header = Buffer.alloc(4);
115
- header.writeUInt32BE(frame.length, 0);
116
- this.txBuffer = Buffer.concat([this.txBuffer, header, frame]);
117
- this.emit("network-activity");
118
- }
119
- receive(frame) {
120
- try {
121
- if (frame.length < 14)
122
- return;
123
- const etherType = frame.readUInt16BE(12);
124
- const payload = frame.subarray(14);
125
- const srcMac = frame.subarray(6, 12);
126
- if (!this.vmMac) {
127
- this.vmMac = Buffer.from(srcMac);
128
- }
129
- if (etherType === ETH_P_ARP) {
130
- this.handleARP(payload);
131
- }
132
- else if (etherType === ETH_P_IP) {
133
- this.handleIP(payload);
134
- }
135
- }
136
- catch (err) {
137
- this.emit("error", err);
138
- }
139
- }
140
- handleARP(packet) {
141
- const op = packet.readUInt16BE(6);
142
- if (op === 1) {
143
- const targetIP = packet.subarray(24, 28);
144
- const targetIPStr = targetIP.join(".");
145
- if (targetIPStr === this.gatewayIP) {
146
- const reply = Buffer.alloc(28);
147
- packet.copy(reply, 0, 0, 8);
148
- reply.writeUInt16BE(2, 6);
149
- this.gatewayMac.copy(reply, 8);
150
- targetIP.copy(reply, 14);
151
- packet.subarray(8, 14).copy(reply, 18);
152
- packet.subarray(14, 18).copy(reply, 24);
153
- this.send(reply, ETH_P_ARP);
154
- }
155
- }
156
- }
157
- handleIP(packet) {
158
- const version = packet[0] >> 4;
159
- if (version !== 4)
160
- return;
161
- const headerLen = (packet[0] & 0x0f) * 4;
162
- const totalLen = packet.readUInt16BE(2);
163
- const protocol = packet[9];
164
- const srcIP = packet.subarray(12, 16);
165
- const dstIP = packet.subarray(16, 20);
166
- const data = packet.subarray(headerLen, totalLen);
167
- if (protocol === IP_PROTO_ICMP) {
168
- this.handleICMP(data, srcIP, dstIP);
169
- }
170
- else if (protocol === IP_PROTO_TCP) {
171
- this.handleTCP(data, srcIP, dstIP);
172
- }
173
- else if (protocol === IP_PROTO_UDP) {
174
- this.handleUDP(data, srcIP, dstIP);
175
- }
176
- }
177
- calculateChecksum(buf) {
178
- let sum = 0;
179
- for (let i = 0; i < buf.length - 1; i += 2) {
180
- sum += buf.readUInt16BE(i);
181
- }
182
- if (buf.length % 2 === 1) {
183
- sum += buf[buf.length - 1] << 8;
184
- }
185
- while (sum >> 16) {
186
- sum = (sum & 0xffff) + (sum >> 16);
187
- }
188
- return ~sum & 0xffff;
189
- }
190
- calculateUdpChecksum(payload, srcIP, dstIP) {
191
- const pseudo = Buffer.alloc(12);
192
- srcIP.copy(pseudo, 0);
193
- dstIP.copy(pseudo, 4);
194
- pseudo[8] = 0;
195
- pseudo[9] = IP_PROTO_UDP;
196
- pseudo.writeUInt16BE(payload.length, 10);
197
- const checksumData = Buffer.concat([pseudo, payload]);
198
- const checksum = this.calculateChecksum(checksumData);
199
- return checksum === 0 ? 0xffff : checksum;
200
- }
201
- handleICMP(data, srcIP, dstIP) {
202
- const type = data[0];
203
- if (type === 8) {
204
- const reply = Buffer.alloc(data.length);
205
- data.copy(reply);
206
- reply[0] = 0;
207
- reply[2] = 0;
208
- reply[3] = 0;
209
- const ck = this.calculateChecksum(reply);
210
- reply.writeUInt16BE(ck, 2);
211
- this.sendIP(reply, IP_PROTO_ICMP, dstIP, srcIP);
212
- }
213
- }
214
- sendIP(payload, protocol, srcIP, dstIP) {
215
- const header = Buffer.alloc(20);
216
- header[0] = 0x45;
217
- header[1] = 0;
218
- header.writeUInt16BE(20 + payload.length, 2);
219
- header.writeUInt16BE(0, 4);
220
- header.writeUInt16BE(0, 6);
221
- header[8] = 64;
222
- header[9] = protocol;
223
- srcIP.copy(header, 12);
224
- dstIP.copy(header, 16);
225
- header.writeUInt16BE(this.calculateChecksum(header), 10);
226
- const packet = Buffer.concat([header, payload]);
227
- if (dstIP[0] === 255 && dstIP[1] === 255 && dstIP[2] === 255 && dstIP[3] === 255) {
228
- this.sendBroadcast(packet, ETH_P_IP);
229
- }
230
- else {
231
- this.send(packet, ETH_P_IP);
232
- }
233
- }
234
- looksLikeTlsClientHello(data) {
235
- if (data.length < 5)
236
- return false;
237
- if (data[0] !== 0x16)
238
- return false; // handshake
239
- if (data[1] !== 0x03)
240
- return false; // TLS major version
241
- return data[2] >= 0x00 && data[2] <= 0x03;
242
- }
243
- matchHttpMethodPrefix(data) {
244
- const snippet = data.toString("ascii", 0, Math.min(data.length, 16));
245
- for (const method of HTTP_METHODS) {
246
- if (snippet.startsWith(`${method} `)) {
247
- return { status: "match", method };
248
- }
249
- if (method.startsWith(snippet)) {
250
- return { status: "partial" };
251
- }
252
- }
253
- return { status: "none" };
254
- }
255
- parseHttpRequestLine(data) {
256
- const lineEnd = data.indexOf("\r\n");
257
- if (lineEnd === -1)
258
- return null;
259
- const line = data.subarray(0, lineEnd).toString("ascii");
260
- const [method, target, version] = line.split(" ");
261
- if (!method || !target || !version)
262
- return null;
263
- if (!version.startsWith("HTTP/"))
264
- return null;
265
- if (!HTTP_METHODS.includes(method))
266
- return null;
267
- return { method, target, version };
268
- }
269
- classifyTcpFlow(data) {
270
- if (data.length === 0) {
271
- return { status: "need-more" };
272
- }
273
- if (this.looksLikeTlsClientHello(data)) {
274
- return { status: "tls" };
275
- }
276
- const prefix = this.matchHttpMethodPrefix(data);
277
- if (prefix.status === "match") {
278
- const requestLine = this.parseHttpRequestLine(data);
279
- if (!requestLine) {
280
- return { status: "need-more" };
281
- }
282
- return {
283
- status: "http",
284
- method: requestLine.method,
285
- isConnect: requestLine.method === "CONNECT",
286
- };
287
- }
288
- if (prefix.status === "partial") {
289
- return { status: "need-more" };
290
- }
291
- if (data.length < 4) {
292
- return { status: "need-more" };
293
- }
294
- return { status: "deny", reason: "unknown-protocol" };
295
- }
296
- rejectTcpFlow(session, key, ack, reason) {
297
- this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, ack, 0x14);
298
- this.callbacks.onTcpClose({ key, destroy: true });
299
- this.natTable.delete(key);
300
- this.emit("tcp-deny", { key, reason });
301
- }
302
- handleTCP(segment, srcIP, dstIP) {
303
- const srcPort = segment.readUInt16BE(0);
304
- const dstPort = segment.readUInt16BE(2);
305
- const seq = segment.readUInt32BE(4);
306
- const ack = segment.readUInt32BE(8);
307
- const offset = (segment[12] >> 4) * 4;
308
- const flags = segment[13];
309
- const payload = segment.subarray(offset);
310
- const SYN = (flags & 0x02) !== 0;
311
- const FIN = (flags & 0x01) !== 0;
312
- const RST = (flags & 0x04) !== 0;
313
- const key = `TCP:${srcIP.join(".")}:${srcPort}:${dstIP.join(".")}:${dstPort}`;
314
- let session = this.natTable.get(key);
315
- if (RST) {
316
- if (session) {
317
- this.callbacks.onTcpClose({ key, destroy: true });
318
- this.natTable.delete(key);
319
- }
320
- return;
321
- }
322
- if (SYN && !session) {
323
- session = {
324
- state: "SYN_SENT",
325
- srcIP: Buffer.from(srcIP),
326
- srcPort,
327
- dstIP: Buffer.from(dstIP),
328
- dstPort,
329
- vmSeq: seq,
330
- vmAck: ack,
331
- mySeq: Math.floor(Math.random() * 0x0fffffff),
332
- myAck: seq + 1,
333
- flowProtocol: null,
334
- pendingData: Buffer.alloc(0),
335
- };
336
- this.natTable.set(key, session);
337
- this.callbacks.onTcpConnect({
338
- key,
339
- dstIP: dstIP.join("."),
340
- dstPort,
341
- srcIP: srcIP.join("."),
342
- srcPort,
343
- });
344
- return;
345
- }
346
- if (!session) {
347
- if (!SYN) {
348
- this.sendTCP(srcIP, srcPort, dstIP, dstPort, 0, seq + (payload.length || 1), 0x04);
349
- }
350
- return;
351
- }
352
- if (payload.length > 0) {
353
- let sendBuffer = null;
354
- const nextAck = session.myAck + payload.length;
355
- if (!session.flowProtocol) {
356
- session.pendingData = Buffer.concat([session.pendingData, payload]);
357
- const classification = this.classifyTcpFlow(session.pendingData);
358
- if (classification.status === "need-more") {
359
- if (session.pendingData.length >= this.MAX_FLOW_SNIFF) {
360
- this.rejectTcpFlow(session, key, nextAck, "sniff-limit-exceeded");
361
- return;
362
- }
363
- }
364
- else if (classification.status === "deny") {
365
- this.rejectTcpFlow(session, key, nextAck, classification.reason);
366
- return;
367
- }
368
- else if (classification.status === "http") {
369
- if (classification.isConnect) {
370
- this.rejectTcpFlow(session, key, nextAck, "connect-not-allowed");
371
- return;
372
- }
373
- session.flowProtocol = "http";
374
- session.httpMethod = classification.method;
375
- }
376
- else if (classification.status === "tls") {
377
- session.flowProtocol = "tls";
378
- }
379
- if (session.flowProtocol) {
380
- const allowed = this.allowTcpFlow({
381
- key,
382
- srcIP: session.srcIP.join("."),
383
- srcPort: session.srcPort,
384
- dstIP: session.dstIP.join("."),
385
- dstPort: session.dstPort,
386
- protocol: session.flowProtocol,
387
- httpMethod: session.httpMethod,
388
- });
389
- if (!allowed) {
390
- this.rejectTcpFlow(session, key, nextAck, "policy-deny");
391
- return;
392
- }
393
- sendBuffer = session.pendingData;
394
- session.pendingData = Buffer.alloc(0);
395
- }
396
- }
397
- else {
398
- sendBuffer = payload;
399
- }
400
- session.vmSeq += payload.length;
401
- session.myAck = nextAck;
402
- if (sendBuffer && sendBuffer.length > 0) {
403
- this.callbacks.onTcpSend({ key, data: Buffer.from(sendBuffer) });
404
- }
405
- this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x10);
406
- }
407
- if (FIN) {
408
- this.callbacks.onTcpClose({ key, destroy: false });
409
- session.myAck++;
410
- this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x10);
411
- if (session.state === "CLOSED_BY_REMOTE" || session.state === "FIN_WAIT") {
412
- this.natTable.delete(key);
413
- }
414
- else {
415
- session.state = "FIN_SENT";
416
- }
417
- }
418
- }
419
- sendTCP(dstIP, dstPort, srcIP, srcPort, seq, ack, flags, payload = Buffer.alloc(0)) {
420
- const header = Buffer.alloc(20);
421
- header.writeUInt16BE(srcPort, 0);
422
- header.writeUInt16BE(dstPort, 2);
423
- header.writeUInt32BE(seq, 4);
424
- header.writeUInt32BE(ack, 8);
425
- header[12] = 0x50;
426
- header[13] = flags;
427
- header.writeUInt16BE(65535, 14);
428
- header.writeUInt16BE(0, 16);
429
- header.writeUInt16BE(0, 18);
430
- const pseudo = Buffer.alloc(12);
431
- srcIP.copy(pseudo, 0);
432
- dstIP.copy(pseudo, 4);
433
- pseudo[8] = 0;
434
- pseudo[9] = IP_PROTO_TCP;
435
- pseudo.writeUInt16BE(20 + payload.length, 10);
436
- const ckData = Buffer.concat([pseudo, header, payload]);
437
- const ck = this.calculateChecksum(ckData);
438
- header.writeUInt16BE(ck, 16);
439
- this.sendIP(Buffer.concat([header, payload]), IP_PROTO_TCP, srcIP, dstIP);
440
- }
441
- handleUDP(segment, srcIP, dstIP) {
442
- const srcPort = segment.readUInt16BE(0);
443
- const dstPort = segment.readUInt16BE(2);
444
- const payload = segment.subarray(8);
445
- if (srcPort === DHCP_CLIENT_PORT && dstPort === DHCP_SERVER_PORT) {
446
- this.handleDHCP(payload);
447
- return;
448
- }
449
- const key = `UDP:${srcIP.join(".")}:${srcPort}:${dstIP.join(".")}:${dstPort}`;
450
- this.callbacks.onUdpSend({
451
- key,
452
- dstIP: dstIP.join("."),
453
- dstPort,
454
- srcIP: srcIP.join("."),
455
- srcPort,
456
- payload: Buffer.from(payload),
457
- });
458
- }
459
- handleDHCP(data) {
460
- if (data.length < 240)
461
- return;
462
- const op = data[0];
463
- if (op !== 1)
464
- return;
465
- const xid = data.readUInt32BE(4);
466
- const flags = data.readUInt16BE(10);
467
- const chaddr = data.subarray(28, 28 + 16);
468
- const magic = data.readUInt32BE(236);
469
- if (magic !== DHCP_MAGIC_COOKIE)
470
- return;
471
- let msgType = 0;
472
- let i = 240;
473
- while (i < data.length) {
474
- const opt = data[i];
475
- if (opt === DHCP_OPT_END)
476
- break;
477
- if (opt === 0) {
478
- i += 1;
479
- continue;
480
- }
481
- const len = data[i + 1];
482
- const optData = data.subarray(i + 2, i + 2 + len);
483
- if (opt === DHCP_OPT_MSG_TYPE && len >= 1) {
484
- msgType = optData[0];
485
- }
486
- else if (opt === DHCP_OPT_REQUESTED_IP) {
487
- // ignored
488
- }
489
- i += 2 + len;
490
- }
491
- if (msgType === DHCP_DISCOVER) {
492
- this.sendDHCPReply(DHCP_OFFER, xid, chaddr, flags);
493
- }
494
- else if (msgType === DHCP_REQUEST) {
495
- this.sendDHCPReply(DHCP_ACK, xid, chaddr, flags);
496
- }
497
- }
498
- sendDHCPReply(msgType, xid, chaddr, flags) {
499
- const reply = Buffer.alloc(300);
500
- reply[0] = 2;
501
- reply[1] = 1;
502
- reply[2] = 6;
503
- reply[3] = 0;
504
- reply.writeUInt32BE(xid, 4);
505
- reply.writeUInt16BE(0, 8);
506
- reply.writeUInt16BE(flags, 10);
507
- const vmIPParts = this.vmIP.split(".").map(Number);
508
- reply[16] = vmIPParts[0];
509
- reply[17] = vmIPParts[1];
510
- reply[18] = vmIPParts[2];
511
- reply[19] = vmIPParts[3];
512
- const gwIPParts = this.gatewayIP.split(".").map(Number);
513
- reply[20] = gwIPParts[0];
514
- reply[21] = gwIPParts[1];
515
- reply[22] = gwIPParts[2];
516
- reply[23] = gwIPParts[3];
517
- chaddr.copy(reply, 28);
518
- reply.writeUInt32BE(DHCP_MAGIC_COOKIE, 236);
519
- let optOffset = 240;
520
- reply[optOffset++] = DHCP_OPT_MSG_TYPE;
521
- reply[optOffset++] = 1;
522
- reply[optOffset++] = msgType;
523
- reply[optOffset++] = DHCP_OPT_SERVER_ID;
524
- reply[optOffset++] = 4;
525
- reply[optOffset++] = gwIPParts[0];
526
- reply[optOffset++] = gwIPParts[1];
527
- reply[optOffset++] = gwIPParts[2];
528
- reply[optOffset++] = gwIPParts[3];
529
- reply[optOffset++] = DHCP_OPT_LEASE_TIME;
530
- reply[optOffset++] = 4;
531
- reply.writeUInt32BE(86400, optOffset);
532
- optOffset += 4;
533
- reply[optOffset++] = DHCP_OPT_SUBNET_MASK;
534
- reply[optOffset++] = 4;
535
- reply[optOffset++] = 255;
536
- reply[optOffset++] = 255;
537
- reply[optOffset++] = 255;
538
- reply[optOffset++] = 0;
539
- reply[optOffset++] = DHCP_OPT_ROUTER;
540
- reply[optOffset++] = 4;
541
- reply[optOffset++] = gwIPParts[0];
542
- reply[optOffset++] = gwIPParts[1];
543
- reply[optOffset++] = gwIPParts[2];
544
- reply[optOffset++] = gwIPParts[3];
545
- reply[optOffset++] = DHCP_OPT_DNS;
546
- reply[optOffset++] = 4;
547
- reply[optOffset++] = 8;
548
- reply[optOffset++] = 8;
549
- reply[optOffset++] = 8;
550
- reply[optOffset++] = 8;
551
- reply[optOffset++] = 28; // DHCP_OPT_BROADCAST
552
- reply[optOffset++] = 4;
553
- reply[optOffset++] = vmIPParts[0];
554
- reply[optOffset++] = vmIPParts[1];
555
- reply[optOffset++] = vmIPParts[2];
556
- reply[optOffset++] = 255;
557
- reply[optOffset++] = DHCP_OPT_END;
558
- const dhcpLen = 300;
559
- const udpLen = 8 + dhcpLen;
560
- const udpHeader = Buffer.alloc(8);
561
- udpHeader.writeUInt16BE(DHCP_SERVER_PORT, 0);
562
- udpHeader.writeUInt16BE(DHCP_CLIENT_PORT, 2);
563
- udpHeader.writeUInt16BE(udpLen, 4);
564
- udpHeader.writeUInt16BE(0, 6);
565
- const udpPayload = Buffer.concat([udpHeader, reply]);
566
- const srcIP = Buffer.from(gwIPParts);
567
- const dstIP = Buffer.from([255, 255, 255, 255]);
568
- const ipHeader = Buffer.alloc(20);
569
- ipHeader[0] = 0x45;
570
- ipHeader[1] = 0;
571
- ipHeader.writeUInt16BE(20 + udpPayload.length, 2);
572
- ipHeader.writeUInt16BE(0, 4);
573
- ipHeader.writeUInt16BE(0, 6);
574
- ipHeader[8] = 64;
575
- ipHeader[9] = IP_PROTO_UDP;
576
- srcIP.copy(ipHeader, 12);
577
- dstIP.copy(ipHeader, 16);
578
- ipHeader.writeUInt16BE(this.calculateChecksum(ipHeader), 10);
579
- const ipPacket = Buffer.concat([ipHeader, udpPayload]);
580
- const dstMac = flags & 0x8000 ? Buffer.from([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]) : chaddr.subarray(0, 6);
581
- const frame = Buffer.alloc(14 + ipPacket.length);
582
- dstMac.copy(frame, 0);
583
- this.gatewayMac.copy(frame, 6);
584
- frame.writeUInt16BE(ETH_P_IP, 12);
585
- ipPacket.copy(frame, 14);
586
- const header = Buffer.alloc(4);
587
- header.writeUInt32BE(frame.length, 0);
588
- this.txBuffer = Buffer.concat([this.txBuffer, header, frame]);
589
- this.emit("network-activity");
590
- this.emit("dhcp", msgType === DHCP_OFFER ? "OFFER" : "ACK", this.vmIP);
591
- }
592
- handleUdpResponse(message) {
593
- const { data, srcIP, srcPort, dstIP, dstPort } = message;
594
- const udpHeader = Buffer.alloc(8);
595
- udpHeader.writeUInt16BE(dstPort, 0);
596
- udpHeader.writeUInt16BE(srcPort, 2);
597
- udpHeader.writeUInt16BE(8 + data.length, 4);
598
- udpHeader.writeUInt16BE(0, 6);
599
- const dstIPBuf = Buffer.from(dstIP.split(".").map(Number));
600
- const srcIPBuf = Buffer.from(srcIP.split(".").map(Number));
601
- const payload = Buffer.concat([udpHeader, Buffer.from(data)]);
602
- const checksum = this.calculateUdpChecksum(payload, dstIPBuf, srcIPBuf);
603
- udpHeader.writeUInt16BE(checksum, 6);
604
- const withChecksum = Buffer.concat([udpHeader, Buffer.from(data)]);
605
- this.sendIP(withChecksum, IP_PROTO_UDP, dstIPBuf, srcIPBuf);
606
- }
607
- handleTcpConnected(message) {
608
- const session = this.natTable.get(message.key);
609
- if (!session)
610
- return;
611
- session.state = "ESTABLISHED";
612
- this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x12);
613
- session.mySeq++;
614
- }
615
- handleTcpData(message) {
616
- const session = this.natTable.get(message.key);
617
- if (!session)
618
- return;
619
- const payload = Buffer.from(message.data);
620
- const MSS = 1460;
621
- let offset = 0;
622
- while (offset < payload.length) {
623
- const chunkSize = Math.min(MSS, payload.length - offset);
624
- const chunk = payload.subarray(offset, offset + chunkSize);
625
- const isLast = offset + chunkSize >= payload.length;
626
- const flags = isLast ? 0x18 : 0x10;
627
- this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, flags, chunk);
628
- session.mySeq += chunk.length;
629
- offset += chunkSize;
630
- }
631
- if (this.txBuffer.length > this.TX_BUFFER_HIGH_WATER && !this.txPaused.has(message.key)) {
632
- this.txPaused.add(message.key);
633
- this.callbacks.onTcpPause({ key: message.key });
634
- }
635
- }
636
- handleTcpEnd(message) {
637
- const session = this.natTable.get(message.key);
638
- if (!session)
639
- return;
640
- this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x11);
641
- session.mySeq++;
642
- session.state = "FIN_WAIT";
643
- }
644
- handleTcpError(message) {
645
- const session = this.natTable.get(message.key);
646
- if (!session)
647
- return;
648
- this.sendTCP(session.srcIP, session.srcPort, session.dstIP, session.dstPort, session.mySeq, session.myAck, 0x04);
649
- this.natTable.delete(message.key);
650
- }
651
- handleTcpClosed(message) {
652
- const session = this.natTable.get(message.key);
653
- if (session) {
654
- session.state = "CLOSED_BY_REMOTE";
655
- }
656
- }
657
- }
658
- exports.NetworkStack = NetworkStack;
package/dist/policy.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });