| 518 | } |
| 519 | |
| 520 | handleTCP(segment, srcIP, dstIP, fullIPPacket) { |
| 521 | const srcPort = segment.readUInt16BE(0); |
| 522 | const dstPort = segment.readUInt16BE(2); |
| 523 | const seq = segment.readUInt32BE(4); |
| 524 | const ack = segment.readUInt32BE(8); |
| 525 | const offset = (segment[12] >> 4) * 4; |
| 526 | const flags = segment[13]; |
| 527 | const payload = segment.subarray(offset); |
| 528 | |
| 529 | const SYN = (flags & 0x02) !== 0; |
| 530 | const ACK = (flags & 0x10) !== 0; |
| 531 | const PSH = (flags & 0x08) !== 0; |
| 532 | const FIN = (flags & 0x01) !== 0; |
| 533 | const RST = (flags & 0x04) !== 0; |
| 534 | |
| 535 | const key = `TCP:${srcIP.join('.')}:${srcPort}:${dstIP.join('.')}:${dstPort}`; |
| 536 | let session = this.natTable.get(key); |
| 537 | |
| 538 | if (RST) { |
| 539 | if (session) { |
| 540 | // Tell main thread to destroy the socket |
| 541 | if (this.netPort) { |
| 542 | this.netPort.postMessage({ type: 'tcp-close', key, destroy: true }); |
| 543 | } |
| 544 | this.natTable.delete(key); |
| 545 | // Clean up flow control state |
| 546 | this.txPaused.delete(key); |
| 547 | } |
| 548 | return; |
| 549 | } |
| 550 | |
| 551 | if (SYN && !session) { |
| 552 | // New Connection - create session state and tell main thread to connect |
| 553 | session = { |
| 554 | state: 'SYN_SENT', |
| 555 | srcIP: Buffer.from(srcIP), |
| 556 | srcPort, |
| 557 | dstIP: Buffer.from(dstIP), |
| 558 | dstPort, |
| 559 | vmSeq: seq, |
| 560 | vmAck: ack, |
| 561 | mySeq: Math.floor(Math.random() * 0xFFFFFFF), |
| 562 | myAck: seq + 1 |
| 563 | }; |
| 564 | this.natTable.set(key, session); |
| 565 | |
| 566 | // Request connection via main thread |
| 567 | if (this.netPort) { |
| 568 | this.netPort.postMessage({ |
| 569 | type: 'tcp-connect', |
| 570 | key, |
| 571 | dstIP: dstIP.join('.'), |
| 572 | dstPort, |
| 573 | srcIP: srcIP.join('.'), |
| 574 | srcPort |
| 575 | }); |
| 576 | } |
| 577 | return; |