feat(core): TCP in the simulation core
engine.ts ports Swift's "Java-compatible TCP sockets" in one piece, since half a state machine could not be checked: server and client sockets (a free port from Java's random numbers on their own seed), the three-way handshake with its result (connected, invalid socket, unreachable, timed out), segments of 1460 bytes, messages up to the push, a timeout of 3 × 2.5 s with at most three attempts, closing through every Java state including TIME_WAIT (2.5 s), sequence numbers modulo 2^32. Three scenarios match the Swift engine trace for trace: a LAN with data over three segments, closing from both ends, a closed port and an unreachable host; two networks through a router with a firewall rule, data lost until the connection closes, and an accepted socket that does not hold the port of its closed listener; CLOSING, reached by a lost FIN. The engine delivers a FIN within the same close, so both ends close at once only with packet loss; an empty message does not arrive in Swift (it does not advance the sequence number), nor here. Swift's four TCP engine tests are ported, with tests for stopping, a foreign SYN+ACK at a listener and the flag names. 17 mutation probes, 16 caught; the other (delivered, not waited, not connected gives unreachable) cannot be reached through Swift's engine, which never sends a reset and always acknowledges correctly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// Ported from filius-ipad ios/FiliusPadTests/TopologyNetworkRuntimeEngineTests.swift:
|
||||
// the event queue, the virtual clock, Java-compatible randomness, restart,
|
||||
// Ethernet/switch/ARP/IPv4/ICMP, routing errors, the firewall, packet loss
|
||||
// and trace retention, UDP sockets. The remaining Swift tests (TCP, DHCP,
|
||||
// and trace retention, UDP and TCP sockets. The remaining Swift tests (DHCP,
|
||||
// DNS, RIP, NAT, remote link, packet viewer) follow with their protocol
|
||||
// slices.
|
||||
|
||||
@@ -21,6 +21,8 @@ import {
|
||||
stableMacAddress,
|
||||
switchConfiguration,
|
||||
TCP_FLAG,
|
||||
TCP_ROUND_TRIP_TIME_MILLISECONDS,
|
||||
tcpFlagDescription,
|
||||
topologySnapshot,
|
||||
traceRetentionPolicy,
|
||||
UNSPECIFIED_MAC_ADDRESS,
|
||||
@@ -209,6 +211,25 @@ describe('event queue and virtual clock', () => {
|
||||
engine.handle({ type: 'start', snapshot: topologySnapshot(input), seed: 14, initialTimeMilliseconds: 0 });
|
||||
expect(engine.bindUdpSocket(nodeId, { localPort: 7 })).toBe(uuid(1));
|
||||
});
|
||||
|
||||
it('forgets TCP sessions and accepted sockets on stop', () => {
|
||||
const [clientId, clientPortId, serverId, serverPortId] = [0x21, 0x22, 0x23, 0x24].map(uuid) as [string, string, string, string];
|
||||
const engine = startedEngine({
|
||||
nodes: [pc(clientId, clientPortId), pc(serverId, serverPortId)],
|
||||
links: [link(clientId, clientPortId, serverId, serverPortId)],
|
||||
deviceConfigurations: new Map([
|
||||
[clientId, device('10.3.0.1')],
|
||||
[serverId, device('10.3.0.2')],
|
||||
]),
|
||||
});
|
||||
engine.openTcpServerSocket(serverId, 80);
|
||||
expect(engine.connectTcp(engine.openTcpClientSocket(clientId, '10.3.0.2', 80)!)).toBe(true);
|
||||
expect(engine.state.tcpSessionsById.size).toBe(3);
|
||||
|
||||
engine.handle({ type: 'stop' });
|
||||
expect(engine.state.tcpSessionsById.size).toBe(0);
|
||||
expect(engine.state.tcpAcceptedSocketIdsByListenerId.size).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('UDP sockets', () => {
|
||||
@@ -738,3 +759,111 @@ describe('packet loss and trace retention', () => {
|
||||
expect(engine.state.nextTraceIdentity).toBe(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TCP sockets', () => {
|
||||
/** Two PCs on one cable, started. */
|
||||
const pair = (first: number, second: number, prefix: string) => {
|
||||
const [clientId, clientPortId, serverId, serverPortId] = [first, first + 0x10, second, second + 0x10].map(uuid) as [
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
string,
|
||||
];
|
||||
const engine = startedEngine({
|
||||
nodes: [pc(clientId, clientPortId), pc(serverId, serverPortId)],
|
||||
links: [link(clientId, clientPortId, serverId, serverPortId)],
|
||||
deviceConfigurations: new Map([
|
||||
[clientId, device(`${prefix}.1`)],
|
||||
[serverId, device(`${prefix}.2`)],
|
||||
]),
|
||||
});
|
||||
return { engine, clientId, serverId };
|
||||
};
|
||||
|
||||
it('makes an established client and an accepted server socket with the three-way handshake', () => {
|
||||
const { engine, clientId, serverId } = pair(0x1701, 0x1702, '10.17.0');
|
||||
const listenerId = engine.openTcpServerSocket(serverId, 8080)!;
|
||||
const clientSocketId = engine.openTcpClientSocket(clientId, '10.17.0.2', 8080)!;
|
||||
|
||||
expect(engine.connectTcp(clientSocketId)).toBe(true);
|
||||
const acceptedSocketId = engine.state.tcpAcceptedSocketIdsByListenerId.get(listenerId)![0]!;
|
||||
expect(engine.state.socketsById.get(clientSocketId)?.tcpState).toBe('ESTABLISHED');
|
||||
expect(engine.state.socketsById.get(acceptedSocketId)?.tcpState).toBe('ESTABLISHED');
|
||||
expect(engine.state.packetTraces.some((trace) => trace.detail === 'TCP SYN_SENT -> ESTABLISHED')).toBe(true);
|
||||
expect(engine.state.packetTraces.some((trace) => trace.detail === 'TCP SYN_RCVD -> ESTABLISHED')).toBe(true);
|
||||
});
|
||||
|
||||
it("sends segments of Java's MSS and reassembles one message up to the push", () => {
|
||||
const { engine, clientId, serverId } = pair(0x1721, 0x1722, '10.18.0');
|
||||
const listenerId = engine.openTcpServerSocket(serverId, 8081)!;
|
||||
const clientSocketId = engine.openTcpClientSocket(clientId, '10.18.0.2', 8081)!;
|
||||
expect(engine.connectTcp(clientSocketId)).toBe(true);
|
||||
const acceptedSocketId = engine.state.tcpAcceptedSocketIdsByListenerId.get(listenerId)![0]!;
|
||||
const payload = Uint8Array.from({ length: 3_001 }, (_, index) => index % 251);
|
||||
|
||||
expect(engine.sendTcp(clientSocketId, payload)).toBe(true);
|
||||
expect(engine.receiveTcp(acceptedSocketId)).toEqual(payload);
|
||||
const payloadLengths = engine.state.packetTraces
|
||||
.filter((trace) => trace.detail?.startsWith('TCP data') === true)
|
||||
.map((trace) => Number(trace.afterHeaders.find((header) => header.name === 'payloadLength')?.value));
|
||||
expect(payloadLengths).toEqual([1_460, 1_460, 81]);
|
||||
});
|
||||
|
||||
it('retransmits a connection attempt at most three times and releases the port', () => {
|
||||
const clientId = uuid(0x1741);
|
||||
const engine = startedEngine({ nodes: [pc(clientId, uuid(0x1751))], links: [], deviceConfigurations: new Map([[clientId, device('10.19.0.1')]]) });
|
||||
const socketId = engine.openTcpClientSocket(clientId, '10.19.0.99', 80)!;
|
||||
const localPort = engine.state.socketsById.get(socketId)!.localPort;
|
||||
|
||||
expect(engine.connectTcp(socketId)).toBe(false);
|
||||
expect(engine.state.tcpSessionsById.get(socketId)?.sendAttempts).toBe(3);
|
||||
expect(engine.state.socketsById.get(socketId)?.tcpState).toBe('CLOSED');
|
||||
expect(engine.isTcpPortReserved(clientId, localPort)).toBe(false);
|
||||
expect(engine.state.packetTraces.filter((trace) => trace.detail?.includes('TCP SYN retransmission') === true)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('drops a SYN+ACK at a listening port with no connection of its own', () => {
|
||||
const { engine, clientId, serverId } = pair(0x1781, 0x1782, '10.21.0');
|
||||
const listenerId = engine.openTcpServerSocket(serverId, 7000)!;
|
||||
const segment = { sourcePort: 80, destinationPort: 7000, sequenceNumber: 5, acknowledgementNumber: 9, flags: TCP_FLAG.synchronize | TCP_FLAG.acknowledgement, payload: new Uint8Array() };
|
||||
engine.sendIPv4Packet(clientId, {
|
||||
identity: engine.allocatePacketIdentity(),
|
||||
senderIPAddress: '10.21.0.1',
|
||||
receiverIPAddress: '10.21.0.2',
|
||||
timeToLive: 64,
|
||||
protocol: 'tcp',
|
||||
payload: { kind: 'tcp', segment },
|
||||
});
|
||||
engine.handle({ type: 'advance', toMilliseconds: engine.state.currentTimeMilliseconds + 1_000 });
|
||||
|
||||
expect(engine.state.tcpAcceptedSocketIdsByListenerId.get(listenerId)).toEqual([]);
|
||||
expect(engine.state.packetTraces.some((trace) => trace.detail === 'TCP destination port closed')).toBe(true);
|
||||
});
|
||||
|
||||
it('names the flags of a segment in Swift\'s order', () => {
|
||||
expect(tcpFlagDescription(TCP_FLAG.acknowledgement | TCP_FLAG.push | TCP_FLAG.reset | TCP_FLAG.synchronize | TCP_FLAG.finish)).toBe(
|
||||
'FIN+SYN+RST+PSH+ACK',
|
||||
);
|
||||
expect(tcpFlagDescription(TCP_FLAG.synchronize | TCP_FLAG.acknowledgement)).toBe('SYN+ACK');
|
||||
expect(tcpFlagDescription(0)).toBe('');
|
||||
});
|
||||
|
||||
it("closes with Java's FIN states, and TIME_WAIT releases both ends", () => {
|
||||
const { engine, clientId, serverId } = pair(0x1761, 0x1762, '10.20.0');
|
||||
const listenerId = engine.openTcpServerSocket(serverId, 9090)!;
|
||||
const clientSocketId = engine.openTcpClientSocket(clientId, '10.20.0.2', 9090)!;
|
||||
expect(engine.connectTcp(clientSocketId)).toBe(true);
|
||||
const serverSocketId = engine.state.tcpAcceptedSocketIdsByListenerId.get(listenerId)![0]!;
|
||||
|
||||
engine.closeTcpSocket(clientSocketId);
|
||||
expect(engine.state.socketsById.get(clientSocketId)?.tcpState).toBe('FIN_WAIT_2');
|
||||
expect(engine.state.socketsById.get(serverSocketId)?.tcpState).toBe('CLOSE_WAIT');
|
||||
engine.closeTcpSocket(serverSocketId);
|
||||
expect(engine.state.socketsById.get(clientSocketId)?.tcpState).toBe('TIME_WAIT');
|
||||
expect(engine.state.socketsById.get(serverSocketId)?.tcpState).toBe('CLOSED');
|
||||
|
||||
engine.handle({ type: 'advance', toMilliseconds: engine.state.currentTimeMilliseconds + TCP_ROUND_TRIP_TIME_MILLISECONDS });
|
||||
expect(engine.state.socketsById.get(clientSocketId)?.tcpState).toBe('CLOSED');
|
||||
expect(engine.state.socketsById.get(listenerId)?.tcpState).toBe('LISTEN');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,6 +75,9 @@ interface Scenario {
|
||||
socket?: string;
|
||||
payload?: string;
|
||||
timeout?: number;
|
||||
// TCP: the payload repeated this many times, for messages longer than a segment.
|
||||
repeatCount?: number;
|
||||
localPort?: number;
|
||||
}[];
|
||||
}
|
||||
|
||||
@@ -281,6 +284,37 @@ function run(scenario: Scenario): Record<string, unknown> {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'openTcpServer':
|
||||
results.push(engine.openTcpServerSocket(step.node!, step.port!, step.localIp) ?? null);
|
||||
break;
|
||||
case 'openTcpClient':
|
||||
results.push(
|
||||
engine.openTcpClientSocket(step.node!, step.target!, step.port!, {
|
||||
...(step.localIp === undefined ? {} : { localIPAddress: step.localIp }),
|
||||
...(step.localPort === undefined ? {} : { localPort: step.localPort }),
|
||||
}) ?? null,
|
||||
);
|
||||
break;
|
||||
case 'connectTcp':
|
||||
results.push(engine.connectTcpWithResult(step.socket!));
|
||||
break;
|
||||
case 'sendTcp':
|
||||
results.push(engine.sendTcp(step.socket!, new TextEncoder().encode((step.payload ?? '').repeat(step.repeatCount ?? 1))));
|
||||
break;
|
||||
case 'receiveTcp': {
|
||||
const message = engine.receiveTcp(step.socket!);
|
||||
results.push(message === undefined ? null : new TextDecoder().decode(message));
|
||||
break;
|
||||
}
|
||||
case 'acceptedTcp':
|
||||
results.push(engine.state.tcpAcceptedSocketIdsByListenerId.get(step.socket!) ?? []);
|
||||
break;
|
||||
case 'peerTcp':
|
||||
results.push(engine.peerTcpSocketId(step.socket!) ?? null);
|
||||
break;
|
||||
case 'cleanTcp':
|
||||
results.push(engine.cleanClosedTcpSocket(step.socket!));
|
||||
break;
|
||||
case 'closeSocket':
|
||||
engine.closeSocket(step.socket!);
|
||||
results.push(!engine.state.socketsById.has(step.socket!));
|
||||
@@ -316,6 +350,19 @@ function run(scenario: Scenario): Record<string, unknown> {
|
||||
remoteIp: socket.remoteIPAddress ?? null,
|
||||
remotePort: socket.remotePort ?? null,
|
||||
queued: state.udpReceiveQueuesBySocketId.get(socket.id)?.length ?? 0,
|
||||
tcpState: socket.tcpState ?? null,
|
||||
parent: socket.parentListenerSocketId === undefined ? null : upper(socket.parentListenerSocketId),
|
||||
session: ((session) =>
|
||||
session === undefined
|
||||
? null
|
||||
: {
|
||||
attempts: session.sendAttempts,
|
||||
next: session.nextSendSequenceNumber,
|
||||
remote: session.remoteSequenceNumber,
|
||||
pending: session.lastSentSegment !== undefined,
|
||||
assembly: session.receiveAssembly.length,
|
||||
messages: session.receivedMessages.length,
|
||||
})(state.tcpSessionsById.get(socket.id)),
|
||||
})),
|
||||
firewallDecisions: state.firewallDecisions.map((decision) => ({
|
||||
packet: decision.packetIdentity,
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
{
|
||||
"seed": 33,
|
||||
"nodes": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000101",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000111",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000102",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000112",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000103",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000113",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000104",
|
||||
"kind": "networkSwitch",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000121",
|
||||
"label": "sw1"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000122",
|
||||
"label": "sw2"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000123",
|
||||
"label": "sw3"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000124",
|
||||
"label": "sw4"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F001",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000101",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000111",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000104",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000121"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F002",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000102",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000112",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000104",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000122"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F003",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000103",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000113",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000104",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000123"
|
||||
}
|
||||
],
|
||||
"devices": {
|
||||
"00000000-0000-0000-0000-000000000101": {
|
||||
"ip": "192.168.0.10",
|
||||
"mask": "255.255.255.0"
|
||||
},
|
||||
"00000000-0000-0000-0000-000000000102": {
|
||||
"ip": "192.168.0.20",
|
||||
"mask": "255.255.255.0"
|
||||
},
|
||||
"00000000-0000-0000-0000-000000000103": {
|
||||
"ip": "192.168.0.30",
|
||||
"mask": "255.255.255.0"
|
||||
}
|
||||
},
|
||||
"switches": {
|
||||
"00000000-0000-0000-0000-000000000104": {
|
||||
"ssid": "lab",
|
||||
"retention": 5000
|
||||
}
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"op": "openTcpServer",
|
||||
"node": "00000000-0000-0000-0000-000000000101",
|
||||
"port": 7
|
||||
},
|
||||
{
|
||||
"op": "openTcpClient",
|
||||
"node": "00000000-0000-0000-0000-000000000102",
|
||||
"target": "192.168.0.10",
|
||||
"port": 7,
|
||||
"localIp": "192.168.0.20"
|
||||
},
|
||||
{
|
||||
"op": "connectTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "sendTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002",
|
||||
"payload": ""
|
||||
},
|
||||
{
|
||||
"op": "receiveTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000003"
|
||||
},
|
||||
{
|
||||
"op": "packetLoss",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"op": "closeSocket",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "packetLoss",
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"op": "closeSocket",
|
||||
"socket": "00000000-0000-0000-0000-000000000003"
|
||||
},
|
||||
{
|
||||
"op": "advance",
|
||||
"to": 30000
|
||||
},
|
||||
{
|
||||
"op": "openTcpClient",
|
||||
"node": "00000000-0000-0000-0000-000000000102",
|
||||
"target": "192.168.0.10",
|
||||
"port": 7,
|
||||
"localIp": "10.0.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"seed": 31,
|
||||
"nodes": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000101",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000111",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000102",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000112",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000103",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000113",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000104",
|
||||
"kind": "networkSwitch",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000121",
|
||||
"label": "sw1"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000122",
|
||||
"label": "sw2"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000123",
|
||||
"label": "sw3"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000124",
|
||||
"label": "sw4"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F001",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000101",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000111",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000104",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000121"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F002",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000102",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000112",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000104",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000122"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F003",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000103",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000113",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000104",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000123"
|
||||
}
|
||||
],
|
||||
"devices": {
|
||||
"00000000-0000-0000-0000-000000000101": {
|
||||
"ip": "192.168.0.10",
|
||||
"mask": "255.255.255.0"
|
||||
},
|
||||
"00000000-0000-0000-0000-000000000102": {
|
||||
"ip": "192.168.0.20",
|
||||
"mask": "255.255.255.0"
|
||||
},
|
||||
"00000000-0000-0000-0000-000000000103": {
|
||||
"ip": "192.168.0.30",
|
||||
"mask": "255.255.255.0"
|
||||
}
|
||||
},
|
||||
"switches": {
|
||||
"00000000-0000-0000-0000-000000000104": {
|
||||
"ssid": "lab",
|
||||
"retention": 5000
|
||||
}
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"op": "openTcpServer",
|
||||
"node": "00000000-0000-0000-0000-000000000101",
|
||||
"port": 80
|
||||
},
|
||||
{
|
||||
"op": "openTcpServer",
|
||||
"node": "00000000-0000-0000-0000-000000000101",
|
||||
"port": 80
|
||||
},
|
||||
{
|
||||
"op": "openTcpClient",
|
||||
"node": "00000000-0000-0000-0000-000000000102",
|
||||
"target": "192.168.0.10",
|
||||
"port": 80
|
||||
},
|
||||
{
|
||||
"op": "connectTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "acceptedTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000001"
|
||||
},
|
||||
{
|
||||
"op": "peerTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "sendTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002",
|
||||
"payload": "GET /"
|
||||
},
|
||||
{
|
||||
"op": "receiveTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000003"
|
||||
},
|
||||
{
|
||||
"op": "sendTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000003",
|
||||
"payload": "x",
|
||||
"repeatCount": 3000
|
||||
},
|
||||
{
|
||||
"op": "receiveTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "receiveTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "closeSocket",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "advance",
|
||||
"to": 3000
|
||||
},
|
||||
{
|
||||
"op": "closeSocket",
|
||||
"socket": "00000000-0000-0000-0000-000000000003"
|
||||
},
|
||||
{
|
||||
"op": "advance",
|
||||
"to": 4000
|
||||
},
|
||||
{
|
||||
"op": "advance",
|
||||
"to": 8000
|
||||
},
|
||||
{
|
||||
"op": "cleanTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000002"
|
||||
},
|
||||
{
|
||||
"op": "cleanTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000001"
|
||||
},
|
||||
{
|
||||
"op": "connectTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000001"
|
||||
},
|
||||
{
|
||||
"op": "openTcpClient",
|
||||
"node": "00000000-0000-0000-0000-000000000103",
|
||||
"target": "192.168.0.10",
|
||||
"port": 81
|
||||
},
|
||||
{
|
||||
"op": "sendTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000004",
|
||||
"payload": "ohne Verbindung"
|
||||
},
|
||||
{
|
||||
"op": "connectTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000004"
|
||||
},
|
||||
{
|
||||
"op": "openTcpClient",
|
||||
"node": "00000000-0000-0000-0000-000000000103",
|
||||
"target": "192.168.0.99",
|
||||
"port": 80,
|
||||
"localPort": 5000
|
||||
},
|
||||
{
|
||||
"op": "connectTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000005"
|
||||
},
|
||||
{
|
||||
"op": "closeSocket",
|
||||
"socket": "00000000-0000-0000-0000-000000000001"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,166 @@
|
||||
{
|
||||
"seed": 32,
|
||||
"nodes": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000201",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000211",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000202",
|
||||
"kind": "router",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000221",
|
||||
"label": "rt1"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000222",
|
||||
"label": "rt2"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000203",
|
||||
"kind": "pc",
|
||||
"ports": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-000000000213",
|
||||
"label": "eth0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F004",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000201",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000211",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000202",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000221"
|
||||
},
|
||||
{
|
||||
"id": "00000000-0000-0000-0000-00000000F005",
|
||||
"sourceNode": "00000000-0000-0000-0000-000000000202",
|
||||
"sourcePort": "00000000-0000-0000-0000-000000000222",
|
||||
"targetNode": "00000000-0000-0000-0000-000000000203",
|
||||
"targetPort": "00000000-0000-0000-0000-000000000213"
|
||||
}
|
||||
],
|
||||
"devices": {
|
||||
"00000000-0000-0000-0000-000000000201": {
|
||||
"ip": "10.0.0.2",
|
||||
"mask": "255.255.255.0",
|
||||
"gateway": "10.0.0.1"
|
||||
},
|
||||
"00000000-0000-0000-0000-000000000202": {
|
||||
"ip": "10.0.0.1",
|
||||
"mask": "255.255.255.0"
|
||||
},
|
||||
"00000000-0000-0000-0000-000000000203": {
|
||||
"ip": "20.0.0.2",
|
||||
"mask": "255.255.255.0",
|
||||
"gateway": "20.0.0.1"
|
||||
}
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"node": "00000000-0000-0000-0000-000000000202",
|
||||
"port": "00000000-0000-0000-0000-000000000221",
|
||||
"ip": "10.0.0.1",
|
||||
"mask": "255.255.255.0"
|
||||
},
|
||||
{
|
||||
"node": "00000000-0000-0000-0000-000000000202",
|
||||
"port": "00000000-0000-0000-0000-000000000222",
|
||||
"ip": "20.0.0.1",
|
||||
"mask": "255.255.255.0"
|
||||
}
|
||||
],
|
||||
"steps": [
|
||||
{
|
||||
"op": "openTcpServer",
|
||||
"node": "00000000-0000-0000-0000-000000000203",
|
||||
"port": 80
|
||||
},
|
||||
{
|
||||
"op": "openTcpServer",
|
||||
"node": "00000000-0000-0000-0000-000000000203",
|
||||
"port": 81
|
||||
},
|
||||
{
|
||||
"op": "openTcpClient",
|
||||
"node": "00000000-0000-0000-0000-000000000201",
|
||||
"target": "20.0.0.2",
|
||||
"port": 80
|
||||
},
|
||||
{
|
||||
"op": "connectTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000003"
|
||||
},
|
||||
{
|
||||
"op": "sendTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000003",
|
||||
"payload": "durch den Router"
|
||||
},
|
||||
{
|
||||
"op": "receiveTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000004"
|
||||
},
|
||||
{
|
||||
"op": "openTcpClient",
|
||||
"node": "00000000-0000-0000-0000-000000000201",
|
||||
"target": "20.0.0.2",
|
||||
"port": 81
|
||||
},
|
||||
{
|
||||
"op": "connectTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000005"
|
||||
},
|
||||
{
|
||||
"op": "packetLoss",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"op": "sendTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000003",
|
||||
"payload": "verloren"
|
||||
},
|
||||
{
|
||||
"op": "packetLoss",
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"op": "sendTcp",
|
||||
"socket": "00000000-0000-0000-0000-000000000003",
|
||||
"payload": "zu spaet"
|
||||
},
|
||||
{
|
||||
"op": "closeSocket",
|
||||
"socket": "00000000-0000-0000-0000-000000000001"
|
||||
},
|
||||
{
|
||||
"op": "openTcpServer",
|
||||
"node": "00000000-0000-0000-0000-000000000203",
|
||||
"port": 80
|
||||
}
|
||||
],
|
||||
"firewalls": {
|
||||
"00000000-0000-0000-0000-000000000202": {
|
||||
"active": true,
|
||||
"defaultPolicy": "accept",
|
||||
"rules": [
|
||||
{
|
||||
"protocol": "tcp",
|
||||
"port": 81,
|
||||
"action": "drop"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -84,30 +84,39 @@
|
||||
"localIp" : null,
|
||||
"localPort" : 51180,
|
||||
"node" : "00000000-0000-0000-0000-000000000102",
|
||||
"parent" : null,
|
||||
"protocol" : "udp",
|
||||
"queued" : 0,
|
||||
"remoteIp" : "192.168.0.10",
|
||||
"remotePort" : 5000
|
||||
"remotePort" : 5000,
|
||||
"session" : null,
|
||||
"tcpState" : null
|
||||
},
|
||||
{
|
||||
"id" : "00000000-0000-0000-0000-000000000003",
|
||||
"localIp" : "192.168.0.30",
|
||||
"localPort" : 7000,
|
||||
"node" : "00000000-0000-0000-0000-000000000103",
|
||||
"parent" : null,
|
||||
"protocol" : "udp",
|
||||
"queued" : 0,
|
||||
"remoteIp" : null,
|
||||
"remotePort" : null
|
||||
"remotePort" : null,
|
||||
"session" : null,
|
||||
"tcpState" : null
|
||||
},
|
||||
{
|
||||
"id" : "00000000-0000-0000-0000-000000000004",
|
||||
"localIp" : null,
|
||||
"localPort" : 5000,
|
||||
"node" : "00000000-0000-0000-0000-000000000101",
|
||||
"parent" : null,
|
||||
"protocol" : "udp",
|
||||
"queued" : 0,
|
||||
"remoteIp" : null,
|
||||
"remotePort" : null
|
||||
"remotePort" : null,
|
||||
"session" : null,
|
||||
"tcpState" : null
|
||||
}
|
||||
],
|
||||
"switchTables" : {
|
||||
|
||||
@@ -96,40 +96,52 @@
|
||||
"localIp" : null,
|
||||
"localPort" : 5000,
|
||||
"node" : "00000000-0000-0000-0000-000000000203",
|
||||
"parent" : null,
|
||||
"protocol" : "udp",
|
||||
"queued" : 0,
|
||||
"remoteIp" : "10.0.0.2",
|
||||
"remotePort" : 54899
|
||||
"remotePort" : 54899,
|
||||
"session" : null,
|
||||
"tcpState" : null
|
||||
},
|
||||
{
|
||||
"id" : "00000000-0000-0000-0000-000000000002",
|
||||
"localIp" : null,
|
||||
"localPort" : 5001,
|
||||
"node" : "00000000-0000-0000-0000-000000000203",
|
||||
"parent" : null,
|
||||
"protocol" : "udp",
|
||||
"queued" : 0,
|
||||
"remoteIp" : null,
|
||||
"remotePort" : null
|
||||
"remotePort" : null,
|
||||
"session" : null,
|
||||
"tcpState" : null
|
||||
},
|
||||
{
|
||||
"id" : "00000000-0000-0000-0000-000000000003",
|
||||
"localIp" : null,
|
||||
"localPort" : 54899,
|
||||
"node" : "00000000-0000-0000-0000-000000000201",
|
||||
"parent" : null,
|
||||
"protocol" : "udp",
|
||||
"queued" : 0,
|
||||
"remoteIp" : "20.0.0.2",
|
||||
"remotePort" : 5000
|
||||
"remotePort" : 5000,
|
||||
"session" : null,
|
||||
"tcpState" : null
|
||||
},
|
||||
{
|
||||
"id" : "00000000-0000-0000-0000-000000000004",
|
||||
"localIp" : null,
|
||||
"localPort" : 5000,
|
||||
"node" : "00000000-0000-0000-0000-000000000202",
|
||||
"parent" : null,
|
||||
"protocol" : "udp",
|
||||
"queued" : 0,
|
||||
"remoteIp" : "10.0.0.2",
|
||||
"remotePort" : 54899
|
||||
"remotePort" : 54899,
|
||||
"session" : null,
|
||||
"tcpState" : null
|
||||
}
|
||||
],
|
||||
"switchTables" : {
|
||||
|
||||
Reference in New Issue
Block a user