From 4024bcf42fac1e5c2fad4058f281a72c88b872ae Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 18 Aug 2026 23:53:39 -0500 Subject: [PATCH] initial --- .gitignore | 3 + bpf.asm | 11 +++ client.cpp | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++++ dhcp4.cpp | 67 +++++++++++++++ dhcp4.h | 71 ++++++++++++++++ eth.h | 11 +++ ipv4.cpp | 70 ++++++++++++++++ ipv4.h | 37 +++++++++ test.cpp | 64 +++++++++++++++ udp4.cpp | 41 ++++++++++ udp4.h | 32 ++++++++ 11 files changed, 640 insertions(+) create mode 100644 .gitignore create mode 100644 bpf.asm create mode 100644 client.cpp create mode 100644 dhcp4.cpp create mode 100644 dhcp4.h create mode 100644 eth.h create mode 100644 ipv4.cpp create mode 100644 ipv4.h create mode 100644 test.cpp create mode 100644 udp4.cpp create mode 100644 udp4.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d866725 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.o +*.out +.gdb_history \ No newline at end of file diff --git a/bpf.asm b/bpf.asm new file mode 100644 index 0000000..38d9e9d --- /dev/null +++ b/bpf.asm @@ -0,0 +1,11 @@ +l0: ldh [12] /* eth.type */ +l1: jeq #0x800, l2, l10 /* if ipv4, l3 */ +l2: ldb [23] /* ip.proto */ +l3: jeq #0x11, l4, l10 /* if UDP, l5 */ +l4: ldh [20] /* ip.frag_offset */ +l5: jset #0x1fff, l10, l6 /* if not fragmented, l7 */ +l6: ldxb 4*([14]&0xf) /* ip.hdr_len * 4 -> X */ +l7: ldh [x + 16] /* 36: UDP destination port */ +l8: jeq #0x44, l9, l10 /* if equal to 68, l10 */ +l9: ret #0x40000 /* keep 262144 bytes */ +l10: ret #0 /* discard the packet */ diff --git a/client.cpp b/client.cpp new file mode 100644 index 0000000..b47151d --- /dev/null +++ b/client.cpp @@ -0,0 +1,233 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ipv4.h" +#include "udp4.h" +#include "dhcp4.h" +#include "eth.h" + +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 dhcp_transaction_id, + uint32_t const dhcp_message_type) +{ + ////////////////////////////////////////////////////////////////////// + // dhcp4 + ////////////////////////////////////////////////////////////////////// + + int dhcp4_offset = (sizeof (eth::header)) + (sizeof (ipv4::header)) + (sizeof (udp4::header)); + int dhcp4_length = dhcp4::make_message(reinterpret_cast(&buf[dhcp4_offset]), + dhcp4::op::bootrequest, + dhcp_transaction_id, + eth_source_address, + dhcp_message_type); + + ////////////////////////////////////////////////////////////////////// + // eth + ////////////////////////////////////////////////////////////////////// + + int eth_offset = 0; + eth::header * eth_header = reinterpret_cast(&buf[eth_offset]); + memcpy(eth_header->destination_address, eth_destination_address, 6); + memcpy(eth_header->source_address, eth_source_address, 6); + eth_header->ether_type = htons(0x0800); + + ////////////////////////////////////////////////////////////////////// + // ipv4 + ////////////////////////////////////////////////////////////////////// + + 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); + + ////////////////////////////////////////////////////////////////////// + // udp4 + ////////////////////////////////////////////////////////////////////// + + int udp4_offset = (sizeof (eth::header)) + (sizeof (ipv4::header)); + udp4::make_header(reinterpret_cast(&buf[udp4_offset]), + htons(68), + htons(67), + ipv4_source_address, + ipv4_destination_address, + &buf[dhcp4_offset], + dhcp4_length); + + return dhcp4_offset + dhcp4_length; +} + +void interface_send(int sock, + int interface_index, + void * buf, + int length, + uint8_t const * eth_destination_address) +{ + struct sockaddr_ll socket_address; + socket_address.sll_ifindex = interface_index; + socket_address.sll_halen = ETH_ALEN; + memcpy(socket_address.sll_addr, eth_destination_address, 6); + int flags = 0; + int sret = sendto(sock, buf, length, flags, + (struct sockaddr *)&socket_address, sizeof(struct sockaddr_ll)); + if (sret < 0) { + perror("sendto"); + exit(EXIT_FAILURE); + } +} + +void attach_dhcp_filter(int sock) +{ + struct sock_filter filter[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 8, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 6, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 4, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x00000044 }, + { 0x06, 0, 0, 0x00040000 }, + { 0x06, 0, 0, 0000000000 }, + }; + + struct sock_fprog fprog = { + .len = sizeof(filter) / sizeof(filter[0]), + .filter = filter, + }; + int ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, (sizeof (fprog))); + if (ret < 0) { + perror("setsockopt(SO_ATTACH_FILTER)"); + exit(EXIT_FAILURE); + } +} + +int main() +{ + srand(time(NULL)); + + uint8_t buf[16384]; + + ////////////////////////////////////////////////////////////////////// + // socket + ////////////////////////////////////////////////////////////////////// + + int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW); + if (s < 0) { + perror("socket"); + exit(EXIT_FAILURE); + } + + { + int enable = 1; + int ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &enable, (sizeof (int))); + if (ret < 0) { + perror("setsockopt(SO_BROADCAST)"); + exit(EXIT_FAILURE); + } + } + + ////////////////////////////////////////////////////////////////////// + // interface index + ////////////////////////////////////////////////////////////////////// + + char const * interface_name = "wlp174s0"; + + struct ifreq if_index; + memset(&if_index, 0, (sizeof (struct ifreq))); + strncpy(if_index.ifr_name, interface_name, IFNAMSIZ - 1); + int iret = ioctl(s, SIOCGIFINDEX, &if_index); + if (iret < 0) { + perror("ioctl(SIOCGIFINDEX)"); + exit(EXIT_FAILURE); + } + printf("interface index %d\n", if_index.ifr_ifindex); + + ////////////////////////////////////////////////////////////////////// + // interface address + ////////////////////////////////////////////////////////////////////// + + struct ifreq if_hwaddr; + memset(&if_hwaddr, 0, sizeof(struct ifreq)); + strncpy(if_hwaddr.ifr_name, interface_name, IFNAMSIZ - 1); + int hret = ioctl(s, SIOCGIFHWADDR, &if_hwaddr); + if (hret < 0) { + perror("ioctl(SIOCGIFHWADDR)"); + exit(EXIT_FAILURE); + } + printf("hardware address %02x:%02x:%02x:%02x:%02x:%02x\n", + (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[0], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[1], + (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[2], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[3], + (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[4], (uint8_t)if_hwaddr.ifr_hwaddr.sa_data[5]); + + ////////////////////////////////////////////////////////////////////// + // bind + ////////////////////////////////////////////////////////////////////// + + struct sockaddr_ll bind_addr = { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_ALL), + .sll_ifindex = if_index.ifr_ifindex, + }; + int bret = bind(s, (struct sockaddr *)&bind_addr, (sizeof (struct sockaddr_ll))); + if (bret < 0) { + perror("bind"); + exit(EXIT_FAILURE); + } + + attach_dhcp_filter(s); + + ////////////////////////////////////////////////////////////////////// + // send + ////////////////////////////////////////////////////////////////////// + + uint32_t dhcp_transaction_id = rand(); + + uint8_t eth_source_address[6] = {}; + 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; + + int length = make_packet(buf, + eth_source_address, + eth_destination_address, + ipv4_source_address, + ipv4_destination_address, + dhcp_transaction_id, + dhcp4::message_type::dhcpdiscover); + + interface_send(s, if_index.ifr_ifindex, buf, length, eth_destination_address); + + uint8_t recvbuf[65536]; + struct sockaddr_ll recv_address; + int flags = 0; + socklen_t socklen = (sizeof (struct sockaddr_ll)); + ssize_t ret = recvfrom(s, recvbuf, 16384, flags, + (struct sockaddr *)&recv_address, &socklen); + printf("recv ret %ld\n", ret); + + close(s); + exit(EXIT_SUCCESS); +} diff --git a/dhcp4.cpp b/dhcp4.cpp new file mode 100644 index 0000000..5359230 --- /dev/null +++ b/dhcp4.cpp @@ -0,0 +1,67 @@ +#include + +#include + +#include "dhcp4.h" + +namespace dhcp4 { + + int make_message(void * buf, + uint32_t bootp_message_type, + uint32_t transaction_id, + uint8_t const * chaddr, + uint32_t dhcp_message_type) + { + memset(buf, 0, (sizeof (message))); + message * msg = reinterpret_cast(buf); + + msg->op = bootp_message_type; + msg->htype = htype::ethernet; + msg->hlen = 6; + msg->xid = htonl(transaction_id); + memcpy(msg->chaddr, chaddr, 6); + + int index = 0; + + uint8_t * cookie = &msg->options[index]; + index += 4; + cookie[0] = 0x63; + cookie[1] = 0x82; + cookie[2] = 0x53; + cookie[3] = 0x63; + + uint8_t * message_type = &msg->options[index]; + index += 2 + 1; + message_type[0] = option::message_type; + message_type[1] = 1; // length + message_type[2] = dhcp_message_type; + + { + uint8_t * prl = &msg->options[index]; + int length = 4; + 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; + } + + uint8_t * end = &msg->options[index]; + index += 1; + end[0] = 255; + + return (sizeof (message)) + index; + } +} diff --git a/dhcp4.h b/dhcp4.h new file mode 100644 index 0000000..fd4ef45 --- /dev/null +++ b/dhcp4.h @@ -0,0 +1,71 @@ +#pragma once + +#include +#include + +namespace dhcp4 { + + struct __attribute__((packed)) message { + uint8_t op; // message type + uint8_t htype; // hardware type + uint8_t hlen; // hardware address length + uint8_t hops; + uint32_t xid; // transaction id + uint16_t secs; // seconds elapsed + uint16_t flags; + uint32_t ciaddr; // client IP address + uint32_t yiaddr; // your (client) IP address + uint32_t siaddr; // next server IP address + uint32_t giaddr; // relay agent IP address + uint8_t chaddr[16]; // client hardware address + uint8_t sname[64]; + uint8_t file[128]; + uint8_t options[]; + }; + + struct op { + enum { + bootrequest = 1, + bootreply = 2, + }; + }; + + struct htype { + enum { + ethernet = 1, + }; + }; + + static_assert((sizeof (message)) == 236); + + struct option { + enum { + ip_address_lease_time = 51, + option_overload = 52, + message_type = 53, + server_identifier = 54, + parameter_request_list = 55, + maximum_message_size = 57, + client_identifier = 61, + }; + }; + + struct message_type { + enum { + dhcpdiscover = 1, + dhcpoffer = 2, + dhcprequest = 3, + dhcpdecline = 4, + dhcpack = 5, + dhcpnak = 6, + dhcprelease = 7, + dhcpinform = 8, + }; + }; + + int make_message(void * buf, + uint32_t bootp_message_type, + uint32_t transaction_id, + uint8_t const * chaddr, + uint32_t dhcp_message_type); +} diff --git a/eth.h b/eth.h new file mode 100644 index 0000000..5fc2a40 --- /dev/null +++ b/eth.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace eth { + struct header { + uint8_t destination_address[6]; + uint8_t source_address[6]; + uint16_t ether_type; + }; +} diff --git a/ipv4.cpp b/ipv4.cpp new file mode 100644 index 0000000..7b7bc02 --- /dev/null +++ b/ipv4.cpp @@ -0,0 +1,70 @@ +#include +#include +#include + +#include + +#include "ipv4.h" + +namespace ipv4 { + + uint32_t checksum_partial(uint32_t sum, void const * src, int length) + { + uint8_t const * addr = reinterpret_cast(src); + + ptrdiff_t i = 0; + while (length >= 2) { + sum += (addr[i+0] << 8) | (addr[i+1] << 0); + i += 2; + length -= 2; + } + + if (length > 0) { + sum += (addr[i+0] << 8); + } + + return sum; + } + + uint32_t checksum_finish(uint32_t sum) + { + while (sum >> 16) { + sum = (sum & 0xffff) + (sum >> 16); + } + + return static_cast(~sum); + } + + uint32_t checksum(void const * src, int length) + { + uint32_t sum = checksum_partial(0, src, length); + return checksum_finish(sum); + } + + header * make_header(void * buf, + uint16_t payload_length, + uint16_t identification, + uint32_t source_address, // big endian + uint32_t destination_address) // big endian + { + memset(buf, 0, (sizeof (header))); + header * hdr = reinterpret_cast
(buf); + + const int version = 4; + const int ihl = (sizeof (header)) / 4; + const int total_length = payload_length + (sizeof (header)); + + hdr->version_ihl = (version << 4) | (ihl << 0); + //hdr->type_of_service = 0xb8; + hdr->total_length = htons(total_length); + hdr->identification = htons(identification); + hdr->time_to_live = 64; + hdr->protocol = protocol::udp; + hdr->source_address = source_address; + hdr->destination_address = destination_address; + + hdr->header_checksum = htons(checksum(buf, (sizeof (header)))); + + return hdr; + } +} diff --git a/ipv4.h b/ipv4.h new file mode 100644 index 0000000..bf52273 --- /dev/null +++ b/ipv4.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +namespace ipv4 { + + struct header { + uint8_t version_ihl; + uint8_t type_of_service; + uint16_t total_length; + uint16_t identification; + uint16_t fragment_offset; + uint8_t time_to_live; + uint8_t protocol; + uint16_t header_checksum; + uint32_t source_address; + uint32_t destination_address; + }; + + static_assert((sizeof (header)) == 20); + + 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); + + header * make_header(void * buf, + uint16_t payload_length, + uint16_t identification, + uint32_t source_address, // big endian + uint32_t destination_address); // big endian + + struct protocol { + enum { + udp = 17, + }; + }; +} diff --git a/test.cpp b/test.cpp new file mode 100644 index 0000000..b6c5184 --- /dev/null +++ b/test.cpp @@ -0,0 +1,64 @@ +#include +#include +#include + +#include + +#include "udp4.h" +#include "ipv4.h" +#include "dhcp4.h" + +void dump_hex(void const * src, int length) +{ + uint8_t const * u8 = reinterpret_cast(src); + for (int i = 0; i < length; i++) { + printf("%02x ", u8[i]); + if (i % 16 == 15) + printf("\n"); + } + printf("\n"); +} + +int main() +{ + int udp_header = 8 + 339; + + unsigned char payload[] = {0x2, 0x1, 0x6, 0x0, 0x12, 0x27, 0x67, 0xa8, 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, 0x5, 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}; + + uint8_t buf[16384]; + + struct in_addr srcA; + struct in_addr dstA; + 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 offset = 0; + ipv4::header * ipv4_header = ipv4::make_header(reinterpret_cast(&buf[offset]), + ipv4_payload_length, + ipv4_identification, + srcA.s_addr, + dstA.s_addr); + offset += (sizeof (ipv4::header)); + dump_hex(ipv4_header, (sizeof (ipv4::header))); + + udp4::header * udp4_header = udp4::make_header(reinterpret_cast(&buf[offset]), + htons(67), + htons(68), + srcA.s_addr, + dstA.s_addr, + payload, + (sizeof (payload))); + offset += (sizeof (udp4::header)); + + dump_hex(udp4_header, (sizeof (udp4::header))); + + uint32_t transaction_id = 0x122767a8; + int dhcp4_length = dhcp4::make_message(reinterpret_cast(&buf[offset]), + dhcp4::op::bootrequest, + transaction_id, + dhcp4::message_type::dhcprequest); + dump_hex(&buf[offset], dhcp4_length); + offset += dhcp4_length; +} diff --git a/udp4.cpp b/udp4.cpp new file mode 100644 index 0000000..8a38d03 --- /dev/null +++ b/udp4.cpp @@ -0,0 +1,41 @@ +#include +#include + +#include + +#include "ipv4.h" +#include "udp4.h" + +namespace udp4 { + header * make_header(void * buf, + uint32_t source_port, + uint32_t destination_port, + uint32_t source_address, + uint32_t destination_address, + void const * payload, + int payload_length) + { + memset(buf, 0, (sizeof (header))); + header * hdr = reinterpret_cast
(buf); + + hdr->source_port = source_port; + hdr->destination_port = destination_port; + hdr->length = htons(payload_length + (sizeof (header))); + + ipv4_psuedo_header phdr; + phdr.source_address = source_address; + phdr.destination_address = destination_address; + phdr.zeros = 0; + phdr.protocol = ipv4::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); + + hdr->checksum = htons(ipv4::checksum_finish(sum)); + + return hdr; + } +} diff --git a/udp4.h b/udp4.h new file mode 100644 index 0000000..628ee9f --- /dev/null +++ b/udp4.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "ipv4.h" + +namespace udp4 { + struct header { + uint16_t source_port; + uint16_t destination_port; + uint16_t length; + uint16_t checksum; + }; + + static_assert((sizeof (header)) == 8); + + struct ipv4_psuedo_header { + uint32_t source_address; + uint32_t destination_address; + uint8_t zeros; + uint8_t protocol; + uint16_t udp_length; + }; + + header * make_header(void * buf, + uint32_t source_port, + uint32_t destination_port, + uint32_t source_address, + uint32_t destination_address, + void const * payload, + int payload_length); +}