diff --git a/ndhc/arp.c b/ndhc/arp.c index df38bde..174f792 100644 --- a/ndhc/arp.c +++ b/ndhc/arp.c @@ -204,12 +204,12 @@ static void arp_failed(struct client_state_t *cs) { log_line("arp: Offered address is in use -- declining"); arp_close_fd(cs); - send_decline(cs->xid, cs->serverAddr, arp_dhcp_packet.yiaddr); + send_decline(cs, arp_dhcp_packet.yiaddr); if (cs->arpPrevState != DS_REQUESTING) ifchange(NULL, IFCHANGE_DECONFIG); cs->dhcpState = DS_SELECTING; - cs->requestedIP = 0; + cs->clientAddr = 0; cs->timeout = 0; cs->packetNum = 0; set_listen_raw(cs); @@ -224,7 +224,7 @@ void arp_gw_failed(struct client_state_t *cs) cs->dhcpState = DS_SELECTING; cs->oldTimeout = 0; cs->timeout = 0; - cs->requestedIP = 0; + cs->clientAddr = 0; cs->packetNum = 0; set_listen_raw(cs); } @@ -237,7 +237,7 @@ void arp_success(struct client_state_t *cs) struct in_addr temp_addr = {.s_addr = arp_dhcp_packet.yiaddr}; log_line("arp: Lease of %s obtained, lease time %ld", inet_ntoa(temp_addr), cs->lease); - cs->requestedIP = arp_dhcp_packet.yiaddr; + cs->clientAddr = arp_dhcp_packet.yiaddr; cs->dhcpState = DS_BOUND; cs->init = 0; ifchange(&arp_dhcp_packet, diff --git a/ndhc/config.h b/ndhc/config.h index 3dc1a4a..7e66d93 100644 --- a/ndhc/config.h +++ b/ndhc/config.h @@ -23,14 +23,6 @@ #include -enum { - IFS_NONE = 0, - IFS_UP, - IFS_DOWN, - IFS_SHUT, - IFS_REMOVED -}; - struct client_state_t { unsigned long long leaseStartTime; int dhcpState; @@ -40,7 +32,7 @@ struct client_state_t { int packetNum; int epollFd, signalFd, listenFd, arpFd, nlFd; int timeout, oldTimeout; - uint32_t requestedIP, serverAddr, routerAddr; + uint32_t clientAddr, serverAddr, routerAddr; uint32_t lease, renewTime, rebindTime, xid; int using_dhcp_bpf; uint8_t routerArp[6]; diff --git a/ndhc/ndhc.c b/ndhc/ndhc.c index da32ea1..3fd9c3b 100644 --- a/ndhc/ndhc.c +++ b/ndhc/ndhc.c @@ -60,9 +60,6 @@ #define VERSION "1.0" struct client_state_t cs = { - .dhcpState = DS_SELECTING, - .arpPrevState = DS_SELECTING, - .ifsPrevState = IFS_NONE, .init = 1, .epollFd = -1, .signalFd = -1, @@ -75,8 +72,6 @@ struct client_state_t cs = { struct client_config_t client_config = { /* Default options. */ .interface = "eth0", - .clientid = NULL, - .hostname = NULL, .arp = "\0\0\0\0\0\0", }; @@ -252,7 +247,7 @@ int main(int argc, char **argv) client_config.quit_after_lease = 1; break; case 'r': - cs.requestedIP = inet_addr(optarg); + cs.clientAddr = inet_addr(optarg); break; case 'u': pwd = getpwnam(optarg); diff --git a/ndhc/netlink.c b/ndhc/netlink.c index 2ee4dd3..59c8377 100644 --- a/ndhc/netlink.c +++ b/ndhc/netlink.c @@ -42,6 +42,14 @@ #define NLMSG_RECVSIZE 8192 +enum { + IFS_NONE = 0, + IFS_UP, + IFS_DOWN, + IFS_SHUT, + IFS_REMOVED +}; + static unsigned int nl_seq; /* internal callback handling */ @@ -115,7 +123,7 @@ static void takedown_if(struct client_state_t *cs) ifchange(NULL, IFCHANGE_DECONFIG); cs->dhcpState = DS_SELECTING; cs->timeout = 0; - cs->requestedIP = 0; + cs->clientAddr = 0; cs->packetNum = 0; set_listen_raw(cs); } diff --git a/ndhc/options.c b/ndhc/options.c index 9f0c6ac..67a60f7 100644 --- a/ndhc/options.c +++ b/ndhc/options.c @@ -308,3 +308,14 @@ void add_option_request_list(struct dhcpmsg *packet) reqdata[1] = j - 2; add_option_string(packet, reqdata); } + +void add_option_vendor_string(struct dhcpmsg *packet) +{ + struct vendor { + char vendor; + char length; + char str[sizeof "ndhc"]; + } vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"}; + add_option_string(packet, (uint8_t *)&vendor_id); +} + diff --git a/ndhc/options.h b/ndhc/options.h index 52cc12d..393a677 100644 --- a/ndhc/options.h +++ b/ndhc/options.h @@ -92,5 +92,6 @@ ssize_t get_end_option_idx(struct dhcpmsg *packet); size_t add_option_string(struct dhcpmsg *packet, uint8_t *optstr); size_t add_u32_option(struct dhcpmsg *packet, uint8_t code, uint32_t data); void add_option_request_list(struct dhcpmsg *packet); +void add_option_vendor_string(struct dhcpmsg *packet); #endif diff --git a/ndhc/packet.c b/ndhc/packet.c index 458c206..bfd4d98 100644 --- a/ndhc/packet.c +++ b/ndhc/packet.c @@ -2,7 +2,6 @@ * Time-stamp: <2011-06-11 11:15:09 njk> * * (c) 2004-2011 Nicholas J. Kain - * (c) 2001 Russ Dill * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -353,7 +351,8 @@ static int create_raw_listen_socket(struct client_state_t *cs, int ifindex) // Verify that the UDP client and server ports match that of the // IANA-assigned DHCP ports. BPF_STMT(BPF_LD + BPF_W + BPF_IND, 0), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (67 << 16) + 68, 1, 0), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, + (DHCP_SERVER_PORT << 16) + DHCP_CLIENT_PORT, 1, 0), BPF_STMT(BPF_RET + BPF_K, 0), // Get the UDP length field and store it in X. BPF_STMT(BPF_LD + BPF_H + BPF_IND, 4), @@ -489,7 +488,7 @@ static int validate_dhcp_packet(struct client_state_t *cs, int len, { ssize_t optlen; if (len < sizeof *packet - sizeof packet->options) { - log_line("Packet is too short to contain magic cookie. Ignoring."); + log_line("Packet is too short to contain magic cookie. Ignoring."); return 0; } if (ntohl(packet->cookie) != DHCP_MAGIC) { @@ -502,7 +501,7 @@ static int validate_dhcp_packet(struct client_state_t *cs, int len, return 0; } if (!(*msg = get_option_data(packet, DHCP_MESSAGE_TYPE, &optlen))) { - log_line("Packet does not specify a DHCP message type. Ignoring."); + log_line("Packet does not specify a DHCP message type. Ignoring."); return 0; } return 1; @@ -550,73 +549,77 @@ static struct dhcpmsg init_packet(char type, uint32_t xid) add_option_string(&packet, client_config.clientid); if (client_config.hostname) add_option_string(&packet, client_config.hostname); - struct vendor { - char vendor; - char length; - char str[sizeof "ndhc"]; - } vendor_id = { DHCP_VENDOR, sizeof "ndhc" - 1, "ndhc"}; - add_option_string(&packet, (uint8_t *)&vendor_id); return packet; } -// Broadcast a DHCP discover packet to the network, with an optionally -// requested IP -int send_discover(uint32_t xid, uint32_t requested) +int send_discover(struct client_state_t *cs) { - struct dhcpmsg packet = init_packet(DHCPDISCOVER, xid); - if (requested) - add_u32_option(&packet, DHCP_REQUESTED_IP, requested); - // Request a RFC-specified max size to work around buggy servers. - add_u32_option(&packet, DHCP_MAX_SIZE, htons(576)); + struct dhcpmsg packet = init_packet(DHCPDISCOVER, cs->xid); + if (cs->clientAddr) + add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr); + add_u32_option(&packet, DHCP_MAX_SIZE, + htons(sizeof(struct ip_udp_dhcp_packet))); add_option_request_list(&packet); + add_option_vendor_string(&packet); log_line("Sending discover..."); return send_dhcp_raw(&packet); } -// Broadcasts a DHCP request message -int send_selecting(uint32_t xid, uint32_t server, uint32_t requested) +int send_selecting(struct client_state_t *cs) { - struct dhcpmsg packet = init_packet(DHCPREQUEST, xid); - add_u32_option(&packet, DHCP_REQUESTED_IP, requested); - add_u32_option(&packet, DHCP_SERVER_ID, server); + struct dhcpmsg packet = init_packet(DHCPREQUEST, cs->xid); + add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr); + add_u32_option(&packet, DHCP_SERVER_ID, cs->serverAddr); + add_u32_option(&packet, DHCP_MAX_SIZE, + htons(sizeof(struct ip_udp_dhcp_packet))); add_option_request_list(&packet); + add_option_vendor_string(&packet); log_line("Sending select for %s...", - inet_ntoa((struct in_addr){.s_addr = requested})); + inet_ntoa((struct in_addr){.s_addr = cs->clientAddr})); return send_dhcp_raw(&packet); } -// Unicasts or broadcasts a DHCP renew message -int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) +int send_renew(struct client_state_t *cs) { - struct dhcpmsg packet = init_packet(DHCPREQUEST, xid); - packet.ciaddr = ciaddr; + struct dhcpmsg packet = init_packet(DHCPREQUEST, cs->xid); + packet.ciaddr = cs->clientAddr; + add_u32_option(&packet, DHCP_MAX_SIZE, + htons(sizeof(struct ip_udp_dhcp_packet))); add_option_request_list(&packet); + add_option_vendor_string(&packet); log_line("Sending renew..."); - if (server) - return send_dhcp_cooked(&packet, ciaddr, server); - else - return send_dhcp_raw(&packet); + return send_dhcp_cooked(&packet, cs->clientAddr, cs->serverAddr); } -// Broadcast a DHCP decline message -int send_decline(uint32_t xid, uint32_t server, uint32_t requested) +int send_rebind(struct client_state_t *cs) { - struct dhcpmsg packet = init_packet(DHCPDECLINE, xid); - // DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP - add_u32_option(&packet, DHCP_REQUESTED_IP, requested); + struct dhcpmsg packet = init_packet(DHCPREQUEST, cs->xid); + packet.ciaddr = cs->clientAddr; + add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr); + add_u32_option(&packet, DHCP_MAX_SIZE, + htons(sizeof(struct ip_udp_dhcp_packet))); + add_option_request_list(&packet); + add_option_vendor_string(&packet); + log_line("Sending rebind..."); + return send_dhcp_raw(&packet); +} + +int send_decline(struct client_state_t *cs, uint32_t server) +{ + struct dhcpmsg packet = init_packet(DHCPDECLINE, cs->xid); + add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr); add_u32_option(&packet, DHCP_SERVER_ID, server); log_line("Sending decline..."); return send_dhcp_raw(&packet); } -// Unicasts a DHCP release message -int send_release(uint32_t server, uint32_t ciaddr) +int send_release(struct client_state_t *cs) { struct dhcpmsg packet = init_packet(DHCPRELEASE, libc_random_u32()); - packet.ciaddr = ciaddr; - add_u32_option(&packet, DHCP_REQUESTED_IP, ciaddr); - add_u32_option(&packet, DHCP_SERVER_ID, server); + packet.ciaddr = cs->clientAddr; + add_u32_option(&packet, DHCP_REQUESTED_IP, cs->clientAddr); + add_u32_option(&packet, DHCP_SERVER_ID, cs->serverAddr); log_line("Sending release..."); - return send_dhcp_cooked(&packet, ciaddr, server); + return send_dhcp_cooked(&packet, cs->clientAddr, cs->serverAddr); } diff --git a/ndhc/packet.h b/ndhc/packet.h index fb71d9b..e12597b 100644 --- a/ndhc/packet.h +++ b/ndhc/packet.h @@ -79,10 +79,11 @@ void set_listen_raw(struct client_state_t *cs); void set_listen_cooked(struct client_state_t *cs); void set_listen_none(struct client_state_t *cs); void handle_packet(struct client_state_t *cs); -int send_discover(uint32_t xid, uint32_t requested); -int send_selecting(uint32_t xid, uint32_t server, uint32_t requested); -int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr); -int send_decline(uint32_t xid, uint32_t server, uint32_t requested); -int send_release(uint32_t server, uint32_t ciaddr); +int send_discover(struct client_state_t *cs); +int send_selecting(struct client_state_t *cs); +int send_renew(struct client_state_t *cs); +int send_rebind(struct client_state_t *cs); +int send_decline(struct client_state_t *cs, uint32_t server); +int send_release(struct client_state_t *cs); #endif diff --git a/ndhc/state.c b/ndhc/state.c index 7dd0224..62ff5df 100644 --- a/ndhc/state.c +++ b/ndhc/state.c @@ -63,7 +63,7 @@ static int delay_timeout(int numpackets) static void requesting_timeout(struct client_state_t *cs) { if (cs->packetNum < 5) { - send_selecting(cs->xid, cs->serverAddr, cs->requestedIP); + send_selecting(cs); cs->timeout = delay_timeout(cs->packetNum); cs->packetNum++; } else { @@ -107,7 +107,7 @@ static void renewing_timeout(struct client_state_t *cs) if (ct < rbt) { long long wt = (rbt - ct) / 2; if (wt >= 30000) - send_renew(cs->xid, cs->serverAddr, cs->requestedIP); + send_renew(cs); else wt = rbt - ct; cs->timeout = wt; @@ -133,7 +133,7 @@ static void rebinding_timeout(struct client_state_t *cs) if (ct < elt) { long long wt = (elt - ct) / 2; if (wt >= 30000) - send_renew(cs->xid, 0, cs->requestedIP); + send_rebind(cs); else wt = elt - ct; cs->timeout = wt; @@ -176,7 +176,7 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet, ifchange(NULL, IFCHANGE_DECONFIG); cs->dhcpState = DS_SELECTING; cs->timeout = 30000; - cs->requestedIP = 0; + cs->clientAddr = 0; cs->packetNum = 0; set_listen_raw(cs); } @@ -188,7 +188,7 @@ static void an_packet(struct client_state_t *cs, struct dhcpmsg *packet, ifchange(NULL, IFCHANGE_DECONFIG); cs->dhcpState = DS_SELECTING; cs->timeout = 3000; - cs->requestedIP = 0; + cs->clientAddr = 0; cs->packetNum = 0; set_listen_raw(cs); } @@ -203,7 +203,7 @@ static void selecting_packet(struct client_state_t *cs, struct dhcpmsg *packet, if ((temp = get_option_data(packet, DHCP_SERVER_ID, &optlen))) { memcpy(&cs->serverAddr, temp, 4); cs->xid = packet->xid; - cs->requestedIP = packet->yiaddr; + cs->clientAddr = packet->yiaddr; cs->dhcpState = DS_REQUESTING; cs->timeout = 0; cs->packetNum = 0; @@ -221,7 +221,7 @@ static void selecting_timeout(struct client_state_t *cs) { if (cs->packetNum == 0) cs->xid = libc_random_u32(); - send_discover(cs->xid, cs->requestedIP); + send_discover(cs); cs->timeout = delay_timeout(cs->packetNum); cs->packetNum++; if (cs->init && cs->packetNum >= 2) { @@ -245,9 +245,9 @@ static void anfrelease(struct client_state_t *cs) static void nfrelease(struct client_state_t *cs) { log_line("Unicasting a release of %s to %s.", - inet_ntoa((struct in_addr){.s_addr=cs->requestedIP}), + inet_ntoa((struct in_addr){.s_addr=cs->clientAddr}), inet_ntoa((struct in_addr){.s_addr=cs->serverAddr})); - send_release(cs->serverAddr, cs->requestedIP); + send_release(cs); ifchange(NULL, IFCHANGE_DECONFIG); frelease(cs); } @@ -270,7 +270,7 @@ static void frenew(struct client_state_t *cs) arp_close_fd(cs); cs->dhcpState = DS_RENEWING; set_listen_cooked(cs); - send_renew(cs->xid, cs->serverAddr, cs->requestedIP); + send_renew(cs); break; case DS_ARP_CHECK: // Cancel arp ping in progress and treat as previous state.