From f4a00f38264e97b29771d7a5f192b4e284f80307 Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Fri, 12 Nov 2010 14:33:17 -0500 Subject: [PATCH] Whitespace and indentation normalization. --- README | 5 +- ifchd/ifchd.c | 13 +- ifchd/linux.c | 135 ++++--- ifchd/linux.h | 9 +- ndhc/clientpacket.c | 389 ++++++++++---------- ndhc/dhcpc.c | 863 ++++++++++++++++++++++---------------------- ndhc/options.c | 114 +++--- ndhc/packet.c | 297 ++++++++------- ndhc/script.c | 368 ++++++++++--------- ndhc/socket.c | 188 +++++----- 10 files changed, 1183 insertions(+), 1198 deletions(-) diff --git a/README b/README index fd99441..52f7c3d 100644 --- a/README +++ b/README @@ -10,10 +10,7 @@ C99-compliant C compiler (for C99 struct subobject init) CMake (tested: 2.8) -Tested with glibc 2.2.x and 2.3.x. dietlibc is not compatible. I have not yet -tested uclibc. - -I may bother to port to other operating systems, but don't count on it. +Tested with glibc. dietlibc is not compatible. I have not tested uclibc. INTRODUCTION ------------ diff --git a/ifchd/ifchd.c b/ifchd/ifchd.c index c5153bd..790e381 100644 --- a/ifchd/ifchd.c +++ b/ifchd/ifchd.c @@ -1,7 +1,7 @@ /* ifchd.c - interface change daemon - * Time-stamp: <2010-11-12 12:04:25 njk> + * Time-stamp: <2010-11-12 14:27:47 njk> * - * (C) 2004 Nicholas J. Kain + * (C) 2004-2010 Nicholas J. Kain * * 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 @@ -16,7 +16,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ #include @@ -654,7 +653,7 @@ static void dispatch_work(void) idle_time[i] = time(NULL); memset(buf, '\0', sizeof(buf)); -dispatch_work_read_again: +read_again: ret = (int) read(sks[i], buf, MAX_BUF / 2 - 1); /* Check to see if peer closed socket */ @@ -666,7 +665,7 @@ dispatch_work_read_again: if (ret == -1) { if (errno == EINTR) - goto dispatch_work_read_again; + goto read_again; log_line("dispatch_work: read returned %s.\n", strerror(errno)); close(sks[i]); new_sk(i, -1); @@ -747,7 +746,7 @@ int main(int argc, char** argv) { printf( "ifchd %s, if change daemon. Licensed under GNU GPL.\n", IFCHD_VERSION); printf( -"Copyright (C) 2004 Nicholas J. Kain\n" +"Copyright (C) 2004-2010 Nicholas J. Kain\n" "Usage: ifchd [OPTIONS]\n" " -d, --detach detach from TTY and daemonize\n" " -n, --nodetach stay attached to TTY\n" @@ -772,7 +771,7 @@ int main(int argc, char** argv) { printf( "ifchd %s, if change daemon. Licensed under GNU GPL.\n", IFCHD_VERSION); printf( -"Copyright (C) 2004 Nicholas J. Kain\n" +"Copyright (C) 2004-2010 Nicholas J. Kain\n" "This is free software; see the source for copying conditions. There is NO\n" "WARRANTY; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); exit(EXIT_FAILURE); diff --git a/ifchd/linux.c b/ifchd/linux.c index 72d6e71..7ee7589 100644 --- a/ifchd/linux.c +++ b/ifchd/linux.c @@ -1,7 +1,7 @@ /* linux.c - ifchd Linux-specific functions - * Time-stamp: <2010-11-12 08:45:42 njk> + * Time-stamp: <2010-11-12 14:29:32 njk> * - * (C) 2004 Nicholas J. Kain + * (C) 2004-2010 Nicholas J. Kain * * 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 @@ -16,7 +16,6 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ #include @@ -59,7 +58,7 @@ void initialize_if_data(void) { int i; for (i = 0; i < SOCK_QUEUE; i++) { - clear_if_data(i); + clear_if_data(i); } } @@ -67,7 +66,7 @@ void initialize_if_data(void) void add_permitted_if(char *s) { if (!s) - return; + return; add_to_strlist(&okif, s); } @@ -78,15 +77,15 @@ static int is_permitted(char *name) /* If empty, permit all. */ if (!okif) - return 1; + return 1; if (!name || strlen(name) == 0) - return 0; + return 0; p = okif; while (p) { - if (strcmp(name, p->str) == 0) - return 1; - p = p->next; + if (strcmp(name, p->str) == 0) + return 1; + p = p->next; } log_line("attempt to modify interface %s denied\n", name); return 0; @@ -101,24 +100,24 @@ int authorized_peer(int sk, pid_t pid, uid_t uid, gid_t gid) /* No credentials to verify. */ if ( !(pid || uid || gid) ) - return 1; + return 1; /* Verify that peer has authorized uid/gid/pid. */ cl = sizeof(struct ucred); if (getsockopt(sk, SOL_SOCKET, SO_PEERCRED, &cr, &cl) != -1) { - if ((pid == 0 || cr.pid == pid) || - (uid == 0 || cr.uid == uid) || - (gid == 0 || cr.gid == gid)) - ret = 1; + if ((pid == 0 || cr.pid == pid) || + (uid == 0 || cr.uid == uid) || + (gid == 0 || cr.gid == gid)) + ret = 1; } else - log_line("getsockopt returned an error: %s\n", strerror(errno)); + log_line("getsockopt returned an error: %s\n", strerror(errno)); return ret; } void perform_interface(int idx, char *str) { if (!str) - return; + return; /* Update interface name. */ memset(ifnam[idx], '\0', IFNAMSIZ); @@ -131,32 +130,32 @@ static int set_if_flag(int idx, short flag) struct ifreq ifrt; if (!is_permitted(ifnam[idx])) - goto out0; + goto out0; fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd == -1) { - log_line("%s: (set_if_flag) failed to open interface socket: %s\n", - ifnam[idx], strerror(errno)); - goto out0; + log_line("%s: (set_if_flag) failed to open interface socket: %s\n", + ifnam[idx], strerror(errno)); + goto out0; } strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ); if (ioctl(fd, SIOCGIFFLAGS, &ifrt) < 0) { - log_line("%s: unknown interface: %s\n", ifnam[idx], strerror(errno)); - goto out1; + log_line("%s: unknown interface: %s\n", ifnam[idx], strerror(errno)); + goto out1; } strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ); ifrt.ifr_flags |= flag; if (ioctl(fd, SIOCSIFFLAGS, &ifrt) < 0) { - log_line("%s: failed to set interface flags: %s\n", - ifnam[idx], strerror(errno)); - goto out1; + log_line("%s: failed to set interface flags: %s\n", + ifnam[idx], strerror(errno)); + goto out1; } ret = 0; -out1: + out1: close(fd); -out0: + out0: return ret; } @@ -169,13 +168,13 @@ void perform_ip(int idx, char *str) struct sockaddr_in sin; if (!str) - return; + return; if (!is_permitted(ifnam[idx])) - return; + return; if (!inet_aton(str, &ipaddr)) - return; + return; if (set_if_flag(idx, (IFF_UP | IFF_RUNNING))) - return; + return; strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ); memset(&sin, 0, sizeof(struct sockaddr)); @@ -185,13 +184,13 @@ void perform_ip(int idx, char *str) fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd == -1) { - log_line("%s: (perform_ip) failed to open interface socket: %s\n", - ifnam[idx], strerror(errno)); - return; + log_line("%s: (perform_ip) failed to open interface socket: %s\n", + ifnam[idx], strerror(errno)); + return; } if (ioctl(fd, SIOCSIFADDR, &ifrt) < 0) - log_line("%s: failed to configure IP: %s\n", - ifnam[idx], strerror(errno)); + log_line("%s: failed to configure IP: %s\n", + ifnam[idx], strerror(errno)); close(fd); } @@ -204,11 +203,11 @@ void perform_subnet(int idx, char *str) struct sockaddr_in sin; if (!str) - return; + return; if (!is_permitted(ifnam[idx])) - return; + return; if (!inet_aton(str, &subnet)) - return; + return; strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ); memset(&sin, 0, sizeof(struct sockaddr)); @@ -218,15 +217,15 @@ void perform_subnet(int idx, char *str) fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd == -1) { - log_line("%s: (perform_ip) failed to open interface socket: %s\n", - ifnam[idx], strerror(errno)); - return; + log_line("%s: (perform_ip) failed to open interface socket: %s\n", + ifnam[idx], strerror(errno)); + return; } if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) { - sin.sin_addr.s_addr = 0xffffffff; - if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) - log_line("%s: failed to configure subnet: %s\n", - ifnam[idx], strerror(errno)); + sin.sin_addr.s_addr = 0xffffffff; + if (ioctl(fd, SIOCSIFNETMASK, &ifrt) < 0) + log_line("%s: failed to configure subnet: %s\n", + ifnam[idx], strerror(errno)); } close(fd); } @@ -241,11 +240,11 @@ void perform_router(int idx, char *str) int fd; if (!str) - return; + return; if (!is_permitted(ifnam[idx])) - return; + return; if (!inet_aton(str, &router)) - return; + return; memset(&rt, 0, sizeof(struct rtentry)); dest = (struct sockaddr_in *) &rt.rt_dst; @@ -265,12 +264,12 @@ void perform_router(int idx, char *str) fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd == -1) { - log_line("%s: (perform_router) failed to open interface socket: %s\n", - ifnam[idx], strerror(errno)); - return; + log_line("%s: (perform_router) failed to open interface socket: %s\n", + ifnam[idx], strerror(errno)); + return; } if (ioctl(fd, SIOCADDRT, &rt)) - log_line("%s: failed to set route: %s\n", ifnam[idx], strerror(errno)); + log_line("%s: failed to set route: %s\n", ifnam[idx], strerror(errno)); close(fd); } @@ -281,9 +280,9 @@ void perform_mtu(int idx, char *str) struct ifreq ifrt; if (!str) - return; + return; if (!is_permitted(ifnam[idx])) - return; + return; mtu = strtol(str, NULL, 10); ifrt.ifr_mtu = mtu; @@ -291,13 +290,13 @@ void perform_mtu(int idx, char *str) fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd == -1) { - log_line("%s: (perform_mtu) failed to open interface socket: %s\n", - ifnam[idx], strerror(errno)); - return; + log_line("%s: (perform_mtu) failed to open interface socket: %s\n", + ifnam[idx], strerror(errno)); + return; } if (ioctl(fd, SIOCSIFMTU, &ifrt) < 0) - log_line("%s: failed to set MTU (%d): %s\n", ifnam[idx], mtu, - strerror(errno)); + log_line("%s: failed to set MTU (%d): %s\n", ifnam[idx], mtu, + strerror(errno)); close(fd); } @@ -309,11 +308,11 @@ void perform_broadcast(int idx, char *str) struct sockaddr_in sin; if (!str) - return; + return; if (!is_permitted(ifnam[idx])) - return; + return; if (!inet_aton(str, &broadcast)) - return; + return; strlcpy(ifrt.ifr_name, ifnam[idx], IFNAMSIZ); memset(&sin, 0, sizeof(struct sockaddr)); @@ -323,11 +322,11 @@ void perform_broadcast(int idx, char *str) fd = socket(PF_INET, SOCK_DGRAM, 0); if (fd == -1) { - log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", ifnam[idx], strerror(errno)); - return; + log_line("%s: (perform_broadcast) failed to open interface socket: %s\n", ifnam[idx], strerror(errno)); + return; } if (ioctl(fd, SIOCSIFBRDADDR, &ifrt) < 0) - log_line("%s: failed to set broadcast: %s\n", - ifnam[idx], strerror(errno)); + log_line("%s: failed to set broadcast: %s\n", + ifnam[idx], strerror(errno)); close(fd); } diff --git a/ifchd/linux.h b/ifchd/linux.h index d26ad04..e8fa1bc 100644 --- a/ifchd/linux.h +++ b/ifchd/linux.h @@ -1,7 +1,7 @@ /* linux.h - ifchd Linux-specific functions include - * Time-stamp: <2010-11-12 09:03:29 njk> - * - * (C) 2004 Nicholas J. Kain + * Time-stamp: <2010-11-12 14:31:33 njk> + * + * (C) 2004-2010 Nicholas J. Kain * * 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 @@ -16,11 +16,10 @@ * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ #ifndef NJK_IFCHD_LINUX_H_ -#define NJK_IFCHD_LINUX_H_ 1 +#define NJK_IFCHD_LINUX_H_ void clear_if_data(int idx); void initialize_if_data(void); void add_permitted_if(char *s); diff --git a/ndhc/clientpacket.c b/ndhc/clientpacket.c index 2134299..755b52d 100644 --- a/ndhc/clientpacket.c +++ b/ndhc/clientpacket.c @@ -2,6 +2,7 @@ * * Packet generation and dispatching functions for the DHCP client. * + * Nicholas J. Kain 2004-2010 * Russ Dill July 2001 * * This program is free software; you can redistribute it and/or modify @@ -18,7 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + #include #include #include @@ -43,256 +44,246 @@ /* Create a random xid */ unsigned long random_xid(void) { - static int initialized; - if (!initialized) { - int fd; - unsigned long seed; + static int initialized; + if (!initialized) { + int fd; + unsigned long seed; - fd = open("/dev/urandom", O_RDONLY); - if (fd == -1 || read(fd, &seed, sizeof(seed)) < 0) { - log_warning("Could not load seed from /dev/urandom: %s", - strerror(errno)); - seed = time(0); - } - if (fd != -1) - close(fd); - srand(seed); - initialized++; - } - return rand(); + fd = open("/dev/urandom", O_RDONLY); + if (fd == -1 || read(fd, &seed, sizeof(seed)) < 0) { + log_warning("Could not load seed from /dev/urandom: %s", + strerror(errno)); + seed = time(0); + } + if (fd != -1) + close(fd); + srand(seed); + initialized++; + } + return rand(); } - /* initialize a packet with the proper defaults */ static void init_packet(struct dhcpMessage *packet, char type) { - struct vendor { - char vendor; - char length; - char str[sizeof("ndhc")]; - } vendor_id = { DHCP_VENDOR, sizeof("ndhc") - 1, "ndhc"}; - - init_header(packet, type); - memcpy(packet->chaddr, client_config.arp, 6); - add_option_string(packet->options, client_config.clientid); - if (client_config.hostname) - add_option_string(packet->options, client_config.hostname); - add_option_string(packet->options, (unsigned char *)&vendor_id); -} + struct vendor { + char vendor; + char length; + char str[sizeof("ndhc")]; + } vendor_id = { DHCP_VENDOR, sizeof("ndhc") - 1, "ndhc"}; + init_header(packet, type); + memcpy(packet->chaddr, client_config.arp, 6); + add_option_string(packet->options, client_config.clientid); + if (client_config.hostname) + add_option_string(packet->options, client_config.hostname); + add_option_string(packet->options, (unsigned char *)&vendor_id); +} /* Add a paramater request list for stubborn DHCP servers. Pull the data * from the struct in options.c. Don't do bounds checking here because it * goes towards the head of the packet. */ static void add_requests(struct dhcpMessage *packet) { - int end = end_option(packet->options); - int i, len = 0; - - packet->options[end + OPT_CODE] = DHCP_PARAM_REQ; - for (i = 0; options[i].code; i++) - if (options[i].flags & OPTION_REQ) - packet->options[end + OPT_DATA + len++] = options[i].code; - packet->options[end + OPT_LEN] = len; - packet->options[end + OPT_DATA + len] = DHCP_END; + int end = end_option(packet->options); + int i, len = 0; + packet->options[end + OPT_CODE] = DHCP_PARAM_REQ; + for (i = 0; options[i].code; i++) + if (options[i].flags & OPTION_REQ) + packet->options[end + OPT_DATA + len++] = options[i].code; + packet->options[end + OPT_LEN] = len; + packet->options[end + OPT_DATA + len] = DHCP_END; } - /* Broadcast a DHCP discover packet to the network, with an optionally * requested IP */ int send_discover(unsigned long xid, unsigned long requested) { - struct dhcpMessage packet; + struct dhcpMessage packet; - init_packet(&packet, DHCPDISCOVER); - packet.xid = xid; - if (requested) - add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); + init_packet(&packet, DHCPDISCOVER); + packet.xid = xid; + if (requested) + add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); - add_requests(&packet); - log_line("Sending discover..."); - return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, - SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); + add_requests(&packet); + log_line("Sending discover..."); + return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, + SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); } - /* Broadcasts a DHCP request message */ int send_selecting(unsigned long xid, unsigned long server, - unsigned long requested) + unsigned long requested) { - struct dhcpMessage packet; - struct in_addr addr; + struct dhcpMessage packet; + struct in_addr addr; - init_packet(&packet, DHCPREQUEST); - packet.xid = xid; + init_packet(&packet, DHCPREQUEST); + packet.xid = xid; - add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); - add_simple_option(packet.options, DHCP_SERVER_ID, server); - - add_requests(&packet); - addr.s_addr = requested; - log_line("Sending select for %s...", inet_ntoa(addr)); - return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, - SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); + add_simple_option(packet.options, DHCP_REQUESTED_IP, requested); + add_simple_option(packet.options, DHCP_SERVER_ID, server); + + add_requests(&packet); + addr.s_addr = requested; + log_line("Sending select for %s...", inet_ntoa(addr)); + return raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, + SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); } - /* Unicasts or broadcasts a DHCP renew message */ int send_renew(unsigned long xid, unsigned long server, unsigned long ciaddr) { - struct dhcpMessage packet; - int ret = 0; + struct dhcpMessage packet; + int ret = 0; - init_packet(&packet, DHCPREQUEST); - packet.xid = xid; - packet.ciaddr = ciaddr; - - add_requests(&packet); - log_line("Sending renew..."); - if (server) - ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); - else - ret = raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, - SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); - return ret; -} + init_packet(&packet, DHCPREQUEST); + packet.xid = xid; + packet.ciaddr = ciaddr; + add_requests(&packet); + log_line("Sending renew..."); + if (server) + ret = kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); + else + ret = raw_packet(&packet, INADDR_ANY, CLIENT_PORT, INADDR_BROADCAST, + SERVER_PORT, MAC_BCAST_ADDR, client_config.ifindex); + return ret; +} /* Unicasts a DHCP release message */ int send_release(unsigned long server, unsigned long ciaddr) { - struct dhcpMessage packet; + struct dhcpMessage packet; - init_packet(&packet, DHCPRELEASE); - packet.xid = random_xid(); - packet.ciaddr = ciaddr; - - add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr); - add_simple_option(packet.options, DHCP_SERVER_ID, server); + init_packet(&packet, DHCPRELEASE); + packet.xid = random_xid(); + packet.ciaddr = ciaddr; - log_line("Sending release..."); - return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); + add_simple_option(packet.options, DHCP_REQUESTED_IP, ciaddr); + add_simple_option(packet.options, DHCP_SERVER_ID, server); + + log_line("Sending release..."); + return kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); } - /* return -1 on errors that are fatal for the socket, * -2 for those that aren't */ int get_raw_packet(struct dhcpMessage *payload, int fd) { - struct udp_dhcp_packet packet; - uint32_t source, dest; - uint16_t check; + struct udp_dhcp_packet packet; + uint32_t source, dest; + uint16_t check; - ssize_t len = 0; - const ssize_t wanted = sizeof(struct iphdr) + sizeof(struct udphdr); + ssize_t len = 0; + const ssize_t wanted = sizeof(struct iphdr) + sizeof(struct udphdr); - memset(&packet, 0, sizeof(struct udp_dhcp_packet)); - while (len < wanted) { - ssize_t r = read(fd, &packet + len, - sizeof(struct udp_dhcp_packet) - len); - if (r == 0) - break; - if (r == -1) { - if (errno == EINTR) - continue; - if (errno == EAGAIN || errno == EWOULDBLOCK) { - log_line("EAGAIN or EWOULDBLOCK hit"); - break; - } - log_line("couldn't read on raw listening socket -- ignoring"); - usleep(500000); /* possible down interface, looping condition */ - return -1; - } - len += r; - } + memset(&packet, 0, sizeof(struct udp_dhcp_packet)); + while (len < wanted) { + ssize_t r = read(fd, &packet + len, + sizeof(struct udp_dhcp_packet) - len); + if (r == 0) + break; + if (r == -1) { + if (errno == EINTR) + continue; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + log_line("EAGAIN or EWOULDBLOCK hit"); + break; + } + log_line("couldn't read on raw listening socket -- ignoring"); + usleep(500000); /* possible down interface, looping condition */ + return -1; + } + len += r; + } - if (len == 0) { - usleep(50000); - return -2; - } + if (len == 0) { + usleep(50000); + return -2; + } - log_line("len: %d wanted: %d", len, wanted); - if (len < wanted) { - log_line("Message too short to contain IP + UDP headers, ignoring"); - sleep(1); - return -2; - } - - if (len < ntohs(packet.ip.tot_len)) { - log_line("Truncated packet"); - return -2; - } - - /* ignore any extra garbage bytes */ - len = ntohs(packet.ip.tot_len); - - /* Make sure its the right packet for us, and that it passes - * sanity checks */ - if (packet.ip.protocol != IPPROTO_UDP) { - log_line("IP header is not UDP"); - sleep(1); - return -2; - } - if (packet.ip.version != IPVERSION) { - log_line("IP version is not IPv4"); - sleep(1); - return -2; - } - if (packet.ip.ihl != sizeof(packet.ip) >> 2) { - log_line("IP header length incorrect"); - sleep(1); - return -2; - } - if (packet.udp.dest != htons(CLIENT_PORT)) { - log_line("UDP destination port incorrect"); - sleep(1); - return -2; - } - if (len > (int)sizeof(struct udp_dhcp_packet)) { - log_line("Data longer than that of a IP+UDP+DHCP message"); - sleep(1); - return -2; - } - if (ntohs(packet.udp.len) != (short)(len - sizeof(packet.ip))) { - log_line("UDP header length incorrect"); - sleep(1); - return -2; - } + log_line("len: %d wanted: %d", len, wanted); + if (len < wanted) { + log_line("Message too short to contain IP + UDP headers, ignoring"); + sleep(1); + return -2; + } - /* check IP checksum */ - check = packet.ip.check; - packet.ip.check = 0; - if (check != checksum(&(packet.ip), sizeof(packet.ip))) { - log_line("bad IP header checksum, ignoring"); - return -1; - } - - /* verify the UDP checksum by replacing the header with a psuedo header */ - source = packet.ip.saddr; - dest = packet.ip.daddr; - check = packet.udp.check; - packet.udp.check = 0; - memset(&packet.ip, 0, sizeof(packet.ip)); + if (len < ntohs(packet.ip.tot_len)) { + log_line("Truncated packet"); + return -2; + } - packet.ip.protocol = IPPROTO_UDP; - packet.ip.saddr = source; - packet.ip.daddr = dest; - packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */ - if (check && check != checksum(&packet, len)) { - log_error("packet with bad UDP checksum received, ignoring"); - return -2; - } - - memcpy(payload, &(packet.data), - len - (sizeof(packet.ip) + sizeof(packet.udp))); - - if (ntohl(payload->cookie) != DHCP_MAGIC) { - log_error("received bogus message (bad magic) -- ignoring"); - return -2; - } - log_line("oooooh!!! got some!"); - return len - (sizeof(packet.ip) + sizeof(packet.udp)); - + /* ignore any extra garbage bytes */ + len = ntohs(packet.ip.tot_len); + + /* Make sure its the right packet for us, and that it passes + * sanity checks */ + if (packet.ip.protocol != IPPROTO_UDP) { + log_line("IP header is not UDP"); + sleep(1); + return -2; + } + if (packet.ip.version != IPVERSION) { + log_line("IP version is not IPv4"); + sleep(1); + return -2; + } + if (packet.ip.ihl != sizeof(packet.ip) >> 2) { + log_line("IP header length incorrect"); + sleep(1); + return -2; + } + if (packet.udp.dest != htons(CLIENT_PORT)) { + log_line("UDP destination port incorrect"); + sleep(1); + return -2; + } + if (len > (int)sizeof(struct udp_dhcp_packet)) { + log_line("Data longer than that of a IP+UDP+DHCP message"); + sleep(1); + return -2; + } + if (ntohs(packet.udp.len) != (short)(len - sizeof(packet.ip))) { + log_line("UDP header length incorrect"); + sleep(1); + return -2; + } + + /* check IP checksum */ + check = packet.ip.check; + packet.ip.check = 0; + if (check != checksum(&(packet.ip), sizeof(packet.ip))) { + log_line("bad IP header checksum, ignoring"); + return -1; + } + + /* verify the UDP checksum by replacing the header with a psuedo header */ + source = packet.ip.saddr; + dest = packet.ip.daddr; + check = packet.udp.check; + packet.udp.check = 0; + memset(&packet.ip, 0, sizeof(packet.ip)); + + packet.ip.protocol = IPPROTO_UDP; + packet.ip.saddr = source; + packet.ip.daddr = dest; + packet.ip.tot_len = packet.udp.len; /* cheat on the psuedo-header */ + if (check && check != checksum(&packet, len)) { + log_error("packet with bad UDP checksum received, ignoring"); + return -2; + } + + memcpy(payload, &(packet.data), + len - (sizeof(packet.ip) + sizeof(packet.udp))); + + if (ntohl(payload->cookie) != DHCP_MAGIC) { + log_error("received bogus message (bad magic) -- ignoring"); + return -2; + } + log_line("oooooh!!! got some!"); + return len - (sizeof(packet.ip) + sizeof(packet.udp)); } - diff --git a/ndhc/dhcpc.c b/ndhc/dhcpc.c index 053aab3..ab32628 100644 --- a/ndhc/dhcpc.c +++ b/ndhc/dhcpc.c @@ -2,8 +2,8 @@ * * ndhc DHCP client * + * Nicholas J. Kain 2004-2010 * Russ Dill July 2001 - * Nicholas Kain 2004 * * 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 @@ -19,7 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + #include #include #include @@ -60,28 +60,28 @@ static int state, packet_num, fd, listen_mode; static sig_atomic_t pending_exit, pending_renew, pending_release; enum { - LISTEN_NONE, - LISTEN_KERNEL, - LISTEN_RAW + LISTEN_NONE, + LISTEN_KERNEL, + LISTEN_RAW }; struct client_config_t client_config = { - /* Default options. */ - .abort_if_no_lease = 0, - .foreground = 0, - .quit_after_lease = 0, - .background_if_no_lease = 0, - .interface = "eth0", - .script = "none", - .clientid = NULL, - .hostname = NULL, - .ifindex = 0, - .arp = "\0", + /* Default options. */ + .abort_if_no_lease = 0, + .foreground = 0, + .quit_after_lease = 0, + .background_if_no_lease = 0, + .interface = "eth0", + .script = "none", + .clientid = NULL, + .hostname = NULL, + .ifindex = 0, + .arp = "\0", }; static void show_usage(void) { - printf( + printf( "Usage: ndhc [OPTIONS]\n\n" " -c, --clientid=CLIENTID Client identifier\n" " -H, --hostname=HOSTNAME Client hostname\n" @@ -97,495 +97,494 @@ static void show_usage(void) " -u, --user Change privileges to this user\n" " -C, --chroot Directory to which udhcp should chroot\n" " -v, --version Display version\n" - ); - exit(EXIT_SUCCESS); + ); + exit(EXIT_SUCCESS); } /* just a little helper */ static void change_mode(int new_mode) { - log_line("entering %s listen mode", - new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); - close(fd); - fd = -1; - listen_mode = new_mode; + log_line("entering %s listen mode", + new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none"); + close(fd); + fd = -1; + listen_mode = new_mode; } /* perform a renew */ static void perform_renew(void) { - log_line("Performing a DHCP renew..."); - switch (state) { - case BOUND: - change_mode(LISTEN_KERNEL); - case RENEWING: - case REBINDING: - state = RENEW_REQUESTED; - break; - case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ - run_script(NULL, SCRIPT_DECONFIG); - case REQUESTING: - case RELEASED: - change_mode(LISTEN_RAW); - state = INIT_SELECTING; - break; - case INIT_SELECTING: - break; - } + log_line("Performing a DHCP renew..."); + switch (state) { + case BOUND: + change_mode(LISTEN_KERNEL); + case RENEWING: + case REBINDING: + state = RENEW_REQUESTED; + break; + case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ + run_script(NULL, SCRIPT_DECONFIG); + case REQUESTING: + case RELEASED: + change_mode(LISTEN_RAW); + state = INIT_SELECTING; + break; + case INIT_SELECTING: + break; + } - /* start things over */ - packet_num = 0; + /* start things over */ + packet_num = 0; - /* Kill any timeouts because the user wants this to hurry along */ - timeout = 0; + /* Kill any timeouts because the user wants this to hurry along */ + timeout = 0; } /* perform a release */ static void perform_release(void) { - char buf[32]; - struct in_addr temp_addr; + char buf[32]; + struct in_addr temp_addr; - memset(buf, '\0', sizeof buf); + memset(buf, '\0', sizeof buf); - /* send release packet */ - if (state == BOUND || state == RENEWING || state == REBINDING) { - temp_addr.s_addr = server_addr; - snprintf(buf, sizeof buf, "%s", inet_ntoa(temp_addr)); - temp_addr.s_addr = requested_ip; - log_line("Unicasting a release of %s to %s.", - inet_ntoa(temp_addr), buf); - send_release(server_addr, requested_ip); /* unicast */ - run_script(NULL, SCRIPT_DECONFIG); - } - log_line("Entering released state."); + /* send release packet */ + if (state == BOUND || state == RENEWING || state == REBINDING) { + temp_addr.s_addr = server_addr; + snprintf(buf, sizeof buf, "%s", inet_ntoa(temp_addr)); + temp_addr.s_addr = requested_ip; + log_line("Unicasting a release of %s to %s.", + inet_ntoa(temp_addr), buf); + send_release(server_addr, requested_ip); /* unicast */ + run_script(NULL, SCRIPT_DECONFIG); + } + log_line("Entering released state."); - change_mode(LISTEN_NONE); - state = RELEASED; - timeout = 0x7fffffff; + change_mode(LISTEN_NONE); + state = RELEASED; + timeout = 0x7fffffff; } static void signal_handler(int sig) { - switch (sig) { - case SIGUSR1: - pending_renew = 1; - break; - case SIGUSR2: - pending_release = 1; - break; - case SIGTERM: - pending_exit = 1; - break; - } + switch (sig) { + case SIGUSR1: + pending_renew = 1; + break; + case SIGUSR2: + pending_release = 1; + break; + case SIGTERM: + pending_exit = 1; + break; + } } static void background(void) { - if (daemon(0, 0) == -1) { - perror("fork"); - exit(EXIT_SUCCESS); - } - client_config.foreground = 1; /* Do not fork again. */ + if (daemon(0, 0) == -1) { + perror("fork"); + exit(EXIT_SUCCESS); + } + client_config.foreground = 1; /* Do not fork again. */ } static void handle_timeout(void) { - time_t now = time(0); + time_t now = time(0); - /* timeout dropped to zero */ - switch (state) { - case INIT_SELECTING: - if (packet_num < 3) { - if (packet_num == 0) - xid = random_xid(); + /* timeout dropped to zero */ + switch (state) { + case INIT_SELECTING: + if (packet_num < 3) { + if (packet_num == 0) + xid = random_xid(); - /* send discover packet */ - send_discover(xid, requested_ip); /* broadcast */ + /* send discover packet */ + send_discover(xid, requested_ip); /* broadcast */ - timeout = now + ((packet_num == 2) ? 4 : 2); - packet_num++; - } else { - if (client_config.background_if_no_lease) { - log_line("No lease, going to background."); - background(); - } else if (client_config.abort_if_no_lease) { - log_line("No lease, failing."); - exit(EXIT_FAILURE); - } - /* wait to try again */ - packet_num = 0; - timeout = now + 60; - } - break; - case RENEW_REQUESTED: - case REQUESTING: - if (packet_num < 3) { - /* send request packet */ - if (state == RENEW_REQUESTED) - /* unicast */ - send_renew(xid, server_addr, requested_ip); - else - /* broadcast */ - send_selecting(xid, server_addr, requested_ip); - timeout = now + ((packet_num == 2) ? 10 : 2); - packet_num++; - } else { - /* timed out, go back to init state */ - if (state == RENEW_REQUESTED) - run_script(NULL, SCRIPT_DECONFIG); - state = INIT_SELECTING; - timeout = now; - packet_num = 0; - change_mode(LISTEN_RAW); - } - break; - case BOUND: - /* Lease is starting to run out, time to enter renewing state */ - state = RENEWING; - change_mode(LISTEN_KERNEL); - log_line("Entering renew state."); - /* fall right through */ - case RENEWING: - /* Either set a new T1, or enter REBINDING state */ - if ((t2 - t1) <= (lease / 14400 + 1)) { - /* timed out, enter rebinding state */ - state = REBINDING; - timeout = now + (t2 - t1); - log_line("Entering rebinding state."); - } else { - /* send a request packet */ - send_renew(xid, server_addr, requested_ip); /* unicast */ + timeout = now + ((packet_num == 2) ? 4 : 2); + packet_num++; + } else { + if (client_config.background_if_no_lease) { + log_line("No lease, going to background."); + background(); + } else if (client_config.abort_if_no_lease) { + log_line("No lease, failing."); + exit(EXIT_FAILURE); + } + /* wait to try again */ + packet_num = 0; + timeout = now + 60; + } + break; + case RENEW_REQUESTED: + case REQUESTING: + if (packet_num < 3) { + /* send request packet */ + if (state == RENEW_REQUESTED) + /* unicast */ + send_renew(xid, server_addr, requested_ip); + else + /* broadcast */ + send_selecting(xid, server_addr, requested_ip); + timeout = now + ((packet_num == 2) ? 10 : 2); + packet_num++; + } else { + /* timed out, go back to init state */ + if (state == RENEW_REQUESTED) + run_script(NULL, SCRIPT_DECONFIG); + state = INIT_SELECTING; + timeout = now; + packet_num = 0; + change_mode(LISTEN_RAW); + } + break; + case BOUND: + /* Lease is starting to run out, time to enter renewing state */ + state = RENEWING; + change_mode(LISTEN_KERNEL); + log_line("Entering renew state."); + /* fall right through */ + case RENEWING: + /* Either set a new T1, or enter REBINDING state */ + if ((t2 - t1) <= (lease / 14400 + 1)) { + /* timed out, enter rebinding state */ + state = REBINDING; + timeout = now + (t2 - t1); + log_line("Entering rebinding state."); + } else { + /* send a request packet */ + send_renew(xid, server_addr, requested_ip); /* unicast */ - t1 = ((t2 - t1) >> 1) + t1; - timeout = t1 + start; - } - break; - case REBINDING: - /* Either set a new T2, or enter INIT state */ - if ((lease - t2) <= (lease / 14400 + 1)) { - /* timed out, enter init state */ - state = INIT_SELECTING; - log_line("Lease lost, entering init state."); - run_script(NULL, SCRIPT_DECONFIG); - timeout = now; - packet_num = 0; - change_mode(LISTEN_RAW); - } else { - /* send a request packet */ - send_renew(xid, 0, requested_ip); /* broadcast */ + t1 = ((t2 - t1) >> 1) + t1; + timeout = t1 + start; + } + break; + case REBINDING: + /* Either set a new T2, or enter INIT state */ + if ((lease - t2) <= (lease / 14400 + 1)) { + /* timed out, enter init state */ + state = INIT_SELECTING; + log_line("Lease lost, entering init state."); + run_script(NULL, SCRIPT_DECONFIG); + timeout = now; + packet_num = 0; + change_mode(LISTEN_RAW); + } else { + /* send a request packet */ + send_renew(xid, 0, requested_ip); /* broadcast */ - t2 = ((lease - t2) >> 1) + t2; - timeout = t2 + start; - } - break; - case RELEASED: - /* yah, I know, *you* say it would never happen */ - timeout = 0x7fffffff; - break; - } + t2 = ((lease - t2) >> 1) + t2; + timeout = t2 + start; + } + break; + case RELEASED: + /* yah, I know, *you* say it would never happen */ + timeout = 0x7fffffff; + break; + } } static void handle_packet(void) { - unsigned char *temp = NULL, *message = NULL; - int len; - time_t now = time(0); - struct in_addr temp_addr; - struct dhcpMessage packet; - - log_line("got a packet"); + unsigned char *temp = NULL, *message = NULL; + int len; + time_t now = time(0); + struct in_addr temp_addr; + struct dhcpMessage packet; - if (listen_mode == LISTEN_KERNEL) - len = get_packet(&packet, fd); - else - len = get_raw_packet(&packet, fd); + log_line("got a packet"); - if (len == -1 && errno != EINTR) { - log_error("error on read, %s, reopening socket.", - strerror(errno)); - change_mode(listen_mode); /* just close and reopen */ - } + if (listen_mode == LISTEN_KERNEL) + len = get_packet(&packet, fd); + else + len = get_raw_packet(&packet, fd); - if (len < 0) - return; + if (len == -1 && errno != EINTR) { + log_error("error on read, %s, reopening socket.", + strerror(errno)); + change_mode(listen_mode); /* just close and reopen */ + } - if (packet.xid != xid) { - log_line("Ignoring XID %lx (our xid is %lx).", - (unsigned long) packet.xid, xid); - return; - } + if (len < 0) + return; - if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { - log_line("couldnt get option from packet -- ignoring"); - return; - } + if (packet.xid != xid) { + log_line("Ignoring XID %lx (our xid is %lx).", + (unsigned long) packet.xid, xid); + return; + } - switch (state) { - case INIT_SELECTING: - /* Must be a DHCPOFFER to one of our xid's */ - if (*message == DHCPOFFER) { - if ((temp = get_option(&packet, DHCP_SERVER_ID))) { - memcpy(&server_addr, temp, 4); - xid = packet.xid; - requested_ip = packet.yiaddr; + if ((message = get_option(&packet, DHCP_MESSAGE_TYPE)) == NULL) { + log_line("couldnt get option from packet -- ignoring"); + return; + } - /* enter requesting state */ - state = REQUESTING; - timeout = now; - packet_num = 0; - } else { - log_line("No server ID in message"); - } - } - break; - case RENEW_REQUESTED: - case REQUESTING: - case RENEWING: - case REBINDING: - if (*message == DHCPACK) { - if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) { - log_line("No lease time received, assuming 1h."); - lease = 60 * 60; - } else { - memcpy(&lease, temp, 4); - lease = ntohl(lease); - } + switch (state) { + case INIT_SELECTING: + /* Must be a DHCPOFFER to one of our xid's */ + if (*message == DHCPOFFER) { + if ((temp = get_option(&packet, DHCP_SERVER_ID))) { + memcpy(&server_addr, temp, 4); + xid = packet.xid; + requested_ip = packet.yiaddr; - /* enter bound state */ - t1 = lease >> 1; + /* enter requesting state */ + state = REQUESTING; + timeout = now; + packet_num = 0; + } else { + log_line("No server ID in message"); + } + } + break; + case RENEW_REQUESTED: + case REQUESTING: + case RENEWING: + case REBINDING: + if (*message == DHCPACK) { + if (!(temp = get_option(&packet, DHCP_LEASE_TIME))) { + log_line("No lease time received, assuming 1h."); + lease = 60 * 60; + } else { + memcpy(&lease, temp, 4); + lease = ntohl(lease); + } - /* little fixed point for n * .875 */ - t2 = (lease * 0x7) >> 3; - temp_addr.s_addr = packet.yiaddr; - log_line("Lease of %s obtained, lease time %ld.", - inet_ntoa(temp_addr), lease); - start = now; - timeout = t1 + start; - requested_ip = packet.yiaddr; - run_script(&packet, - ((state == RENEWING || state == REBINDING) - ? SCRIPT_RENEW : SCRIPT_BOUND)); + /* enter bound state */ + t1 = lease >> 1; - state = BOUND; - change_mode(LISTEN_NONE); - if (client_config.quit_after_lease) - exit(EXIT_SUCCESS); - if (!client_config.foreground) - background(); + /* little fixed point for n * .875 */ + t2 = (lease * 0x7) >> 3; + temp_addr.s_addr = packet.yiaddr; + log_line("Lease of %s obtained, lease time %ld.", + inet_ntoa(temp_addr), lease); + start = now; + timeout = t1 + start; + requested_ip = packet.yiaddr; + run_script(&packet, + ((state == RENEWING || state == REBINDING) + ? SCRIPT_RENEW : SCRIPT_BOUND)); - } else if (*message == DHCPNAK) { - /* return to init state */ - log_line("Received DHCP NAK."); - run_script(&packet, SCRIPT_NAK); - if (state != REQUESTING) - run_script(NULL, SCRIPT_DECONFIG); - state = INIT_SELECTING; - timeout = now; - requested_ip = 0; - packet_num = 0; - change_mode(LISTEN_RAW); - sleep(3); /* avoid excessive network traffic */ - } - break; - case BOUND: - case RELEASED: - default: - break; - } + state = BOUND; + change_mode(LISTEN_NONE); + if (client_config.quit_after_lease) + exit(EXIT_SUCCESS); + if (!client_config.foreground) + background(); + + } else if (*message == DHCPNAK) { + /* return to init state */ + log_line("Received DHCP NAK."); + run_script(&packet, SCRIPT_NAK); + if (state != REQUESTING) + run_script(NULL, SCRIPT_DECONFIG); + state = INIT_SELECTING; + timeout = now; + requested_ip = 0; + packet_num = 0; + change_mode(LISTEN_RAW); + sleep(3); /* avoid excessive network traffic */ + } + break; + case BOUND: + case RELEASED: + default: + break; + } } static int do_work(void) { - struct timeval tv; - fd_set rfds; - for (;;) { + struct timeval tv; + fd_set rfds; + for (;;) { - /* Handle signals asynchronously. */ - if (pending_renew) - perform_renew(); - if (pending_release) - perform_release(); - if (pending_exit) { - log_line("Received SIGTERM. Exiting gracefully."); - exit(EXIT_SUCCESS); - } + /* Handle signals asynchronously. */ + if (pending_renew) + perform_renew(); + if (pending_release) + perform_release(); + if (pending_exit) { + log_line("Received SIGTERM. Exiting gracefully."); + exit(EXIT_SUCCESS); + } - tv.tv_sec = timeout - time(0); - tv.tv_usec = 0; + tv.tv_sec = timeout - time(0); + tv.tv_usec = 0; - if (listen_mode != LISTEN_NONE && fd < 0) { - if (listen_mode == LISTEN_KERNEL) - fd = listen_socket(INADDR_ANY, CLIENT_PORT, - client_config.interface); - else - fd = raw_socket(client_config.ifindex); + if (listen_mode != LISTEN_NONE && fd < 0) { + if (listen_mode == LISTEN_KERNEL) + fd = listen_socket(INADDR_ANY, CLIENT_PORT, + client_config.interface); + else + fd = raw_socket(client_config.ifindex); - if (fd < 0) { - log_error("FATAL: couldn't listen on socket: %s.", - strerror(errno)); - exit(EXIT_FAILURE); - } - } + if (fd < 0) { + log_error("FATAL: couldn't listen on socket: %s.", + strerror(errno)); + exit(EXIT_FAILURE); + } + } - if (tv.tv_sec <= 0) { - handle_timeout(); - continue; - } + if (tv.tv_sec <= 0) { + handle_timeout(); + continue; + } - FD_ZERO(&rfds); - if (fd >= 0) - FD_SET(fd, &rfds); - if (select(fd + 1, &rfds, NULL, NULL, &tv) == -1) { - switch (errno) { - case EBADF: - fd = -1; - default: - log_error("Error: \"%s\" on select!", - strerror(errno)); - case EINTR: /* Signal received, go back to top. */ - continue; - } - } + FD_ZERO(&rfds); + if (fd >= 0) + FD_SET(fd, &rfds); + if (select(fd + 1, &rfds, NULL, NULL, &tv) == -1) { + switch (errno) { + case EBADF: + fd = -1; + default: + log_error("Error: \"%s\" on select!", + strerror(errno)); + case EINTR: /* Signal received, go back to top. */ + continue; + } + } - if (listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) - handle_packet(); - } + if (listen_mode != LISTEN_NONE && FD_ISSET(fd, &rfds)) + handle_packet(); + } } int main(int argc, char **argv) { - char chroot_dir[255]; - int c, len; - struct passwd *pwd; - uid_t uid = 0; - gid_t gid = 0; - static struct option arg_options[] = { - {"clientid", required_argument, 0, 'c'}, - {"foreground", no_argument, 0, 'f'}, - {"background", no_argument, 0, 'b'}, - {"hostname", required_argument, 0, 'H'}, - {"hostname", required_argument, 0, 'h'}, - {"interface", required_argument, 0, 'i'}, - {"now", no_argument, 0, 'n'}, - {"quit", no_argument, 0, 'q'}, - {"request", required_argument, 0, 'r'}, - {"version", no_argument, 0, 'v'}, - {"user", required_argument, 0, 'u'}, - {"chroot", required_argument, 0, 'C'}, - {"help", no_argument, 0, '?'}, - {0, 0, 0, 0} - }; + char chroot_dir[255]; + int c, len; + struct passwd *pwd; + uid_t uid = 0; + gid_t gid = 0; + static struct option arg_options[] = { + {"clientid", required_argument, 0, 'c'}, + {"foreground", no_argument, 0, 'f'}, + {"background", no_argument, 0, 'b'}, + {"hostname", required_argument, 0, 'H'}, + {"hostname", required_argument, 0, 'h'}, + {"interface", required_argument, 0, 'i'}, + {"now", no_argument, 0, 'n'}, + {"quit", no_argument, 0, 'q'}, + {"request", required_argument, 0, 'r'}, + {"version", no_argument, 0, 'v'}, + {"user", required_argument, 0, 'u'}, + {"chroot", required_argument, 0, 'C'}, + {"help", no_argument, 0, '?'}, + {0, 0, 0, 0} + }; - /* get options */ - while (1) { - int option_index = 0; - c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:u:C:v", arg_options, - &option_index); - if (c == -1) break; - - switch (c) { - case 'c': - len = strlen(optarg) > 255 ? 255 : strlen(optarg); - if (client_config.clientid) - free(client_config.clientid); - client_config.clientid = xmalloc(len + 1); - client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; - client_config.clientid[OPT_LEN] = len; - strlcpy((char *)client_config.clientid + OPT_DATA, optarg, - len + 1 - (OPT_DATA - OPT_CODE)); - break; - case 'f': - client_config.foreground = 1; - break; - case 'b': - client_config.background_if_no_lease = 1; - break; - case 'h': - case 'H': - len = strlen(optarg) > 255 ? 255 : strlen(optarg); - if (client_config.hostname) - free(client_config.hostname); - client_config.hostname = xmalloc(len + 1); - client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; - client_config.hostname[OPT_LEN] = len; - strlcpy((char*)client_config.hostname + OPT_DATA, optarg, - len + 1 - (OPT_DATA - OPT_CODE)); - break; - case 'i': - client_config.interface = optarg; - break; - case 'n': - client_config.abort_if_no_lease = 1; - break; - case 'q': - client_config.quit_after_lease = 1; - break; - case 'r': - requested_ip = inet_addr(optarg); - break; - case 'u': - pwd = getpwnam(optarg); - if (pwd) { - uid = (int)pwd->pw_uid; - gid = (int)pwd->pw_gid; - } else { - printf("Bad username provided.\n"); - exit(EXIT_FAILURE); - } - break; - case 'C': - strlcpy(chroot_dir, optarg, sizeof chroot_dir); - break; - case 'v': - printf("ndhc, version " VERSION "\n\n"); - exit(EXIT_SUCCESS); - break; - default: - show_usage(); - } - } + /* get options */ + while (1) { + int option_index = 0; + c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:u:C:v", arg_options, + &option_index); + if (c == -1) break; - log_line("ndhc client " VERSION " started."); + switch (c) { + case 'c': + len = strlen(optarg) > 255 ? 255 : strlen(optarg); + if (client_config.clientid) + free(client_config.clientid); + client_config.clientid = xmalloc(len + 1); + client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; + client_config.clientid[OPT_LEN] = len; + strlcpy((char *)client_config.clientid + OPT_DATA, optarg, + len + 1 - (OPT_DATA - OPT_CODE)); + break; + case 'f': + client_config.foreground = 1; + break; + case 'b': + client_config.background_if_no_lease = 1; + break; + case 'h': + case 'H': + len = strlen(optarg) > 255 ? 255 : strlen(optarg); + if (client_config.hostname) + free(client_config.hostname); + client_config.hostname = xmalloc(len + 1); + client_config.hostname[OPT_CODE] = DHCP_HOST_NAME; + client_config.hostname[OPT_LEN] = len; + strlcpy((char*)client_config.hostname + OPT_DATA, optarg, + len + 1 - (OPT_DATA - OPT_CODE)); + break; + case 'i': + client_config.interface = optarg; + break; + case 'n': + client_config.abort_if_no_lease = 1; + break; + case 'q': + client_config.quit_after_lease = 1; + break; + case 'r': + requested_ip = inet_addr(optarg); + break; + case 'u': + pwd = getpwnam(optarg); + if (pwd) { + uid = (int)pwd->pw_uid; + gid = (int)pwd->pw_gid; + } else { + printf("Bad username provided.\n"); + exit(EXIT_FAILURE); + } + break; + case 'C': + strlcpy(chroot_dir, optarg, sizeof chroot_dir); + break; + case 'v': + printf("ndhc, version " VERSION "\n\n"); + exit(EXIT_SUCCESS); + break; + default: + show_usage(); + } + } - if (read_interface(client_config.interface, &client_config.ifindex, - NULL, client_config.arp) < 0) - exit(EXIT_FAILURE); - - if (!client_config.clientid) { - client_config.clientid = xmalloc(6 + 3); - client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; - client_config.clientid[OPT_LEN] = 7; - client_config.clientid[OPT_DATA] = 1; - memcpy(client_config.clientid + 3, client_config.arp, 6); - } + log_line("ndhc client " VERSION " started."); - /* setup signal handlers */ - signal(SIGUSR1, signal_handler); - signal(SIGUSR2, signal_handler); - signal(SIGTERM, signal_handler); + if (read_interface(client_config.interface, &client_config.ifindex, + NULL, client_config.arp) < 0) + exit(EXIT_FAILURE); - if (chdir(chroot_dir)) { - printf("Failed to chdir(%s)!\n", chroot_dir); - exit(EXIT_FAILURE); - } + if (!client_config.clientid) { + client_config.clientid = xmalloc(6 + 3); + client_config.clientid[OPT_CODE] = DHCP_CLIENT_ID; + client_config.clientid[OPT_LEN] = 7; + client_config.clientid[OPT_DATA] = 1; + memcpy(client_config.clientid + 3, client_config.arp, 6); + } - if (chroot(chroot_dir)) { - printf("Failed to chroot(%s)!\n", chroot_dir); - exit(EXIT_FAILURE); - } + /* setup signal handlers */ + signal(SIGUSR1, signal_handler); + signal(SIGUSR2, signal_handler); + signal(SIGTERM, signal_handler); - set_cap(uid, gid, - "cap_net_bind_service,cap_net_broadcast,cap_net_raw=ep"); - drop_root(uid, gid); - - state = INIT_SELECTING; - run_script(NULL, SCRIPT_DECONFIG); - change_mode(LISTEN_RAW); + if (chdir(chroot_dir)) { + printf("Failed to chdir(%s)!\n", chroot_dir); + exit(EXIT_FAILURE); + } - do_work(); - - return EXIT_SUCCESS; + if (chroot(chroot_dir)) { + printf("Failed to chroot(%s)!\n", chroot_dir); + exit(EXIT_FAILURE); + } + + set_cap(uid, gid, + "cap_net_bind_service,cap_net_broadcast,cap_net_raw=ep"); + drop_root(uid, gid); + + state = INIT_SELECTING; + run_script(NULL, SCRIPT_DECONFIG); + change_mode(LISTEN_RAW); + + do_work(); + + return EXIT_SUCCESS; } - diff --git a/ndhc/options.c b/ndhc/options.c index d8be6d9..3bd5fb0 100644 --- a/ndhc/options.c +++ b/ndhc/options.c @@ -1,9 +1,9 @@ -/* - * options.c -- DHCP server option packet tools +/* + * options.c -- DHCP server option packet tools * Rewrite by Russ Dill July 2001 - * Fixes and hardening: Nicholas Kain + * Fixes and hardening: Nicholas J. Kain */ - + #include #include #include @@ -16,47 +16,47 @@ /* supported options are easily added here */ struct dhcp_option options[] = { - /* name[10] flags code */ - {"subnet", OPTION_IP | OPTION_REQ, 0x01}, - {"timezone", OPTION_S32, 0x02}, - {"router", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03}, - {"timesvr", OPTION_IP | OPTION_LIST, 0x04}, - {"namesvr", OPTION_IP | OPTION_LIST, 0x05}, - {"dns", OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06}, - {"logsvr", OPTION_IP | OPTION_LIST, 0x07}, - {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08}, - {"lprsvr", OPTION_IP | OPTION_LIST, 0x09}, - {"hostname", OPTION_STRING | OPTION_REQ, 0x0c}, - {"bootsize", OPTION_U16, 0x0d}, - {"domain", OPTION_STRING | OPTION_REQ, 0x0f}, - {"swapsvr", OPTION_IP, 0x10}, - {"rootpath", OPTION_STRING, 0x11}, - {"ipttl", OPTION_U8, 0x17}, - {"mtu", OPTION_U16, 0x1a}, - {"broadcast", OPTION_IP | OPTION_REQ, 0x1c}, - {"ntpsrv", OPTION_IP | OPTION_LIST, 0x2a}, - {"wins", OPTION_IP | OPTION_LIST, 0x2c}, - {"requestip", OPTION_IP, 0x32}, - {"lease", OPTION_U32, 0x33}, - {"dhcptype", OPTION_U8, 0x35}, - {"serverid", OPTION_IP, 0x36}, - {"message", OPTION_STRING, 0x38}, - {"tftp", OPTION_STRING, 0x42}, - {"bootfile", OPTION_STRING, 0x43}, - {"", 0x00, 0x00} + /* name[10] flags code */ + {"subnet" , OPTION_IP | OPTION_REQ, 0x01}, + {"timezone" , OPTION_S32, 0x02}, + {"router" , OPTION_IP | OPTION_LIST | OPTION_REQ, 0x03}, + {"timesvr" , OPTION_IP | OPTION_LIST, 0x04}, + {"namesvr" , OPTION_IP | OPTION_LIST, 0x05}, + {"dns" , OPTION_IP | OPTION_LIST | OPTION_REQ, 0x06}, + {"logsvr" , OPTION_IP | OPTION_LIST, 0x07}, + {"cookiesvr", OPTION_IP | OPTION_LIST, 0x08}, + {"lprsvr" , OPTION_IP | OPTION_LIST, 0x09}, + {"hostname" , OPTION_STRING | OPTION_REQ, 0x0c}, + {"bootsize" , OPTION_U16, 0x0d}, + {"domain" , OPTION_STRING | OPTION_REQ, 0x0f}, + {"swapsvr" , OPTION_IP, 0x10}, + {"rootpath" , OPTION_STRING, 0x11}, + {"ipttl" , OPTION_U8, 0x17}, + {"mtu" , OPTION_U16, 0x1a}, + {"broadcast", OPTION_IP | OPTION_REQ, 0x1c}, + {"ntpsrv" , OPTION_IP | OPTION_LIST, 0x2a}, + {"wins" , OPTION_IP | OPTION_LIST, 0x2c}, + {"requestip", OPTION_IP, 0x32}, + {"lease" , OPTION_U32, 0x33}, + {"dhcptype" , OPTION_U8, 0x35}, + {"serverid" , OPTION_IP, 0x36}, + {"message" , OPTION_STRING, 0x38}, + {"tftp" , OPTION_STRING, 0x42}, + {"bootfile" , OPTION_STRING, 0x43}, + {"" , 0x00, 0x00} }; /* Lengths of the different option types */ int option_lengths[] = { - [OPTION_IP] = 4, - [OPTION_IP_PAIR] = 8, - [OPTION_BOOLEAN] = 1, - [OPTION_STRING] = 1, - [OPTION_U8] = 1, - [OPTION_U16] = 2, - [OPTION_S16] = 2, - [OPTION_U32] = 4, - [OPTION_S32] = 4 + [OPTION_IP] = 4, + [OPTION_IP_PAIR] = 8, + [OPTION_BOOLEAN] = 1, + [OPTION_STRING] = 1, + [OPTION_U8] = 1, + [OPTION_U16] = 2, + [OPTION_S16] = 2, + [OPTION_U32] = 4, + [OPTION_S32] = 4 }; @@ -66,7 +66,7 @@ unsigned char *get_option(struct dhcpMessage *packet, int code) int i = 0, length = 308; unsigned char *optionptr; int over = 0, done = 0, curr = OPTION_FIELD; - + optionptr = packet->options; while (!done) { if (i >= length) { @@ -79,7 +79,7 @@ unsigned char *get_option(struct dhcpMessage *packet, int code) return NULL; } return optionptr + i + 2; - } + } switch (optionptr[i + OPT_CODE]) { case DHCP_PADDING: i++; @@ -114,7 +114,7 @@ unsigned char *get_option(struct dhcpMessage *packet, int code) /* return the position of the 'end' option */ -int end_option(unsigned char *optionptr) +int end_option(unsigned char *optionptr) { int i = 0; @@ -133,11 +133,11 @@ int end_option(unsigned char *optionptr) int add_option_string(unsigned char *optionptr, unsigned char *string) { int end = end_option(optionptr); - + /* end position + string length + option code/length + end option */ if (end + string[OPT_LEN] + 2 + 1 >= 308) { log_error("Option 0x%02x did not fit into the packet!", - string[OPT_CODE]); + string[OPT_CODE]); return 0; } log_line("adding option 0x%02x", string[OPT_CODE]); @@ -147,16 +147,16 @@ int add_option_string(unsigned char *optionptr, unsigned char *string) } int add_simple_option(unsigned char *optionptr, unsigned char code, - uint32_t data) + uint32_t data) { int i, length = 0; unsigned char option[2 + 4]; - + for (i = 0; options[i].code; i++) if (options[i].code == code) { length = option_lengths[options[i].flags & TYPE_MASK]; } - + option[OPT_CODE] = code; option[OPT_LEN] = (unsigned char)length; @@ -189,7 +189,7 @@ struct option_set *find_option(struct option_set *opt_list, char code) /* add an option to the opt_list */ void attach_option(struct option_set **opt_list, struct dhcp_option *option, - char *buffer, int length) + char *buffer, int length) { struct option_set *existing, *new, **curr; @@ -199,29 +199,29 @@ void attach_option(struct option_set **opt_list, struct dhcp_option *option, option->name); if (option->flags & OPTION_LIST) { if (existing->data[OPT_LEN] + length <= 255) { - existing->data = realloc(existing->data, - existing->data[OPT_LEN] + length + 2); + existing->data = realloc(existing->data, + existing->data[OPT_LEN] + length + 2); memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, - length); + length); existing->data[OPT_LEN] += length; } /* else, ignore the data; we could put this in a second option in the future */ } /* else, ignore the new data */ } else { log_line("Attaching option %s to list", option->name); - + /* make a new option */ new = xmalloc(sizeof(struct option_set)); new->data = xmalloc(length + 2); new->data[OPT_CODE] = option->code; new->data[OPT_LEN] = length; memcpy(new->data + 2, buffer, length); - + curr = opt_list; while (*curr && (*curr)->data[OPT_CODE] < option->code) curr = &(*curr)->next; - + new->next = *curr; - *curr = new; + *curr = new; } } diff --git a/ndhc/packet.c b/ndhc/packet.c index 444acfe..5ad1a49 100644 --- a/ndhc/packet.c +++ b/ndhc/packet.c @@ -13,191 +13,186 @@ #include "dhcpd.h" #include "options.h" - void init_header(struct dhcpMessage *packet, char type) { - memset(packet, 0, sizeof(struct dhcpMessage)); - switch (type) { - case DHCPDISCOVER: - case DHCPREQUEST: - case DHCPRELEASE: - case DHCPINFORM: - packet->op = BOOTREQUEST; - break; - case DHCPOFFER: - case DHCPACK: - case DHCPNAK: - packet->op = BOOTREPLY; - } - packet->htype = ETH_10MB; - packet->hlen = ETH_10MB_LEN; - packet->cookie = htonl(DHCP_MAGIC); - packet->options[0] = DHCP_END; - add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); + memset(packet, 0, sizeof(struct dhcpMessage)); + switch (type) { + case DHCPDISCOVER: + case DHCPREQUEST: + case DHCPRELEASE: + case DHCPINFORM: + packet->op = BOOTREQUEST; + break; + case DHCPOFFER: + case DHCPACK: + case DHCPNAK: + packet->op = BOOTREPLY; + } + packet->htype = ETH_10MB; + packet->hlen = ETH_10MB_LEN; + packet->cookie = htonl(DHCP_MAGIC); + packet->options[0] = DHCP_END; + add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type); } - /* read a packet from socket fd, return -1 on read error, -2 on packet error */ int get_packet(struct dhcpMessage *packet, int fd) { - int bytes; - int i; - const char broken_vendors[][8] = { - "MSFT 98", - "" - }; - unsigned char *vendor; + int bytes; + int i; + const char broken_vendors[][8] = { + "MSFT 98", + "" + }; + unsigned char *vendor; - memset(packet, 0, sizeof(struct dhcpMessage)); - bytes = read(fd, packet, sizeof(struct dhcpMessage)); - if (bytes < 0) { - log_line("couldn't read on listening socket, ignoring"); - return -1; - } + memset(packet, 0, sizeof(struct dhcpMessage)); + bytes = read(fd, packet, sizeof(struct dhcpMessage)); + if (bytes < 0) { + log_line("couldn't read on listening socket, ignoring"); + return -1; + } - if (ntohl(packet->cookie) != DHCP_MAGIC) { - log_error("received bogus message, ignoring."); - return -2; + if (ntohl(packet->cookie) != DHCP_MAGIC) { + log_error("received bogus message, ignoring."); + return -2; + } + log_line("Received a packet"); + + if (packet->op == BOOTREQUEST + && (vendor = get_option(packet, DHCP_VENDOR))) + { + for (i = 0; broken_vendors[i][0]; i++) { + if (vendor[OPT_LEN - 2] == (unsigned char)strlen(broken_vendors[i]) + && !strncmp((char *)vendor, broken_vendors[i], + vendor[OPT_LEN - 2])) + { + log_line("broken client (%s), forcing broadcast", + broken_vendors[i]); + packet->flags |= htons(BROADCAST_FLAG); + } } - log_line("Received a packet"); - - if (packet->op == BOOTREQUEST - && (vendor = get_option(packet, DHCP_VENDOR))) - { - for (i = 0; broken_vendors[i][0]; i++) { - if (vendor[OPT_LEN - 2] == (unsigned char)strlen(broken_vendors[i]) - && !strncmp((char *)vendor, broken_vendors[i], - vendor[OPT_LEN - 2])) - { - log_line("broken client (%s), forcing broadcast", - broken_vendors[i]); - packet->flags |= htons(BROADCAST_FLAG); - } - } - } - return bytes; + } + return bytes; } uint16_t checksum(void *addr, int count) { - /* Compute Internet Checksum for "count" bytes - * beginning at location "addr". - */ - register int32_t sum = 0; - uint16_t *source = (uint16_t *)addr; + /* Compute Internet Checksum for "count" bytes + * beginning at location "addr". + */ + register int32_t sum = 0; + uint16_t *source = (uint16_t *)addr; - while (count > 1) { - sum += *source++; - count -= 2; - } + while (count > 1) { + sum += *source++; + count -= 2; + } - /* Add left-over byte, if any */ - if (count > 0) { - /* Make sure that the left-over byte is added correctly both - * with little and big endian hosts */ - uint16_t tmp = 0; - *(unsigned char *) (&tmp) = * (unsigned char *) source; - sum += tmp; - } - /* Fold 32-bit sum to 16 bits */ - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); + /* Add left-over byte, if any */ + if (count > 0) { + /* Make sure that the left-over byte is added correctly both + * with little and big endian hosts */ + uint16_t tmp = 0; + *(unsigned char *) (&tmp) = * (unsigned char *) source; + sum += tmp; + } + /* Fold 32-bit sum to 16 bits */ + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); - return ~sum; + return ~sum; } - /* Constuct a ip/udp header for a packet, and specify the source and dest * hardware address */ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, - int source_port, uint32_t dest_ip, int dest_port, - unsigned char *dest_arp, int ifindex) + int source_port, uint32_t dest_ip, int dest_port, + unsigned char *dest_arp, int ifindex) { - int fd, result = -1; - struct sockaddr_ll dest; - struct udp_dhcp_packet packet; + int fd, result = -1; + struct sockaddr_ll dest; + struct udp_dhcp_packet packet; - if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { - log_error("socket call failed: %s", strerror(errno)); - goto out; - } - - memset(&dest, 0, sizeof(dest)); - memset(&packet, 0, sizeof(packet)); - - dest.sll_family = AF_PACKET; - dest.sll_protocol = htons(ETH_P_IP); - dest.sll_ifindex = ifindex; - dest.sll_halen = 6; - memcpy(dest.sll_addr, dest_arp, 6); - if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { - log_error("bind call failed: %s", strerror(errno)); - goto out_fd; - } + if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { + log_error("socket call failed: %s", strerror(errno)); + goto out; + } - packet.ip.protocol = IPPROTO_UDP; - packet.ip.saddr = source_ip; - packet.ip.daddr = dest_ip; - packet.udp.source = htons(source_port); - packet.udp.dest = htons(dest_port); - /* cheat on the psuedo-header */ - packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); - packet.ip.tot_len = packet.udp.len; - memcpy(&(packet.data), payload, sizeof(struct dhcpMessage)); - packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet)); - - packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet)); - packet.ip.ihl = sizeof(packet.ip) >> 2; - packet.ip.version = IPVERSION; - packet.ip.ttl = IPDEFTTL; - packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip)); + memset(&dest, 0, sizeof(dest)); + memset(&packet, 0, sizeof(packet)); - result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, - (struct sockaddr *)&dest, sizeof dest); - if (result <= 0) { - log_error("write on socket failed: %s", - strerror(errno)); - } -out_fd: - close(fd); -out: - return result; + dest.sll_family = AF_PACKET; + dest.sll_protocol = htons(ETH_P_IP); + dest.sll_ifindex = ifindex; + dest.sll_halen = 6; + memcpy(dest.sll_addr, dest_arp, 6); + if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) { + log_error("bind call failed: %s", strerror(errno)); + goto out_fd; + } + + packet.ip.protocol = IPPROTO_UDP; + packet.ip.saddr = source_ip; + packet.ip.daddr = dest_ip; + packet.udp.source = htons(source_port); + packet.udp.dest = htons(dest_port); + /* cheat on the psuedo-header */ + packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); + packet.ip.tot_len = packet.udp.len; + memcpy(&(packet.data), payload, sizeof(struct dhcpMessage)); + packet.udp.check = checksum(&packet, sizeof(struct udp_dhcp_packet)); + + packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet)); + packet.ip.ihl = sizeof(packet.ip) >> 2; + packet.ip.version = IPVERSION; + packet.ip.ttl = IPDEFTTL; + packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip)); + + result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, + (struct sockaddr *)&dest, sizeof dest); + if (result <= 0) { + log_error("write on socket failed: %s", + strerror(errno)); + } + out_fd: + close(fd); + out: + return result; } - /* Let the kernel do all the work for packet generation */ int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, - int source_port, uint32_t dest_ip, int dest_port) + int source_port, uint32_t dest_ip, int dest_port) { - int n = 1, fd, result = -1; - struct sockaddr_in client; - - if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - goto out; - - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) - goto out_fd; + int n = 1, fd, result = -1; + struct sockaddr_in client; - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(source_port); - client.sin_addr.s_addr = source_ip; + if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + goto out; - if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) - goto out_fd; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &n, sizeof(n)) == -1) + goto out_fd; - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(dest_port); - client.sin_addr.s_addr = dest_ip; + memset(&client, 0, sizeof(client)); + client.sin_family = AF_INET; + client.sin_port = htons(source_port); + client.sin_addr.s_addr = source_ip; - if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) - goto out_fd; + if (bind(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) + goto out_fd; - result = write(fd, payload, sizeof(struct dhcpMessage)); -out_fd: - close(fd); -out: - return result; -} + memset(&client, 0, sizeof(client)); + client.sin_family = AF_INET; + client.sin_port = htons(dest_port); + client.sin_addr.s_addr = dest_ip; + if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) + goto out_fd; + + result = write(fd, payload, sizeof(struct dhcpMessage)); + out_fd: + close(fd); + out: + return result; +} diff --git a/ndhc/script.c b/ndhc/script.c index 585acee..bd5751a 100644 --- a/ndhc/script.c +++ b/ndhc/script.c @@ -3,7 +3,7 @@ * Functions to call the interface change daemon * * Russ Dill July 2001 - * Nicholas Kain 2004 + * Nicholas J. Kain 2004-2010 * * 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 @@ -40,219 +40,229 @@ #include "log.h" #include "script.h" -static int snprintip(char *dest, size_t size, unsigned char *ip) { - if (!dest) return -1; - return snprintf(dest, size, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); +static int snprintip(char *dest, size_t size, unsigned char *ip) +{ + if (!dest) return -1; + return snprintf(dest, size, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); } -static int sprintip(char *dest, size_t size, char *pre, unsigned char *ip) { - if (!dest) return -1; - return snprintf(dest, size, "%s%d.%d.%d.%d", pre, ip[0], ip[1], ip[2], ip[3]); +static int sprintip(char *dest, size_t size, char *pre, unsigned char *ip) +{ + if (!dest) return -1; + return snprintf(dest, size, "%s%d.%d.%d.%d", + pre, ip[0], ip[1], ip[2], ip[3]); } /* Fill dest with the text of option 'option'. */ -static void fill_options(char *dest, unsigned char *option, struct dhcp_option *type_p, unsigned int maxlen) +static void fill_options(char *dest, unsigned char *option, + struct dhcp_option *type_p, unsigned int maxlen) { - int type, optlen; - uint16_t val_u16; - int16_t val_s16; - uint32_t val_u32; - int32_t val_s32; - int len = option[OPT_LEN - 2]; - char *odest; - - odest = dest; - - dest += snprintf(dest, maxlen, "%s=", type_p->name); + int type, optlen; + uint16_t val_u16; + int16_t val_s16; + uint32_t val_u32; + int32_t val_s32; + int len = option[OPT_LEN - 2]; + char *odest; - type = type_p->flags & TYPE_MASK; - optlen = option_lengths[type]; - for(;;) { - switch (type) { - case OPTION_IP_PAIR: - dest += sprintip(dest, maxlen - (dest - odest), "", option); - *(dest++) = '/'; - option += 4; - optlen = 4; - case OPTION_IP: /* Works regardless of host byte order. */ - dest += sprintip(dest, maxlen - (dest - odest), "", option); - break; - case OPTION_BOOLEAN: - dest += snprintf(dest, maxlen - (dest - odest), *option ? "yes " : "no "); - break; - case OPTION_U8: - dest += snprintf(dest, maxlen - (dest - odest), "%u ", *option); - break; - case OPTION_U16: - memcpy(&val_u16, option, 2); - dest += snprintf(dest, maxlen - (dest - odest), "%u ", ntohs(val_u16)); - break; - case OPTION_S16: - memcpy(&val_s16, option, 2); - dest += snprintf(dest, maxlen - (dest - odest), "%d ", ntohs(val_s16)); - break; - case OPTION_U32: - memcpy(&val_u32, option, 4); - dest += snprintf(dest, maxlen - (dest - odest), "%lu ", (unsigned long) ntohl(val_u32)); - break; - case OPTION_S32: - memcpy(&val_s32, option, 4); - dest += snprintf(dest, maxlen - (dest - odest), "%ld ", (long) ntohl(val_s32)); - break; - case OPTION_STRING: - if ( (maxlen - (dest - odest)) < (unsigned)len) return; - memcpy(dest, option, len); - dest[len] = '\0'; - return; /* Short circuit this case */ - } - option += optlen; - len -= optlen; - if (len <= 0) break; - } + odest = dest; + + dest += snprintf(dest, maxlen, "%s=", type_p->name); + + type = type_p->flags & TYPE_MASK; + optlen = option_lengths[type]; + for(;;) { + switch (type) { + case OPTION_IP_PAIR: + dest += sprintip(dest, maxlen - (dest - odest), "", option); + *(dest++) = '/'; + option += 4; + optlen = 4; + case OPTION_IP: /* Works regardless of host byte order. */ + dest += sprintip(dest, maxlen - (dest - odest), "", option); + break; + case OPTION_BOOLEAN: + dest += snprintf(dest, maxlen - (dest - odest), + *option ? "yes " : "no "); + break; + case OPTION_U8: + dest += snprintf(dest, maxlen - (dest - odest), + "%u ", *option); + break; + case OPTION_U16: + memcpy(&val_u16, option, 2); + dest += snprintf(dest, maxlen - (dest - odest), + "%u ", ntohs(val_u16)); + break; + case OPTION_S16: + memcpy(&val_s16, option, 2); + dest += snprintf(dest, maxlen - (dest - odest), + "%d ", ntohs(val_s16)); + break; + case OPTION_U32: + memcpy(&val_u32, option, 4); + dest += snprintf(dest, maxlen - (dest - odest), + "%lu ", (unsigned long) ntohl(val_u32)); + break; + case OPTION_S32: + memcpy(&val_s32, option, 4); + dest += snprintf(dest, maxlen - (dest - odest), + "%ld ", (long) ntohl(val_s32)); + break; + case OPTION_STRING: + if ( (maxlen - (dest - odest)) < (unsigned)len) return; + memcpy(dest, option, len); + dest[len] = '\0'; + return; /* Short circuit this case */ + } + option += optlen; + len -= optlen; + if (len <= 0) break; + } } static int open_ifch(void) { - int sockfd, ret; - struct sockaddr_un address = - { - .sun_family = AF_UNIX, - .sun_path = "ifchange" - }; + int sockfd, ret; + struct sockaddr_un address = { + .sun_family = AF_UNIX, + .sun_path = "ifchange" + }; - sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - ret = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + ret = connect(sockfd, (struct sockaddr *)&address, sizeof(address)); - if (ret == -1) { - log_error("unable to connect to ifchd!"); - exit(EXIT_FAILURE); - } + if (ret == -1) { + log_error("unable to connect to ifchd!"); + exit(EXIT_FAILURE); + } - return sockfd; + return sockfd; } static void sockwrite(int fd, const void *buf, size_t count) { - int ret; + int ret; -sockwrite_again: - ret = write(fd, buf, count); - if (ret == -1) { - if (errno == EAGAIN) - goto sockwrite_again; - log_error("error while writing to unix socket!"); - exit(EXIT_FAILURE); - } - if (ret < 0) ret = 0; - if ((unsigned int)ret < strlen(buf)) { - log_error("incomplete write!"); - } - log_line("writing: %s", (char *)buf); -} + sockwrite_again: + ret = write(fd, buf, count); + if (ret == -1) { + if (errno == EAGAIN) + goto sockwrite_again; + log_error("error while writing to unix socket!"); + exit(EXIT_FAILURE); + } + if (ret < 0) ret = 0; + if ((unsigned int)ret < strlen(buf)) { + log_error("incomplete write!"); + } + log_line("writing: %s", (char *)buf); +} static void deconfig_if(void) { - int sockfd; - char buf[256]; - - memset(buf, '\0', sizeof buf); - - sockfd = open_ifch(); - - snprintf(buf, sizeof buf, "interface:%s:", - client_config.interface); - sockwrite(sockfd, buf, strlen(buf)); + int sockfd; + char buf[256]; - snprintf(buf, sizeof buf, "ip:0.0.0.0:"); - sockwrite(sockfd, buf, strlen(buf)); - - close(sockfd); - exit(EXIT_SUCCESS); + memset(buf, '\0', sizeof buf); + + sockfd = open_ifch(); + + snprintf(buf, sizeof buf, "interface:%s:", + client_config.interface); + sockwrite(sockfd, buf, strlen(buf)); + + snprintf(buf, sizeof buf, "ip:0.0.0.0:"); + sockwrite(sockfd, buf, strlen(buf)); + + close(sockfd); + exit(EXIT_SUCCESS); } -static void translate_option(int sockfd, struct dhcpMessage *packet, int opt) { - char buf[256], buf2[256]; - unsigned char *p; - int i; +static void translate_option(int sockfd, struct dhcpMessage *packet, int opt) +{ + char buf[256], buf2[256]; + unsigned char *p; + int i; - if (!packet) return; + if (!packet) return; - memset(buf, '\0', sizeof(buf)); - memset(buf2, '\0', sizeof(buf2)); - - p = get_option(packet, options[opt].code); - fill_options(buf2, p, &options[opt], sizeof(buf2) - 1); - snprintf(buf, sizeof buf, "%s:", buf2); - for (i=0; i<256; i++) { - if (buf[i] == '\0') break; - if (buf[i] == '=') { - buf[i] = ':'; - break; - } - } - sockwrite(sockfd, buf, strlen(buf)); + memset(buf, '\0', sizeof(buf)); + memset(buf2, '\0', sizeof(buf2)); + + p = get_option(packet, options[opt].code); + fill_options(buf2, p, &options[opt], sizeof(buf2) - 1); + snprintf(buf, sizeof buf, "%s:", buf2); + for (i=0; i<256; i++) { + if (buf[i] == '\0') break; + if (buf[i] == '=') { + buf[i] = ':'; + break; + } + } + sockwrite(sockfd, buf, strlen(buf)); } static void bound_if(struct dhcpMessage *packet) { - int sockfd; - char buf[256], buf2[256]; - char ip[32]; - - if (!packet) return; - - memset(buf, '\0', sizeof(buf)); - memset(ip, '\0', sizeof(ip)); - memset(buf2, '\0', sizeof(buf2)); - - sockfd = open_ifch(); + int sockfd; + char buf[256], buf2[256]; + char ip[32]; - snprintf(buf, sizeof buf, "interface:%s:", client_config.interface); - sockwrite(sockfd, buf, strlen(buf)); + if (!packet) return; - snprintip(ip, sizeof ip, (unsigned char *) &packet->yiaddr); - snprintf(buf, sizeof buf, "ip:%s:", ip); - sockwrite(sockfd, buf, strlen(buf)); - - translate_option(sockfd, packet, 0); - translate_option(sockfd, packet, 2); - translate_option(sockfd, packet, 5); - translate_option(sockfd, packet, 9); - translate_option(sockfd, packet, 11); - translate_option(sockfd, packet, 15); - translate_option(sockfd, packet, 16); - translate_option(sockfd, packet, 17); - - close(sockfd); - exit(EXIT_SUCCESS); + memset(buf, '\0', sizeof(buf)); + memset(ip, '\0', sizeof(ip)); + memset(buf2, '\0', sizeof(buf2)); + + sockfd = open_ifch(); + + snprintf(buf, sizeof buf, "interface:%s:", client_config.interface); + sockwrite(sockfd, buf, strlen(buf)); + + snprintip(ip, sizeof ip, (unsigned char *) &packet->yiaddr); + snprintf(buf, sizeof buf, "ip:%s:", ip); + sockwrite(sockfd, buf, strlen(buf)); + + translate_option(sockfd, packet, 0); + translate_option(sockfd, packet, 2); + translate_option(sockfd, packet, 5); + translate_option(sockfd, packet, 9); + translate_option(sockfd, packet, 11); + translate_option(sockfd, packet, 15); + translate_option(sockfd, packet, 16); + translate_option(sockfd, packet, 17); + + close(sockfd); + exit(EXIT_SUCCESS); } void run_script(struct dhcpMessage *packet, int mode) { - int pid; - - pid = fork(); - if (pid) { - waitpid(pid, NULL, 0); - return; - } else if (pid == 0) { - switch (mode) { - case SCRIPT_DECONFIG: - deconfig_if(); - break; - case SCRIPT_BOUND: - bound_if(packet); - break; - case SCRIPT_RENEW: - bound_if(packet); - break; - case SCRIPT_NAK: - deconfig_if(); - break; - default: - break; - } - log_error("invalid script mode: %d", mode); - exit(EXIT_FAILURE); - } + int pid; + + pid = fork(); + if (pid) { + waitpid(pid, NULL, 0); + return; + } else if (pid == 0) { + switch (mode) { + case SCRIPT_DECONFIG: + deconfig_if(); + break; + case SCRIPT_BOUND: + bound_if(packet); + break; + case SCRIPT_RENEW: + bound_if(packet); + break; + case SCRIPT_NAK: + deconfig_if(); + break; + default: + break; + } + log_error("invalid script mode: %d", mode); + exit(EXIT_FAILURE); + } } diff --git a/ndhc/socket.c b/ndhc/socket.c index 35ee330..b09a644 100644 --- a/ndhc/socket.c +++ b/ndhc/socket.c @@ -1,14 +1,11 @@ /* * socket.c -- DHCP server client/server socket creation * - * udhcp client/server + * Copyright (C) 2004-2010 Nicholas J. Kain + * Rewrite by Russ Dill July 2001 * Copyright (C) 1999 Matthew Ramsay * Chris Trew * - * Rewrite by Russ Dill July 2001 - * - * Cleanup and fixes, Nicholas Kain 2004 - * * 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 * the Free Software Foundation; either version 2 of the License, or @@ -40,116 +37,115 @@ #include "strl.h" int read_interface(char *interface, int *ifindex, uint32_t *addr, - unsigned char *arp) + unsigned char *arp) { - int fd, ret = -1; - struct ifreq ifr; - struct sockaddr_in *our_ip; + int fd, ret = -1; + struct ifreq ifr; + struct sockaddr_in *our_ip; - memset(&ifr, 0, sizeof(struct ifreq)); - if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { - log_error("socket failed!: %s", strerror(errno)); - goto out; - } + memset(&ifr, 0, sizeof(struct ifreq)); + if((fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) { + log_error("socket failed!: %s", strerror(errno)); + goto out; + } - ifr.ifr_addr.sa_family = AF_INET; - strlcpy(ifr.ifr_name, interface, IFNAMSIZ); + ifr.ifr_addr.sa_family = AF_INET; + strlcpy(ifr.ifr_name, interface, IFNAMSIZ); - if (addr) { - if (ioctl(fd, SIOCGIFADDR, &ifr)) { - log_error("Couldn't get IP for %s.", strerror(errno)); - goto out_fd; - } - our_ip = (struct sockaddr_in *) &ifr.ifr_addr; - *addr = our_ip->sin_addr.s_addr; - log_line("%s (our ip) = %s", ifr.ifr_name, - inet_ntoa(our_ip->sin_addr)); - } + if (addr) { + if (ioctl(fd, SIOCGIFADDR, &ifr)) { + log_error("Couldn't get IP for %s.", strerror(errno)); + goto out_fd; + } + our_ip = (struct sockaddr_in *) &ifr.ifr_addr; + *addr = our_ip->sin_addr.s_addr; + log_line("%s (our ip) = %s", ifr.ifr_name, + inet_ntoa(our_ip->sin_addr)); + } - if (ioctl(fd, SIOCGIFINDEX, &ifr)) { - log_error("SIOCGIFINDEX failed!: %s", strerror(errno)); - goto out_fd; - } + if (ioctl(fd, SIOCGIFINDEX, &ifr)) { + log_error("SIOCGIFINDEX failed!: %s", strerror(errno)); + goto out_fd; + } - log_line("adapter index %d", ifr.ifr_ifindex); - *ifindex = ifr.ifr_ifindex; + log_line("adapter index %d", ifr.ifr_ifindex); + *ifindex = ifr.ifr_ifindex; - if (ioctl(fd, SIOCGIFHWADDR, &ifr)) { - log_error("Couldn't get MAC for %s", strerror(errno)); - goto out_fd; - } + if (ioctl(fd, SIOCGIFHWADDR, &ifr)) { + log_error("Couldn't get MAC for %s", strerror(errno)); + goto out_fd; + } - memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); - log_line("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x", - arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); - ret = 0; -out_fd: - close(fd); -out: - return ret; + memcpy(arp, ifr.ifr_hwaddr.sa_data, 6); + log_line("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x", + arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]); + ret = 0; + out_fd: + close(fd); + out: + return ret; } int listen_socket(unsigned int ip, int port, char *inf) { - struct ifreq interface; - int fd; - struct sockaddr_in addr; - int n = 1; + struct ifreq interface; + int fd; + struct sockaddr_in addr; + int n = 1; - log_line("Opening listen socket on 0x%08x:%d %s", ip, port, inf); - if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { - log_error("socket call failed: %s", strerror(errno)); - goto out; - } - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = ip; + log_line("Opening listen socket on 0x%08x:%d %s", ip, port, inf); + if ((fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + log_error("socket call failed: %s", strerror(errno)); + goto out; + } - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof n) == -1) - goto out_fd; - if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&n, sizeof n) == -1) - goto out_fd; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = ip; - strlcpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ); - if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, - (char *)&interface, sizeof interface) < 0) - goto out_fd; - - if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) - goto out_fd; - - return fd; -out_fd: - close(fd); -out: - return -1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&n, sizeof n) == -1) + goto out_fd; + if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (char *)&n, sizeof n) == -1) + goto out_fd; + + strlcpy(interface.ifr_ifrn.ifrn_name, inf, IFNAMSIZ); + if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, + (char *)&interface, sizeof interface) < 0) + goto out_fd; + + if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) + goto out_fd; + + return fd; + out_fd: + close(fd); + out: + return -1; } int raw_socket(int ifindex) { - int fd; - struct sockaddr_ll sock; + int fd; + struct sockaddr_ll sock; - log_line("Opening raw socket on ifindex %d", ifindex); - if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { - log_error("socket call failed: %s", strerror(errno)); - goto out; - } - - sock.sll_family = AF_PACKET; - sock.sll_protocol = htons(ETH_P_IP); - sock.sll_ifindex = ifindex; - if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) { - log_error("bind call failed: %s", strerror(errno)); - goto out_fd; - } + log_line("Opening raw socket on ifindex %d", ifindex); + if ((fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) { + log_error("socket call failed: %s", strerror(errno)); + goto out; + } - return fd; -out_fd: - close(fd); -out: - return -1; + sock.sll_family = AF_PACKET; + sock.sll_protocol = htons(ETH_P_IP); + sock.sll_ifindex = ifindex; + if (bind(fd, (struct sockaddr *) &sock, sizeof(sock)) < 0) { + log_error("bind call failed: %s", strerror(errno)); + goto out_fd; + } + + return fd; + out_fd: + close(fd); + out: + return -1; } -