Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/graphics/renderables/packet_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export class PacketInfo extends BaseInfo {
private addToggleInfo(): void {
const packetDetails = this.packet.getPacketDetails(
this.packet.viewgraph.getLayer(),
this.packet.rawPacket,
);

const toggleInfo = new ToggleInfo({
Expand Down
16 changes: 16 additions & 0 deletions src/packets/arp.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IpAddress } from "./ip";
import { ARP_PROTOCOL_TYPE, FramePayload, MacAddress } from "./ethernet";
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";
import { Layer } from "../types/layer";

const ETHERNET_HTYPE = 1;
const IPv4_PTYPE = 0x0800;
Expand Down Expand Up @@ -92,6 +93,21 @@ export abstract class ArpPacket implements FramePayload {
return `ARP-${this.type}`;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
getPayload(layer: Layer): Record<string, string | number | object> {
return {
[TOOLTIP_KEYS.HTYPE]: this.htype,
[TOOLTIP_KEYS.PTYPE]: this.ptype,
[TOOLTIP_KEYS.HLEN]: this.hlen,
[TOOLTIP_KEYS.PLEN]: this.plen,
[TOOLTIP_KEYS.OP]: this.op,
[TOOLTIP_KEYS.SHA]: this.sha.toString(),
[TOOLTIP_KEYS.SPA]: this.spa.toString(),
[TOOLTIP_KEYS.THA]: this.tha.toString(),
[TOOLTIP_KEYS.TPA]: this.tpa.toString(),
};
}

// eslint-disable-next-line
getDetails(_layer: number): Record<string, string | number | object> {
return {
Expand Down
10 changes: 8 additions & 2 deletions src/packets/ethernet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CRC32 } from "@tsxper/crc32";
import { Layer } from "../types/layer";
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";

// From https://en.wikipedia.org/wiki/EtherType
export const IP_PROTOCOL_TYPE = 0x0800;
Expand Down Expand Up @@ -176,12 +177,15 @@ export class EthernetFrame {
getDetails(layer: Layer) {
if (layer == Layer.Link) {
const ethernetDetails = {
EtherType: this.type.toString(),
[TOOLTIP_KEYS.ETHERTYPE]: this.type.toString(),
[TOOLTIP_KEYS.SOURCE_MAC_ADDRESS]: this.source.toString(),
[TOOLTIP_KEYS.DESTINATION_MAC_ADDRESS]: this.destination.toString(),
[TOOLTIP_KEYS.CRC]: this.crc.toString(16).padStart(8, "0"),
};
// Merge Ethernet details with payload details
return {
...ethernetDetails,
...this.payload.getDetails(layer),
Payload: this.payload.getPayload(layer),
};
} else {
return this.payload.getDetails(layer);
Expand All @@ -196,6 +200,8 @@ export interface FramePayload {
type(): number;
// Get details of the payload
getDetails(layer: Layer): Record<string, string | number | object>;
// Get payload data for Link layer
getPayload(layer: Layer): Record<string, string | number | object> | string;
}

export function compareMacs(mac1: MacAddress, mac2: MacAddress): number {
Expand Down
20 changes: 18 additions & 2 deletions src/packets/ip.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { FramePayload, IP_PROTOCOL_TYPE } from "./ethernet";
import { Layer } from "../types/layer";
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";
import { TcpSegment, TcpSegmentToBytesProps } from "./tcp";

// Taken from here: https://en.wikipedia.org/wiki/List_of_IP_protocol_numbers
export const ICMP_PROTOCOL_NUMBER = 1;
Expand Down Expand Up @@ -175,7 +177,7 @@ export interface IpPayload {
// Length of the payload in bytes
byteLength(): number;
// The bytes equivalent of the payload
toBytes(): Uint8Array;
toBytes(tcpToBytesProps?: TcpSegmentToBytesProps): Uint8Array;
// The number of the protocol
protocol(): number;
// Packet protocol name
Expand Down Expand Up @@ -284,7 +286,13 @@ export class IPv4Packet implements FramePayload {
}
let payload = new Uint8Array(0);
if (withPayload) {
payload = this.payload.toBytes();
payload =
this.payload instanceof TcpSegment
? this.payload.toBytes({
srcIpAddress: this.sourceAddress,
dstIpAddress: this.destinationAddress,
})
: this.payload.toBytes();
}
return Uint8Array.from([
(this.version << 4) | this.internetHeaderLength,
Expand Down Expand Up @@ -321,6 +329,11 @@ export class IPv4Packet implements FramePayload {
return IP_PROTOCOL_TYPE;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
getPayload(layer: Layer): Record<string, string | number | object> | string {
return "IPv4 Datagram";
}

getDetails(layer: Layer) {
if (layer == Layer.Network) {
return {
Expand All @@ -333,6 +346,9 @@ export class IPv4Packet implements FramePayload {
"Time to Live": this.timeToLive,
Protocol: this.protocol,
"Header Checksum": this.headerChecksum,
[TOOLTIP_KEYS.SOURCE_IP_ADDRESS]: this.sourceAddress.toString(),
[TOOLTIP_KEYS.DESTINATION_IP_ADDRESS]:
this.destinationAddress.toString(),
Payload: this.payload.getPayload(),
};
} else {
Expand Down
24 changes: 17 additions & 7 deletions src/packets/tcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ function bitSet(value: boolean, bit: number): number {
return value ? 1 << bit : 0;
}

export interface TcpSegmentToBytesProps {
withChecksum?: boolean;
srcIpAddress?: IpAddress;
dstIpAddress?: IpAddress;
}

export class TcpSegment implements IpPayload {
// Info taken from the original RFC: https://www.ietf.org/rfc/rfc793.txt
// 0 1 2 3
Expand Down Expand Up @@ -129,8 +135,8 @@ export class TcpSegment implements IpPayload {
public window = 0xffff;

// 2 bytes
get checksum(): number {
return this.computeChecksum();
checksum(srcIpAddress: IpAddress, dstIpAddress: IpAddress): number {
return this.computeChecksum(srcIpAddress, dstIpAddress);
}

// 2 bytes
Expand Down Expand Up @@ -178,12 +184,12 @@ export class TcpSegment implements IpPayload {
return this;
}

computeChecksum(): number {
computeChecksum(srcIpAddress: IpAddress, dstIpAddress: IpAddress): number {
const segmentBytes = this.toBytes({ withChecksum: false });

const pseudoHeaderBytes = Uint8Array.from([
...this.srcIpAddress.octets,
...this.dstIpAddress.octets,
...srcIpAddress.octets,
...dstIpAddress.octets,
0,
TCP_PROTOCOL_NUMBER,
...uintToBytes(segmentBytes.length, 2),
Expand All @@ -203,8 +209,12 @@ export class TcpSegment implements IpPayload {

toBytes({
withChecksum = true,
}: { withChecksum?: boolean } = {}): Uint8Array {
const checksum = withChecksum ? this.checksum : 0;
srcIpAddress,
dstIpAddress,
}: TcpSegmentToBytesProps = {}): Uint8Array {
const checksum = withChecksum
? this.checksum(srcIpAddress, dstIpAddress)
: 0;
return Uint8Array.from([
...uintToBytes(this.sourcePort, 2),
...uintToBytes(this.destinationPort, 2),
Expand Down
31 changes: 9 additions & 22 deletions src/programs/echo_sender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { ProgramBase } from "./program_base";
import { ViewGraph } from "../types/graphs/viewgraph";
import { ProgramInfo } from "../graphics/renderables/device_info";
import { EchoRequest } from "../packets/icmp";
import { IpAddress, IPv4Packet } from "../packets/ip";
import { IPv4Packet } from "../packets/ip";
import { ViewNetworkDevice } from "../types/view-devices/vNetworkDevice";
import { EthernetFrame, MacAddress } from "../packets/ethernet";
import { EthernetFrame } from "../packets/ethernet";
import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants";
import { Layer } from "../types/layer";

Expand Down Expand Up @@ -57,40 +57,27 @@ export class SingleEcho extends ProgramBase {
this.dstId,
this.viewgraph,
);
let src: { ip: IpAddress; mac: MacAddress },
dst: { ip: IpAddress; mac: MacAddress },
sendingIface: number;
if (!forwardingData) {
console.warn(
`Device ${this.srcId} could not send ping to device ${this.dstId}`,
);
src = {
mac: srcDevice.interfaces[0].mac,
ip: srcDevice.interfaces[0].ip,
};
dst = {
mac: dstDevice.interfaces[0].mac,
ip: dstDevice.interfaces[0].ip,
};
sendingIface = 0;
} else {
({ src, dst, sendingIface } = forwardingData);
return;
}
const { src, dst, nextHop, sendingIface } = forwardingData;
const echoRequest = new EchoRequest(0);
// Wrap in IP datagram
const ipPacket = new IPv4Packet(src.ip, dst.ip, echoRequest);

// Resolve destination MAC address
const dstMac = srcDevice.resolveAddress(dst.ip);
if (!dstMac) {
// Resolve next hop MAC address
const nextHopMac = srcDevice.resolveAddress(nextHop.ip);
if (!nextHopMac || !nextHopMac.mac) {
console.debug(
`Device ${this.srcId} couldn't resolve MAC address for device with IP ${dst.ip.toString()}. Program cancelled`,
`Device ${this.srcId} couldn't resolve next hop MAC address for device with IP ${nextHop.ip.toString()}. Program cancelled`,
);
return;
}

// Wrap in Ethernet frame
const ethernetFrame = new EthernetFrame(src.mac, dst.mac, ipPacket);
const ethernetFrame = new EthernetFrame(src.mac, nextHopMac.mac, ipPacket);
sendViewPacket(this.viewgraph, this.srcId, ethernetFrame, sendingIface);
}

Expand Down
5 changes: 4 additions & 1 deletion src/programs/http_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ export class HttpClient extends ProgramBase {
// Write request
const socket = await this.runner.tcpConnect(this.dstId);
if (!socket) {
console.warn("HttpClient failed to connect");
console.error("HttpClient failed to connect");
showError(
"Failed to connect to HTTP server. Make sure the forwarding table is set up correctly.",
);
return;
}
if (this.stopped) {
Expand Down
5 changes: 2 additions & 3 deletions src/styles/info.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
padding: 0; /* Removes default padding */
margin: 0; /* Removes default margin */
list-style: none; /* Removes list bullets */
overflow: auto; /* Enables scrolling if the content is too large */
overflow-x: auto;
}

/* Ensures each item takes up the full width */
Expand Down Expand Up @@ -101,7 +101,6 @@
border: 1px solid #bfbfbf; /* Adds a subtle border */
width: 100%; /* Ensures the container occupies the full width */
max-width: 100%; /* Prevents it from exceeding the sidebar width */
overflow-x: auto; /* Enables horizontal scrolling if needed */
box-sizing: border-box; /* Ensures padding and border do not affect width */
display: block;
}
Expand All @@ -113,9 +112,9 @@
background-color: #111; /* Dark background for better contrast */
padding: 10px; /* Adds spacing inside */
border-radius: 6px; /* Rounds the corners */
width: 100%; /* Ensures it takes the full width of the container */
max-width: 100%; /* Prevents it from exceeding the container */
display: block;
overflow-x: auto;
}

/* TCP Flags Table Styles */
Expand Down
11 changes: 8 additions & 3 deletions src/types/data-devices/dNetworkDevice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export abstract class DataNetworkDevice extends DataDevice {
): { mac: MacAddress; edited: boolean } | undefined {
const entry = this.arpTable.get(ip.toString());
if (!entry) {
// Buscar el dispositivo y la MAC real si no está en la tabla
// Search for the device and the real MAC if it is not in the table
const device = this.datagraph.getDeviceByIP(ip);
if (!device) {
console.warn(`Device with ip ${ip.toString()} not found in DataGraph`);
Expand All @@ -62,8 +62,13 @@ export abstract class DataNetworkDevice extends DataDevice {
const iface = device.interfaces.find((iface) => iface.ip?.equals(ip));
return iface ? { mac: iface.mac, edited: false } : undefined;
}
// Si la entrada existe pero la MAC es "", se considera eliminada
if (entry.mac === "") return undefined;
// If the entry exists but the MAC is "", it is considered deleted
if (entry.mac === "") {
console.debug(
`Interface ${ip.toString()} from device ${this.id} is deleted`,
);
return undefined;
}
return { mac: MacAddress.parse(entry.mac), edited: entry.edited };
}

Expand Down
2 changes: 1 addition & 1 deletion src/types/network-modules/tables/arp_table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export function removeArpTableEntry(
): void {
const device = dataGraph.getDevice(deviceId);
if (!device || !(device instanceof DataNetworkDevice)) {
console.warn(`Device with ID ${deviceId} is not a network device.`);
console.error(`Network Device with ID ${deviceId} not found.`);
return;
}
device.arpTable.add({ ip, mac: "", edited: false });
Expand Down
16 changes: 8 additions & 8 deletions src/types/network-modules/tcp/tcpState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,23 @@ function sendIpPacket(
console.warn(`Device ${dst.id} is not reachable from device ${src.id}`);
return false;
}
const [srcData, dstData, sendingIface] = [
const [srcData, nextHopData, dstData, sendingIface] = [
forwardingData.src,
forwardingData.nextHop,
forwardingData.dst,
forwardingData.sendingIface,
];

// Resolve destination MAC address
const dstMac = src.resolveAddress(dstData.ip);
if (!dstMac) {
console.warn(
`Device ${src.id} couldn't resolve MAC address for device with IP ${dstData.ip.toString()}. Program cancelled`,
// Resolve next hop MAC address
const nextHopMac = src.resolveAddress(nextHopData.ip);
if (!nextHopMac || !nextHopMac.mac) {
console.debug(
`Device ${this.srcId} couldn't resolve next hop MAC address for device with IP ${nextHopData.ip.toString()}. Program cancelled`,
);
return false;
}

const ipPacket = new IPv4Packet(srcData.ip, dstData.ip, payload);
const frame = new EthernetFrame(srcData.mac, dstData.mac, ipPacket);
const frame = new EthernetFrame(srcData.mac, nextHopData.mac, ipPacket);

sendViewPacket(src.viewgraph, src.id, frame, sendingIface);
return true;
Expand Down
4 changes: 2 additions & 2 deletions src/types/packet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,8 @@ export class Packet extends Graphics {
this.removeHighlight();
}

getPacketDetails(layer: Layer, rawPacket: EthernetFrame) {
return rawPacket.getDetails(layer);
getPacketDetails(layer: Layer) {
return this.rawPacket.getDetails(layer);
}

isVisible(): boolean {
Expand Down
Loading