diff --git a/IP Packet Reader/IPv4.c b/IP Packet Reader/IPv4.c index 761b26b..1c697b8 100644 --- a/IP Packet Reader/IPv4.c +++ b/IP Packet Reader/IPv4.c @@ -11,8 +11,7 @@ #include "protocol.h" #define IHL(ihl) (0x0F & ihl) -#define FLAGS(byte) (0xE0 & byte) // (0x8000 & byte) -#define FRAG_OFFSET(byte) (printf("%i", 3)); +#define FLAGS(byte) ((byte & 0xE0) >> 5) // Extract the 3 flag bits #define IPv4AddressPrint(identifier, addr) \ printf("%s:\t\t%d.%d.%d.%d\n", identifier, addr[0], addr[1], addr[2], addr[3]); @@ -36,7 +35,16 @@ void create_IPv4_packet_file(IPv4_Packet *packet, FILE *file, int8_t ihl) { packet->IHL = IHL(ihl); // figure out the length of the header for IPv4. unsigned char buffer[packet->IHL * 4]; - fread(buffer, sizeof(char), packet->IHL * 4 - 1, file); + if (packet->IHL < 5) { + fprintf(stderr, "Error: Invalid IHL value %d (must be at least 5)\n", packet->IHL); + return; + } + + size_t bytes_read = fread(buffer, sizeof(char), packet->IHL * 4 - 1, file); + if (bytes_read != packet->IHL * 4 - 1) { + fprintf(stderr, "Error: Could not read complete IPv4 header\n"); + return; + } packet->TOS = buffer[0]; packet->total_length = (buffer[1] << 8) | buffer[2]; // total length of the packet including its payload. @@ -44,7 +52,7 @@ void create_IPv4_packet_file(IPv4_Packet *packet, FILE *file, int8_t ihl) { // flags for fragmentation packet->Flags = FLAGS(buffer[5]); - packet->fragment_off = (0x0E & buffer[5])<<8 | buffer[6]; + packet->fragment_off = ((buffer[5] & 0x1F) << 8) | buffer[6]; packet->TTL = buffer[7]; // time to live packet->protocol = buffer[8]; // protocol @@ -52,7 +60,7 @@ void create_IPv4_packet_file(IPv4_Packet *packet, FILE *file, int8_t ihl) { // parses the addresses into the address space address_parser(packet->source_address, buffer, 11); - address_parser(packet->destination_addres, buffer, 15); + address_parser(packet->destination_address, buffer, 15); } @@ -68,21 +76,39 @@ void print_IPv4_packet(IPv4_Packet *packet) { Print("Flags", packet->Flags); Print("Fragment Offset", packet->fragment_off); ProtocolPrint(get_protocol(packet->protocol), packet->protocol); + Print("TTL", packet->TTL); Print("Checksum", packet->checksum); - IPv4AddressPrint("Source Address", packet->source_address) - IPv4AddressPrint("Desination Address", packet->destination_addres); + IPv4AddressPrint("Source Address", packet->source_address); + IPv4AddressPrint("Destination Address", packet->destination_address); } void create_IPv4_packets(int amount, FILE *file) { + if (file == NULL) { + fprintf(stderr, "Error: Invalid file pointer\n"); + return; + } + for(int i = 0; i < amount; i++) { IPv4_Packet packet; packet.version = 4; packet.IHL = 5; packet.TOS = 0; - packet.TTL = 20 + rand() % (65615 - 0 + 1); - packet.ID = 0; + packet.total_length = 20 + (rand() % 1480); // Typical MTU is 1500 + packet.TTL = 64; // Common TTL value + packet.ID = rand() % 65536; + packet.Flags = 0; + packet.fragment_off = 0; + packet.protocol = 6; // TCP + packet.checksum = 0; // Would need to calculate actual checksum + + // Generate random source and destination addresses + for (int j = 0; j < 4; j++) { + packet.source_address[j] = rand() % 256; + packet.destination_address[j] = rand() % 256; + } + + // Write the packet to the file + // This would need to be implemented to actually write the binary data } } - - diff --git a/IP Packet Reader/IPv4.h b/IP Packet Reader/IPv4.h index 0e400c8..46c7d49 100644 --- a/IP Packet Reader/IPv4.h +++ b/IP Packet Reader/IPv4.h @@ -21,13 +21,19 @@ #include #include -/// IPv4_Packet - struct that +/// IPv4_Packet - structure to hold IPv4 packet data typedef struct { - unsigned int version: 4, IHL: 4, - TOS: 8, total_length: 16, ID: 16, - Flags: 3, fragment_off: 13, - TTL: 8, protocol: 8, checksum: 16; - unsigned int source_address[4], destination_addres[4]; + unsigned int version: 4, // IP version (4 for IPv4) + IHL: 4, // Internet Header Length (in 32-bit words) + TOS: 8, // Type of Service + total_length: 16, // Total Length of the packet + ID: 16, // Identification + Flags: 3, // Flags for fragmentation + fragment_off: 13, // Fragment Offset + TTL: 8, // Time to Live + protocol: 8, // Protocol + checksum: 16; // Header Checksum + unsigned int source_address[4], destination_address[4]; // Source and destination IP addresses } IPv4_Packet; /// print_IPv4_packet - prints the IPv4 packet @@ -37,8 +43,8 @@ void print_IPv4_packet(IPv4_Packet *packet); /// create_IPv4_packet_file - parses the packet data into a IPv4_Packet struct /// param packet - pointer to the packet struct /// param file - pointer to the file -/// param ihl - the internet header length -void create_IPv4_packet(IPv4_Packet *packet, FILE *file, int8_t version); +/// param ihl - the first byte already read from the file +void create_IPv4_packet_file(IPv4_Packet *packet, FILE *file, int8_t version); /// create_IPv4_packets - creates IPv4 packets with randomized values /// param amount - the amount of packets to create diff --git a/IP Packet Reader/IPv6.c b/IP Packet Reader/IPv6.c index 6a54d13..7ab0439 100644 --- a/IP Packet Reader/IPv6.c +++ b/IP Packet Reader/IPv6.c @@ -8,9 +8,14 @@ #include "IPv6.h" #include "protocol.h" +#include #define IPv6_Header 40 +/// address_parser - parses the address into an integer array +/// param address - pointer to the address location +/// param buffer - the buffer with the binary to the packet +/// param i - the starting index for the buffer static void address_parser(unsigned int *address, unsigned char *buffer, int i) { int index = 0; for (int j = i; j < i+16; j++) { @@ -19,55 +24,65 @@ static void address_parser(unsigned int *address, unsigned char *buffer, int i) } } -/// simplify_IPv6_address - turns the address into a char of hex. -/// param packet - the pointer to the IPv6 -/// param address - the address pointer +/// simplify_IPv6_address - formats the IPv6 address into standard notation +/// param address_string - output string buffer +/// param address - the address array static void simplify_IPv6_address(unsigned char *address_string, unsigned int *address) { - int i = 0; + char temp[8][5]; // 8 groups of max 4 hex chars each + int i, j; - for (int j = 0; j < 16; j += 2) { - int compressed = 1; - - int n = (address[j] << 8) | address[j+1]; - if (n == 0 && j != 14 && compressed) { - int m = (address[j+2] << 8) | address[j+3]; - if (m == 0) { - j += 4; - for (int k = j; j < 16; j += 2) { - int b = (address[k] << 8) | address[k+1]; - if (b != 0) { - j = k-2; - k = 16; - } - } - address[i] = ':'; - compressed = 0; + // Format each 16-bit group as hex + for (i = 0; i < 8; i++) { + int value = (address[i*2] << 8) | address[i*2+1]; + sprintf((char*)&temp[i], "%x", value); + } + + // Find longest run of zeros for :: compression + int zero_start = -1; + int zero_length = 0; + int current_start = -1; + int current_length = 0; + + for (i = 0; i < 8; i++) { + if (strcmp(temp[i], "0") == 0) { + if (current_start == -1) { + current_start = i; + current_length = 1; } else { - address_string[i] = '0'; - address_string[i+1] = ':'; - i += 2; + current_length++; } } else { - while(n != 0) { - // temporary variable to store remainder - int temp = 0; - - // storing remainder in temp variable. - temp = n % 16; - - // check if temp < 10 - if(temp < 10) { - address_string[i] = temp + 48; - i++; - } - else { - address_string[i] = temp + 55; - i++; - } - n = n/16; + if (current_length > zero_length) { + zero_length = current_length; + zero_start = current_start; + } + current_start = -1; + current_length = 0; + } + } + + // Check if the last run is the longest + if (current_length > zero_length) { + zero_length = current_length; + zero_start = current_start; + } + + // Only compress if we have at least 2 consecutive zero groups + if (zero_length < 2) { + zero_start = -1; + } + + // Build the final string + address_string[0] = '\0'; + for (i = 0; i < 8; i++) { + if (i == zero_start) { + strcat((char*)address_string, "::"); + i += zero_length - 1; // Skip the compressed zeros + } else { + strcat((char*)address_string, temp[i]); + if (i < 7 && (i + 1 != zero_start)) { + strcat((char*)address_string, ":"); } - address_string[i] = ':'; - i++; } } } @@ -75,17 +90,25 @@ static void simplify_IPv6_address(unsigned char *address_string, unsigned int *a void create_IPv6_packet(IPv6_Packet *packet, FILE *file, int8_t byte) { packet->version = 6; unsigned char buffer[IPv6_Header]; - fread(buffer, sizeof(unsigned char), IPv6_Header - 1, file); - packet->traffic_class = ((byte << 4) & 0x0F) | buffer[0]; - packet->flow_label = ((((buffer[0] & 0x0F) << 8) | buffer[1]) << 8) | buffer[2]; + size_t bytes_read = fread(buffer, sizeof(unsigned char), IPv6_Header - 1, file); + if (bytes_read != IPv6_Header - 1) { + fprintf(stderr, "Error: Could not read complete IPv6 header\n"); + return; + } + + // Parse the IPv6 header fields + packet->traffic_class = ((byte & 0x0F) << 4) | ((buffer[0] & 0xF0) >> 4); + packet->flow_label = ((buffer[0] & 0x0F) << 16) | (buffer[1] << 8) | buffer[2]; packet->payload_length = (buffer[3] << 8) | buffer[4]; - packet->next_header = (buffer[5]); - packet->hop_limit = (buffer[6]); + packet->next_header = buffer[5]; + packet->hop_limit = buffer[6]; + // Parse source and destination addresses address_parser(packet->source_address, buffer, 7); - address_parser(packet->source_address, buffer, 23); + address_parser(packet->destination_address, buffer, 23); + // Format addresses for display simplify_IPv6_address(packet->source_string, packet->source_address); simplify_IPv6_address(packet->destination_string, packet->destination_address); } @@ -98,7 +121,8 @@ void print_IPv6_packet(IPv6_Packet *packet) { Print("Traffic Class", packet->traffic_class); Print("Flow Label", packet->flow_label); Print("Payload Length", packet->payload_length); - Print("Next Header", packet->next_header); - printf("Source Address\t\t%s", packet->source_string); - printf("Destination Address\t\t%s", packet->destination_string); + ProtocolPrint(get_protocol(packet->next_header), packet->next_header); + Print("Hop Limit", packet->hop_limit); + printf("Source Address:\t\t%s\n", packet->source_string); + printf("Destination Address:\t%s\n", packet->destination_string); } diff --git a/IP Packet Reader/IPv6.h b/IP Packet Reader/IPv6.h index 24b6b70..ddef76c 100644 --- a/IP Packet Reader/IPv6.h +++ b/IP Packet Reader/IPv6.h @@ -24,6 +24,7 @@ #include +/// IPv6_Packet - structure to hold IPv6 packet data typedef struct { unsigned int version: 4, traffic_class: 8, flow_label: 20; unsigned int payload_length: 16, next_header: 8, hop_limit: 8; @@ -31,8 +32,14 @@ typedef struct { unsigned char source_string[40], destination_string[40]; } IPv6_Packet; +/// create_IPv6_packet - parses the packet data into an IPv6_Packet struct +/// param packet - pointer to the packet struct +/// param file - pointer to the file +/// param byte - the first byte already read from the file void create_IPv6_packet(IPv6_Packet *packet, FILE *file, int8_t byte); +/// print_IPv6_packet - prints the IPv6 packet +/// param packet - pointer to the packet being printed void print_IPv6_packet(IPv6_Packet *packet); #endif /* IPv6_h */ diff --git a/IP Packet Reader/main.c b/IP Packet Reader/main.c index f1ecb59..50964cd 100644 --- a/IP Packet Reader/main.c +++ b/IP Packet Reader/main.c @@ -16,7 +16,7 @@ #define USAGE printf("./main [packet files]\n"); -#define VERSION(version) ((0xF0 & version) >> 4); +#define VERSION(version) ((0xF0 & version) >> 4) /// main - parses the packet files @@ -26,7 +26,7 @@ int main(int argc, const char * argv[]) { int8_t byte; int8_t version; - if (argc < 1) { + if (argc < 2) { USAGE; return 1; } @@ -37,8 +37,13 @@ int main(int argc, const char * argv[]) { for(int i = 1; i < argc; i++) { FILE *file = fopen(argv[i], "r"); + if (file == NULL) { + fprintf(stderr, "Error: Could not open file %s\n", argv[i]); + continue; + } + while ((fread(&byte, 1, 1, file))) { - version = VERSION(byte) + version = VERSION(byte); // hand over to IPv4 or IPv6 if(version == 4) { IPv4_Packet packet; @@ -47,12 +52,14 @@ int main(int argc, const char * argv[]) { } else if(version == 6) { IPv6_Packet packet; create_IPv6_packet(&packet, file, byte); + print_IPv6_packet(&packet); } else { - perror("This is not a packet. This program strictly takes packets.\n"); - return 3; + fprintf(stderr, "Error: This is not a valid IP packet (version %d). This program strictly takes IPv4 or IPv6 packets.\n", version); + break; } } + + fclose(file); } return 0; } - diff --git a/IP Packet Reader/packet_generator.c b/IP Packet Reader/packet_generator.c new file mode 100644 index 0000000..fa0aef8 --- /dev/null +++ b/IP Packet Reader/packet_generator.c @@ -0,0 +1,143 @@ +// +// packet_generator.c +// IP Packet Reader +// +// Created by Codegen on 2025-05-09. +// + +#include +#include +#include +#include + +// Function to generate a random IPv4 packet +void generate_ipv4_packet(FILE *file) { + unsigned char packet[20]; // Basic IPv4 header without options + memset(packet, 0, sizeof(packet)); + + // Version (4) and IHL (5 words = 20 bytes) + packet[0] = 0x45; + + // Type of Service / DSCP + packet[1] = 0x00; + + // Total Length (header + data) - just header for simplicity + packet[2] = 0x00; + packet[3] = 0x14; // 20 bytes + + // Identification + packet[4] = rand() % 256; + packet[5] = rand() % 256; + + // Flags and Fragment Offset + packet[6] = 0x40; // Don't fragment + packet[7] = 0x00; + + // TTL + packet[8] = 0x40; // 64 + + // Protocol (TCP = 6, UDP = 17, ICMP = 1) + packet[9] = 0x06; // TCP + + // Header Checksum (set to 0 for simplicity) + packet[10] = 0x00; + packet[11] = 0x00; + + // Source IP (192.168.1.1) + packet[12] = 192; + packet[13] = 168; + packet[14] = 1; + packet[15] = 1; + + // Destination IP (10.0.0.1) + packet[16] = 10; + packet[17] = 0; + packet[18] = 0; + packet[19] = 1; + + // Write the packet to the file + fwrite(packet, 1, sizeof(packet), file); +} + +// Function to generate a random IPv6 packet +void generate_ipv6_packet(FILE *file) { + unsigned char packet[40]; // Basic IPv6 header + memset(packet, 0, sizeof(packet)); + + // Version (6), Traffic Class, and Flow Label + packet[0] = 0x60; + packet[1] = 0x00; + packet[2] = 0x00; + packet[3] = 0x00; + + // Payload Length (0 for simplicity) + packet[4] = 0x00; + packet[5] = 0x00; + + // Next Header (TCP = 6) + packet[6] = 0x06; + + // Hop Limit + packet[7] = 0x40; // 64 + + // Source Address (2001:db8::1) + packet[8] = 0x20; + packet[9] = 0x01; + packet[10] = 0x0d; + packet[11] = 0xb8; + // Rest of source address (12-23) left as zeros + packet[23] = 0x01; + + // Destination Address (2001:db8::2) + packet[24] = 0x20; + packet[25] = 0x01; + packet[26] = 0x0d; + packet[27] = 0xb8; + // Rest of destination address (28-39) left as zeros + packet[39] = 0x02; + + // Write the packet to the file + fwrite(packet, 1, sizeof(packet), file); +} + +int main(int argc, char *argv[]) { + if (argc < 3) { + printf("Usage: %s [count]\n", argv[0]); + printf(" type: 4 for IPv4, 6 for IPv6\n"); + printf(" count: number of packets to generate (default: 1)\n"); + return 1; + } + + const char *filename = argv[1]; + int type = atoi(argv[2]); + int count = (argc > 3) ? atoi(argv[3]) : 1; + + if (type != 4 && type != 6) { + printf("Error: Type must be 4 (IPv4) or 6 (IPv6)\n"); + return 1; + } + + FILE *file = fopen(filename, "wb"); + if (!file) { + printf("Error: Could not open file %s for writing\n", filename); + return 1; + } + + // Seed the random number generator + srand(time(NULL)); + + // Generate the specified number of packets + for (int i = 0; i < count; i++) { + if (type == 4) { + generate_ipv4_packet(file); + } else { + generate_ipv6_packet(file); + } + } + + fclose(file); + printf("Generated %d IPv%d packet(s) in file %s\n", count, type, filename); + + return 0; +} + diff --git a/IP Packet Reader/protocol.c b/IP Packet Reader/protocol.c index cf5b22d..6dcc87a 100644 --- a/IP Packet Reader/protocol.c +++ b/IP Packet Reader/protocol.c @@ -10,30 +10,56 @@ char *get_protocol(unsigned int protocol) { switch (protocol) { // checks protocols and prints which one it is. + case 0: + return "HOPOPT"; // IPv6 Hop-by-Hop Option case 1: - return "ICMP"; + return "ICMP"; // Internet Control Message Protocol case 2: - return "IGMP"; + return "IGMP"; // Internet Group Management Protocol + case 3: + return "GGP"; // Gateway-to-Gateway Protocol + case 4: + return "IP-in-IP"; // IP in IP (encapsulation) case 6: - return "TCP"; + return "TCP"; // Transmission Control Protocol + case 8: + return "EGP"; // Exterior Gateway Protocol case 9: - return "IGRP"; + return "IGRP"; // Interior Gateway Routing Protocol case 17: - return "UDP"; + return "UDP"; // User Datagram Protocol + case 41: + return "IPv6"; // IPv6 encapsulation + case 43: + return "IPv6-Route"; // Routing Header for IPv6 + case 44: + return "IPv6-Frag"; // Fragment Header for IPv6 case 47: - return "GRE"; + return "GRE"; // Generic Routing Encapsulation case 50: - return "ESP"; + return "ESP"; // Encapsulating Security Payload case 51: - return "AH"; + return "AH"; // Authentication Header case 57: - return "SKIP"; + return "SKIP"; // SKIP + case 58: + return "IPv6-ICMP"; // ICMP for IPv6 + case 59: + return "IPv6-NoNxt"; // No Next Header for IPv6 + case 60: + return "IPv6-Opts"; // Destination Options for IPv6 case 88: - return "EIGZRP"; + return "EIGRP"; // Enhanced Interior Gateway Routing Protocol case 89: - return "OSPF"; + return "OSPF"; // Open Shortest Path First + case 103: + return "PIM"; // Protocol Independent Multicast + case 112: + return "VRRP"; // Virtual Router Redundancy Protocol case 115: - return "L2TP"; + return "L2TP"; // Layer 2 Tunneling Protocol + case 132: + return "SCTP"; // Stream Control Transmission Protocol } return "Unknown Protocol"; } diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ad85b79 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +CC = gcc +CFLAGS = -Wall -Wextra -g +SRC_DIR = IP\ Packet\ Reader +SRCS = $(SRC_DIR)/main.c $(SRC_DIR)/IPv4.c $(SRC_DIR)/IPv6.c $(SRC_DIR)/protocol.c +OBJS = $(SRCS:.c=.o) +TARGET = ip_packet_parser +GEN_SRC = $(SRC_DIR)/packet_generator.c +GEN_TARGET = packet_generator + +all: $(TARGET) $(GEN_TARGET) + +$(TARGET): $(OBJS) + $(CC) $(CFLAGS) -o $@ $^ + +$(GEN_TARGET): $(GEN_SRC) + $(CC) $(CFLAGS) -o $@ $^ + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJS) $(TARGET) $(GEN_TARGET) + +.PHONY: all clean diff --git a/README.md b/README.md index 9040fc7..10097e9 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,131 @@ # IP-Packet Parser ------- -One of my first projects I worked on. -It was interesting project because I learned a lot about how packets worked. -It opened me up to a lot of different networking ideas and concepts that I now have an over-arching high-level knowledge of the concepts in netowrking. -This was the turning point to where I also started to prefer C/C++ in industry and appreciated all it taught me. - -## Compile ------- -This is simply compiled with GCC on each file. - -### IPV4 -By far the easiest and has an interesting packet structure. -It was very fun to make and taught me a lot about bits and bit manipulation especially used in signal processing at the software level. - -### IPV6 -A harder attempt since IPv6 can collapse but it was still a fun and education time. + +A C-based tool for parsing and analyzing IPv4 and IPv6 packet headers. + +## Overview + +This project provides a packet parser that can read binary IP packet data from files and display the header information in a human-readable format. It supports both IPv4 and IPv6 protocols and identifies various transport layer protocols. + +The parser extracts and displays key information from packet headers, including: + +- IP version +- Header length +- Traffic class/Type of service +- Flow labels +- Packet length +- Fragmentation information +- TTL/Hop limit +- Protocol type +- Checksums +- Source and destination addresses + +## Features + +- Parse IPv4 packet headers +- Parse IPv6 packet headers +- Identify and display transport layer protocols +- Process multiple packet files in a single run +- Generate random IPv4 and IPv6 packets for testing + +## Compilation + +The project can be compiled using the provided Makefile: + +```bash +# Compile both the parser and packet generator +make + +# Compile only the parser +make ip_packet_parser + +# Compile only the packet generator +make packet_generator + +# Clean up compiled files +make clean +``` + +Alternatively, you can compile manually using GCC: + +```bash +# Compile the parser +gcc -o ip_packet_parser IP\ Packet\ Reader/main.c IP\ Packet\ Reader/IPv4.c IP\ Packet\ Reader/IPv6.c IP\ Packet\ Reader/protocol.c + +# Compile the packet generator +gcc -o packet_generator IP\ Packet\ Reader/packet_generator.c +``` + +## Usage + +### Packet Parser + +```bash +./ip_packet_parser [packet_file1] [packet_file2] ... +``` + +### Packet Generator + +```bash +./packet_generator [count] + type: 4 for IPv4, 6 for IPv6 + count: number of packets to generate (default: 1) +``` + +### Example + +```bash +# Generate a sample IPv4 packet +./packet_generator sample_ipv4.bin 4 + +# Generate 5 IPv6 packets +./packet_generator sample_ipv6.bin 6 5 + +# Parse the generated packets +./ip_packet_parser sample_ipv4.bin sample_ipv6.bin +``` + +## IPv4 Header Structure + +``` + IPv4 Packet Header Design + Bits + |0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31| +B 0 |-vers-|--IHL--|---------TOS---------|--------------------TLength---------------------| +Y 4 |----------------ID------------------|--Flags-|-----------Fragment-OffSet-------------| +T 8 |------TTL-----|-------Protocol------|------------------Checksum----------------------| +E 12 |------------------------------Source-Address-----------------------------------------| +S 16 |-----------------------------Destination-Address-------------------------------------| + 20 |---------------------------------Options---------------------------------------------| +``` + +## IPv6 Header Structure + +``` + IPv6 Packet Header Design + Bits + |0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31| + 0 |-vers--|---Trafic-Class--|-----------------------Flow-Label--------------------------| + 4 |--------------Payload-Length---------|------Next-Header-----|------Hop-Limit---------| +B 8 |-------------------------------Source-Address----------------------------------------| +Y 12 |-------------------------------------------------------------------------------------| +T 16 |-------------------------------------------------------------------------------------| +E 20 |-------------------------------------------------------------------------------------| +S 24 |-----------------------------Destination-Address-------------------------------------| + 28 |-------------------------------------------------------------------------------------| + 32 |-------------------------------------------------------------------------------------| + 36 |-------------------------------------------------------------------------------------| +``` + +## Learning Outcomes + +This project provided valuable learning experiences in: + +- Network protocol analysis +- Bit manipulation in C +- Binary file parsing +- Network address formatting +- Protocol encapsulation + +## License + +See the [LICENSE](LICENSE) file for details.