Skip to content

Commit 5d20654

Browse files
Debug and improve ARP-related functionality (#266)
Co-authored-by: Tomás Grüner <[email protected]>
1 parent 3272f12 commit 5d20654

File tree

17 files changed

+132
-83
lines changed

17 files changed

+132
-83
lines changed

src/graphics/renderables/packet_info.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ export class PacketInfo extends BaseInfo {
108108
private addToggleInfo(): void {
109109
const packetDetails = this.packet.getPacketDetails(
110110
this.packet.viewgraph.getLayer(),
111-
this.packet.rawPacket,
112111
);
113112

114113
const toggleInfo = new ToggleInfo({

src/packets/arp.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { IpAddress } from "./ip";
22
import { ARP_PROTOCOL_TYPE, FramePayload, MacAddress } from "./ethernet";
33
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";
4+
import { Layer } from "../types/layer";
45

56
const ETHERNET_HTYPE = 1;
67
const IPv4_PTYPE = 0x0800;
@@ -92,6 +93,21 @@ export abstract class ArpPacket implements FramePayload {
9293
return `ARP-${this.type}`;
9394
}
9495

96+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
97+
getPayload(layer: Layer): Record<string, string | number | object> {
98+
return {
99+
[TOOLTIP_KEYS.HTYPE]: this.htype,
100+
[TOOLTIP_KEYS.PTYPE]: this.ptype,
101+
[TOOLTIP_KEYS.HLEN]: this.hlen,
102+
[TOOLTIP_KEYS.PLEN]: this.plen,
103+
[TOOLTIP_KEYS.OP]: this.op,
104+
[TOOLTIP_KEYS.SHA]: this.sha.toString(),
105+
[TOOLTIP_KEYS.SPA]: this.spa.toString(),
106+
[TOOLTIP_KEYS.THA]: this.tha.toString(),
107+
[TOOLTIP_KEYS.TPA]: this.tpa.toString(),
108+
};
109+
}
110+
95111
// eslint-disable-next-line
96112
getDetails(_layer: number): Record<string, string | number | object> {
97113
return {

src/packets/ethernet.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { CRC32 } from "@tsxper/crc32";
22
import { Layer } from "../types/layer";
3+
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";
34

45
// From https://en.wikipedia.org/wiki/EtherType
56
export const IP_PROTOCOL_TYPE = 0x0800;
@@ -176,12 +177,15 @@ export class EthernetFrame {
176177
getDetails(layer: Layer) {
177178
if (layer == Layer.Link) {
178179
const ethernetDetails = {
179-
EtherType: this.type.toString(),
180+
[TOOLTIP_KEYS.ETHERTYPE]: this.type.toString(),
181+
[TOOLTIP_KEYS.SOURCE_MAC_ADDRESS]: this.source.toString(),
182+
[TOOLTIP_KEYS.DESTINATION_MAC_ADDRESS]: this.destination.toString(),
183+
[TOOLTIP_KEYS.CRC]: this.crc.toString(16).padStart(8, "0"),
180184
};
181185
// Merge Ethernet details with payload details
182186
return {
183187
...ethernetDetails,
184-
...this.payload.getDetails(layer),
188+
Payload: this.payload.getPayload(layer),
185189
};
186190
} else {
187191
return this.payload.getDetails(layer);
@@ -196,6 +200,8 @@ export interface FramePayload {
196200
type(): number;
197201
// Get details of the payload
198202
getDetails(layer: Layer): Record<string, string | number | object>;
203+
// Get payload data for Link layer
204+
getPayload(layer: Layer): Record<string, string | number | object> | string;
199205
}
200206

201207
export function compareMacs(mac1: MacAddress, mac2: MacAddress): number {

src/packets/ip.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { FramePayload, IP_PROTOCOL_TYPE } from "./ethernet";
22
import { Layer } from "../types/layer";
3+
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";
4+
import { TcpSegment, TcpSegmentToBytesProps } from "./tcp";
35

46
// Taken from here: https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
57
export const ICMP_PROTOCOL_NUMBER = 1;
@@ -175,7 +177,7 @@ export interface IpPayload {
175177
// Length of the payload in bytes
176178
byteLength(): number;
177179
// The bytes equivalent of the payload
178-
toBytes(): Uint8Array;
180+
toBytes(tcpToBytesProps?: TcpSegmentToBytesProps): Uint8Array;
179181
// The number of the protocol
180182
protocol(): number;
181183
// Packet protocol name
@@ -284,7 +286,13 @@ export class IPv4Packet implements FramePayload {
284286
}
285287
let payload = new Uint8Array(0);
286288
if (withPayload) {
287-
payload = this.payload.toBytes();
289+
payload =
290+
this.payload instanceof TcpSegment
291+
? this.payload.toBytes({
292+
srcIpAddress: this.sourceAddress,
293+
dstIpAddress: this.destinationAddress,
294+
})
295+
: this.payload.toBytes();
288296
}
289297
return Uint8Array.from([
290298
(this.version << 4) | this.internetHeaderLength,
@@ -321,6 +329,11 @@ export class IPv4Packet implements FramePayload {
321329
return IP_PROTOCOL_TYPE;
322330
}
323331

332+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
333+
getPayload(layer: Layer): Record<string, string | number | object> | string {
334+
return "IPv4 Datagram";
335+
}
336+
324337
getDetails(layer: Layer) {
325338
if (layer == Layer.Network) {
326339
return {
@@ -333,6 +346,9 @@ export class IPv4Packet implements FramePayload {
333346
"Time to Live": this.timeToLive,
334347
Protocol: this.protocol,
335348
"Header Checksum": this.headerChecksum,
349+
[TOOLTIP_KEYS.SOURCE_IP_ADDRESS]: this.sourceAddress.toString(),
350+
[TOOLTIP_KEYS.DESTINATION_IP_ADDRESS]:
351+
this.destinationAddress.toString(),
336352
Payload: this.payload.getPayload(),
337353
};
338354
} else {

src/packets/tcp.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@ function bitSet(value: boolean, bit: number): number {
7171
return value ? 1 << bit : 0;
7272
}
7373

74+
export interface TcpSegmentToBytesProps {
75+
withChecksum?: boolean;
76+
srcIpAddress?: IpAddress;
77+
dstIpAddress?: IpAddress;
78+
}
79+
7480
export class TcpSegment implements IpPayload {
7581
// Info taken from the original RFC: https://www.ietf.org/rfc/rfc793.txt
7682
// 0 1 2 3
@@ -129,8 +135,8 @@ export class TcpSegment implements IpPayload {
129135
public window = 0xffff;
130136

131137
// 2 bytes
132-
get checksum(): number {
133-
return this.computeChecksum();
138+
checksum(srcIpAddress: IpAddress, dstIpAddress: IpAddress): number {
139+
return this.computeChecksum(srcIpAddress, dstIpAddress);
134140
}
135141

136142
// 2 bytes
@@ -178,12 +184,12 @@ export class TcpSegment implements IpPayload {
178184
return this;
179185
}
180186

181-
computeChecksum(): number {
187+
computeChecksum(srcIpAddress: IpAddress, dstIpAddress: IpAddress): number {
182188
const segmentBytes = this.toBytes({ withChecksum: false });
183189

184190
const pseudoHeaderBytes = Uint8Array.from([
185-
...this.srcIpAddress.octets,
186-
...this.dstIpAddress.octets,
191+
...srcIpAddress.octets,
192+
...dstIpAddress.octets,
187193
0,
188194
TCP_PROTOCOL_NUMBER,
189195
...uintToBytes(segmentBytes.length, 2),
@@ -203,8 +209,12 @@ export class TcpSegment implements IpPayload {
203209

204210
toBytes({
205211
withChecksum = true,
206-
}: { withChecksum?: boolean } = {}): Uint8Array {
207-
const checksum = withChecksum ? this.checksum : 0;
212+
srcIpAddress,
213+
dstIpAddress,
214+
}: TcpSegmentToBytesProps = {}): Uint8Array {
215+
const checksum = withChecksum
216+
? this.checksum(srcIpAddress, dstIpAddress)
217+
: 0;
208218
return Uint8Array.from([
209219
...uintToBytes(this.sourcePort, 2),
210220
...uintToBytes(this.destinationPort, 2),

src/programs/echo_sender.ts

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import { ProgramBase } from "./program_base";
55
import { ViewGraph } from "../types/graphs/viewgraph";
66
import { ProgramInfo } from "../graphics/renderables/device_info";
77
import { EchoRequest } from "../packets/icmp";
8-
import { IpAddress, IPv4Packet } from "../packets/ip";
8+
import { IPv4Packet } from "../packets/ip";
99
import { ViewNetworkDevice } from "../types/view-devices/vNetworkDevice";
10-
import { EthernetFrame, MacAddress } from "../packets/ethernet";
10+
import { EthernetFrame } from "../packets/ethernet";
1111
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";
1212
import { Layer } from "../types/layer";
1313

@@ -57,40 +57,27 @@ export class SingleEcho extends ProgramBase {
5757
this.dstId,
5858
this.viewgraph,
5959
);
60-
let src: { ip: IpAddress; mac: MacAddress },
61-
dst: { ip: IpAddress; mac: MacAddress },
62-
sendingIface: number;
6360
if (!forwardingData) {
6461
console.warn(
6562
`Device ${this.srcId} could not send ping to device ${this.dstId}`,
6663
);
67-
src = {
68-
mac: srcDevice.interfaces[0].mac,
69-
ip: srcDevice.interfaces[0].ip,
70-
};
71-
dst = {
72-
mac: dstDevice.interfaces[0].mac,
73-
ip: dstDevice.interfaces[0].ip,
74-
};
75-
sendingIface = 0;
76-
} else {
77-
({ src, dst, sendingIface } = forwardingData);
64+
return;
7865
}
66+
const { src, dst, nextHop, sendingIface } = forwardingData;
7967
const echoRequest = new EchoRequest(0);
8068
// Wrap in IP datagram
8169
const ipPacket = new IPv4Packet(src.ip, dst.ip, echoRequest);
8270

83-
// Resolve destination MAC address
84-
const dstMac = srcDevice.resolveAddress(dst.ip);
85-
if (!dstMac) {
71+
// Resolve next hop MAC address
72+
const nextHopMac = srcDevice.resolveAddress(nextHop.ip);
73+
if (!nextHopMac || !nextHopMac.mac) {
8674
console.debug(
87-
`Device ${this.srcId} couldn't resolve MAC address for device with IP ${dst.ip.toString()}. Program cancelled`,
75+
`Device ${this.srcId} couldn't resolve next hop MAC address for device with IP ${nextHop.ip.toString()}. Program cancelled`,
8876
);
89-
return;
9077
}
9178

9279
// Wrap in Ethernet frame
93-
const ethernetFrame = new EthernetFrame(src.mac, dst.mac, ipPacket);
80+
const ethernetFrame = new EthernetFrame(src.mac, nextHopMac.mac, ipPacket);
9481
sendViewPacket(this.viewgraph, this.srcId, ethernetFrame, sendingIface);
9582
}
9683

src/programs/http_client.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,10 @@ export class HttpClient extends ProgramBase {
9090
// Write request
9191
const socket = await this.runner.tcpConnect(this.dstId);
9292
if (!socket) {
93-
console.warn("HttpClient failed to connect");
93+
console.error("HttpClient failed to connect");
94+
showError(
95+
"Failed to connect to HTTP server. Make sure the forwarding table is set up correctly.",
96+
);
9497
return;
9598
}
9699
if (this.stopped) {

src/styles/info.css

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
padding: 0; /* Removes default padding */
1111
margin: 0; /* Removes default margin */
1212
list-style: none; /* Removes list bullets */
13-
overflow: auto; /* Enables scrolling if the content is too large */
13+
overflow-x: auto;
1414
}
1515

1616
/* Ensures each item takes up the full width */
@@ -101,7 +101,6 @@
101101
border: 1px solid #bfbfbf; /* Adds a subtle border */
102102
width: 100%; /* Ensures the container occupies the full width */
103103
max-width: 100%; /* Prevents it from exceeding the sidebar width */
104-
overflow-x: auto; /* Enables horizontal scrolling if needed */
105104
box-sizing: border-box; /* Ensures padding and border do not affect width */
106105
display: block;
107106
}
@@ -113,9 +112,9 @@
113112
background-color: #111; /* Dark background for better contrast */
114113
padding: 10px; /* Adds spacing inside */
115114
border-radius: 6px; /* Rounds the corners */
116-
width: 100%; /* Ensures it takes the full width of the container */
117115
max-width: 100%; /* Prevents it from exceeding the container */
118116
display: block;
117+
overflow-x: auto;
119118
}
120119

121120
/* TCP Flags Table Styles */

src/types/data-devices/dNetworkDevice.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export abstract class DataNetworkDevice extends DataDevice {
5353
): { mac: MacAddress; edited: boolean } | undefined {
5454
const entry = this.arpTable.get(ip.toString());
5555
if (!entry) {
56-
// Buscar el dispositivo y la MAC real si no está en la tabla
56+
// Search for the device and the real MAC if it is not in the table
5757
const device = this.datagraph.getDeviceByIP(ip);
5858
if (!device) {
5959
console.warn(`Device with ip ${ip.toString()} not found in DataGraph`);
@@ -62,8 +62,13 @@ export abstract class DataNetworkDevice extends DataDevice {
6262
const iface = device.interfaces.find((iface) => iface.ip?.equals(ip));
6363
return iface ? { mac: iface.mac, edited: false } : undefined;
6464
}
65-
// Si la entrada existe pero la MAC es "", se considera eliminada
66-
if (entry.mac === "") return undefined;
65+
// If the entry exists but the MAC is "", it is considered deleted
66+
if (entry.mac === "") {
67+
console.debug(
68+
`Interface ${ip.toString()} from device ${this.id} is deleted`,
69+
);
70+
return undefined;
71+
}
6772
return { mac: MacAddress.parse(entry.mac), edited: entry.edited };
6873
}
6974

src/types/network-modules/tables/arp_table.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export function removeArpTableEntry(
5252
): void {
5353
const device = dataGraph.getDevice(deviceId);
5454
if (!device || !(device instanceof DataNetworkDevice)) {
55-
console.warn(`Device with ID ${deviceId} is not a network device.`);
55+
console.error(`Network Device with ID ${deviceId} not found.`);
5656
return;
5757
}
5858
device.arpTable.add({ ip, mac: "", edited: false });

0 commit comments

Comments
 (0)