diff --git a/.gitignore b/.gitignore index d866725..edffee9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +* +!*.* +!*/ + *.o *.out -.gdb_history \ No newline at end of file +.gdb_history diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b22b0fd --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ +OPT = -O0 -fno-stack-protector + +CFLAGS = -g -gdwarf-4 -Wall -Wextra -Wno-error -Wfatal-errors +#CFLAGS += -Wno-error=unused-parameter +#CFLAGS += -Wno-error=unused-variable +#CFLAGS += -Wno-error=unused-but-set-variable +CFLAGS += -Wno-missing-field-initializers +CFLAGS += -I../../include +CFLAGS += $(OPT) + +LDFLAGS += $(OPT) + +CXXFLAGS = -std=c++23 + +OBJS = \ + dhcp4.o \ + ip4.o \ + packet.o \ + udp4.o \ + eth.o + +all: client test2 + +%.o: %.cpp + $(CXX) $(CFLAGS) $(CXXFLAGS) $(FREETYPE_CFLAGS) -c $< -o $@ + +%: %.o $(OBJS) + $(CXX) $(LDFLAGS) $^ -o $@ + +.SUFFIXES: +.INTERMEDIATE: +.SECONDARY: +.PHONY: all clean phony + +%: RCS/%,v +%: RCS/% +%: %,v +%: s.% +%: SCCS/s.% diff --git a/client.cpp b/client.cpp index b47151d..4f63fe5 100644 --- a/client.cpp +++ b/client.cpp @@ -13,7 +13,7 @@ #include #include -#include "ipv4.h" +#include "ip4.h" #include "udp4.h" #include "dhcp4.h" #include "eth.h" @@ -21,8 +21,8 @@ int make_packet(uint8_t * buf, uint8_t const * eth_source_address, uint8_t const * eth_destination_address, - uint32_t const ipv4_source_address, - uint32_t const ipv4_destination_address, + uint32_t const ip4_source_address, + uint32_t const ip4_destination_address, uint32_t const dhcp_transaction_id, uint32_t const dhcp_message_type) { @@ -30,7 +30,7 @@ int make_packet(uint8_t * buf, // dhcp4 ////////////////////////////////////////////////////////////////////// - int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ipv4::header)) + (sizeof (udp4::header)); + int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)) + (sizeof (udp4::header)); int dhcp4_length = dhcp4::make_message(reinterpret_cast(&buf[dhcp4_offset]), dhcp4::op::bootrequest, dhcp_transaction_id, @@ -48,28 +48,28 @@ int make_packet(uint8_t * buf, eth_header->ether_type = htons(0x0800); ////////////////////////////////////////////////////////////////////// - // ipv4 + // ip4 ////////////////////////////////////////////////////////////////////// - int ipv4_offset = (sizeof (eth::header)); - int ipv4_payload_length = dhcp4_length + (sizeof (udp4::header)); - int ipv4_identification = 55179; - ipv4::make_header(reinterpret_cast(&buf[ipv4_offset]), - ipv4_payload_length, - ipv4_identification, - ipv4_source_address, - ipv4_destination_address); + int ip4_offset = (sizeof (eth::header)); + int ip4_payload_length = dhcp4_length + (sizeof (udp4::header)); + int ip4_identification = 55179; + ip4::make_header(reinterpret_cast(&buf[ip4_offset]), + ip4_payload_length, + ip4_identification, + ip4_source_address, + ip4_destination_address); ////////////////////////////////////////////////////////////////////// // udp4 ////////////////////////////////////////////////////////////////////// - int udp4_offset = (sizeof (eth::header)) + (sizeof (ipv4::header)); + int udp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)); udp4::make_header(reinterpret_cast(&buf[udp4_offset]), htons(68), htons(67), - ipv4_source_address, - ipv4_destination_address, + ip4_source_address, + ip4_destination_address, &buf[dhcp4_offset], dhcp4_length); @@ -207,14 +207,14 @@ int main() memcpy(eth_source_address, if_hwaddr.ifr_hwaddr.sa_data, 6); uint8_t eth_destination_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - uint32_t ipv4_source_address = 0x00000000; - uint32_t ipv4_destination_address = 0xffffffff; + uint32_t ip4_source_address = 0x00000000; + uint32_t ip4_destination_address = 0xffffffff; int length = make_packet(buf, eth_source_address, eth_destination_address, - ipv4_source_address, - ipv4_destination_address, + ip4_source_address, + ip4_destination_address, dhcp_transaction_id, dhcp4::message_type::dhcpdiscover); diff --git a/dhcp4.cpp b/dhcp4.cpp index 5359230..db3aea2 100644 --- a/dhcp4.cpp +++ b/dhcp4.cpp @@ -38,24 +38,13 @@ namespace dhcp4 { { uint8_t * prl = &msg->options[index]; - int length = 4; + int length = 3; index += 2 + length; prl[0] = option::parameter_request_list; prl[1] = length; - prl[2] = 1; // subnet mask - prl[3] = 3; // router - prl[4] = 6; // domain name server - prl[5] = 28; // broadcast address - } - - if (0) { - uint8_t * message_size = &msg->options[index]; - int length = 2; - index += 2 + length; - message_size[0] = option::maximum_message_size; - message_size[1] = length; - message_size[2] = 0x05; - message_size[3] = 0xc0; + prl[2] = option::subnet_mask; + prl[3] = option::router; + prl[4] = option::domain_name_server; } uint8_t * end = &msg->options[index]; @@ -64,4 +53,37 @@ namespace dhcp4 { return (sizeof (message)) + index; } + + void parse_options(message const * m, int options_length, options * o) + { + uint8_t const * options = m->options; + + int index = 4; + while (index + 2 <= options_length) { + int option = options[index + 0]; + int option_length = options[index + 1]; + + //printf("option %d length %d\n", option, option_length); + + switch (option) { + case option::message_type: + o->message_type = options[index + 2]; + break; + case option::subnet_mask: + o->subnet_mask = *reinterpret_cast(&options[index + 2]); + break; + case option::router: + o->router = *reinterpret_cast(&options[index + 2]); + break; + case option::domain_name_server: + o->domain_name_server = *reinterpret_cast(&options[index + 2]); + break; + default: + break; + } + + index += 2 + option_length; + } + assert(options[index] == 255); + } } diff --git a/dhcp4.h b/dhcp4.h index fd4ef45..9147d93 100644 --- a/dhcp4.h +++ b/dhcp4.h @@ -23,6 +23,13 @@ namespace dhcp4 { uint8_t options[]; }; + struct options { + int message_type; // 53 + uint32_t subnet_mask; // 1 + uint32_t router; // 3 + uint32_t domain_name_server; // 6 + }; + struct op { enum { bootrequest = 1, @@ -40,6 +47,10 @@ namespace dhcp4 { struct option { enum { + subnet_mask = 1, + router = 3, + domain_name_server = 6, + broadcast_address = 28, ip_address_lease_time = 51, option_overload = 52, message_type = 53, @@ -68,4 +79,6 @@ namespace dhcp4 { uint32_t transaction_id, uint8_t const * chaddr, uint32_t dhcp_message_type); + + void parse_options(message const * m, int options_length, options * o); } diff --git a/eth.cpp b/eth.cpp new file mode 100644 index 0000000..4954c62 --- /dev/null +++ b/eth.cpp @@ -0,0 +1,15 @@ +#include +#include + +#include "eth.h" + +namespace eth { + char const * tostr(uint8_t const * buf) + { + static char tmp[18]; + int ret = snprintf(tmp, 18, + "%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + assert(ret > 0); + return tmp; + } +} diff --git a/eth.h b/eth.h index 5fc2a40..bd20857 100644 --- a/eth.h +++ b/eth.h @@ -8,4 +8,6 @@ namespace eth { uint8_t source_address[6]; uint16_t ether_type; }; + + char const * tostr(uint8_t const * buf); } diff --git a/ipv4.cpp b/ip4.cpp similarity index 90% rename from ipv4.cpp rename to ip4.cpp index 7b7bc02..0340e49 100644 --- a/ipv4.cpp +++ b/ip4.cpp @@ -4,9 +4,15 @@ #include -#include "ipv4.h" +#include "ip4.h" -namespace ipv4 { +namespace ip4 { + + char const * tostr(uint32_t a) + { + static char tmp[16]; + return inet_ntop(AF_INET, reinterpret_cast(&a), tmp, 16); + } uint32_t checksum_partial(uint32_t sum, void const * src, int length) { diff --git a/ipv4.h b/ip4.h similarity index 94% rename from ipv4.h rename to ip4.h index bf52273..e77fbe7 100644 --- a/ipv4.h +++ b/ip4.h @@ -2,7 +2,7 @@ #include -namespace ipv4 { +namespace ip4 { struct header { uint8_t version_ihl; @@ -19,6 +19,8 @@ namespace ipv4 { static_assert((sizeof (header)) == 20); + char const * tostr(uint32_t a); + uint32_t checksum_partial(uint32_t sum, void const * src, int length); uint32_t checksum_finish(uint32_t sum); uint32_t checksum(void const * src, int length); diff --git a/packet.cpp b/packet.cpp new file mode 100644 index 0000000..9c79e53 --- /dev/null +++ b/packet.cpp @@ -0,0 +1,62 @@ +#include + +#include + +#include "packet.h" + +namespace packet { + + void parse(uint8_t const * buf, int length, packet * p) + { + ////////////////////////////////////////////////////////////////////// + // eth + ////////////////////////////////////////////////////////////////////// + + eth::header const * eth_header = reinterpret_cast(&buf[eth_offset]); + + //printf("eth source address "); + //print_eth_address(eth_header->source_address); + //printf("eth destination address "); + //print_eth_address(eth_header->destination_address); + + ////////////////////////////////////////////////////////////////////// + // ip4 + ////////////////////////////////////////////////////////////////////// + + ip4::header const * ip4_header = reinterpret_cast(&buf[ip4_offset]); + //printf("ip4 total length: %d\n", ntohs(ip4_header->total_length)); + assert(ip4_offset + ntohs(ip4_header->total_length) == length); + + printf("ip4 source address: %s\n", ip4::tostr(ip4_header->source_address)); + printf("ip4 destination address: %s\n", ip4::tostr(ip4_header->destination_address)); + + ////////////////////////////////////////////////////////////////////// + // udp4 + ////////////////////////////////////////////////////////////////////// + + udp4::header const * udp4_header = reinterpret_cast(&buf[udp4_offset]); + //printf("udp4 length: %d\n", ntohs(udp4_header->length)); + assert(udp4_offset + ntohs(udp4_header->length) == length); + + ////////////////////////////////////////////////////////////////////// + // dhcp4 + ////////////////////////////////////////////////////////////////////// + + dhcp4::message const * dhcp4_message = reinterpret_cast(&buf[dhcp4_offset]); + uint8_t const * dhcp4_options = dhcp4_message->options; + //printf("dhcp4 cookie %02x %02x %02x %02x\n", dhcp4_options[0], dhcp4_options[1], dhcp4_options[2], dhcp4_options[3]); + assert(dhcp4_options[0] == 0x63 && + dhcp4_options[1] == 0x82 && + dhcp4_options[2] == 0x53 && + dhcp4_options[3] == 0x63); + + ////////////////////////////////////////////////////////////////////// + // packet + ////////////////////////////////////////////////////////////////////// + + p->eth = eth_header; + p->ip4 = ip4_header; + p->udp4 = udp4_header; + p->dhcp4 = dhcp4_message; + } +} diff --git a/packet.h b/packet.h new file mode 100644 index 0000000..377d7b0 --- /dev/null +++ b/packet.h @@ -0,0 +1,22 @@ +#pragma once + +#include "eth.h" +#include "ip4.h" +#include "udp4.h" +#include "dhcp4.h" + +namespace packet { + struct packet { + eth::header const * eth; + ip4::header const * ip4; + udp4::header const * udp4; + dhcp4::message const * dhcp4; + }; + + void parse(uint8_t const * buf, int length, packet * p); + + const int eth_offset = 0; + const int ip4_offset = (sizeof (eth::header)); + const int udp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)); + const int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ip4::header)) + (sizeof (udp4::header)); +}; diff --git a/test.cpp b/test.cpp index b6c5184..b25fc5e 100644 --- a/test.cpp +++ b/test.cpp @@ -5,7 +5,7 @@ #include #include "udp4.h" -#include "ipv4.h" +#include "ip4.h" #include "dhcp4.h" void dump_hex(void const * src, int length) @@ -32,16 +32,16 @@ int main() inet_aton("192.168.1.1", &srcA); inet_aton("192.168.1.240", &dstA); - int ipv4_payload_length = (sizeof (payload)) + (sizeof (udp4::header)); - int ipv4_identification = 55179; + int ip4_payload_length = (sizeof (payload)) + (sizeof (udp4::header)); + int ip4_identification = 55179; int offset = 0; - ipv4::header * ipv4_header = ipv4::make_header(reinterpret_cast(&buf[offset]), - ipv4_payload_length, - ipv4_identification, + ip4::header * ip4_header = ip4::make_header(reinterpret_cast(&buf[offset]), + ip4_payload_length, + ip4_identification, srcA.s_addr, dstA.s_addr); - offset += (sizeof (ipv4::header)); - dump_hex(ipv4_header, (sizeof (ipv4::header))); + offset += (sizeof (ip4::header)); + dump_hex(ip4_header, (sizeof (ip4::header))); udp4::header * udp4_header = udp4::make_header(reinterpret_cast(&buf[offset]), htons(67), diff --git a/test2.cpp b/test2.cpp new file mode 100644 index 0000000..567bcd0 --- /dev/null +++ b/test2.cpp @@ -0,0 +1,31 @@ +#include +#include +#include + +#include + +#include "packet.h" + +unsigned char bytes[] = {0xf4, 0x7b, 0x9, 0x99, 0x3e, 0x28, 0x0, 0xbc, 0x2f, 0x8c, 0x58, 0x20, 0x8, 0x0, 0x45, 0xb8, 0x1, 0x6f, 0x48, 0x9d, 0x0, 0x0, 0x40, 0x11, 0xab, 0xe7, 0xc0, 0xa8, 0x1, 0x1, 0xc0, 0xa8, 0x1, 0xf0, 0x0, 0x43, 0x0, 0x44, 0x1, 0x5b, 0xe6, 0xe6, 0x2, 0x1, 0x6, 0x0, 0x99, 0x87, 0x50, 0x1a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0xa8, 0x1, 0xf0, 0xc0, 0xa8, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0xf4, 0x7b, 0x9, 0x99, 0x3e, 0x28, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x63, 0x82, 0x53, 0x63, 0x35, 0x1, 0x2, 0x36, 0x4, 0xc0, 0xa8, 0x1, 0x1, 0x33, 0x4, 0x0, 0x1, 0x51, 0x80, 0x3a, 0x4, 0x0, 0x0, 0xa8, 0xc0, 0x3b, 0x4, 0x0, 0x1, 0x27, 0x50, 0x1c, 0x4, 0xc0, 0xa8, 0x1, 0xff, 0x3, 0x4, 0xc0, 0xa8, 0x1, 0x1, 0xf, 0x3, 0x6c, 0x61, 0x6e, 0x1, 0x4, 0xff, 0xff, 0xff, 0x0, 0x6, 0x4, 0xc0, 0xa8, 0x1, 0x1, 0x7d, 0x28, 0x0, 0x0, 0xd, 0xe9, 0x23, 0x6, 0x8, 0x47, 0x52, 0x42, 0x45, 0x33, 0x33, 0x31, 0x43, 0x5, 0xf, 0x52, 0x30, 0x31, 0x43, 0x31, 0x4d, 0x32, 0x35, 0x34, 0x36, 0x30, 0x30, 0x32, 0x48, 0x45, 0x4, 0x6, 0x30, 0x30, 0x30, 0x46, 0x42, 0x33, 0xff}; + +void parse_packet(uint8_t const * buf, int length) +{ + packet::packet p; + packet::parse(buf, length, &p); + + printf("dhcp4 op: %d\n", p.dhcp4->op); + printf("dhcp4 yiaddr: %s\n", ip4::tostr(p.dhcp4->yiaddr)); + + int dhcp4_options_length = length - (packet::dhcp4_offset + (offsetof (dhcp4::message, options))); + dhcp4::options options = {}; + dhcp4::parse_options(p.dhcp4, dhcp4_options_length, &options); + printf("message type: %d\n", options.message_type); + printf("subnet mask: %s\n", ip4::tostr(options.subnet_mask)); + printf("router: %s\n", ip4::tostr(options.router)); + printf("domain name server: %s\n", ip4::tostr(options.domain_name_server)); +} + +int main() +{ + parse_packet(bytes, (sizeof (bytes))); +} diff --git a/udp4.cpp b/udp4.cpp index 8a38d03..4a70e64 100644 --- a/udp4.cpp +++ b/udp4.cpp @@ -3,7 +3,7 @@ #include -#include "ipv4.h" +#include "ip4.h" #include "udp4.h" namespace udp4 { @@ -22,19 +22,19 @@ namespace udp4 { hdr->destination_port = destination_port; hdr->length = htons(payload_length + (sizeof (header))); - ipv4_psuedo_header phdr; + ip4_psuedo_header phdr; phdr.source_address = source_address; phdr.destination_address = destination_address; phdr.zeros = 0; - phdr.protocol = ipv4::protocol::udp; + phdr.protocol = ip4::protocol::udp; phdr.udp_length = hdr->length; // already big endian uint32_t sum = 0; - sum = ipv4::checksum_partial(sum, reinterpret_cast(&phdr), (sizeof (ipv4_psuedo_header))); - sum = ipv4::checksum_partial(sum, reinterpret_cast(hdr), (sizeof (header))); - sum = ipv4::checksum_partial(sum, reinterpret_cast(payload), payload_length); + sum = ip4::checksum_partial(sum, reinterpret_cast(&phdr), (sizeof (ip4_psuedo_header))); + sum = ip4::checksum_partial(sum, reinterpret_cast(hdr), (sizeof (header))); + sum = ip4::checksum_partial(sum, reinterpret_cast(payload), payload_length); - hdr->checksum = htons(ipv4::checksum_finish(sum)); + hdr->checksum = htons(ip4::checksum_finish(sum)); return hdr; } diff --git a/udp4.h b/udp4.h index 628ee9f..ef8812e 100644 --- a/udp4.h +++ b/udp4.h @@ -2,7 +2,7 @@ #include -#include "ipv4.h" +#include "ip4.h" namespace udp4 { struct header { @@ -14,7 +14,7 @@ namespace udp4 { static_assert((sizeof (header)) == 8); - struct ipv4_psuedo_header { + struct ip4_psuedo_header { uint32_t source_address; uint32_t destination_address; uint8_t zeros;