From 1b48532c662470f5dd4090d47e1e2c333e967caf Mon Sep 17 00:00:00 2001 From: Sebastian Schmelzer Date: Sat, 3 Dec 2011 13:31:09 +0100 Subject: codeformating, change to log4cxx --- src/customdhcpcd/arp.c | 421 ++++----- src/customdhcpcd/arp.h | 2 +- src/customdhcpcd/client.c | 1973 ++++++++++++++++++++++-------------------- src/customdhcpcd/client.h | 2 +- src/customdhcpcd/common.c | 285 +++--- src/customdhcpcd/common.h | 2 +- src/customdhcpcd/configure.c | 1267 ++++++++++++++------------- src/customdhcpcd/configure.h | 4 +- src/customdhcpcd/dhcp.c | 1480 ++++++++++++++++--------------- src/customdhcpcd/dhcp.h | 191 ++-- src/customdhcpcd/dhcpcd.c | 1237 +++++++++++++------------- src/customdhcpcd/dhcpcd.h | 89 +- src/customdhcpcd/duid.c | 147 ++-- src/customdhcpcd/duid.h | 2 +- src/customdhcpcd/info.c | 799 +++++++++-------- src/customdhcpcd/info.h | 4 +- src/customdhcpcd/interface.c | 1615 +++++++++++++++++----------------- src/customdhcpcd/interface.h | 60 +- src/customdhcpcd/ipv4ll.c | 50 +- src/customdhcpcd/ipv4ll.h | 2 +- src/customdhcpcd/logger.c | 189 ++-- src/customdhcpcd/logger.h | 2 +- src/customdhcpcd/logwriter.c | 436 +++++----- src/customdhcpcd/logwriter.h | 11 +- src/customdhcpcd/signal.c | 216 ++--- src/customdhcpcd/signal.h | 2 +- src/customdhcpcd/socket.c | 1064 ++++++++++++----------- src/customdhcpcd/socket.h | 10 +- 28 files changed, 6026 insertions(+), 5536 deletions(-) (limited to 'src/customdhcpcd') diff --git a/src/customdhcpcd/arp.c b/src/customdhcpcd/arp.c index 794850c..29a22f2 100644 --- a/src/customdhcpcd/arp.c +++ b/src/customdhcpcd/arp.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -74,211 +74,232 @@ #ifdef ENABLE_ARP static int send_arp (const interface_t *iface, int op, struct in_addr sip, - const unsigned char *taddr, struct in_addr tip) + const unsigned char *taddr, struct in_addr tip) { - struct arphdr *arp; - size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip)); - caddr_t tha; - int retval; - - arp = xzalloc (arpsize); - arp->ar_hrd = htons (iface->family); - arp->ar_pro = htons (ETHERTYPE_IP); - arp->ar_hln = iface->hwlen; - arp->ar_pln = sizeof (sip); - arp->ar_op = htons (op); - memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln); - memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln); - if (taddr) { - /* NetBSD can return NULL from ar_tha, which is probably wrong - * but we still need to deal with it */ - if (! (tha = ar_tha (arp))) { - free (arp); - errno = EINVAL; - return (-1); - } - memcpy (tha, taddr, (size_t) arp->ar_hln); - } - memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln); - - retval = send_packet (iface, ETHERTYPE_ARP, - (unsigned char *) arp, arphdr_len (arp)); - free (arp); - return (retval); + struct arphdr *arp; + size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip)); + caddr_t tha; + int retval; + + arp = xzalloc (arpsize); + arp->ar_hrd = htons (iface->family); + arp->ar_pro = htons (ETHERTYPE_IP); + arp->ar_hln = iface->hwlen; + arp->ar_pln = sizeof (sip); + arp->ar_op = htons (op); + memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln); + memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln); + if (taddr) + { + /* NetBSD can return NULL from ar_tha, which is probably wrong + * but we still need to deal with it */ + if (! (tha = ar_tha (arp))) + { + free (arp); + errno = EINVAL; + return (-1); + } + memcpy (tha, taddr, (size_t) arp->ar_hln); + } + memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln); + + retval = send_packet (iface, ETHERTYPE_ARP, + (unsigned char *) arp, arphdr_len (arp)); + free (arp); + return (retval); } int arp_claim (interface_t *iface, struct in_addr address) { - struct arphdr *reply = NULL; - long timeout = 0; - unsigned char *buffer; - int retval = -1; - int nprobes = 0; - int nclaims = 0; - struct in_addr null_address; - struct pollfd fds[] = { - { -1, POLLIN, 0 }, - { -1, POLLIN, 0 } - }; - - if (! iface) - return (-1); - - if (! iface->arpable) { - logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); - return (0); - } - - if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && - ! IN_LINKLOCAL (ntohl (address.s_addr))) - logger (LOG_INFO, - "checking %s is available on attached networks", - inet_ntoa (address)); - - if (! open_socket (iface, ETHERTYPE_ARP)) - return (-1); - - fds[0].fd = signal_fd (); - fds[1].fd = iface->fd; - - memset (&null_address, 0, sizeof (null_address)); - - buffer = xmalloc (iface->buffer_length); - reply = xmalloc (iface->buffer_length); - - for (;;) { - size_t bufpos = 0; - size_t buflen = iface->buffer_length; - int bytes; - int s = 0; - struct timeval stopat; - struct timeval now; - - /* Only poll if we have a timeout */ - if (timeout > 0) { - s = poll (fds, 2, timeout); - if (s == -1) { - if (errno == EINTR) { - if (signal_exists (NULL) == -1) { - errno = 0; - continue; - } else - break; - } - - logger (LOG_ERR, "poll: `%s'", - strerror (errno)); - break; - } - } - - /* Timed out */ - if (s == 0) { - if (nprobes < NPROBES) { - nprobes ++; - timeout = PROBE_INTERVAL; - logger (LOG_DEBUG, "sending ARP probe #%d", - nprobes); - if (send_arp (iface, ARPOP_REQUEST, - null_address, NULL, - address) == -1) - break; - - /* IEEE1394 cannot set ARP target address - * according to RFC2734 */ - if (nprobes >= NPROBES && - iface->family == ARPHRD_IEEE1394) - nclaims = NCLAIMS; - } else if (nclaims < NCLAIMS) { - nclaims ++; - timeout = CLAIM_INTERVAL; - logger (LOG_DEBUG, "sending ARP claim #%d", - nclaims); - if (send_arp (iface, ARPOP_REQUEST, - address, iface->hwaddr, - address) == -1) - break; - } else { - /* No replies, so done */ - retval = 0; - break; - } - - /* Setup our stop time */ - if (get_time (&stopat) != 0) - break; - stopat.tv_usec += timeout; - - continue; - } - - /* We maybe ARP flooded, so check our time */ - if (get_time (&now) != 0) - break; - if (timercmp (&now, &stopat, >)) { - timeout = 0; - continue; - } - - if (! fds[1].revents & POLLIN) - continue; - - memset (buffer, 0, buflen); - do { - union { - unsigned char *c; - struct in_addr *a; - } rp; - union { - unsigned char *c; - struct ether_addr *a; - } rh; - - memset (reply, 0, iface->buffer_length); - if ((bytes = get_packet (iface, (unsigned char *) reply, - buffer, - &buflen, &bufpos)) == -1) - break; - - /* Only these types are recognised */ - if (reply->ar_op != htons (ARPOP_REPLY)) - continue; - - /* Protocol must be IP. */ - if (reply->ar_pro != htons (ETHERTYPE_IP)) - continue; - if (reply->ar_pln != sizeof (address)) - continue; - if ((unsigned) bytes < sizeof (reply) + - 2 * (4 + reply->ar_hln)) - continue; - - rp.c = (unsigned char *) ar_spa (reply); - rh.c = (unsigned char *) ar_sha (reply); - - /* Ensure the ARP reply is for the our address */ - if (rp.a->s_addr != address.s_addr) - continue; - - /* Some systems send a reply back from our hwaddress, - * which is wierd */ - if (reply->ar_hln == iface->hwlen && - memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) - continue; - - logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", - inet_ntoa (*rp.a), - hwaddr_ntoa (rh.c, (size_t) reply->ar_hln)); - retval = -1; - goto eexit; - } while (bufpos != 0); - } + struct arphdr *reply = NULL; + long timeout = 0; + unsigned char *buffer; + int retval = -1; + int nprobes = 0; + int nclaims = 0; + struct in_addr null_address; + struct pollfd fds[] = + { + { -1, POLLIN, 0 }, + { -1, POLLIN, 0 } + }; + + if (! iface) + return (-1); + + if (! iface->arpable) + { + logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); + return (0); + } + + if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && + ! IN_LINKLOCAL (ntohl (address.s_addr))) + logger (LOG_INFO, + "checking %s is available on attached networks", + inet_ntoa (address)); + + if (! open_socket (iface, ETHERTYPE_ARP)) + return (-1); + + fds[0].fd = signal_fd (); + fds[1].fd = iface->fd; + + memset (&null_address, 0, sizeof (null_address)); + + buffer = xmalloc (iface->buffer_length); + reply = xmalloc (iface->buffer_length); + + for (;;) + { + size_t bufpos = 0; + size_t buflen = iface->buffer_length; + int bytes; + int s = 0; + struct timeval stopat; + struct timeval now; + + /* Only poll if we have a timeout */ + if (timeout > 0) + { + s = poll (fds, 2, timeout); + if (s == -1) + { + if (errno == EINTR) + { + if (signal_exists (NULL) == -1) + { + errno = 0; + continue; + } + else + break; + } + + logger (LOG_ERR, "poll: `%s'", + strerror (errno)); + break; + } + } + + /* Timed out */ + if (s == 0) + { + if (nprobes < NPROBES) + { + nprobes ++; + timeout = PROBE_INTERVAL; + logger (LOG_DEBUG, "sending ARP probe #%d", + nprobes); + if (send_arp (iface, ARPOP_REQUEST, + null_address, NULL, + address) == -1) + break; + + /* IEEE1394 cannot set ARP target address + * according to RFC2734 */ + if (nprobes >= NPROBES && + iface->family == ARPHRD_IEEE1394) + nclaims = NCLAIMS; + } + else if (nclaims < NCLAIMS) + { + nclaims ++; + timeout = CLAIM_INTERVAL; + logger (LOG_DEBUG, "sending ARP claim #%d", + nclaims); + if (send_arp (iface, ARPOP_REQUEST, + address, iface->hwaddr, + address) == -1) + break; + } + else + { + /* No replies, so done */ + retval = 0; + break; + } + + /* Setup our stop time */ + if (get_time (&stopat) != 0) + break; + stopat.tv_usec += timeout; + + continue; + } + + /* We maybe ARP flooded, so check our time */ + if (get_time (&now) != 0) + break; + if (timercmp (&now, &stopat, > )) + { + timeout = 0; + continue; + } + + if (! fds[1].revents & POLLIN) + continue; + + memset (buffer, 0, buflen); + do + { + union + { + unsigned char *c; + struct in_addr *a; + } rp; + union + { + unsigned char *c; + struct ether_addr *a; + } rh; + + memset (reply, 0, iface->buffer_length); + if ((bytes = get_packet (iface, (unsigned char *) reply, + buffer, + &buflen, &bufpos)) == -1) + break; + + /* Only these types are recognised */ + if (reply->ar_op != htons (ARPOP_REPLY)) + continue; + + /* Protocol must be IP. */ + if (reply->ar_pro != htons (ETHERTYPE_IP)) + continue; + if (reply->ar_pln != sizeof (address)) + continue; + if ((unsigned) bytes < sizeof (reply) + + 2 * (4 + reply->ar_hln)) + continue; + + rp.c = (unsigned char *) ar_spa (reply); + rh.c = (unsigned char *) ar_sha (reply); + + /* Ensure the ARP reply is for the our address */ + if (rp.a->s_addr != address.s_addr) + continue; + + /* Some systems send a reply back from our hwaddress, + * which is wierd */ + if (reply->ar_hln == iface->hwlen && + memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) + continue; + + logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", + inet_ntoa (*rp.a), + hwaddr_ntoa (rh.c, (size_t) reply->ar_hln)); + retval = -1; + goto eexit; + } + while (bufpos != 0); + } eexit: - close (iface->fd); - iface->fd = -1; - free (buffer); - free (reply); - return (retval); + close (iface->fd); + iface->fd = -1; + free (buffer); + free (reply); + return (retval); } #endif diff --git a/src/customdhcpcd/arp.h b/src/customdhcpcd/arp.h index 3b7e8ef..bb99e48 100644 --- a/src/customdhcpcd/arp.h +++ b/src/customdhcpcd/arp.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved diff --git a/src/customdhcpcd/client.c b/src/customdhcpcd/client.c index b007fd6..cb22d24 100644 --- a/src/customdhcpcd/client.c +++ b/src/customdhcpcd/client.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -72,7 +72,7 @@ #ifdef THERE_IS_NO_FORK # ifndef ENABLE_INFO - # error "Non MMU requires ENABLE_INFO to work" +# error "Non MMU requires ENABLE_INFO to work" # endif #endif @@ -97,7 +97,7 @@ #define STATE_RENEW_REQUESTED 6 #define STATE_RELEASED 7 -/* We should define a maximum for the NAK exponential backoff */ +/* We should define a maximum for the NAK exponential backoff */ #define NAKOFF_MAX 60 #define SOCKET_CLOSED 0 @@ -105,1045 +105,1140 @@ /* Indexes for pollfds */ #define POLLFD_SIGNAL 0 -#define POLLFD_IFACE 1 - -typedef struct _state { - int *pidfd; - bool forked; - int state; - uint32_t xid; - dhcp_t *dhcp; - int socket; - interface_t *interface; - time_t start; - time_t last_sent; - time_t last_type; - long timeout; - time_t nakoff; - bool daemonised; - bool persistent; - unsigned char *buffer; - size_t buffer_len; - size_t buffer_pos; +#define POLLFD_IFACE 1 + +typedef struct _state +{ + int *pidfd; + bool forked; + int state; + uint32_t xid; + dhcp_t *dhcp; + int socket; + interface_t *interface; + time_t start; + time_t last_sent; + time_t last_type; + long timeout; + time_t nakoff; + bool daemonised; + bool persistent; + unsigned char *buffer; + size_t buffer_len; + size_t buffer_pos; } state_t; static pid_t daemonise (int *pidfd) { - pid_t pid; - sigset_t full; - sigset_t old; + pid_t pid; + sigset_t full; + sigset_t old; #ifdef THERE_IS_NO_FORK - char **argv; - int i; + char **argv; + int i; #endif - sigfillset (&full); - sigprocmask (SIG_SETMASK, &full, &old); + sigfillset (&full); + sigprocmask (SIG_SETMASK, &full, &old); #ifndef THERE_IS_NO_FORK - logger (LOG_DEBUG, "forking to background"); - switch (pid = fork()) { - case -1: - logger (LOG_ERR, "fork: %s", strerror (errno)); - exit (EXIT_FAILURE); - /* NOT REACHED */ - case 0: - setsid (); - close_fds (); - break; - default: - /* Reset our signals as we're the parent about to exit. */ - signal_reset (); - break; - } + logger (LOG_DEBUG, "forking to background"); + switch (pid = fork()) + { + case -1: + logger (LOG_ERR, "fork: %s", strerror (errno)); + exit (EXIT_FAILURE); + /* NOT REACHED */ + case 0: + setsid (); + close_fds (); + break; + default: + /* Reset our signals as we're the parent about to exit. */ + signal_reset (); + break; + } #else - logger (LOG_INFO, "forking to background"); - - /* We need to add --daemonise to our options */ - argv = xmalloc (sizeof (char *) * (dhcpcd_argc + 4)); - argv[0] = dhcpcd; - for (i = 1; i < dhcpcd_argc; i++) - argv[i] = dhcpcd_argv[i]; - argv[i] = (char *) "--daemonised"; - if (dhcpcd_skiproutes) { - argv[++i] = (char *) "--skiproutes"; - argv[++i] = dhcpcd_skiproutes; - } - argv[i + 1] = NULL; - - switch (pid = vfork ()) { - case -1: - logger (LOG_ERR, "vfork: %s", strerror (errno)); - _exit (EXIT_FAILURE); - case 0: - signal_reset (); - sigprocmask (SIG_SETMASK, &old, NULL); - execvp (dhcpcd, argv); - logger (LOG_ERR, "execl `%s': %s", dhcpcd, - strerror (errno)); - _exit (EXIT_FAILURE); - } - - free (argv); + logger (LOG_INFO, "forking to background"); + + /* We need to add --daemonise to our options */ + argv = xmalloc (sizeof (char *) * (dhcpcd_argc + 4)); + argv[0] = dhcpcd; + for (i = 1; i < dhcpcd_argc; i++) + argv[i] = dhcpcd_argv[i]; + argv[i] = (char *) "--daemonised"; + if (dhcpcd_skiproutes) + { + argv[++i] = (char *) "--skiproutes"; + argv[++i] = dhcpcd_skiproutes; + } + argv[i + 1] = NULL; + + switch (pid = vfork ()) + { + case -1: + logger (LOG_ERR, "vfork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + case 0: + signal_reset (); + sigprocmask (SIG_SETMASK, &old, NULL); + execvp (dhcpcd, argv); + logger (LOG_ERR, "execl `%s': %s", dhcpcd, + strerror (errno)); + _exit (EXIT_FAILURE); + } + + free (argv); #endif - /* Done with the fd now */ - if (pid != 0) { - writepid (*pidfd, pid); - close (*pidfd); - *pidfd = -1; + /* Done with the fd now */ + if (pid != 0) + { + writepid (*pidfd, pid); + close (*pidfd); + *pidfd = -1; - } + } - sigprocmask (SIG_SETMASK, &old, NULL); - return (pid); + sigprocmask (SIG_SETMASK, &old, NULL); + return (pid); } #ifdef ENABLE_INFO static bool get_old_lease (state_t *state, const options_t *options) { - interface_t *iface = state->interface; - dhcp_t *dhcp = state->dhcp; - struct timeval tv; - unsigned int offset = 0; + interface_t *iface = state->interface; + dhcp_t *dhcp = state->dhcp; + struct timeval tv; + unsigned int offset = 0; - if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - logger (LOG_INFO, "trying to use old lease in `%s'", - iface->infofile); - if (! read_info (iface, dhcp)) - return (false); + if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + logger (LOG_INFO, "trying to use old lease in `%s'", + iface->infofile); + if (! read_info (iface, dhcp)) + return (false); - /* Vitaly important we remove the server information here */ - memset (&dhcp->serveraddress, 0, sizeof (dhcp->serveraddress)); - memset (dhcp->servername, 0, sizeof (dhcp->servername)); + /* Vitaly important we remove the server information here */ + memset (&dhcp->serveraddress, 0, sizeof (dhcp->serveraddress)); + memset (dhcp->servername, 0, sizeof (dhcp->servername)); #ifdef ENABLE_ARP - /* Check that no-one is using the address */ - if ((options->dolastlease || - (IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && - (! options->doipv4ll || - arp_claim (iface, dhcp->address))))) - { - memset (&dhcp->address, 0, sizeof (dhcp->address)); - memset (&dhcp->netmask, 0, sizeof (dhcp->netmask)); - memset (&dhcp->broadcast, 0, sizeof (dhcp->broadcast)); - return (false); - } - - /* Ok, lets use this */ - if (IN_LINKLOCAL (dhcp->address.s_addr)) - return (true); + /* Check that no-one is using the address */ + if ((options->dolastlease || + (IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && + (! options->doipv4ll || + arp_claim (iface, dhcp->address))))) + { + memset (&dhcp->address, 0, sizeof (dhcp->address)); + memset (&dhcp->netmask, 0, sizeof (dhcp->netmask)); + memset (&dhcp->broadcast, 0, sizeof (dhcp->broadcast)); + return (false); + } + + /* Ok, lets use this */ + if (IN_LINKLOCAL (dhcp->address.s_addr)) + return (true); #endif - /* Ensure that we can still use the lease */ - if (gettimeofday (&tv, NULL) == -1) { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return (false); - } - - offset = tv.tv_sec - dhcp->leasedfrom; - if (dhcp->leasedfrom && - tv.tv_sec - dhcp->leasedfrom > dhcp->leasetime) - { - logger (LOG_ERR, "lease expired %u seconds ago", - offset + dhcp->leasetime); - return (false); - } - - if (dhcp->leasedfrom == 0) - offset = 0; - state->timeout = dhcp->renewaltime - offset; - iface->start_uptime = uptime (); - return (true); + /* Ensure that we can still use the lease */ + if (gettimeofday (&tv, NULL) == -1) + { + logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); + return (false); + } + + offset = tv.tv_sec - dhcp->leasedfrom; + if (dhcp->leasedfrom && + tv.tv_sec - dhcp->leasedfrom > dhcp->leasetime) + { + logger (LOG_ERR, "lease expired %u seconds ago", + offset + dhcp->leasetime); + return (false); + } + + if (dhcp->leasedfrom == 0) + offset = 0; + state->timeout = dhcp->renewaltime - offset; + iface->start_uptime = uptime (); + return (true); } #endif #ifdef THERE_IS_NO_FORK static void remove_skiproutes (dhcp_t *dhcp, interface_t *iface) { - int i = -1; - route_t *route; - route_t *newroute; - - free_route (iface->previous_routes); - iface->previous_routes = NULL; - - NSTAILQ_FOREACH (route, dhcp->routes, entries) { - i++; - - /* Check that we did add this route or not */ - if (dhcpcd_skiproutes) { - char *sk = xstrdup (dhcpcd_skiproutes); - char *skp = sk; - char *token; - bool found = false; - - while ((token = strsep (&skp, ","))) { - if (isdigit (*token) && atoi (token) == i) { - found = true; - break; - } - } - free (sk); - if (found) - continue; - } - - if (! iface->previous_routes) { - iface->previous_routes = xmalloc (sizeof (*iface->previous_routes)); - STAILQ_INIT (iface->previous_routes); - } - - newroute = xmalloc (sizeof (*newroute)); - memcpy (newroute, route, sizeof (*newroute)); - STAILQ_INSERT_TAIL (iface->previous_routes, newroute, entries); - } - - /* We no longer need this argument */ - free (dhcpcd_skiproutes); - dhcpcd_skiproutes = NULL; + int i = -1; + route_t *route; + route_t *newroute; + + free_route (iface->previous_routes); + iface->previous_routes = NULL; + + NSTAILQ_FOREACH (route, dhcp->routes, entries) + { + i++; + + /* Check that we did add this route or not */ + if (dhcpcd_skiproutes) + { + char *sk = xstrdup (dhcpcd_skiproutes); + char *skp = sk; + char *token; + bool found = false; + + while ((token = strsep (&skp, ","))) + { + if (isdigit (*token) && atoi (token) == i) + { + found = true; + break; + } + } + free (sk); + if (found) + continue; + } + + if (! iface->previous_routes) + { + iface->previous_routes = xmalloc (sizeof (*iface->previous_routes)); + STAILQ_INIT (iface->previous_routes); + } + + newroute = xmalloc (sizeof (*newroute)); + memcpy (newroute, route, sizeof (*newroute)); + STAILQ_INSERT_TAIL (iface->previous_routes, newroute, entries); + } + + /* We no longer need this argument */ + free (dhcpcd_skiproutes); + dhcpcd_skiproutes = NULL; } #endif static bool client_setup (state_t *state, const options_t *options) { - dhcp_t *dhcp = state->dhcp; - interface_t *iface = state->interface; - - state->state = STATE_INIT; - state->last_type = DHCP_DISCOVER; - state->nakoff = 1; - state->daemonised = options->daemonised; - state->persistent = options->persistent; - - if (options->request_address.s_addr == 0 && - (options->doinform || options->dorequest || options->daemonised)) - { + dhcp_t *dhcp = state->dhcp; + interface_t *iface = state->interface; + + state->state = STATE_INIT; + state->last_type = DHCP_DISCOVER; + state->nakoff = 1; + state->daemonised = options->daemonised; + state->persistent = options->persistent; + + if (options->request_address.s_addr == 0 && + (options->doinform || options->dorequest || options->daemonised)) + { #ifdef ENABLE_INFO - if (! get_old_lease (state, options)) + if (! get_old_lease (state, options)) #endif - { - free (dhcp); - return (false); - } - state->timeout = 0; - - if (! options->daemonised && - IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) - { - logger (LOG_ERR, "cannot request a link local address"); - return (false); - } + { + free (dhcp); + return (false); + } + state->timeout = 0; + + if (! options->daemonised && + IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) + { + logger (LOG_ERR, "cannot request a link local address"); + return (false); + } #ifdef THERE_IS_NO_FORK - if (options->daemonised) { - state->state = STATE_BOUND; - state->timeout = dhcp->renewaltime; - iface->previous_address = dhcp->address; - iface->previous_netmask = dhcp->netmask; - remove_skiproutes (dhcp, iface); - } + if (options->daemonised) + { + state->state = STATE_BOUND; + state->timeout = dhcp->renewaltime; + iface->previous_address = dhcp->address; + iface->previous_netmask = dhcp->netmask; + remove_skiproutes (dhcp, iface); + } #endif - } else { - dhcp->address = options->request_address; - dhcp->netmask = options->request_netmask; - if (dhcp->netmask.s_addr == 0) - dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); - dhcp->broadcast.s_addr = dhcp->address.s_addr | - ~dhcp->netmask.s_addr; - } - - /* Remove all existing addresses. - * After all, we ARE a DHCP client whose job it is to configure the - * interface. We only do this on start, so persistent addresses - * can be added afterwards by the user if needed. */ - if (! options->test && ! options->daemonised) { - if (! options->doinform) { - flush_addresses (iface->name); - } else { - /* The inform address HAS to be configured for it to - * work with most DHCP servers */ - if (options->doinform && - has_address (iface->name, dhcp->address) < 1) - { - add_address (iface->name, dhcp->address, - dhcp->netmask, dhcp->broadcast); - iface->previous_address = dhcp->address; - iface->previous_netmask = dhcp->netmask; - } - } - } - - if (*options->clientid) { - /* Attempt to see if the ClientID is a hardware address */ - iface->clientid_len = hwaddr_aton (NULL, options->clientid); - if (iface->clientid_len) { - iface->clientid = xmalloc (iface->clientid_len); - hwaddr_aton (iface->clientid, options->clientid); - } else { - /* Nope, so mark it as-is */ - iface->clientid_len = strlen (options->clientid) + 1; - iface->clientid = xmalloc (iface->clientid_len); - *iface->clientid = '\0'; - memcpy (iface->clientid + 1, - options->clientid, iface->clientid_len - 1); - } - } else { + } + else + { + dhcp->address = options->request_address; + dhcp->netmask = options->request_netmask; + if (dhcp->netmask.s_addr == 0) + dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); + dhcp->broadcast.s_addr = dhcp->address.s_addr | + ~dhcp->netmask.s_addr; + } + + /* Remove all existing addresses. + * After all, we ARE a DHCP client whose job it is to configure the + * interface. We only do this on start, so persistent addresses + * can be added afterwards by the user if needed. */ + if (! options->test && ! options->daemonised) + { + if (! options->doinform) + { + flush_addresses (iface->name); + } + else + { + /* The inform address HAS to be configured for it to + * work with most DHCP servers */ + if (options->doinform && + has_address (iface->name, dhcp->address) < 1) + { + add_address (iface->name, dhcp->address, + dhcp->netmask, dhcp->broadcast); + iface->previous_address = dhcp->address; + iface->previous_netmask = dhcp->netmask; + } + } + } + + if (*options->clientid) + { + /* Attempt to see if the ClientID is a hardware address */ + iface->clientid_len = hwaddr_aton (NULL, options->clientid); + if (iface->clientid_len) + { + iface->clientid = xmalloc (iface->clientid_len); + hwaddr_aton (iface->clientid, options->clientid); + } + else + { + /* Nope, so mark it as-is */ + iface->clientid_len = strlen (options->clientid) + 1; + iface->clientid = xmalloc (iface->clientid_len); + *iface->clientid = '\0'; + memcpy (iface->clientid + 1, + options->clientid, iface->clientid_len - 1); + } + } + else + { #ifdef ENABLE_DUID - unsigned char *duid = NULL; - size_t duid_len = 0; - - if (options->doduid) { - duid = xmalloc (DUID_LEN); - duid_len = get_duid (duid, iface); - } - - if (duid_len > 0) { - logger (LOG_INFO, "DUID = %s", hwaddr_ntoa (duid, duid_len)); - - iface->clientid_len = duid_len + 5; - iface->clientid = xmalloc (iface->clientid_len); - *iface->clientid = 255; /* RFC 4361 */ - - /* IAID is 4 bytes, so if the iface name is 4 bytes use it */ - if (strlen (iface->name) == 4) { - memcpy (iface->clientid + 1, iface->name, 4); - } else { - /* Name isn't 4 bytes, so use the index */ - uint32_t ul = htonl (if_nametoindex (iface->name)); - memcpy (iface->clientid + 1, &ul, 4); - } - - memcpy (iface->clientid + 5, duid, duid_len); - free (duid); - } else { + unsigned char *duid = NULL; + size_t duid_len = 0; + + if (options->doduid) + { + duid = xmalloc (DUID_LEN); + duid_len = get_duid (duid, iface); + } + + if (duid_len > 0) + { + logger (LOG_INFO, "DUID = %s", hwaddr_ntoa (duid, duid_len)); + + iface->clientid_len = duid_len + 5; + iface->clientid = xmalloc (iface->clientid_len); + *iface->clientid = 255; /* RFC 4361 */ + + /* IAID is 4 bytes, so if the iface name is 4 bytes use it */ + if (strlen (iface->name) == 4) + { + memcpy (iface->clientid + 1, iface->name, 4); + } + else + { + /* Name isn't 4 bytes, so use the index */ + uint32_t ul = htonl (if_nametoindex (iface->name)); + memcpy (iface->clientid + 1, &ul, 4); + } + + memcpy (iface->clientid + 5, duid, duid_len); + free (duid); + } + else + { #else - { + { #endif - iface->clientid_len = iface->hwlen + 1; - iface->clientid = xmalloc (iface->clientid_len); - *iface->clientid = iface->family; - memcpy (iface->clientid + 1, iface->hwaddr, iface->hwlen); - } - } - - return (true); + iface->clientid_len = iface->hwlen + 1; + iface->clientid = xmalloc (iface->clientid_len); + *iface->clientid = iface->family; + memcpy (iface->clientid + 1, iface->hwaddr, iface->hwlen); + } + } + + return (true); } static bool do_socket (state_t *state, int mode) { - if (state->interface->fd >= 0) - close (state->interface->fd); + if (state->interface->fd >= 0) + close (state->interface->fd); #ifdef __linux - if (mode == SOCKET_CLOSED && state->interface->listen_fd >= 0) { - close (state->interface->listen_fd); - state->interface->listen_fd = -1; - } + if (mode == SOCKET_CLOSED && state->interface->listen_fd >= 0) + { + close (state->interface->listen_fd); + state->interface->listen_fd = -1; + } #endif - state->interface->fd = -1; - if (mode == SOCKET_OPEN) - if (open_socket (state->interface, ETHERTYPE_IP) == -1) - return (false); - state->socket = mode; - return (true); + state->interface->fd = -1; + if (mode == SOCKET_OPEN) + if (open_socket (state->interface, ETHERTYPE_IP) == -1) + return (false); + state->socket = mode; + return (true); } static bool _send_message (state_t *state, int type, const options_t *options) { - ssize_t retval; - - state->last_type = type; - state->last_sent = uptime (); - logSendToQt(type); - retval = send_message (state->interface, state->dhcp, state->xid, - type, options); - return (retval == -1 ? false : true); + ssize_t retval; + + state->last_type = type; + state->last_sent = uptime (); + logSendToQt(type); + retval = send_message (state->interface, state->dhcp, state->xid, + type, options); + return (retval == -1 ? false : true); } static void drop_config (state_t *state, const options_t *options) { - if (! state->persistent) - configure (options, state->interface, state->dhcp, false); + if (! state->persistent) + configure (options, state->interface, state->dhcp, false); - free_dhcp (state->dhcp); - memset (state->dhcp, 0, sizeof (*state->dhcp)); + free_dhcp (state->dhcp); + memset (state->dhcp, 0, sizeof (*state->dhcp)); } static int wait_for_packet (struct pollfd *fds, state_t *state, - const options_t *options) + const options_t *options) { - dhcp_t *dhcp = state->dhcp; - interface_t *iface = state->interface; - int timeout = 0; - int retval = 0; - - if (! (state->timeout > 0 || - (options->timeout == 0 && - (state->state != STATE_INIT || state->xid)))) { - /* We need to zero our signal fd, otherwise we will block - * trying to read a signal. */ - fds[POLLFD_SIGNAL].revents = 0; - return (0); - } - - fds[POLLFD_IFACE].fd = iface->fd; - - if ((options->timeout == 0 && state->xid) || - (dhcp->leasetime == (unsigned) -1 && - state->state == STATE_BOUND)) - { - logger (LOG_DEBUG, "waiting for infinity"); - while (retval == 0) { - if (iface->fd == -1) - retval = poll (fds, 1, INFTIM); - else { - /* Slow down our requests */ - if (timeout < TIMEOUT_MINI_INF) - timeout += TIMEOUT_MINI; - else if (timeout > TIMEOUT_MINI_INF) - timeout = TIMEOUT_MINI_INF; - - retval = poll (fds, 2, timeout * 1000); - if (retval == -1 && errno == EINTR) { - /* If interupted, continue as normal as - * the signal will be delivered down - * the pipe */ - retval = 0; - continue; - } - if (retval == 0) - _send_message (state, state->last_type, - options); - } - } - - return (retval); - } - - /* Resend our message if we're getting loads of packets. - * As we use BPF or LPF, we shouldn't hit this as much, but it's - * still nice to have. */ - if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI) - _send_message (state, state->last_type, options); - - logger (LOG_DEBUG, "waiting for %ld seconds", - (unsigned long) state->timeout); - /* If we're waiting for a reply, then we re-send the last - * DHCP request periodically in-case of a bad line */ - retval = 0; - while (state->timeout > 0 && retval == 0) { - if (iface->fd == -1) - timeout = (int) state->timeout; - else { - timeout = TIMEOUT_MINI; - if (state->timeout < timeout) - timeout = (int) state->timeout; - } - timeout *= 1000; - state->start = uptime (); - retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout); - state->timeout -= uptime () - state->start; - if (retval == -1 && errno == EINTR) { - /* If interupted, continue as normal as the signal - * will be delivered down the pipe */ - retval = 0; - continue; - } - if (retval == 0 && iface->fd != -1 && state->timeout > 0) - _send_message (state, state->last_type, options); - } - - return (retval); + dhcp_t *dhcp = state->dhcp; + interface_t *iface = state->interface; + int timeout = 0; + int retval = 0; + + if (! (state->timeout > 0 || + (options->timeout == 0 && + (state->state != STATE_INIT || state->xid)))) + { + /* We need to zero our signal fd, otherwise we will block + * trying to read a signal. */ + fds[POLLFD_SIGNAL].revents = 0; + return (0); + } + + fds[POLLFD_IFACE].fd = iface->fd; + + if ((options->timeout == 0 && state->xid) || + (dhcp->leasetime == (unsigned) - 1 && + state->state == STATE_BOUND)) + { + logger (LOG_DEBUG, "waiting for infinity"); + while (retval == 0) + { + if (iface->fd == -1) + retval = poll (fds, 1, INFTIM); + else + { + /* Slow down our requests */ + if (timeout < TIMEOUT_MINI_INF) + timeout += TIMEOUT_MINI; + else if (timeout > TIMEOUT_MINI_INF) + timeout = TIMEOUT_MINI_INF; + + retval = poll (fds, 2, timeout * 1000); + if (retval == -1 && errno == EINTR) + { + /* If interupted, continue as normal as + * the signal will be delivered down + * the pipe */ + retval = 0; + continue; + } + if (retval == 0) + _send_message (state, state->last_type, + options); + } + } + + return (retval); + } + + /* Resend our message if we're getting loads of packets. + * As we use BPF or LPF, we shouldn't hit this as much, but it's + * still nice to have. */ + if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI) + _send_message (state, state->last_type, options); + + logger (LOG_DEBUG, "waiting for %ld seconds", + (unsigned long) state->timeout); + /* If we're waiting for a reply, then we re-send the last + * DHCP request periodically in-case of a bad line */ + retval = 0; + while (state->timeout > 0 && retval == 0) + { + if (iface->fd == -1) + timeout = (int) state->timeout; + else + { + timeout = TIMEOUT_MINI; + if (state->timeout < timeout) + timeout = (int) state->timeout; + } + timeout *= 1000; + state->start = uptime (); + retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout); + state->timeout -= uptime () - state->start; + if (retval == -1 && errno == EINTR) + { + /* If interupted, continue as normal as the signal + * will be delivered down the pipe */ + retval = 0; + continue; + } + if (retval == 0 && iface->fd != -1 && state->timeout > 0) + _send_message (state, state->last_type, options); + } + + return (retval); } static bool handle_signal (int sig, state_t *state, const options_t *options) { - switch (sig) { - case SIGINT: - logger (LOG_INFO, "received SIGINT, stopping"); - return (false); - case SIGTERM: - logger (LOG_INFO, "received SIGTERM, stopping"); - return (false); - - case SIGALRM: - logger (LOG_INFO, "received SIGALRM, renewing lease"); - switch (state->state) { - case STATE_BOUND: - case STATE_RENEWING: - case STATE_REBINDING: - state->state = STATE_RENEW_REQUESTED; - break; - case STATE_RENEW_REQUESTED: - case STATE_REQUESTING: - case STATE_RELEASED: - state->state = STATE_INIT; - break; - } - state->timeout = 0; - state->xid = 0; - return (true); - - case SIGHUP: - if (state->state != STATE_BOUND && - state->state != STATE_RENEWING && - state->state != STATE_REBINDING) - { - logger (LOG_ERR, - "received SIGHUP, but we no have lease to release"); - return (false); - } - - logger (LOG_INFO, "received SIGHUP, releasing lease"); - if (! IN_LINKLOCAL (ntohl (state->dhcp->address.s_addr))) { - do_socket (state, SOCKET_OPEN); - state->xid = (uint32_t) random (); - if ((open_socket (state->interface, false)) >= 0) { - _send_message (state, DHCP_RELEASE, options); - } - do_socket (state, SOCKET_CLOSED); - } - unlink (state->interface->infofile); - return (false); - - default: - logger (LOG_ERR, - "received signal %d, but don't know what to do with it", - sig); - } - - return (false); + switch (sig) + { + case SIGINT: + logger (LOG_INFO, "received SIGINT, stopping"); + return (false); + case SIGTERM: + logger (LOG_INFO, "received SIGTERM, stopping"); + return (false); + + case SIGALRM: + logger (LOG_INFO, "received SIGALRM, renewing lease"); + switch (state->state) + { + case STATE_BOUND: + case STATE_RENEWING: + case STATE_REBINDING: + state->state = STATE_RENEW_REQUESTED; + break; + case STATE_RENEW_REQUESTED: + case STATE_REQUESTING: + case STATE_RELEASED: + state->state = STATE_INIT; + break; + } + state->timeout = 0; + state->xid = 0; + return (true); + + case SIGHUP: + if (state->state != STATE_BOUND && + state->state != STATE_RENEWING && + state->state != STATE_REBINDING) + { + logger (LOG_ERR, + "received SIGHUP, but we no have lease to release"); + return (false); + } + + logger (LOG_INFO, "received SIGHUP, releasing lease"); + if (! IN_LINKLOCAL (ntohl (state->dhcp->address.s_addr))) + { + do_socket (state, SOCKET_OPEN); + state->xid = (uint32_t) random (); + if ((open_socket (state->interface, false)) >= 0) + { + _send_message (state, DHCP_RELEASE, options); + } + do_socket (state, SOCKET_CLOSED); + } + unlink (state->interface->infofile); + return (false); + + default: + logger (LOG_ERR, + "received signal %d, but don't know what to do with it", + sig); + } + + return (false); } static int handle_timeout (state_t *state, const options_t *options) { - dhcp_t *dhcp = state->dhcp; - interface_t *iface = state->interface; - - /* No NAK, so reset the backoff */ - state->nakoff = 1; - - if (state->state == STATE_INIT && state->xid != 0) { - if (iface->previous_address.s_addr != 0 && - ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && - ! options->doinform) - { - logger (LOG_ERR, "lost lease"); - if (! options->persistent) - drop_config (state, options); - } else if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - logger (LOG_ERR, "timed out"); - - do_socket (state, SOCKET_CLOSED); - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); + dhcp_t *dhcp = state->dhcp; + interface_t *iface = state->interface; + + /* No NAK, so reset the backoff */ + state->nakoff = 1; + + if (state->state == STATE_INIT && state->xid != 0) + { + if (iface->previous_address.s_addr != 0 && + ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && + ! options->doinform) + { + logger (LOG_ERR, "lost lease"); + if (! options->persistent) + drop_config (state, options); + } + else if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + logger (LOG_ERR, "timed out"); + + do_socket (state, SOCKET_CLOSED); + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); #ifdef ENABLE_INFO - if (! options->test && - (options->doipv4ll || options->dolastlease)) - { - errno = 0; - if (! get_old_lease (state, options)) - { - if (errno == EINTR) - return (0); - if (options->dolastlease) - return (-1); - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - } else if (errno == EINTR) - return (0); - } + if (! options->test && + (options->doipv4ll || options->dolastlease)) + { + errno = 0; + if (! get_old_lease (state, options)) + { + if (errno == EINTR) + return (0); + if (options->dolastlease) + return (-1); + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + } + else if (errno == EINTR) + return (0); + } #endif #ifdef ENABLE_IPV4LL - if (! options->test && options->doipv4ll && - (! dhcp->address.s_addr || - (! IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && - ! options->dolastlease))) - { - logger (LOG_INFO, "probing for an IPV4LL address"); - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - if (ipv4ll_get_address (iface, dhcp) == -1) { - if (! state->daemonised) - return (-1); - - /* start over */ - state->xid = 0; - return (0); - } - state->timeout = dhcp->renewaltime; - } + if (! options->test && options->doipv4ll && + (! dhcp->address.s_addr || + (! IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && + ! options->dolastlease))) + { + logger (LOG_INFO, "probing for an IPV4LL address"); + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + if (ipv4ll_get_address (iface, dhcp) == -1) + { + if (! state->daemonised) + return (-1); + + /* start over */ + state->xid = 0; + return (0); + } + state->timeout = dhcp->renewaltime; + } #endif #if defined (ENABLE_INFO) || defined (ENABLE_IPV4LL) - if (dhcp->address.s_addr) { - if (! state->daemonised && - IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) - logger (LOG_WARNING, "using IPV4LL address %s", - inet_ntoa (dhcp->address)); - if (configure (options, iface, dhcp, true) == -1 && - ! state->daemonised) - return (-1); - - state->state = STATE_BOUND; - if (! state->daemonised && options->daemonise) { - switch (daemonise (state->pidfd)) { - case -1: - return (-1); - case 0: - state->daemonised = true; - return (0); - default: - state->persistent = true; - state->forked = true; - return (-1); - } - } - - state->timeout = dhcp->renewaltime; - state->xid = 0; - return (0); - } + if (dhcp->address.s_addr) + { + if (! state->daemonised && + IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) + logger (LOG_WARNING, "using IPV4LL address %s", + inet_ntoa (dhcp->address)); + if (configure (options, iface, dhcp, true) == -1 && + ! state->daemonised) + return (-1); + + state->state = STATE_BOUND; + if (! state->daemonised && options->daemonise) + { + switch (daemonise (state->pidfd)) + { + case -1: + return (-1); + case 0: + state->daemonised = true; + return (0); + default: + state->persistent = true; + state->forked = true; + return (-1); + } + } + + state->timeout = dhcp->renewaltime; + state->xid = 0; + return (0); + } #endif - if (! state->daemonised) - return (-1); - } - - switch (state->state) { - case STATE_INIT: - state->xid = (uint32_t) random (); - do_socket (state, SOCKET_OPEN); - state->timeout = options->timeout; - iface->start_uptime = uptime (); - if (dhcp->address.s_addr == 0) { - if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - logger (LOG_INFO, "broadcasting for a lease"); - _send_message (state, DHCP_DISCOVER, options); - } else if (options->doinform) { - logger (LOG_INFO, "broadcasting inform for %s", - inet_ntoa (dhcp->address)); - _send_message (state, DHCP_INFORM, options); - state->state = STATE_REQUESTING; - } else { - logger (LOG_INFO, "broadcasting for a lease of %s", - inet_ntoa (dhcp->address)); - _send_message (state, DHCP_REQUEST, options); - state->state = STATE_REQUESTING; - } - - break; - case STATE_BOUND: - case STATE_RENEW_REQUESTED: - if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) { - memset (&dhcp->address, 0, sizeof (dhcp->address)); - state->state = STATE_INIT; - state->xid = 0; - break; - } - state->state = STATE_RENEWING; - state->xid = (uint32_t) random (); - /* FALLTHROUGH */ - case STATE_RENEWING: - iface->start_uptime = uptime (); - logger (LOG_INFO, "renewing lease of %s", inet_ntoa - (dhcp->address)); - do_socket (state, SOCKET_OPEN); - _send_message (state, DHCP_REQUEST, options); - state->timeout = dhcp->rebindtime - dhcp->renewaltime; - state->state = STATE_REBINDING; - break; - case STATE_REBINDING: - logger (LOG_ERR, "lost lease, attemping to rebind"); - memset (&dhcp->address, 0, sizeof (dhcp->address)); - do_socket (state, SOCKET_OPEN); - if (state->xid == 0) - state->xid = (uint32_t) random (); - dhcp->serveraddress.s_addr = 0; - _send_message (state, DHCP_REQUEST, options); - state->timeout = dhcp->leasetime - dhcp->rebindtime; - state->state = STATE_REQUESTING; - break; - case STATE_REQUESTING: - state->state = STATE_INIT; - do_socket (state, SOCKET_CLOSED); - state->timeout = 0; - break; - - case STATE_RELEASED: - dhcp->leasetime = 0; - break; - } - - return (0); + if (! state->daemonised) + return (-1); + } + + switch (state->state) + { + case STATE_INIT: + state->xid = (uint32_t) random (); + do_socket (state, SOCKET_OPEN); + state->timeout = options->timeout; + iface->start_uptime = uptime (); + if (dhcp->address.s_addr == 0) + { + if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + logger (LOG_INFO, "broadcasting for a lease"); + _send_message (state, DHCP_DISCOVER, options); + } + else if (options->doinform) + { + logger (LOG_INFO, "broadcasting inform for %s", + inet_ntoa (dhcp->address)); + _send_message (state, DHCP_INFORM, options); + state->state = STATE_REQUESTING; + } + else + { + logger (LOG_INFO, "broadcasting for a lease of %s", + inet_ntoa (dhcp->address)); + _send_message (state, DHCP_REQUEST, options); + state->state = STATE_REQUESTING; + } + + break; + case STATE_BOUND: + case STATE_RENEW_REQUESTED: + if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) + { + memset (&dhcp->address, 0, sizeof (dhcp->address)); + state->state = STATE_INIT; + state->xid = 0; + break; + } + state->state = STATE_RENEWING; + state->xid = (uint32_t) random (); + /* FALLTHROUGH */ + case STATE_RENEWING: + iface->start_uptime = uptime (); + logger (LOG_INFO, "renewing lease of %s", inet_ntoa + (dhcp->address)); + do_socket (state, SOCKET_OPEN); + _send_message (state, DHCP_REQUEST, options); + state->timeout = dhcp->rebindtime - dhcp->renewaltime; + state->state = STATE_REBINDING; + break; + case STATE_REBINDING: + logger (LOG_ERR, "lost lease, attemping to rebind"); + memset (&dhcp->address, 0, sizeof (dhcp->address)); + do_socket (state, SOCKET_OPEN); + if (state->xid == 0) + state->xid = (uint32_t) random (); + dhcp->serveraddress.s_addr = 0; + _send_message (state, DHCP_REQUEST, options); + state->timeout = dhcp->leasetime - dhcp->rebindtime; + state->state = STATE_REQUESTING; + break; + case STATE_REQUESTING: + state->state = STATE_INIT; + do_socket (state, SOCKET_CLOSED); + state->timeout = 0; + break; + + case STATE_RELEASED: + dhcp->leasetime = 0; + break; + } + + return (0); } static int handle_dhcp (state_t *state, int type, const options_t *options) { - struct timespec ts; - interface_t *iface = state->interface; - dhcp_t *dhcp = state->dhcp; - - /* We should restart on a NAK */ - if (type == DHCP_NAK) { - logger (LOG_INFO, "received NAK: %s", dhcp->message); - logToQt(LOG_INFO, DHCP_NAK, ""); - state->state = STATE_INIT; - state->timeout = 0; - state->xid = 0; - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - - /* If we constantly get NAKS then we should slowly back off */ - if (state->nakoff > 0) { - logger (LOG_DEBUG, "sleeping for %ld seconds", - (long) state->nakoff); - ts.tv_sec = state->nakoff; - ts.tv_nsec = 0; - state->nakoff *= 2; - if (state->nakoff > NAKOFF_MAX) - state->nakoff = NAKOFF_MAX; - nanosleep (&ts, NULL); - } - - return (0); - } - - /* No NAK, so reset the backoff */ - state->nakoff = 1; - - if (type == DHCP_OFFER && state->state == STATE_INIT) { - char *addr = strdup (inet_ntoa (dhcp->address)); - if (dhcp->servername[0]) - logger (LOG_INFO, "offered %s from %s `%s'", - addr, inet_ntoa (dhcp->serveraddress), - dhcp->servername); - else - logger (LOG_INFO, "offered %s from %s", - addr, inet_ntoa (dhcp->serveraddress)); - free (addr); - - logToQt(LOG_INFO, DHCP_OFFER, ""); + struct timespec ts; + interface_t *iface = state->interface; + dhcp_t *dhcp = state->dhcp; + + /* We should restart on a NAK */ + if (type == DHCP_NAK) + { + logger (LOG_INFO, "received NAK: %s", dhcp->message); + logToQt(LOG_INFO, DHCP_NAK, ""); + state->state = STATE_INIT; + state->timeout = 0; + state->xid = 0; + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + + /* If we constantly get NAKS then we should slowly back off */ + if (state->nakoff > 0) + { + logger (LOG_DEBUG, "sleeping for %ld seconds", + (long) state->nakoff); + ts.tv_sec = state->nakoff; + ts.tv_nsec = 0; + state->nakoff *= 2; + if (state->nakoff > NAKOFF_MAX) + state->nakoff = NAKOFF_MAX; + nanosleep (&ts, NULL); + } + + return (0); + } + + /* No NAK, so reset the backoff */ + state->nakoff = 1; + + if (type == DHCP_OFFER && state->state == STATE_INIT) + { + char *addr = strdup (inet_ntoa (dhcp->address)); + if (dhcp->servername[0]) + logger (LOG_INFO, "offered %s from %s `%s'", + addr, inet_ntoa (dhcp->serveraddress), + dhcp->servername); + else + logger (LOG_INFO, "offered %s from %s", + addr, inet_ntoa (dhcp->serveraddress)); + free (addr); + + logToQt(LOG_INFO, DHCP_OFFER, ""); #ifdef ENABLE_INFO - if (options->test) { - write_info (iface, dhcp, options, false); - errno = 0; - return (-1); - } + if (options->test) + { + write_info (iface, dhcp, options, false); + errno = 0; + return (-1); + } #endif - _send_message (state, DHCP_REQUEST, options); - state->state = STATE_REQUESTING; - - return (0); - } - - if (type == DHCP_OFFER) { - logger (LOG_INFO, "got subsequent offer of %s, ignoring ", - inet_ntoa (dhcp->address)); - return (0); - } - - /* We should only be dealing with acks */ - if (type != DHCP_ACK) { - logger (LOG_ERR, "%d not an ACK or OFFER", type); - return (0); - } - - /* if we are here, than we received an ACK and can go on with configuration */ - logToQt(LOG_INFO, DHCP_ACK, ""); - - switch (state->state) { - case STATE_RENEW_REQUESTED: - case STATE_REQUESTING: - case STATE_RENEWING: - case STATE_REBINDING: - break; - default: - logger (LOG_ERR, "wrong state %d", state->state); - } - - do_socket (state, SOCKET_CLOSED); + _send_message (state, DHCP_REQUEST, options); + state->state = STATE_REQUESTING; + + return (0); + } + + if (type == DHCP_OFFER) + { + logger (LOG_INFO, "got subsequent offer of %s, ignoring ", + inet_ntoa (dhcp->address)); + return (0); + } + + /* We should only be dealing with acks */ + if (type != DHCP_ACK) + { + logger (LOG_ERR, "%d not an ACK or OFFER", type); + return (0); + } + + /* if we are here, than we received an ACK and can go on with configuration */ + logToQt(LOG_INFO, DHCP_ACK, ""); + + switch (state->state) + { + case STATE_RENEW_REQUESTED: + case STATE_REQUESTING: + case STATE_RENEWING: + case STATE_REBINDING: + break; + default: + logger (LOG_ERR, "wrong state %d", state->state); + } + + do_socket (state, SOCKET_CLOSED); #ifdef ENABLE_ARP - if (options->doarp && iface->previous_address.s_addr != - dhcp->address.s_addr) - { - errno = 0; - logToQt(LOG_INFO, DHCPCD_ARP_TEST, ""); - if (arp_claim (iface, dhcp->address)) { - do_socket (state, SOCKET_OPEN); - _send_message (state, DHCP_DECLINE, options); - do_socket (state, SOCKET_CLOSED); - - free_dhcp (dhcp); - memset (dhcp, 0, sizeof (*dhcp)); - state->xid = 0; - state->timeout = 0; - state->state = STATE_INIT; - - /* RFC 2131 says that we should wait for 10 seconds - * before doing anything else */ - logger (LOG_INFO, "sleeping for 10 seconds"); - ts.tv_sec = 10; - ts.tv_nsec = 0; - nanosleep (&ts, NULL); - return (0); - } else if (errno == EINTR) - return (0); - } + if (options->doarp && iface->previous_address.s_addr != + dhcp->address.s_addr) + { + errno = 0; + logToQt(LOG_INFO, DHCPCD_ARP_TEST, ""); + if (arp_claim (iface, dhcp->address)) + { + do_socket (state, SOCKET_OPEN); + _send_message (state, DHCP_DECLINE, options); + do_socket (state, SOCKET_CLOSED); + + free_dhcp (dhcp); + memset (dhcp, 0, sizeof (*dhcp)); + state->xid = 0; + state->timeout = 0; + state->state = STATE_INIT; + + /* RFC 2131 says that we should wait for 10 seconds + * before doing anything else */ + logger (LOG_INFO, "sleeping for 10 seconds"); + ts.tv_sec = 10; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); + return (0); + } + else if (errno == EINTR) + return (0); + } #endif - if (options->doinform) { - if (options->request_address.s_addr != 0) - dhcp->address = options->request_address; - else - dhcp->address = iface->previous_address; - - logger (LOG_INFO, "received approval for %s", - inet_ntoa (dhcp->address)); - if (iface->previous_netmask.s_addr != dhcp->netmask.s_addr) { - add_address (iface->name, dhcp->address, - dhcp->netmask, dhcp->broadcast); - iface->previous_netmask.s_addr = dhcp->netmask.s_addr; - } - state->timeout = options->leasetime; - if (state->timeout == 0) - state->timeout = DEFAULT_LEASETIME; - state->state = STATE_INIT; - } else if (dhcp->leasetime == (unsigned) -1) { - dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; - state->timeout = 1; /* So we wait for infinity */ - logger (LOG_INFO, "leased %s for infinity", - inet_ntoa (dhcp->address)); - state->state = STATE_BOUND; - } else { - if (! dhcp->leasetime) { - dhcp->leasetime = DEFAULT_LEASETIME; - logger(LOG_INFO, - "no lease time supplied, assuming %d seconds", - dhcp->leasetime); - } - logger (LOG_INFO, "leased %s for %u seconds", - inet_ntoa (dhcp->address), dhcp->leasetime); - - if (dhcp->rebindtime >= dhcp->leasetime) { - dhcp->rebindtime = (dhcp->leasetime * 0.875); - logger (LOG_ERR, - "rebind time greater than lease " - "time, forcing to %u seconds", - dhcp->rebindtime); - } - - if (dhcp->renewaltime > dhcp->rebindtime) { - dhcp->renewaltime = (dhcp->leasetime * 0.5); - logger (LOG_ERR, - "renewal time greater than rebind time, " - "forcing to %u seconds", - dhcp->renewaltime); - } - - if (! dhcp->renewaltime) { - dhcp->renewaltime = (dhcp->leasetime * 0.5); - logger (LOG_INFO, - "no renewal time supplied, assuming %d seconds", - dhcp->renewaltime); - } else - logger (LOG_DEBUG, "renew in %u seconds", - dhcp->renewaltime); - - if (! dhcp->rebindtime) { - dhcp->rebindtime = (dhcp->leasetime * 0.875); - logger (LOG_INFO, - "no rebind time supplied, assuming %d seconds", - dhcp->rebindtime); - } else - logger (LOG_DEBUG, "rebind in %u seconds", - dhcp->rebindtime); - - state->timeout = dhcp->renewaltime; - state->state = STATE_BOUND; - } - - state->xid = 0; - - logToQt(LOG_INFO, DHCPCD_CONFIGURE, ""); - if (configure (options, iface, dhcp, true) == -1 && - ! state->daemonised) - return (-1); - - if (! state->daemonised && options->daemonise) { - switch (daemonise (state->pidfd)) { - case 0: - state->daemonised = true; - return (0); - case -1: - return (-1); - default: - state->persistent = true; - state->forked = true; - return (-1); - } - } - - return (0); + if (options->doinform) + { + if (options->request_address.s_addr != 0) + dhcp->address = options->request_address; + else + dhcp->address = iface->previous_address; + + logger (LOG_INFO, "received approval for %s", + inet_ntoa (dhcp->address)); + if (iface->previous_netmask.s_addr != dhcp->netmask.s_addr) + { + add_address (iface->name, dhcp->address, + dhcp->netmask, dhcp->broadcast); + iface->previous_netmask.s_addr = dhcp->netmask.s_addr; + } + state->timeout = options->leasetime; + if (state->timeout == 0) + state->timeout = DEFAULT_LEASETIME; + state->state = STATE_INIT; + } + else if (dhcp->leasetime == (unsigned) - 1) + { + dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; + state->timeout = 1; /* So we wait for infinity */ + logger (LOG_INFO, "leased %s for infinity", + inet_ntoa (dhcp->address)); + state->state = STATE_BOUND; + } + else + { + if (! dhcp->leasetime) + { + dhcp->leasetime = DEFAULT_LEASETIME; + logger(LOG_INFO, + "no lease time supplied, assuming %d seconds", + dhcp->leasetime); + } + logger (LOG_INFO, "leased %s for %u seconds", + inet_ntoa (dhcp->address), dhcp->leasetime); + + if (dhcp->rebindtime >= dhcp->leasetime) + { + dhcp->rebindtime = (dhcp->leasetime * 0.875); + logger (LOG_ERR, + "rebind time greater than lease " + "time, forcing to %u seconds", + dhcp->rebindtime); + } + + if (dhcp->renewaltime > dhcp->rebindtime) + { + dhcp->renewaltime = (dhcp->leasetime * 0.5); + logger (LOG_ERR, + "renewal time greater than rebind time, " + "forcing to %u seconds", + dhcp->renewaltime); + } + + if (! dhcp->renewaltime) + { + dhcp->renewaltime = (dhcp->leasetime * 0.5); + logger (LOG_INFO, + "no renewal time supplied, assuming %d seconds", + dhcp->renewaltime); + } + else + logger (LOG_DEBUG, "renew in %u seconds", + dhcp->renewaltime); + + if (! dhcp->rebindtime) + { + dhcp->rebindtime = (dhcp->leasetime * 0.875); + logger (LOG_INFO, + "no rebind time supplied, assuming %d seconds", + dhcp->rebindtime); + } + else + logger (LOG_DEBUG, "rebind in %u seconds", + dhcp->rebindtime); + + state->timeout = dhcp->renewaltime; + state->state = STATE_BOUND; + } + + state->xid = 0; + + logToQt(LOG_INFO, DHCPCD_CONFIGURE, ""); + if (configure (options, iface, dhcp, true) == -1 && + ! state->daemonised) + return (-1); + + if (! state->daemonised && options->daemonise) + { + switch (daemonise (state->pidfd)) + { + case 0: + state->daemonised = true; + return (0); + case -1: + return (-1); + default: + state->persistent = true; + state->forked = true; + return (-1); + } + } + + return (0); } static int handle_packet (state_t *state, const options_t *options) { - interface_t *iface = state->interface; - bool valid = false; - int type; - struct dhcp_t *new_dhcp; - dhcpmessage_t message; - - /* Allocate our buffer space for BPF. - * We cannot do this until we have opened our socket as we don't - * know how much of a buffer we need until then. */ - if (! state->buffer) - state->buffer = xmalloc (iface->buffer_length); - state->buffer_len = iface->buffer_length; - state->buffer_pos = 0; - - /* We loop through until our buffer is empty. - * The benefit is that if we get >1 DHCP packet in our buffer and - * the first one fails for any reason, we can use the next. */ - - memset (&message, 0, sizeof (message)); - new_dhcp = xmalloc (sizeof (*new_dhcp)); - - do { - if (get_packet (iface, (unsigned char *) &message, - state->buffer, - &state->buffer_len, &state->buffer_pos) == -1) - break; - - if (state->xid != message.xid) { - logger (LOG_DEBUG, - "ignoring packet with xid 0x%x as it's not ours (0x%x)", - message.xid, state->xid); - continue; - } - - logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid); - memset (new_dhcp, 0, sizeof (*new_dhcp)); - type = parse_dhcpmessage (new_dhcp, &message); - if (type == -1) { - logger (LOG_ERR, "failed to parse packet"); - free_dhcp (new_dhcp); - /* We don't abort on this, so return zero */ - return (0); - } - - /* If we got here then the DHCP packet is valid and appears to - * be for us, so let's clear the buffer as we don't care about - * any more DHCP packets at this point. */ - valid = true; - break; - } while (state->buffer_pos != 0); - - /* No packets for us, so wait until we get one */ - if (! valid) { - free (new_dhcp); - return (0); - } - - /* new_dhcp is now our master DHCP message */ - free_dhcp (state->dhcp); - free (state->dhcp); - state->dhcp = new_dhcp; - new_dhcp = NULL; - - return (handle_dhcp (state, type, options)); + interface_t *iface = state->interface; + bool valid = false; + int type; + struct dhcp_t *new_dhcp; + dhcpmessage_t message; + + /* Allocate our buffer space for BPF. + * We cannot do this until we have opened our socket as we don't + * know how much of a buffer we need until then. */ + if (! state->buffer) + state->buffer = xmalloc (iface->buffer_length); + state->buffer_len = iface->buffer_length; + state->buffer_pos = 0; + + /* We loop through until our buffer is empty. + * The benefit is that if we get >1 DHCP packet in our buffer and + * the first one fails for any reason, we can use the next. */ + + memset (&message, 0, sizeof (message)); + new_dhcp = xmalloc (sizeof (*new_dhcp)); + + do + { + if (get_packet (iface, (unsigned char *) &message, + state->buffer, + &state->buffer_len, &state->buffer_pos) == -1) + break; + + if (state->xid != message.xid) + { + logger (LOG_DEBUG, + "ignoring packet with xid 0x%x as it's not ours (0x%x)", + message.xid, state->xid); + continue; + } + + logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid); + memset (new_dhcp, 0, sizeof (*new_dhcp)); + type = parse_dhcpmessage (new_dhcp, &message); + if (type == -1) + { + logger (LOG_ERR, "failed to parse packet"); + free_dhcp (new_dhcp); + /* We don't abort on this, so return zero */ + return (0); + } + + /* If we got here then the DHCP packet is valid and appears to + * be for us, so let's clear the buffer as we don't care about + * any more DHCP packets at this point. */ + valid = true; + break; + } + while (state->buffer_pos != 0); + + /* No packets for us, so wait until we get one */ + if (! valid) + { + free (new_dhcp); + return (0); + } + + /* new_dhcp is now our master DHCP message */ + free_dhcp (state->dhcp); + free (state->dhcp); + state->dhcp = new_dhcp; + new_dhcp = NULL; + + return (handle_dhcp (state, type, options)); } int dhcp_run (const options_t *options, int *pidfd) { - interface_t *iface; - state_t *state = NULL; - struct pollfd fds[] = { - { -1, POLLIN, 0 }, - { -1, POLLIN, 0 } - }; - int retval = -1; - int sig; - - if (! options) - return (-1); - - /*read_interface : defined in interface.c*/ - iface = read_interface (options->interface, options->metric); - if (! iface) - goto eexit; - - state = xzalloc (sizeof (*state)); - state->dhcp = xzalloc (sizeof (*state->dhcp)); - state->pidfd = pidfd; - state->interface = iface; - - if (! client_setup (state, options)) - goto eexit; - - if (signal_init () == -1) - goto eexit; - if (signal_setup () == -1) - goto eexit; - - fds[POLLFD_SIGNAL].fd = signal_fd (); - - for (;;) { - retval = wait_for_packet (fds, state, options); - - /* We should always handle our signals first */ - if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) { - if (handle_signal (sig, state, options)) - retval = 0; - else - retval = -1; - } else if (retval == 0) - retval = handle_timeout (state, options); - else if (retval > 0 && - state->socket != SOCKET_CLOSED && - fds[POLLFD_IFACE].revents & POLLIN) - retval = handle_packet (state, options); - else if (retval == -1 && errno == EINTR) { - /* The interupt will be handled above */ - retval = 0; - } else { - logger (LOG_ERR, "poll: %s", strerror (errno)); - retval = -1; - } - - if (retval != 0) - break; - } + interface_t *iface; + state_t *state = NULL; + struct pollfd fds[] = + { + { -1, POLLIN, 0 }, + { -1, POLLIN, 0 } + }; + int retval = -1; + int sig; + + if (! options) + return (-1); + + /*read_interface : defined in interface.c*/ + iface = read_interface (options->interface, options->metric); + if (! iface) + goto eexit; + + state = xzalloc (sizeof (*state)); + state->dhcp = xzalloc (sizeof (*state->dhcp)); + state->pidfd = pidfd; + state->interface = iface; + + if (! client_setup (state, options)) + goto eexit; + + if (signal_init () == -1) + goto eexit; + if (signal_setup () == -1) + goto eexit; + + fds[POLLFD_SIGNAL].fd = signal_fd (); + + for (;;) + { + retval = wait_for_packet (fds, state, options); + + /* We should always handle our signals first */ + if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) + { + if (handle_signal (sig, state, options)) + retval = 0; + else + retval = -1; + } + else if (retval == 0) + retval = handle_timeout (state, options); + else if (retval > 0 && + state->socket != SOCKET_CLOSED && + fds[POLLFD_IFACE].revents & POLLIN) + retval = handle_packet (state, options); + else if (retval == -1 && errno == EINTR) + { + /* The interupt will be handled above */ + retval = 0; + } + else + { + logger (LOG_ERR, "poll: %s", strerror (errno)); + retval = -1; + } + + if (retval != 0) + break; + } eexit: - if (iface) { - do_socket (state, SOCKET_CLOSED); - drop_config (state, options); - free_route (iface->previous_routes); - free (iface->clientid); - free (iface); - } - - if (state) { - if (state->forked) - retval = 0; - - if (state->daemonised) - unlink (options->pidfile); - - free_dhcp (state->dhcp); - free (state->dhcp); - free (state->buffer); - free (state); - } - - return (retval); + if (iface) + { + do_socket (state, SOCKET_CLOSED); + drop_config (state, options); + free_route (iface->previous_routes); + free (iface->clientid); + free (iface); + } + + if (state) + { + if (state->forked) + retval = 0; + + if (state->daemonised) + unlink (options->pidfile); + + free_dhcp (state->dhcp); + free (state->dhcp); + free (state->buffer); + free (state); + } + + return (retval); } diff --git a/src/customdhcpcd/client.h b/src/customdhcpcd/client.h index fa6ea9b..247abe9 100644 --- a/src/customdhcpcd/client.h +++ b/src/customdhcpcd/client.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved diff --git a/src/customdhcpcd/common.c b/src/customdhcpcd/common.c index 99471bc..707ea32 100644 --- a/src/customdhcpcd/common.c +++ b/src/customdhcpcd/common.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -41,28 +41,30 @@ * This means we read the whole line and avoid any nasty buffer overflows. */ char *get_line (FILE *fp) { - char *line = NULL; - char *p; - size_t len = 0; - size_t last = 0; - - if (feof (fp)) - return (NULL); - - do { - len += BUFSIZ; - line = xrealloc (line, sizeof (char) * len); - p = line + last; - memset (p, 0, BUFSIZ); - fgets (p, BUFSIZ, fp); - last += strlen (p); - } while (! feof (fp) && line[last - 1] != '\n'); - - /* Trim the trailing newline */ - if (*line && line[--last] == '\n') - line[last] = '\0'; - - return (line); + char *line = NULL; + char *p; + size_t len = 0; + size_t last = 0; + + if (feof (fp)) + return (NULL); + + do + { + len += BUFSIZ; + line = xrealloc (line, sizeof (char) * len); + p = line + last; + memset (p, 0, BUFSIZ); + fgets (p, BUFSIZ, fp); + last += strlen (p); + } + while (! feof (fp) && line[last - 1] != '\n'); + + /* Trim the trailing newline */ + if (*line && line[--last] == '\n') + line[last] = '\0'; + + return (line); } /* OK, this should be in dhcpcd.c @@ -70,19 +72,20 @@ char *get_line (FILE *fp) #ifndef HAVE_SRANDOMDEV void srandomdev (void) { - int fd; - unsigned long seed; - - fd = open ("/dev/urandom", 0); - if (fd == -1 || read (fd, &seed, sizeof (seed)) == -1) { - logger (LOG_WARNING, "Could not read from /dev/urandom: %s", - strerror (errno)); - seed = time (0); - } - if (fd >= 0) - close(fd); - - srandom (seed); + int fd; + unsigned long seed; + + fd = open ("/dev/urandom", 0); + if (fd == -1 || read (fd, &seed, sizeof (seed)) == -1) + { + logger (LOG_WARNING, "Could not read from /dev/urandom: %s", + strerror (errno)); + seed = time (0); + } + if (fd >= 0) + close(fd); + + srandom (seed); } #endif @@ -90,54 +93,58 @@ void srandomdev (void) #ifndef HAVE_STRLCPY size_t strlcpy (char *dst, const char *src, size_t size) { - const char *s = src; - size_t n = size; - - if (n && --n) - do { - if (! (*dst++ = *src++)) - break; - } while (--n); - - if (! n) { - if (size) - *dst = '\0'; - while (*src++); - } - - return (src - s - 1); + const char *s = src; + size_t n = size; + + if (n && --n) + do + { + if (! (*dst++ = *src++)) + break; + } + while (--n); + + if (! n) + { + if (size) + *dst = '\0'; + while (*src++); + } + + return (src - s - 1); } #endif /* Close our fd's */ int close_fds (void) { - int fd; - - if ((fd = open ("/dev/null", O_RDWR)) == -1) { - logger (LOG_ERR, "open `/dev/null': %s", strerror (errno)); - return (-1); - } - - dup2 (fd, fileno (stdin)); - dup2 (fd, fileno (stdout)); - dup2 (fd, fileno (stderr)); - if (fd > 2) - close (fd); - return (0); + int fd; + + if ((fd = open ("/dev/null", O_RDWR)) == -1) + { + logger (LOG_ERR, "open `/dev/null': %s", strerror (errno)); + return (-1); + } + + dup2 (fd, fileno (stdin)); + dup2 (fd, fileno (stdout)); + dup2 (fd, fileno (stderr)); + if (fd > 2) + close (fd); + return (0); } int close_on_exec (int fd) { - int flags; - - if ((flags = fcntl (fd, F_GETFD, 0)) == -1 - || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1) - { - logger (LOG_ERR, "fcntl: %s", strerror (errno)); - return (-1); - } - return (0); + int flags; + + if ((flags = fcntl (fd, F_GETFD, 0)) == -1 + || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1) + { + logger (LOG_ERR, "fcntl: %s", strerror (errno)); + return (-1); + } + return (0); } /* Handy function to get the time. @@ -148,102 +155,108 @@ int close_on_exec (int fd) int get_time (struct timeval *tp) { #if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC) - struct timespec ts; - static clockid_t posix_clock; - static int posix_clock_set = 0; - - if (! posix_clock_set) { - if (sysconf (_SC_MONOTONIC_CLOCK) >= 0) - posix_clock = CLOCK_MONOTONIC; - else - posix_clock = CLOCK_REALTIME; - posix_clock_set = 1; - } - - if (clock_gettime (posix_clock, &ts) == -1) { - logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); - return (-1); - } - - tp->tv_sec = ts.tv_sec; - tp->tv_usec = ts.tv_nsec / 1000; - return (0); + struct timespec ts; + static clockid_t posix_clock; + static int posix_clock_set = 0; + + if (! posix_clock_set) + { + if (sysconf (_SC_MONOTONIC_CLOCK) >= 0) + posix_clock = CLOCK_MONOTONIC; + else + posix_clock = CLOCK_REALTIME; + posix_clock_set = 1; + } + + if (clock_gettime (posix_clock, &ts) == -1) + { + logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); + return (-1); + } + + tp->tv_sec = ts.tv_sec; + tp->tv_usec = ts.tv_nsec / 1000; + return (0); #else - if (gettimeofday (tp, NULL) == -1) { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return (-1); - } - return (0); + if (gettimeofday (tp, NULL) == -1) + { + logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); + return (-1); + } + return (0); #endif } time_t uptime (void) { - struct timeval tp; + struct timeval tp; - if (get_time (&tp) == -1) - return (-1); + if (get_time (&tp) == -1) + return (-1); - return (tp.tv_sec); + return (tp.tv_sec); } void writepid (int fd, pid_t pid) { - char spid[16]; - if (ftruncate (fd, (off_t) 0) == -1) { - logger (LOG_ERR, "ftruncate: %s", strerror (errno)); - } else { - ssize_t len; - snprintf (spid, sizeof (spid), "%u", pid); - len = pwrite (fd, spid, strlen (spid), (off_t) 0); - if (len != (ssize_t) strlen (spid)) - logger (LOG_ERR, "pwrite: %s", strerror (errno)); - } + char spid[16]; + if (ftruncate (fd, (off_t) 0) == -1) + { + logger (LOG_ERR, "ftruncate: %s", strerror (errno)); + } + else + { + ssize_t len; + snprintf (spid, sizeof (spid), "%u", pid); + len = pwrite (fd, spid, strlen (spid), (off_t) 0); + if (len != (ssize_t) strlen (spid)) + logger (LOG_ERR, "pwrite: %s", strerror (errno)); + } } void *xmalloc (size_t s) { - void *value = malloc (s); + void *value = malloc (s); - if (value) - return (value); + if (value) + return (value); - logger (LOG_ERR, "memory exhausted"); + logger (LOG_ERR, "memory exhausted"); - exit (EXIT_FAILURE); - /* NOTREACHED */ + exit (EXIT_FAILURE); + /* NOTREACHED */ } void *xzalloc (size_t s) { - void *value = xmalloc (s); - memset (value, 0, s); - return (value); + void *value = xmalloc (s); + memset (value, 0, s); + return (value); } void *xrealloc (void *ptr, size_t s) { - void *value = realloc (ptr, s); + void *value = realloc (ptr, s); - if (value) - return (value); + if (value) + return (value); - logger (LOG_ERR, "memory exhausted"); - exit (EXIT_FAILURE); - /* NOTREACHED */ + logger (LOG_ERR, "memory exhausted"); + exit (EXIT_FAILURE); + /* NOTREACHED */ } char *xstrdup (const char *str) { - char *value; + char *value; - if (! str) - return (NULL); + if (! str) + return (NULL); - if ((value = strdup (str))) - return (value); + if ((value = strdup (str))) + return (value); - logger (LOG_ERR, "memory exhausted"); - exit (EXIT_FAILURE); - /* NOTREACHED */ + logger (LOG_ERR, "memory exhausted"); + exit (EXIT_FAILURE); + /* NOTREACHED */ } diff --git a/src/customdhcpcd/common.h b/src/customdhcpcd/common.h index 46f1886..5d68f7f 100644 --- a/src/customdhcpcd/common.h +++ b/src/customdhcpcd/common.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved diff --git a/src/customdhcpcd/configure.c b/src/customdhcpcd/configure.c index b69ccdc..00d75d0 100644 --- a/src/customdhcpcd/configure.c +++ b/src/customdhcpcd/configure.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -63,340 +63,360 @@ static int file_in_path (const char *file) { - char *p = getenv ("PATH"); - char *path; - char *token; - struct stat s; - char mypath[PATH_MAX]; - int retval = -1; - - if (! p) { - errno = ENOENT; - return (-1); - } - - path = strdup (p); - p = path; - while ((token = strsep (&p, ":"))) { - snprintf (mypath, PATH_MAX, "%s/%s", token, file); - if (stat (mypath, &s) == 0) { - retval = 0; - break; - } - } - free (path); - return (retval); + char *p = getenv ("PATH"); + char *path; + char *token; + struct stat s; + char mypath[PATH_MAX]; + int retval = -1; + + if (! p) + { + errno = ENOENT; + return (-1); + } + + path = strdup (p); + p = path; + while ((token = strsep (&p, ":"))) + { + snprintf (mypath, PATH_MAX, "%s/%s", token, file); + if (stat (mypath, &s) == 0) + { + retval = 0; + break; + } + } + free (path); + return (retval); } /* IMPORTANT: Ensure that the last parameter is NULL when calling */ static int exec_cmd (const char *cmd, const char *args, ...) { - va_list va; - char **argv; - int n = 1; - int ret = 0; - pid_t pid; - sigset_t full; - sigset_t old; - - va_start (va, args); - while (va_arg (va, char *) != NULL) - n++; - va_end (va); - argv = xmalloc (sizeof (char *) * (n + 2)); - - va_start (va, args); - n = 2; - argv[0] = (char *) cmd; - argv[1] = (char *) args; - while ((argv[n] = va_arg (va, char *)) != NULL) - n++; - va_end (va); - - /* OK, we need to block signals */ - sigfillset (&full); - sigprocmask (SIG_SETMASK, &full, &old); + va_list va; + char **argv; + int n = 1; + int ret = 0; + pid_t pid; + sigset_t full; + sigset_t old; + + va_start (va, args); + while (va_arg (va, char *) != NULL) + n++; + va_end (va); + argv = xmalloc (sizeof (char *) * (n + 2)); + + va_start (va, args); + n = 2; + argv[0] = (char *) cmd; + argv[1] = (char *) args; + while ((argv[n] = va_arg (va, char *)) != NULL) + n++; + va_end (va); + + /* OK, we need to block signals */ + sigfillset (&full); + sigprocmask (SIG_SETMASK, &full, &old); #ifdef THERE_IS_NO_FORK - signal_reset (); - pid = vfork (); + signal_reset (); + pid = vfork (); #else - pid = fork(); + pid = fork(); #endif - switch (pid) { - case -1: - logger (LOG_ERR, "vfork: %s", strerror (errno)); - ret = -1; - break; - case 0: + switch (pid) + { + case -1: + logger (LOG_ERR, "vfork: %s", strerror (errno)); + ret = -1; + break; + case 0: #ifndef THERE_IS_NO_FORK - signal_reset (); + signal_reset (); #endif - sigprocmask (SIG_SETMASK, &old, NULL); - if (execvp (cmd, argv) && errno != ENOENT) - logger (LOG_ERR, "error executing \"%s\": %s", - cmd, strerror (errno)); - _exit (111); - /* NOTREACHED */ - } + sigprocmask (SIG_SETMASK, &old, NULL); + if (execvp (cmd, argv) && errno != ENOENT) + logger (LOG_ERR, "error executing \"%s\": %s", + cmd, strerror (errno)); + _exit (111); + /* NOTREACHED */ + } #ifdef THERE_IS_NO_FORK - signal_setup (); + signal_setup (); #endif - /* Restore our signals */ - sigprocmask (SIG_SETMASK, &old, NULL); + /* Restore our signals */ + sigprocmask (SIG_SETMASK, &old, NULL); - free (argv); - return (ret); + free (argv); + return (ret); } static void exec_script (const char *script, const char *infofile, - const char *arg) + const char *arg) { - struct stat buf; + struct stat buf; - if (! script || ! infofile || ! arg) - return; + if (! script || ! infofile || ! arg) + return; - if (stat (script, &buf) == -1) { - if (strcmp (script, DEFAULT_SCRIPT) != 0) - logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT)); - return; - } + if (stat (script, &buf) == -1) + { + if (strcmp (script, DEFAULT_SCRIPT) != 0) + logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT)); + return; + } #ifdef ENABLE_INFO - logger (LOG_DEBUG, "exec \"%s\" \"%s\" \"%s\"", script, infofile, arg); - exec_cmd (script, infofile, arg, (char *) NULL); + logger (LOG_DEBUG, "exec \"%s\" \"%s\" \"%s\"", script, infofile, arg); + exec_cmd (script, infofile, arg, (char *) NULL); #else - logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg); - exec_cmd (script, "", arg, (char *) NULL); + logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg); + exec_cmd (script, "", arg, (char *) NULL); #endif } static int make_resolv (const char *ifname, const dhcp_t *dhcp) { - FILE *f = NULL; - address_t *address; + FILE *f = NULL; + address_t *address; #ifdef ENABLE_RESOLVCONF - char *resolvconf = NULL; - - if (file_in_path ("resolvconf") == 0) { - size_t len = strlen ("resolvconf -a ") + strlen (ifname) + 1; - resolvconf = xmalloc (sizeof (char) * len); - snprintf (resolvconf, len, "resolvconf -a %s", ifname); - if ((f = popen (resolvconf , "w"))) - logger (LOG_DEBUG, - "sending DNS information to resolvconf"); - else if (errno == EEXIST) - logger (LOG_ERR, "popen: %s", strerror (errno)); - - if (ferror (f)) - logger (LOG_ERR, "ferror"); - free (resolvconf); - } -#endif - if (! f) { - logger (LOG_DEBUG, "writing "RESOLVFILE); - if (! (f = fopen(RESOLVFILE, "w"))) - logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno)); - } - - if (! f) - return (-1); - - fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); - if (dhcp->dnssearch) - fprintf (f, "search %s\n", dhcp->dnssearch); - else if (dhcp->dnsdomain) { - fprintf (f, "search %s\n", dhcp->dnsdomain); - } - - STAILQ_FOREACH (address, dhcp->dnsservers, entries) - fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); + char *resolvconf = NULL; + + if (file_in_path ("resolvconf") == 0) + { + size_t len = strlen ("resolvconf -a ") + strlen (ifname) + 1; + resolvconf = xmalloc (sizeof (char) * len); + snprintf (resolvconf, len, "resolvconf -a %s", ifname); + if ((f = popen (resolvconf , "w"))) + logger (LOG_DEBUG, + "sending DNS information to resolvconf"); + else if (errno == EEXIST) + logger (LOG_ERR, "popen: %s", strerror (errno)); + + if (ferror (f)) + logger (LOG_ERR, "ferror"); + free (resolvconf); + } +#endif + if (! f) + { + logger (LOG_DEBUG, "writing "RESOLVFILE); + if (! (f = fopen(RESOLVFILE, "w"))) + logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno)); + } + + if (! f) + return (-1); + + fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); + if (dhcp->dnssearch) + fprintf (f, "search %s\n", dhcp->dnssearch); + else if (dhcp->dnsdomain) + { + fprintf (f, "search %s\n", dhcp->dnsdomain); + } + + STAILQ_FOREACH (address, dhcp->dnsservers, entries) + fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); #ifdef ENABLE_RESOLVCONF - if (resolvconf) - pclose (f); - else + if (resolvconf) + pclose (f); + else #endif - fclose (f); + fclose (f); - /* Refresh the local resolver */ - res_init (); - return (0); + /* Refresh the local resolver */ + res_init (); + return (0); } static void restore_resolv (const char *ifname) { #ifdef ENABLE_RESOLVCONF - if (file_in_path ("resolvconf") == 0) { - logger (LOG_DEBUG, "removing information from resolvconf"); - exec_cmd("resolvconf", "-d", ifname, (char *) NULL); - } + if (file_in_path ("resolvconf") == 0) + { + logger (LOG_DEBUG, "removing information from resolvconf"); + exec_cmd("resolvconf", "-d", ifname, (char *) NULL); + } #endif } static bool in_addresses (const struct address_head *addresses, - struct in_addr address) + struct in_addr address) { - const address_t *addr; + const address_t *addr; - STAILQ_FOREACH (addr, addresses, entries) - if (addr->address.s_addr == address.s_addr) - return (true); + STAILQ_FOREACH (addr, addresses, entries) + if (addr->address.s_addr == address.s_addr) + return (true); - return (false); + return (false); } static bool in_routes (const struct route_head *routes, route_t *route) { - const route_t *r; - - if (! routes) - return (false); - - STAILQ_FOREACH (r, routes, entries) - if (r->destination.s_addr == route->destination.s_addr && - r->netmask.s_addr == route->netmask.s_addr && - r->gateway.s_addr == route->gateway.s_addr) - return (true); - - return (false); + const route_t *r; + + if (! routes) + return (false); + + STAILQ_FOREACH (r, routes, entries) + if (r->destination.s_addr == route->destination.s_addr && + r->netmask.s_addr == route->netmask.s_addr && + r->gateway.s_addr == route->gateway.s_addr) + return (true); + + return (false); } #ifdef ENABLE_NTP static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) { - FILE *f; - address_t *address; - char *a; - char *line; - int tomatch = 0; - char *token; - bool ntp = false; - - STAILQ_FOREACH (address, dhcp->ntpservers, entries) - tomatch++; - - /* Check that we really need to update the servers. - * We do this because ntp has to be restarted to - * work with a changed config. */ - if (! (f = fopen (file, "r"))) { - if (errno != ENOENT) { - logger (LOG_ERR, "fopen `%s': %s", - file, strerror (errno)); - return (-1); - } - } else { - while (tomatch != 0 && (line = get_line (f))) { - struct in_addr addr; - - a = line; - token = strsep (&a, " "); - if (! token || strcmp (token, "server") != 0) - goto next; - - if ((token = strsep (&a, " \n")) == NULL) - goto next; - - if (inet_aton (token, &addr) == 1 && - in_addresses (dhcp->ntpservers, addr)) - tomatch--; + FILE *f; + address_t *address; + char *a; + char *line; + int tomatch = 0; + char *token; + bool ntp = false; + + STAILQ_FOREACH (address, dhcp->ntpservers, entries) + tomatch++; + + /* Check that we really need to update the servers. + * We do this because ntp has to be restarted to + * work with a changed config. */ + if (! (f = fopen (file, "r"))) + { + if (errno != ENOENT) + { + logger (LOG_ERR, "fopen `%s': %s", + file, strerror (errno)); + return (-1); + } + } + else + { + while (tomatch != 0 && (line = get_line (f))) + { + struct in_addr addr; + + a = line; + token = strsep (&a, " "); + if (! token || strcmp (token, "server") != 0) + goto next; + + if ((token = strsep (&a, " \n")) == NULL) + goto next; + + if (inet_aton (token, &addr) == 1 && + in_addresses (dhcp->ntpservers, addr)) + tomatch--; next: - free (line); - } - fclose (f); - - /* File has the same name servers that we do, - * so no need to restart ntp */ - if (tomatch == 0) { - logger (LOG_DEBUG, "%s already configured, skipping", - file); - return (0); - } - } - - logger (LOG_DEBUG, "writing %s", file); - if (! (f = fopen (file, "w"))) { - logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno)); - return (-1); - } - - fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); + free (line); + } + fclose (f); + + /* File has the same name servers that we do, + * so no need to restart ntp */ + if (tomatch == 0) + { + logger (LOG_DEBUG, "%s already configured, skipping", + file); + return (0); + } + } + + logger (LOG_DEBUG, "writing %s", file); + if (! (f = fopen (file, "w"))) + { + logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno)); + return (-1); + } + + fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); #ifdef NTPFILE - if (strcmp (file, NTPFILE) == 0) { - ntp = true; - fprintf (f, "restrict default noquery notrust nomodify\n"); - fprintf (f, "restrict 127.0.0.1\n"); - } -#endif - - STAILQ_FOREACH (address, dhcp->ntpservers, entries) { - a = inet_ntoa (address->address); - if (ntp) - fprintf (f, "restrict %s nomodify notrap noquery\n", a); - fprintf (f, "server %s\n", a); - } - fclose (f); - - return (1); + if (strcmp (file, NTPFILE) == 0) + { + ntp = true; + fprintf (f, "restrict default noquery notrust nomodify\n"); + fprintf (f, "restrict 127.0.0.1\n"); + } +#endif + + STAILQ_FOREACH (address, dhcp->ntpservers, entries) + { + a = inet_ntoa (address->address); + if (ntp) + fprintf (f, "restrict %s nomodify notrap noquery\n", a); + fprintf (f, "server %s\n", a); + } + fclose (f); + + return (1); } static int make_ntp (const char *ifname, const dhcp_t *dhcp) { - /* On some systems we have only have one ntp service, but we don't - * know which configuration file we're using. So we need to write - * to both and restart accordingly. */ + /* On some systems we have only have one ntp service, but we don't + * know which configuration file we're using. So we need to write + * to both and restart accordingly. */ - bool restart_ntp = false; - bool restart_openntp = false; - int retval = 0; + bool restart_ntp = false; + bool restart_openntp = false; + int retval = 0; #ifdef NTPFILE - if (_make_ntp (NTPFILE, ifname, dhcp) > 0) - restart_ntp = true; + if (_make_ntp (NTPFILE, ifname, dhcp) > 0) + restart_ntp = true; #endif #ifdef OPENNTPFILE - if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0) - restart_openntp = true; + if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0) + restart_openntp = true; #endif #ifdef NTPSERVICE - if (restart_ntp) { + if (restart_ntp) + { #ifdef NTPCHECK - if (system (NTPCHECK) == 0) + if (system (NTPCHECK) == 0) #endif - retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, - (char *) NULL); - } + retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, + (char *) NULL); + } #endif #if defined (NTPSERVICE) && defined (OPENNTPSERVICE) - if (restart_openntp && - (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp)) - { + if (restart_openntp && + (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp)) + { #ifdef OPENNTPCHECK - if (system (OPENNTPCHECK) == 0) + if (system (OPENNTPCHECK) == 0) #endif - retval += exec_cmd (OPENNTPSERVICE, - OPENNTPRESTARTARGS, (char *) NULL); - } + retval += exec_cmd (OPENNTPSERVICE, + OPENNTPRESTARTARGS, (char *) NULL); + } #elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE) - if (restart_openntp) { + if (restart_openntp) + { #ifdef OPENNTPCHECK - if (system (OPENNTPCHECK) == 0) + if (system (OPENNTPCHECK) == 0) #endif - retval += exec_cmd (OPENNTPSERVICE, - OPENNTPRESTARTARGS, (char *) NULL); - } + retval += exec_cmd (OPENNTPSERVICE, + OPENNTPRESTARTARGS, (char *) NULL); + } #endif - return (retval); + return (retval); } #endif @@ -404,411 +424,438 @@ static int make_ntp (const char *ifname, const dhcp_t *dhcp) #define PREFIXSIZE 256 static int make_nis (const char *ifname, const dhcp_t *dhcp) { - FILE *f; - address_t *address; - char *prefix; - - logger (LOG_DEBUG, "writing "NISFILE); - if (! (f = fopen(NISFILE, "w"))) { - logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno)); - return (-1); - } - - prefix = xmalloc (sizeof (char) * PREFIXSIZE); - *prefix = '\0'; - fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); - - if (dhcp->nisdomain) { - setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain)); - - if (dhcp->nisservers) - snprintf (prefix, PREFIXSIZE, "domain %s server", - dhcp->nisdomain); - else - fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); - } - else - snprintf (prefix, PREFIXSIZE, "%s", "ypserver"); - - NSTAILQ_FOREACH (address, dhcp->nisservers, entries) - fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); - - free (prefix); - fclose (f); + FILE *f; + address_t *address; + char *prefix; + + logger (LOG_DEBUG, "writing "NISFILE); + if (! (f = fopen(NISFILE, "w"))) + { + logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno)); + return (-1); + } + + prefix = xmalloc (sizeof (char) * PREFIXSIZE); + *prefix = '\0'; + fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); + + if (dhcp->nisdomain) + { + setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain)); + + if (dhcp->nisservers) + snprintf (prefix, PREFIXSIZE, "domain %s server", + dhcp->nisdomain); + else + fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); + } + else + snprintf (prefix, PREFIXSIZE, "%s", "ypserver"); + + NSTAILQ_FOREACH (address, dhcp->nisservers, entries) + fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); + + free (prefix); + fclose (f); #ifdef NISCHECK - if (system (NISCHECK) == 0) + if (system (NISCHECK) == 0) #endif - exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); - return (0); + exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); + return (0); } #endif static char *lookuphostname (char *hostname, const dhcp_t *dhcp, - const options_t *options) + const options_t *options) { - union { - struct sockaddr sa; - struct sockaddr_in sin; - } su; - socklen_t salen; - char *addr; - struct addrinfo hints; - struct addrinfo *res = NULL; - int result; - char *p; - - logger (LOG_DEBUG, "Looking up hostname via DNS"); - addr = xmalloc (sizeof (char) * NI_MAXHOST); - salen = sizeof (su.sa); - memset (&su.sa, 0, salen); - su.sin.sin_family = AF_INET; - memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr)); - - if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST, - NULL, 0, NI_NAMEREQD)) != 0) { - logger (LOG_ERR, - "Failed to lookup hostname via DNS: %s", - gai_strerror (result)); - free (addr); - return (NULL); - } - - /* Check for a malicious PTR record */ - memset (&hints, 0, sizeof (hints)); - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICHOST; - result = getaddrinfo (addr, "0", &hints, &res); - if (res) - freeaddrinfo (res); - if (result == 0) - logger (LOG_ERR, "malicious PTR record detected"); - if (result == 0 || ! *addr) { - free (addr); - return (NULL); - } - - p = strchr (addr, '.'); - if (p) { - switch (options->dohostname) { - case 1: /* -H */ - case 4: /* -HHHH */ - break; - case 2: /* -HH */ - case 5: /* -HHHHH */ - /* Strip out the domain if it matches */ - p++; - if (*p && dhcp->dnssearch) { - char *s = xstrdup (dhcp->dnssearch); - char *sp = s; - char *t; - - while ((t = strsep (&sp, " "))) - if (strcmp (t, p) == 0) { - *--p = '\0'; - break; - } - free (s); - } else if (dhcp->dnsdomain) { - if (strcmp (dhcp->dnsdomain, p) == 0) - *--p = '\0'; - } - break; - case 3: /* -HHH */ - case 6: /* -HHHHHH */ - /* Just strip the domain */ - *p = '\0'; - break; - default: /* Too many H! */ - break; - } - } - - strlcpy (hostname, addr, MAXHOSTNAMELEN); - free (addr); - return (hostname); + union + { + struct sockaddr sa; + struct sockaddr_in sin; + } su; + socklen_t salen; + char *addr; + struct addrinfo hints; + struct addrinfo *res = NULL; + int result; + char *p; + + logger (LOG_DEBUG, "Looking up hostname via DNS"); + addr = xmalloc (sizeof (char) * NI_MAXHOST); + salen = sizeof (su.sa); + memset (&su.sa, 0, salen); + su.sin.sin_family = AF_INET; + memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr)); + + if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST, + NULL, 0, NI_NAMEREQD)) != 0) + { + logger (LOG_ERR, + "Failed to lookup hostname via DNS: %s", + gai_strerror (result)); + free (addr); + return (NULL); + } + + /* Check for a malicious PTR record */ + memset (&hints, 0, sizeof (hints)); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + result = getaddrinfo (addr, "0", &hints, &res); + if (res) + freeaddrinfo (res); + if (result == 0) + logger (LOG_ERR, "malicious PTR record detected"); + if (result == 0 || ! *addr) + { + free (addr); + return (NULL); + } + + p = strchr (addr, '.'); + if (p) + { + switch (options->dohostname) + { + case 1: /* -H */ + case 4: /* -HHHH */ + break; + case 2: /* -HH */ + case 5: /* -HHHHH */ + /* Strip out the domain if it matches */ + p++; + if (*p && dhcp->dnssearch) + { + char *s = xstrdup (dhcp->dnssearch); + char *sp = s; + char *t; + + while ((t = strsep (&sp, " "))) + if (strcmp (t, p) == 0) + { + *--p = '\0'; + break; + } + free (s); + } + else if (dhcp->dnsdomain) + { + if (strcmp (dhcp->dnsdomain, p) == 0) + *--p = '\0'; + } + break; + case 3: /* -HHH */ + case 6: /* -HHHHHH */ + /* Just strip the domain */ + *p = '\0'; + break; + default: /* Too many H! */ + break; + } + } + + strlcpy (hostname, addr, MAXHOSTNAMELEN); + free (addr); + return (hostname); } int configure (const options_t *options, interface_t *iface, - const dhcp_t *dhcp, bool up) + const dhcp_t *dhcp, bool up) { - route_t *route = NULL; - struct route_head *new_routes = NULL; - route_t *new_route = NULL; - char *newhostname = NULL; - char *curhostname = NULL; - int remember; + route_t *route = NULL; + struct route_head *new_routes = NULL; + route_t *new_route = NULL; + char *newhostname = NULL; + char *curhostname = NULL; + int remember; #ifdef ENABLE_IPV4LL - bool haslinklocal = false; + bool haslinklocal = false; #endif #ifdef THERE_IS_NO_FORK - int skip = 0; - size_t skiplen; - char *skipp; -#endif - - if (! options || ! iface || ! dhcp) - return (-1); - - if (dhcp->address.s_addr == 0) - up = 0; - - logGatewayToFile(iface, dhcp); - - /* Remove old routes. - * Always do this as the interface may have >1 address not added by us - * so the routes we added may still exist. */ - NSTAILQ_FOREACH (route, iface->previous_routes, entries) - if ((route->destination.s_addr || options->dogateway) && - (! up || ! in_routes (dhcp->routes, route))) - del_route (iface->name, route->destination, - route->netmask, route->gateway, - options->metric); - /* If we aren't up, then reset the interface as much as we can */ - if (! up) { - if (iface->previous_routes) { - free_route (iface->previous_routes); - iface->previous_routes = NULL; - } - - /* Restore the original MTU value */ - if (iface->mtu && iface->previous_mtu != iface->mtu) { - set_mtu (iface->name, iface->mtu); - iface->previous_mtu = iface->mtu; - } + int skip = 0; + size_t skiplen; + char *skipp; +#endif + + if (! options || ! iface || ! dhcp) + return (-1); + + if (dhcp->address.s_addr == 0) + up = 0; + + logGatewayToFile(iface, dhcp); + + /* Remove old routes. + * Always do this as the interface may have >1 address not added by us + * so the routes we added may still exist. */ + NSTAILQ_FOREACH (route, iface->previous_routes, entries) + if ((route->destination.s_addr || options->dogateway) && + (! up || ! in_routes (dhcp->routes, route))) + del_route (iface->name, route->destination, + route->netmask, route->gateway, + options->metric); + /* If we aren't up, then reset the interface as much as we can */ + if (! up) + { + if (iface->previous_routes) + { + free_route (iface->previous_routes); + iface->previous_routes = NULL; + } + + /* Restore the original MTU value */ + if (iface->mtu && iface->previous_mtu != iface->mtu) + { + set_mtu (iface->name, iface->mtu); + iface->previous_mtu = iface->mtu; + } #ifdef ENABLE_INFO - /* If we haven't created an info file, do so now */ - if (! dhcp->frominfo) - write_info (iface, dhcp, options, false); -#endif - - /* Only reset things if we had set them before */ - if (iface->previous_address.s_addr != 0) { - if (! options->keep_address) { - del_address (iface->name, - iface->previous_address, - iface->previous_netmask); - memset (&iface->previous_address, - 0, sizeof (iface->previous_address)); - memset (&iface->previous_netmask, - 0, sizeof (iface->previous_netmask)); - } - } - - restore_resolv (iface->name); - exec_script (options->script, iface->infofile, "down"); - - return (0); - } - - /* Set the MTU requested. - * If the DHCP server no longer sends one OR it's invalid then - * we restore the original MTU */ - if (options->domtu) { - unsigned short mtu = iface->mtu; - if (dhcp->mtu) - mtu = dhcp->mtu; - - if (mtu != iface->previous_mtu) { - if (set_mtu (iface->name, mtu) == 0) - iface->previous_mtu = mtu; - } - } - - /* This also changes netmask */ - if (! options->doinform || ! has_address (iface->name, dhcp->address)) - if (add_address (iface->name, dhcp->address, dhcp->netmask, - dhcp->broadcast) == -1 && errno != EEXIST) - return (false); - - /* Now delete the old address if different */ - if (iface->previous_address.s_addr != dhcp->address.s_addr && - iface->previous_address.s_addr != 0 && - ! options->keep_address) - del_address (iface->name, - iface->previous_address, iface->previous_netmask); + /* If we haven't created an info file, do so now */ + if (! dhcp->frominfo) + write_info (iface, dhcp, options, false); +#endif + + /* Only reset things if we had set them before */ + if (iface->previous_address.s_addr != 0) + { + if (! options->keep_address) + { + del_address (iface->name, + iface->previous_address, + iface->previous_netmask); + memset (&iface->previous_address, + 0, sizeof (iface->previous_address)); + memset (&iface->previous_netmask, + 0, sizeof (iface->previous_netmask)); + } + } + + restore_resolv (iface->name); + exec_script (options->script, iface->infofile, "down"); + + return (0); + } + + /* Set the MTU requested. + * If the DHCP server no longer sends one OR it's invalid then + * we restore the original MTU */ + if (options->domtu) + { + unsigned short mtu = iface->mtu; + if (dhcp->mtu) + mtu = dhcp->mtu; + + if (mtu != iface->previous_mtu) + { + if (set_mtu (iface->name, mtu) == 0) + iface->previous_mtu = mtu; + } + } + + /* This also changes netmask */ + if (! options->doinform || ! has_address (iface->name, dhcp->address)) + if (add_address (iface->name, dhcp->address, dhcp->netmask, + dhcp->broadcast) == -1 && errno != EEXIST) + return (false); + + /* Now delete the old address if different */ + if (iface->previous_address.s_addr != dhcp->address.s_addr && + iface->previous_address.s_addr != 0 && + ! options->keep_address) + del_address (iface->name, + iface->previous_address, iface->previous_netmask); #ifdef __linux__ - /* On linux, we need to change the subnet route to have our metric. */ - if (iface->previous_address.s_addr != dhcp->address.s_addr && - options->metric > 0 && - dhcp->netmask.s_addr != INADDR_BROADCAST) - { - struct in_addr td; - struct in_addr tg; - memset (&td, 0, sizeof (td)); - memset (&tg, 0, sizeof (tg)); - td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; - add_route (iface->name, td, dhcp->netmask, tg, options->metric); - del_route (iface->name, td, dhcp->netmask, tg, 0); - } + /* On linux, we need to change the subnet route to have our metric. */ + if (iface->previous_address.s_addr != dhcp->address.s_addr && + options->metric > 0 && + dhcp->netmask.s_addr != INADDR_BROADCAST) + { + struct in_addr td; + struct in_addr tg; + memset (&td, 0, sizeof (td)); + memset (&tg, 0, sizeof (tg)); + td.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; + add_route (iface->name, td, dhcp->netmask, tg, options->metric); + del_route (iface->name, td, dhcp->netmask, tg, 0); + } #endif #ifdef THERE_IS_NO_FORK - free (dhcpcd_skiproutes); - /* We can never have more than 255 routes. So we need space - * for 255 3 digit numbers and commas */ - skiplen = 255 * 4 + 1; - skipp = dhcpcd_skiproutes = xmalloc (sizeof (char) * skiplen); - *skipp = '\0'; + free (dhcpcd_skiproutes); + /* We can never have more than 255 routes. So we need space + * for 255 3 digit numbers and commas */ + skiplen = 255 * 4 + 1; + skipp = dhcpcd_skiproutes = xmalloc (sizeof (char) * skiplen); + *skipp = '\0'; #endif - /* Remember added routes */ - NSTAILQ_FOREACH (route, dhcp->routes, entries) { + /* Remember added routes */ + NSTAILQ_FOREACH (route, dhcp->routes, entries) + { #ifdef ENABLE_IPV4LL - /* Check if we have already got a link locale route dished - * out by the DHCP server */ - if (route->destination.s_addr == htonl (LINKLOCAL_ADDR) && - route->netmask.s_addr == htonl (LINKLOCAL_MASK)) - haslinklocal = true; -#endif - /* Don't set default routes if not asked to */ - if (route->destination.s_addr == 0 && - route->netmask.s_addr == 0 && - ! options->dogateway) - continue; - - remember = add_route (iface->name, route->destination, - route->netmask, route->gateway, - options->metric); - /* If we failed to add the route, we may have already added it - ourselves. If so, remember it again. */ - if (remember < 0 && in_routes (iface->previous_routes, route)) - remember = 1; - - if (remember >= 0) { - if (! new_routes) { - new_routes = xmalloc (sizeof (*new_routes)); - STAILQ_INIT (new_routes); - } - new_route = xmalloc (sizeof (route_t)); - memcpy (new_route, route, sizeof (*new_route)); - STAILQ_INSERT_TAIL (new_routes, new_route, entries); - } + /* Check if we have already got a link locale route dished + * out by the DHCP server */ + if (route->destination.s_addr == htonl (LINKLOCAL_ADDR) && + route->netmask.s_addr == htonl (LINKLOCAL_MASK)) + haslinklocal = true; +#endif + /* Don't set default routes if not asked to */ + if (route->destination.s_addr == 0 && + route->netmask.s_addr == 0 && + ! options->dogateway) + continue; + + remember = add_route (iface->name, route->destination, + route->netmask, route->gateway, + options->metric); + /* If we failed to add the route, we may have already added it + ourselves. If so, remember it again. */ + if (remember < 0 && in_routes (iface->previous_routes, route)) + remember = 1; + + if (remember >= 0) + { + if (! new_routes) + { + new_routes = xmalloc (sizeof (*new_routes)); + STAILQ_INIT (new_routes); + } + new_route = xmalloc (sizeof (route_t)); + memcpy (new_route, route, sizeof (*new_route)); + STAILQ_INSERT_TAIL (new_routes, new_route, entries); + } #ifdef THERE_IS_NO_FORK - /* If we have daemonised yet we need to record which routes - * we failed to add so we can skip them */ - else if (! options->daemonised) { - /* We can never have more than 255 / 4 routes, - * so 3 chars is plently */ - if (*skipp) - *skipp++ = ','; - skipp += snprintf (skipp, - dhcpcd_skiproutes + skiplen - skipp, - "%d", skip); - } - skip++; -#endif - } + /* If we have daemonised yet we need to record which routes + * we failed to add so we can skip them */ + else if (! options->daemonised) + { + /* We can never have more than 255 / 4 routes, + * so 3 chars is plently */ + if (*skipp) + *skipp++ = ','; + skipp += snprintf (skipp, + dhcpcd_skiproutes + skiplen - skipp, + "%d", skip); + } + skip++; +#endif + } #ifdef THERE_IS_NO_FORK - if (*dhcpcd_skiproutes) - *skipp = '\0'; - else { - free (dhcpcd_skiproutes); - dhcpcd_skiproutes = NULL; - } + if (*dhcpcd_skiproutes) + *skipp = '\0'; + else + { + free (dhcpcd_skiproutes); + dhcpcd_skiproutes = NULL; + } #endif #ifdef ENABLE_IPV4LL - /* Ensure we always add the link local route if we got a private - * address and isn't link local itself */ - if (options->doipv4ll && - ! haslinklocal && - IN_PRIVATE (ntohl (dhcp->address.s_addr))) - { - struct in_addr dest; - struct in_addr mask; - struct in_addr gate; - - dest.s_addr = htonl (LINKLOCAL_ADDR); - mask.s_addr = htonl (LINKLOCAL_MASK); - gate.s_addr = 0; - remember = add_route (iface->name, dest, mask, gate, - options->metric); - - if (remember >= 0) { - if (! new_routes) { - new_routes = xmalloc (sizeof (*new_routes)); - STAILQ_INIT (new_routes); - } - new_route = xmalloc (sizeof (*new_route)); - new_route->destination.s_addr = dest.s_addr; - new_route->netmask.s_addr = mask.s_addr; - new_route->gateway.s_addr = gate.s_addr; - STAILQ_INSERT_TAIL (new_routes, new_route, entries); - } - } -#endif - - if (iface->previous_routes) - free_route (iface->previous_routes); - iface->previous_routes = new_routes; - - logToQt(LOG_INFO, DHCPCD_WRITE, ""); - if (options->dodns && dhcp->dnsservers) - make_resolv(iface->name, dhcp); - else - logger (LOG_DEBUG, "no dns information to write"); + /* Ensure we always add the link local route if we got a private + * address and isn't link local itself */ + if (options->doipv4ll && + ! haslinklocal && + IN_PRIVATE (ntohl (dhcp->address.s_addr))) + { + struct in_addr dest; + struct in_addr mask; + struct in_addr gate; + + dest.s_addr = htonl (LINKLOCAL_ADDR); + mask.s_addr = htonl (LINKLOCAL_MASK); + gate.s_addr = 0; + remember = add_route (iface->name, dest, mask, gate, + options->metric); + + if (remember >= 0) + { + if (! new_routes) + { + new_routes = xmalloc (sizeof (*new_routes)); + STAILQ_INIT (new_routes); + } + new_route = xmalloc (sizeof (*new_route)); + new_route->destination.s_addr = dest.s_addr; + new_route->netmask.s_addr = mask.s_addr; + new_route->gateway.s_addr = gate.s_addr; + STAILQ_INSERT_TAIL (new_routes, new_route, entries); + } + } +#endif + + if (iface->previous_routes) + free_route (iface->previous_routes); + iface->previous_routes = new_routes; + + logToQt(LOG_INFO, DHCPCD_WRITE, ""); + if (options->dodns && dhcp->dnsservers) + make_resolv(iface->name, dhcp); + else + logger (LOG_DEBUG, "no dns information to write"); #ifdef ENABLE_NTP - if (options->dontp && dhcp->ntpservers) - make_ntp(iface->name, dhcp); + if (options->dontp && dhcp->ntpservers) + make_ntp(iface->name, dhcp); #endif #ifdef ENABLE_NIS - if (options->donis && (dhcp->nisservers || dhcp->nisdomain)) - make_nis(iface->name, dhcp); + if (options->donis && (dhcp->nisservers || dhcp->nisdomain)) + make_nis(iface->name, dhcp); #endif - curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); - *curhostname = '\0'; + curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); + *curhostname = '\0'; - gethostname (curhostname, MAXHOSTNAMELEN); - if (options->dohostname || - strlen (curhostname) == 0 || - strcmp (curhostname, "(none)") == 0 || - strcmp (curhostname, "localhost") == 0) - { - newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); + gethostname (curhostname, MAXHOSTNAMELEN); + if (options->dohostname || + strlen (curhostname) == 0 || + strcmp (curhostname, "(none)") == 0 || + strcmp (curhostname, "localhost") == 0) + { + newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); - if (dhcp->hostname) - strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN); - else - *newhostname = '\0'; + if (dhcp->hostname) + strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN); + else + *newhostname = '\0'; - /* Now we have made a resolv.conf we can obtain a hostname - * if we need it */ - if (! *newhostname || options->dohostname > 3) - lookuphostname (newhostname, dhcp, options); + /* Now we have made a resolv.conf we can obtain a hostname + * if we need it */ + if (! *newhostname || options->dohostname > 3) + lookuphostname (newhostname, dhcp, options); - if (*newhostname) { - logger (LOG_INFO, "setting hostname to `%s'", - newhostname); - sethostname (newhostname, (int) strlen (newhostname)); - } + if (*newhostname) + { + logger (LOG_INFO, "setting hostname to `%s'", + newhostname); + sethostname (newhostname, (int) strlen (newhostname)); + } - free (newhostname); - } + free (newhostname); + } - free (curhostname); + free (curhostname); #ifdef ENABLE_INFO - if (! dhcp->frominfo) - write_info (iface, dhcp, options, true); -#endif - - if (iface->previous_address.s_addr != dhcp->address.s_addr || - iface->previous_netmask.s_addr != dhcp->netmask.s_addr) - { - memcpy (&iface->previous_address, - &dhcp->address, sizeof (iface->previous_address)); - memcpy (&iface->previous_netmask, - &dhcp->netmask, sizeof (iface->previous_netmask)); - exec_script (options->script, iface->infofile, "new"); - } else - exec_script (options->script, iface->infofile, "up"); - - return (0); + if (! dhcp->frominfo) + write_info (iface, dhcp, options, true); +#endif + + if (iface->previous_address.s_addr != dhcp->address.s_addr || + iface->previous_netmask.s_addr != dhcp->netmask.s_addr) + { + memcpy (&iface->previous_address, + &dhcp->address, sizeof (iface->previous_address)); + memcpy (&iface->previous_netmask, + &dhcp->netmask, sizeof (iface->previous_netmask)); + exec_script (options->script, iface->infofile, "new"); + } + else + exec_script (options->script, iface->infofile, "up"); + + return (0); } diff --git a/src/customdhcpcd/configure.h b/src/customdhcpcd/configure.h index 3166947..09ab1e0 100644 --- a/src/customdhcpcd/configure.h +++ b/src/customdhcpcd/configure.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -33,6 +33,6 @@ #include "dhcp.h" int configure (const options_t *options, interface_t *iface, - const dhcp_t *dhcp, bool up); + const dhcp_t *dhcp, bool up); #endif diff --git a/src/customdhcpcd/dhcp.c b/src/customdhcpcd/dhcp.c index f625e8f..7c41ad2 100644 --- a/src/customdhcpcd/dhcp.c +++ b/src/customdhcpcd/dhcp.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -61,492 +61,528 @@ } while (0) #endif -typedef struct message { - int value; - const char *name; +typedef struct message +{ + int value; + const char *name; } dhcp_message_t; -static dhcp_message_t dhcp_messages[] = { - { DHCP_DISCOVER, "DHCP_DISCOVER" }, - { DHCP_OFFER, "DHCP_OFFER" }, - { DHCP_REQUEST, "DHCP_REQUEST" }, - { DHCP_DECLINE, "DHCP_DECLINE" }, - { DHCP_ACK, "DHCP_ACK" }, - { DHCP_NAK, "DHCP_NAK" }, - { DHCP_RELEASE, "DHCP_RELEASE" }, - { DHCP_INFORM, "DHCP_INFORM" }, - { -1, NULL } +static dhcp_message_t dhcp_messages[] = +{ + { DHCP_DISCOVER, "DHCP_DISCOVER" }, + { DHCP_OFFER, "DHCP_OFFER" }, + { DHCP_REQUEST, "DHCP_REQUEST" }, + { DHCP_DECLINE, "DHCP_DECLINE" }, + { DHCP_ACK, "DHCP_ACK" }, + { DHCP_NAK, "DHCP_NAK" }, + { DHCP_RELEASE, "DHCP_RELEASE" }, + { DHCP_INFORM, "DHCP_INFORM" }, + { -1, NULL } }; static const char *dhcp_message (int type) { - dhcp_message_t *d; - for (d = dhcp_messages; d->name; d++) - if (d->value == type) - return (d->name); + dhcp_message_t *d; + for (d = dhcp_messages; d->name; d++) + if (d->value == type) + return (d->name); - return (NULL); + return (NULL); } ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, - uint32_t xid, char type, const options_t *options) + uint32_t xid, char type, const options_t *options) { - struct udp_dhcp_packet *packet; - dhcpmessage_t *message; - unsigned char *m; - unsigned char *p; - unsigned char *n_params = NULL; - size_t l; - struct in_addr from; - struct in_addr to; - time_t up = uptime() - iface->start_uptime; - uint32_t ul; - uint16_t sz; - size_t message_length; - ssize_t retval; - - if (!iface || !options || !dhcp) - return -1; - - memset (&from, 0, sizeof (from)); - memset (&to, 0, sizeof (to)); - - if (type == DHCP_RELEASE) - to.s_addr = dhcp->serveraddress.s_addr; - - message = xzalloc (sizeof (*message)); - m = (unsigned char *) message; - p = (unsigned char *) &message->options; - - if ((type == DHCP_INFORM || - type == DHCP_RELEASE || - type == DHCP_REQUEST) && - ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) - { - message->ciaddr = iface->previous_address.s_addr; - from.s_addr = iface->previous_address.s_addr; - - /* Just incase we haven't actually configured the address yet */ - if (type == DHCP_INFORM && iface->previous_address.s_addr == 0) - message->ciaddr = dhcp->address.s_addr; - - /* Zero the address if we're currently on a different subnet */ - if (type == DHCP_REQUEST && - iface->previous_netmask.s_addr != dhcp->netmask.s_addr) - message->ciaddr = from.s_addr = 0; - - if (from.s_addr != 0) - to.s_addr = dhcp->serveraddress.s_addr; - } - - message->op = DHCP_BOOTREQUEST; - message->hwtype = iface->family; - switch (iface->family) { - case ARPHRD_ETHER: - case ARPHRD_IEEE802: - message->hwlen = ETHER_ADDR_LEN; - memcpy (&message->chaddr, &iface->hwaddr, - ETHER_ADDR_LEN); - break; - case ARPHRD_IEEE1394: - case ARPHRD_INFINIBAND: - message->hwlen = 0; - if (message->ciaddr == 0) - message->flags = htons (BROADCAST_FLAG); - break; - default: - logger (LOG_ERR, "dhcp: unknown hardware type %d", - iface->family); - } - - if (up < 0 || up > (time_t) UINT16_MAX) - message->secs = htons ((uint16_t) UINT16_MAX); - else - message->secs = htons (up); - message->xid = xid; - message->cookie = htonl (MAGIC_COOKIE); - - *p++ = DHCP_MESSAGETYPE; - *p++ = 1; - *p++ = type; - - if (type == DHCP_REQUEST) { - *p++ = DHCP_MAXMESSAGESIZE; - *p++ = 2; - sz = get_mtu (iface->name); - if (sz < MTU_MIN) { - if (set_mtu (iface->name, MTU_MIN) == 0) - sz = MTU_MIN; - } - sz = htons (sz); - memcpy (p, &sz, 2); - p += 2; - } - - *p++ = DHCP_CLIENTID; - *p++ = iface->clientid_len; - memcpy (p, iface->clientid, iface->clientid_len); - p+= iface->clientid_len; - - if (type != DHCP_DECLINE && type != DHCP_RELEASE) { - if (options->userclass_len > 0) { - *p++ = DHCP_USERCLASS; - *p++ = options->userclass_len; - memcpy (p, &options->userclass, options->userclass_len); - p += options->userclass_len; - } - - if (*options->classid > 0) { - *p++ = DHCP_CLASSID; - *p++ = l = strlen (options->classid); - memcpy (p, options->classid, l); - p += l; - } - } - - if (type == DHCP_DISCOVER || type == DHCP_REQUEST) { + struct udp_dhcp_packet *packet; + dhcpmessage_t *message; + unsigned char *m; + unsigned char *p; + unsigned char *n_params = NULL; + size_t l; + struct in_addr from; + struct in_addr to; + time_t up = uptime() - iface->start_uptime; + uint32_t ul; + uint16_t sz; + size_t message_length; + ssize_t retval; + + if (!iface || !options || !dhcp) + return -1; + + memset (&from, 0, sizeof (from)); + memset (&to, 0, sizeof (to)); + + if (type == DHCP_RELEASE) + to.s_addr = dhcp->serveraddress.s_addr; + + message = xzalloc (sizeof (*message)); + m = (unsigned char *) message; + p = (unsigned char *) &message->options; + + if ((type == DHCP_INFORM || + type == DHCP_RELEASE || + type == DHCP_REQUEST) && + ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) + { + message->ciaddr = iface->previous_address.s_addr; + from.s_addr = iface->previous_address.s_addr; + + /* Just incase we haven't actually configured the address yet */ + if (type == DHCP_INFORM && iface->previous_address.s_addr == 0) + message->ciaddr = dhcp->address.s_addr; + + /* Zero the address if we're currently on a different subnet */ + if (type == DHCP_REQUEST && + iface->previous_netmask.s_addr != dhcp->netmask.s_addr) + message->ciaddr = from.s_addr = 0; + + if (from.s_addr != 0) + to.s_addr = dhcp->serveraddress.s_addr; + } + + message->op = DHCP_BOOTREQUEST; + message->hwtype = iface->family; + switch (iface->family) + { + case ARPHRD_ETHER: + case ARPHRD_IEEE802: + message->hwlen = ETHER_ADDR_LEN; + memcpy (&message->chaddr, &iface->hwaddr, + ETHER_ADDR_LEN); + break; + case ARPHRD_IEEE1394: + case ARPHRD_INFINIBAND: + message->hwlen = 0; + if (message->ciaddr == 0) + message->flags = htons (BROADCAST_FLAG); + break; + default: + logger (LOG_ERR, "dhcp: unknown hardware type %d", + iface->family); + } + + if (up < 0 || up > (time_t) UINT16_MAX) + message->secs = htons ((uint16_t) UINT16_MAX); + else + message->secs = htons (up); + message->xid = xid; + message->cookie = htonl (MAGIC_COOKIE); + + *p++ = DHCP_MESSAGETYPE; + *p++ = 1; + *p++ = type; + + if (type == DHCP_REQUEST) + { + *p++ = DHCP_MAXMESSAGESIZE; + *p++ = 2; + sz = get_mtu (iface->name); + if (sz < MTU_MIN) + { + if (set_mtu (iface->name, MTU_MIN) == 0) + sz = MTU_MIN; + } + sz = htons (sz); + memcpy (p, &sz, 2); + p += 2; + } + + *p++ = DHCP_CLIENTID; + *p++ = iface->clientid_len; + memcpy (p, iface->clientid, iface->clientid_len); + p += iface->clientid_len; + + if (type != DHCP_DECLINE && type != DHCP_RELEASE) + { + if (options->userclass_len > 0) + { + *p++ = DHCP_USERCLASS; + *p++ = options->userclass_len; + memcpy (p, &options->userclass, options->userclass_len); + p += options->userclass_len; + } + + if (*options->classid > 0) + { + *p++ = DHCP_CLASSID; + *p++ = l = strlen (options->classid); + memcpy (p, options->classid, l); + p += l; + } + } + + if (type == DHCP_DISCOVER || type == DHCP_REQUEST) + { #define PUTADDR(_type, _val) { \ *p++ = _type; \ *p++ = 4; \ memcpy (p, &_val.s_addr, 4); \ p += 4; \ } - if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) - logger (LOG_ERR, - "cannot request a link local address"); - else { - if (dhcp->address.s_addr && - dhcp->address.s_addr != - iface->previous_address.s_addr) - { - PUTADDR (DHCP_ADDRESS, dhcp->address); - if (dhcp->serveraddress.s_addr) - PUTADDR (DHCP_SERVERIDENTIFIER, - dhcp->serveraddress); - } - } + if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) + logger (LOG_ERR, + "cannot request a link local address"); + else + { + if (dhcp->address.s_addr && + dhcp->address.s_addr != + iface->previous_address.s_addr) + { + PUTADDR (DHCP_ADDRESS, dhcp->address); + if (dhcp->serveraddress.s_addr) + PUTADDR (DHCP_SERVERIDENTIFIER, + dhcp->serveraddress); + } + } #undef PUTADDR - if (options->leasetime != 0) { - *p++ = DHCP_LEASETIME; - *p++ = 4; - ul = htonl (options->leasetime); - memcpy (p, &ul, 4); - p += 4; - } - } - - if (type == DHCP_DISCOVER || - type == DHCP_INFORM || - type == DHCP_REQUEST) - { - if (options->hostname[0]) { - if (options->fqdn == FQDN_DISABLE) { - *p++ = DHCP_HOSTNAME; - *p++ = l = strlen (options->hostname); - memcpy (p, options->hostname, l); - p += l; - } else { - /* Draft IETF DHC-FQDN option (81) */ - *p++ = DHCP_FQDN; - *p++ = (l = strlen (options->hostname)) + 3; - /* Flags: 0000NEOS - * S: 1 => Client requests Server to update - * a RR in DNS as well as PTR - * O: 1 => Server indicates to client that - * DNS has been updated - * E: 1 => Name data is DNS format - * N: 1 => Client requests Server to not - * update DNS - */ - *p++ = options->fqdn & 0x9; - *p++ = 0; /* from server for PTR RR */ - *p++ = 0; /* from server for A RR if S=1 */ - memcpy (p, options->hostname, l); - p += l; - } - } - - *p++ = DHCP_PARAMETERREQUESTLIST; - n_params = p; - *p++ = 0; - /* Only request DNSSERVER in discover to keep the packets small. - * RFC2131 Section 3.5 states that the REQUEST must include the - * list from the DISCOVER message, so I think this is ok. */ - - if (type == DHCP_DISCOVER && ! options->test) - *p++ = DHCP_DNSSERVER; - else { - if (type != DHCP_INFORM) { - *p++ = DHCP_RENEWALTIME; - *p++ = DHCP_REBINDTIME; - } - *p++ = DHCP_NETMASK; - *p++ = DHCP_BROADCAST; - - /* -S means request CSR and MSCSR - * -SS means only request MSCSR incase DHCP message - * is too big */ - if (options->domscsr < 2) - *p++ = DHCP_CSR; - if (options->domscsr > 0) - *p++ = DHCP_MSCSR; - /* RFC 3442 states classless static routes should be - * before routers and static routes as classless static - * routes override them both */ - *p++ = DHCP_STATICROUTE; - *p++ = DHCP_ROUTERS; - *p++ = DHCP_HOSTNAME; - *p++ = DHCP_DNSSEARCH; - *p++ = DHCP_DNSDOMAIN; - *p++ = DHCP_DNSSERVER; + if (options->leasetime != 0) + { + *p++ = DHCP_LEASETIME; + *p++ = 4; + ul = htonl (options->leasetime); + memcpy (p, &ul, 4); + p += 4; + } + } + + if (type == DHCP_DISCOVER || + type == DHCP_INFORM || + type == DHCP_REQUEST) + { + if (options->hostname[0]) + { + if (options->fqdn == FQDN_DISABLE) + { + *p++ = DHCP_HOSTNAME; + *p++ = l = strlen (options->hostname); + memcpy (p, options->hostname, l); + p += l; + } + else + { + /* Draft IETF DHC-FQDN option (81) */ + *p++ = DHCP_FQDN; + *p++ = (l = strlen (options->hostname)) + 3; + /* Flags: 0000NEOS + * S: 1 => Client requests Server to update + * a RR in DNS as well as PTR + * O: 1 => Server indicates to client that + * DNS has been updated + * E: 1 => Name data is DNS format + * N: 1 => Client requests Server to not + * update DNS + */ + *p++ = options->fqdn & 0x9; + *p++ = 0; /* from server for PTR RR */ + *p++ = 0; /* from server for A RR if S=1 */ + memcpy (p, options->hostname, l); + p += l; + } + } + + *p++ = DHCP_PARAMETERREQUESTLIST; + n_params = p; + *p++ = 0; + /* Only request DNSSERVER in discover to keep the packets small. + * RFC2131 Section 3.5 states that the REQUEST must include the + * list from the DISCOVER message, so I think this is ok. */ + + if (type == DHCP_DISCOVER && ! options->test) + *p++ = DHCP_DNSSERVER; + else + { + if (type != DHCP_INFORM) + { + *p++ = DHCP_RENEWALTIME; + *p++ = DHCP_REBINDTIME; + } + *p++ = DHCP_NETMASK; + *p++ = DHCP_BROADCAST; + + /* -S means request CSR and MSCSR + * -SS means only request MSCSR incase DHCP message + * is too big */ + if (options->domscsr < 2) + *p++ = DHCP_CSR; + if (options->domscsr > 0) + *p++ = DHCP_MSCSR; + /* RFC 3442 states classless static routes should be + * before routers and static routes as classless static + * routes override them both */ + *p++ = DHCP_STATICROUTE; + *p++ = DHCP_ROUTERS; + *p++ = DHCP_HOSTNAME; + *p++ = DHCP_DNSSEARCH; + *p++ = DHCP_DNSDOMAIN; + *p++ = DHCP_DNSSERVER; #ifdef ENABLE_NIS - *p++ = DHCP_NISDOMAIN; - *p++ = DHCP_NISSERVER; + *p++ = DHCP_NISDOMAIN; + *p++ = DHCP_NISSERVER; #endif #ifdef ENABLE_NTP - *p++ = DHCP_NTPSERVER; + *p++ = DHCP_NTPSERVER; #endif - *p++ = DHCP_MTU; + *p++ = DHCP_MTU; #ifdef ENABLE_INFO - *p++ = DHCP_ROOTPATH; - *p++ = DHCP_SIPSERVER; + *p++ = DHCP_ROOTPATH; + *p++ = DHCP_SIPSERVER; #endif - } + } - *n_params = p - n_params - 1; - } - *p++ = DHCP_END; + *n_params = p - n_params - 1; + } + *p++ = DHCP_END; #ifdef BOOTP_MESSAGE_LENTH_MIN - /* Some crappy DHCP servers think they have to obey the BOOTP minimum - * message length. - * They are wrong, but we should still cater for them. */ - while (p - m < BOOTP_MESSAGE_LENTH_MIN) - *p++ = DHCP_PAD; + /* Some crappy DHCP servers think they have to obey the BOOTP minimum + * message length. + * They are wrong, but we should still cater for them. */ + while (p - m < BOOTP_MESSAGE_LENTH_MIN) + *p++ = DHCP_PAD; #endif - message_length = p - m; + message_length = p - m; - packet = xzalloc (sizeof (*packet)); - make_dhcp_packet (packet, (unsigned char *) message, message_length, - from, to); - free (message); + packet = xzalloc (sizeof (*packet)); + make_dhcp_packet (packet, (unsigned char *) message, message_length, + from, to); + free (message); - logger (LOG_DEBUG, "sending %s with xid 0x%x", - dhcp_message (type), xid); - retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet, - message_length + - sizeof (packet->ip) + sizeof (packet->udp)); - free (packet); - return (retval); + logger (LOG_DEBUG, "sending %s with xid 0x%x", + dhcp_message (type), xid); + retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet, + message_length + + sizeof (packet->ip) + sizeof (packet->udp)); + free (packet); + return (retval); } /* Decode an RFC3397 DNS search order option into a space - * seperated string. Returns length of string (including + * seperated string. Returns length of string (including * terminating zero) or zero on error. out may be NULL * to just determine output length. */ static unsigned int decode_search (const unsigned char *p, int len, char *out) { - const unsigned char *r, *q = p; - unsigned int count = 0, l, hops; - - while (q - p < len) { - r = NULL; - hops = 0; - while ((l = *q++)) { - unsigned int label_type = l & 0xc0; - if (label_type == 0x80 || label_type == 0x40) - return 0; - else if (label_type == 0xc0) { /* pointer */ - l = (l & 0x3f) << 8; - l |= *q++; - - /* save source of first jump. */ - if (!r) - r = q; - - hops++; - if (hops > 255) - return 0; - - q = p + l; - if (q - p >= len) - return 0; - } else { - /* straightforward name segment, add with '.' */ - count += l + 1; - if (out) { - memcpy (out, q, l); - out += l; - *out++ = '.'; - } - q += l; - } - } - - /* change last dot to space */ - if (out) - *(out - 1) = ' '; - - if (r) - q = r; - } - - /* change last space to zero terminator */ - if (out) - *(out - 1) = 0; - - return count; + const unsigned char *r, *q = p; + unsigned int count = 0, l, hops; + + while (q - p < len) + { + r = NULL; + hops = 0; + while ((l = *q++)) + { + unsigned int label_type = l & 0xc0; + if (label_type == 0x80 || label_type == 0x40) + return 0; + else if (label_type == 0xc0) /* pointer */ + { + l = (l & 0x3f) << 8; + l |= *q++; + + /* save source of first jump. */ + if (!r) + r = q; + + hops++; + if (hops > 255) + return 0; + + q = p + l; + if (q - p >= len) + return 0; + } + else + { + /* straightforward name segment, add with '.' */ + count += l + 1; + if (out) + { + memcpy (out, q, l); + out += l; + *out++ = '.'; + } + q += l; + } + } + + /* change last dot to space */ + if (out) + *(out - 1) = ' '; + + if (r) + q = r; + } + + /* change last space to zero terminator */ + if (out) + *(out - 1) = 0; + + return count; } /* Add our classless static routes to the routes variable * and return the last route set */ static struct route_head *decode_CSR (const unsigned char *p, int len) { - const unsigned char *q = p; - unsigned int cidr; - unsigned int ocets; - struct route_head *routes = NULL; - route_t *route; - - /* Minimum is 5 -first is CIDR and a router length of 4 */ - if (len < 5) - return NULL; - - while (q - p < len) { - if (! routes) { - routes = xmalloc (sizeof (*routes)); - STAILQ_INIT (routes); - } - - route = xzalloc (sizeof (*route)); - - cidr = *q++; - if (cidr > 32) { - logger (LOG_ERR, - "invalid CIDR of %d in classless static route", - cidr); - free_route (routes); - return (NULL); - } - ocets = (cidr + 7) / 8; - - if (ocets > 0) { - memcpy (&route->destination.s_addr, q, (size_t) ocets); - q += ocets; - } - - /* Now enter the netmask */ - if (ocets > 0) { - memset (&route->netmask.s_addr, 255, (size_t) ocets - 1); - memset ((unsigned char *) &route->netmask.s_addr + - (ocets - 1), - (256 - (1 << (32 - cidr) % 8)), 1); - } - - /* Finally, snag the router */ - memcpy (&route->gateway.s_addr, q, 4); - q += 4; - - STAILQ_INSERT_TAIL (routes, route, entries); - } - - return (routes); + const unsigned char *q = p; + unsigned int cidr; + unsigned int ocets; + struct route_head *routes = NULL; + route_t *route; + + /* Minimum is 5 -first is CIDR and a router length of 4 */ + if (len < 5) + return NULL; + + while (q - p < len) + { + if (! routes) + { + routes = xmalloc (sizeof (*routes)); + STAILQ_INIT (routes); + } + + route = xzalloc (sizeof (*route)); + + cidr = *q++; + if (cidr > 32) + { + logger (LOG_ERR, + "invalid CIDR of %d in classless static route", + cidr); + free_route (routes); + return (NULL); + } + ocets = (cidr + 7) / 8; + + if (ocets > 0) + { + memcpy (&route->destination.s_addr, q, (size_t) ocets); + q += ocets; + } + + /* Now enter the netmask */ + if (ocets > 0) + { + memset (&route->netmask.s_addr, 255, (size_t) ocets - 1); + memset ((unsigned char *) &route->netmask.s_addr + + (ocets - 1), + (256 - (1 << (32 - cidr) % 8)), 1); + } + + /* Finally, snag the router */ + memcpy (&route->gateway.s_addr, q, 4); + q += 4; + + STAILQ_INSERT_TAIL (routes, route, entries); + } + + return (routes); } void free_dhcp (dhcp_t *dhcp) { - if (! dhcp) - return; - - free_route (dhcp->routes); - free (dhcp->hostname); - free_address (dhcp->dnsservers); - free (dhcp->dnsdomain); - free (dhcp->dnssearch); - free_address (dhcp->ntpservers); - free (dhcp->nisdomain); - free_address (dhcp->nisservers); - free (dhcp->rootpath); - free (dhcp->sipservers); - if (dhcp->fqdn) { - free (dhcp->fqdn->name); - free (dhcp->fqdn); - } + if (! dhcp) + return; + + free_route (dhcp->routes); + free (dhcp->hostname); + free_address (dhcp->dnsservers); + free (dhcp->dnsdomain); + free (dhcp->dnssearch); + free_address (dhcp->ntpservers); + free (dhcp->nisdomain); + free_address (dhcp->nisservers); + free (dhcp->rootpath); + free (dhcp->sipservers); + if (dhcp->fqdn) + { + free (dhcp->fqdn->name); + free (dhcp->fqdn); + } } static bool dhcp_add_address (struct address_head **addresses, - const unsigned char *data, - int length) + const unsigned char *data, + int length) { - int i; - address_t *address; - - for (i = 0; i < length; i += 4) { - /* Sanity check */ - if (i + 4 > length) { - logger (LOG_ERR, "invalid address length"); - return (false); - } - - if (*addresses == NULL) { - *addresses = xmalloc (sizeof (**addresses)); - STAILQ_INIT (*addresses); - } - address = xzalloc (sizeof (*address)); - memcpy (&address->address.s_addr, data + i, 4); - STAILQ_INSERT_TAIL (*addresses, address, entries); - } - - return (true); + int i; + address_t *address; + + for (i = 0; i < length; i += 4) + { + /* Sanity check */ + if (i + 4 > length) + { + logger (LOG_ERR, "invalid address length"); + return (false); + } + + if (*addresses == NULL) + { + *addresses = xmalloc (sizeof (**addresses)); + STAILQ_INIT (*addresses); + } + address = xzalloc (sizeof (*address)); + memcpy (&address->address.s_addr, data + i, 4); + STAILQ_INSERT_TAIL (*addresses, address, entries); + } + + return (true); } #ifdef ENABLE_INFO static char *decode_sipservers (const unsigned char *data, int length) { - char *sip = NULL; - char *p; - const char encoding = *data++; - struct in_addr addr; - size_t len; - - length--; - - switch (encoding) { - case 0: - if ((len = decode_search (data, length, NULL)) > 0) { - sip = xmalloc (len); - decode_search (data, length, sip); - } - break; - - case 1: - if (length == 0 || length % 4 != 0) { - logger (LOG_ERR, - "invalid length %d for option 120", - length + 1); - break; - } - len = ((length / 4) * (4 * 4)) + 1; - sip = p = xmalloc (len); - while (length != 0) { - memcpy (&addr.s_addr, data, 4); - data += 4; - p += snprintf (p, len - (p - sip), - "%s ", inet_ntoa (addr)); - length -= 4; - } - *--p = '\0'; - break; - - default: - logger (LOG_ERR, "unknown sip encoding %d", encoding); - break; - } - - return (sip); + char *sip = NULL; + char *p; + const char encoding = *data++; + struct in_addr addr; + size_t len; + + length--; + + switch (encoding) + { + case 0: + if ((len = decode_search (data, length, NULL)) > 0) + { + sip = xmalloc (len); + decode_search (data, length, sip); + } + break; + + case 1: + if (length == 0 || length % 4 != 0) + { + logger (LOG_ERR, + "invalid length %d for option 120", + length + 1); + break; + } + len = ((length / 4) * (4 * 4)) + 1; + sip = p = xmalloc (len); + while (length != 0) + { + memcpy (&addr.s_addr, data, 4); + data += 4; + p += snprintf (p, len - (p - sip), + "%s ", inet_ntoa (addr)); + length -= 4; + } + *--p = '\0'; + break; + + default: + logger (LOG_ERR, "unknown sip encoding %d", encoding); + break; + } + + return (sip); } #endif @@ -555,100 +591,107 @@ static char *decode_sipservers (const unsigned char *data, int length) * for an interface address. */ static uint32_t route_netmask (uint32_t ip_in) { - /* used to be unsigned long - check if error */ - uint32_t p = ntohl (ip_in); - uint32_t t; - - if (IN_CLASSA (p)) - t = ~IN_CLASSA_NET; - else { - if (IN_CLASSB (p)) - t = ~IN_CLASSB_NET; - else { - if (IN_CLASSC (p)) - t = ~IN_CLASSC_NET; - else - t = 0; - } - } - - while (t & p) - t >>= 1; - - return (htonl (~t)); + /* used to be unsigned long - check if error */ + uint32_t p = ntohl (ip_in); + uint32_t t; + + if (IN_CLASSA (p)) + t = ~IN_CLASSA_NET; + else + { + if (IN_CLASSB (p)) + t = ~IN_CLASSB_NET; + else + { + if (IN_CLASSC (p)) + t = ~IN_CLASSC_NET; + else + t = 0; + } + } + + while (t & p) + t >>= 1; + + return (htonl (~t)); } static struct route_head *decode_routes (const unsigned char *data, int length) { - int i; - struct route_head *head = NULL; - route_t *route; - - for (i = 0; i < length; i += 8) { - if (! head) { - head = xmalloc (sizeof (*head)); - STAILQ_INIT (head); - } - route = xzalloc (sizeof (*route)); - memcpy (&route->destination.s_addr, data + i, 4); - memcpy (&route->gateway.s_addr, data + i + 4, 4); - route->netmask.s_addr = - route_netmask (route->destination.s_addr); - STAILQ_INSERT_TAIL (head, route, entries); - } - - return (head); + int i; + struct route_head *head = NULL; + route_t *route; + + for (i = 0; i < length; i += 8) + { + if (! head) + { + head = xmalloc (sizeof (*head)); + STAILQ_INIT (head); + } + route = xzalloc (sizeof (*route)); + memcpy (&route->destination.s_addr, data + i, 4); + memcpy (&route->gateway.s_addr, data + i + 4, 4); + route->netmask.s_addr = + route_netmask (route->destination.s_addr); + STAILQ_INSERT_TAIL (head, route, entries); + } + + return (head); } static struct route_head *decode_routers (const unsigned char *data, int length) { - int i; - struct route_head *head = NULL; - route_t *route = NULL; - - for (i = 0; i < length; i += 4) { - if (! head) { - head = xmalloc (sizeof (*head)); - STAILQ_INIT (head); - } - route = xzalloc (sizeof (*route)); - memcpy (&route->gateway.s_addr, data + i, 4); - STAILQ_INSERT_TAIL (head, route, entries); - } - - return (head); + int i; + struct route_head *head = NULL; + route_t *route = NULL; + + for (i = 0; i < length; i += 4) + { + if (! head) + { + head = xmalloc (sizeof (*head)); + STAILQ_INIT (head); + } + route = xzalloc (sizeof (*route)); + memcpy (&route->gateway.s_addr, data + i, 4); + STAILQ_INSERT_TAIL (head, route, entries); + } + + return (head); } int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message) { - const unsigned char *p = message->options; - const unsigned char *end = p; /* Add size later for gcc-3 issue */ - unsigned char option; - unsigned char length; - unsigned int len = 0; - int retval = -1; - struct timeval tv; - struct route_head *routers = NULL; - struct route_head *routes = NULL; - struct route_head *csr = NULL; - struct route_head *mscsr = NULL; - bool in_overload = false; - bool parse_sname = false; - bool parse_file = false; - - end += sizeof (message->options); - - if (gettimeofday (&tv, NULL) == -1) { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return (-1); - } - - dhcp->address.s_addr = message->yiaddr; - dhcp->leasedfrom = tv.tv_sec; - dhcp->frominfo = false; - dhcp->address.s_addr = message->yiaddr; - strlcpy (dhcp->servername, (char *) message->servername, - sizeof (dhcp->servername)); + const unsigned char *p = message->options; + const unsigned char *end = p; /* Add size later for gcc-3 issue */ + unsigned char option; + unsigned char length; + unsigned int len = 0; + int retval = -1; + struct timeval tv; + struct route_head *routers = NULL; + struct route_head *routes = NULL; + struct route_head *csr = NULL; + struct route_head *mscsr = NULL; + bool in_overload = false; + bool parse_sname = false; + bool parse_file = false; + + end += sizeof (message->options); + + if (gettimeofday (&tv, NULL) == -1) + { + logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); + return (-1); + } + + dhcp->address.s_addr = message->yiaddr; + dhcp->leasedfrom = tv.tv_sec; + dhcp->frominfo = false; + dhcp->address.s_addr = message->yiaddr; + strlcpy (dhcp->servername, (char *) message->servername, + sizeof (dhcp->servername)); #define LEN_ERR \ { \ @@ -659,42 +702,47 @@ int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message) } parse_start: - while (p < end) { - option = *p++; - if (! option) - continue; - - if (option == DHCP_END) - goto eexit; - - length = *p++; - - if (option != DHCP_PAD && length == 0) { - logger (LOG_ERR, "option %d has zero length", option); - retval = -1; - goto eexit; - } - - if (p + length >= end) { - logger (LOG_ERR, "dhcp option exceeds message length"); - retval = -1; - goto eexit; - } - - switch (option) { - case DHCP_MESSAGETYPE: - retval = (int) *p; - p += length; - continue; - - default: - if (length == 0) { - logger (LOG_DEBUG, - "option %d has zero length, skipping", - option); - continue; - } - } + while (p < end) + { + option = *p++; + if (! option) + continue; + + if (option == DHCP_END) + goto eexit; + + length = *p++; + + if (option != DHCP_PAD && length == 0) + { + logger (LOG_ERR, "option %d has zero length", option); + retval = -1; + goto eexit; + } + + if (p + length >= end) + { + logger (LOG_ERR, "dhcp option exceeds message length"); + retval = -1; + goto eexit; + } + + switch (option) + { + case DHCP_MESSAGETYPE: + retval = (int) * p; + p += length; + continue; + + default: + if (length == 0) + { + logger (LOG_DEBUG, + "option %d has zero length, skipping", + option); + continue; + } + } #define LENGTH(_length) \ if (length != _length) \ @@ -721,40 +769,42 @@ parse_start: GET_UINT32 (_val); \ _val = ntohl (_val); - switch (option) { - case DHCP_ADDRESS: - GET_UINT32 (dhcp->address.s_addr); - break; - case DHCP_NETMASK: - GET_UINT32 (dhcp->netmask.s_addr); - break; - case DHCP_BROADCAST: - GET_UINT32 (dhcp->broadcast.s_addr); - break; - case DHCP_SERVERIDENTIFIER: - GET_UINT32 (dhcp->serveraddress.s_addr); - break; - case DHCP_LEASETIME: - GET_UINT32_H (dhcp->leasetime); - break; - case DHCP_RENEWALTIME: - GET_UINT32_H (dhcp->renewaltime); - break; - case DHCP_REBINDTIME: - GET_UINT32_H (dhcp->rebindtime); - break; - case DHCP_MTU: - GET_UINT16_H (dhcp->mtu); - /* Minimum legal mtu is 68 accoridng to - * RFC 2132. In practise it's 576 which is the - * minimum maximum message size. */ - if (dhcp->mtu < MTU_MIN) { - logger (LOG_DEBUG, - "MTU %d is too low, minimum is %d; ignoring", - dhcp->mtu, MTU_MIN); - dhcp->mtu = 0; - } - break; + switch (option) + { + case DHCP_ADDRESS: + GET_UINT32 (dhcp->address.s_addr); + break; + case DHCP_NETMASK: + GET_UINT32 (dhcp->netmask.s_addr); + break; + case DHCP_BROADCAST: + GET_UINT32 (dhcp->broadcast.s_addr); + break; + case DHCP_SERVERIDENTIFIER: + GET_UINT32 (dhcp->serveraddress.s_addr); + break; + case DHCP_LEASETIME: + GET_UINT32_H (dhcp->leasetime); + break; + case DHCP_RENEWALTIME: + GET_UINT32_H (dhcp->renewaltime); + break; + case DHCP_REBINDTIME: + GET_UINT32_H (dhcp->rebindtime); + break; + case DHCP_MTU: + GET_UINT16_H (dhcp->mtu); + /* Minimum legal mtu is 68 accoridng to + * RFC 2132. In practise it's 576 which is the + * minimum maximum message size. */ + if (dhcp->mtu < MTU_MIN) + { + logger (LOG_DEBUG, + "MTU %d is too low, minimum is %d; ignoring", + dhcp->mtu, MTU_MIN); + dhcp->mtu = 0; + } + break; #undef GET_UINT32_H #undef GET_UINT32 @@ -769,24 +819,24 @@ parse_start: memcpy (_var, p, (size_t) length); \ memset (_var + length, 0, 1); \ } - case DHCP_HOSTNAME: - GETSTR (dhcp->hostname); - break; - case DHCP_DNSDOMAIN: - GETSTR (dhcp->dnsdomain); - break; - case DHCP_MESSAGE: - GETSTR (dhcp->message); - break; + case DHCP_HOSTNAME: + GETSTR (dhcp->hostname); + break; + case DHCP_DNSDOMAIN: + GETSTR (dhcp->dnsdomain); + break; + case DHCP_MESSAGE: + GETSTR (dhcp->message); + break; #ifdef ENABLE_INFO - case DHCP_ROOTPATH: - GETSTR (dhcp->rootpath); - break; + case DHCP_ROOTPATH: + GETSTR (dhcp->rootpath); + break; #endif #ifdef ENABLE_NIS - case DHCP_NISDOMAIN: - GETSTR (dhcp->nisdomain); - break; + case DHCP_NISDOMAIN: + GETSTR (dhcp->nisdomain); + break; #endif #undef GETSTR @@ -797,137 +847,147 @@ parse_start: retval = -1; \ goto eexit; \ } - case DHCP_DNSSERVER: - GETADDR (dhcp->dnsservers); - break; + case DHCP_DNSSERVER: + GETADDR (dhcp->dnsservers); + break; #ifdef ENABLE_NTP - case DHCP_NTPSERVER: - GETADDR (dhcp->ntpservers); - break; + case DHCP_NTPSERVER: + GETADDR (dhcp->ntpservers); + break; #endif #ifdef ENABLE_NIS - case DHCP_NISSERVER: - GETADDR (dhcp->nisservers); - break; + case DHCP_NISSERVER: + GETADDR (dhcp->nisservers); + break; #endif #undef GETADDR - case DHCP_DNSSEARCH: - MIN_LENGTH (1); - free (dhcp->dnssearch); - len = decode_search (p, length, NULL); - if (len > 0) { - dhcp->dnssearch = xmalloc (len); - decode_search (p, length, - dhcp->dnssearch); - } - break; - - case DHCP_CSR: - MIN_LENGTH (5); - free_route (csr); - csr = decode_CSR (p, length); - break; - - case DHCP_MSCSR: - MIN_LENGTH (5); - free_route (mscsr); - mscsr = decode_CSR (p, length); - break; + case DHCP_DNSSEARCH: + MIN_LENGTH (1); + free (dhcp->dnssearch); + len = decode_search (p, length, NULL); + if (len > 0) + { + dhcp->dnssearch = xmalloc (len); + decode_search (p, length, + dhcp->dnssearch); + } + break; + + case DHCP_CSR: + MIN_LENGTH (5); + free_route (csr); + csr = decode_CSR (p, length); + break; + + case DHCP_MSCSR: + MIN_LENGTH (5); + free_route (mscsr); + mscsr = decode_CSR (p, length); + break; #ifdef ENABLE_INFO - case DHCP_SIPSERVER: - free (dhcp->sipservers); - dhcp->sipservers = decode_sipservers (p,length); - break; + case DHCP_SIPSERVER: + free (dhcp->sipservers); + dhcp->sipservers = decode_sipservers (p, length); + break; #endif - case DHCP_STATICROUTE: - MULT_LENGTH (8); - free_route (routes); - routes = decode_routes (p, length); - break; - - case DHCP_ROUTERS: - MULT_LENGTH (4); - free_route (routers); - routers = decode_routers (p, length); - break; - - case DHCP_OPTIONSOVERLOADED: - LENGTH (1); - /* The overloaded option in an overloaded option - * should be ignored, overwise we may get an - * infinite loop */ - if (! in_overload) { - if (*p & 1) - parse_file = true; - if (*p & 2) - parse_sname = true; - } - break; - - case DHCP_FQDN: - /* We ignore replies about FQDN */ - break; + case DHCP_STATICROUTE: + MULT_LENGTH (8); + free_route (routes); + routes = decode_routes (p, length); + break; + + case DHCP_ROUTERS: + MULT_LENGTH (4); + free_route (routers); + routers = decode_routers (p, length); + break; + + case DHCP_OPTIONSOVERLOADED: + LENGTH (1); + /* The overloaded option in an overloaded option + * should be ignored, overwise we may get an + * infinite loop */ + if (! in_overload) + { + if (*p & 1) + parse_file = true; + if (*p & 2) + parse_sname = true; + } + break; + + case DHCP_FQDN: + /* We ignore replies about FQDN */ + break; #undef LENGTH #undef MIN_LENGTH #undef MULT_LENGTH - default: - logger (LOG_DEBUG, - "no facility to parse DHCP code %u", - option); - break; - } + default: + logger (LOG_DEBUG, + "no facility to parse DHCP code %u", + option); + break; + } - p += length; - } + p += length; + } eexit: - /* We may have options overloaded, so go back and grab them */ - if (parse_file) { - parse_file = false; - p = message->bootfile; - end = p + sizeof (message->bootfile); - in_overload = true; - goto parse_start; - } else if (parse_sname) { - parse_sname = false; - p = message->servername; - end = p + sizeof (message->servername); - memset (dhcp->servername, 0, sizeof (dhcp->servername)); - in_overload = true; - goto parse_start; - } - - /* Fill in any missing fields */ - if (! dhcp->netmask.s_addr) - dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); - if (! dhcp->broadcast.s_addr) - dhcp->broadcast.s_addr = dhcp->address.s_addr | - ~dhcp->netmask.s_addr; - - /* If we have classess static routes then we discard - * static routes and routers according to RFC 3442 */ - if (csr) { - dhcp->routes = csr; - free_route (mscsr); - free_route (routers); - free_route (routes); - } else if (mscsr) { - dhcp->routes = mscsr; - free_route (routers); - free_route (routes); - } else { - /* Ensure that we apply static routes before routers */ - if (! routes) - routes = routers; - else if (routers) - STAILQ_CONCAT (routes, routers); - dhcp->routes = routes; - } - - return (retval); + /* We may have options overloaded, so go back and grab them */ + if (parse_file) + { + parse_file = false; + p = message->bootfile; + end = p + sizeof (message->bootfile); + in_overload = true; + goto parse_start; + } + else if (parse_sname) + { + parse_sname = false; + p = message->servername; + end = p + sizeof (message->servername); + memset (dhcp->servername, 0, sizeof (dhcp->servername)); + in_overload = true; + goto parse_start; + } + + /* Fill in any missing fields */ + if (! dhcp->netmask.s_addr) + dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); + if (! dhcp->broadcast.s_addr) + dhcp->broadcast.s_addr = dhcp->address.s_addr | + ~dhcp->netmask.s_addr; + + /* If we have classess static routes then we discard + * static routes and routers according to RFC 3442 */ + if (csr) + { + dhcp->routes = csr; + free_route (mscsr); + free_route (routers); + free_route (routes); + } + else if (mscsr) + { + dhcp->routes = mscsr; + free_route (routers); + free_route (routes); + } + else + { + /* Ensure that we apply static routes before routers */ + if (! routes) + routes = routers; + else if (routers) + STAILQ_CONCAT (routes, routers); + dhcp->routes = routes; + } + + return (retval); } diff --git a/src/customdhcpcd/dhcp.h b/src/customdhcpcd/dhcp.h index ef97b75..019d3b3 100644 --- a/src/customdhcpcd/dhcp.h +++ b/src/customdhcpcd/dhcp.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -65,105 +65,106 @@ /* DHCP options */ enum DHCP_OPTIONS { - DHCP_PAD = 0, - DHCP_NETMASK = 1, - DHCP_TIMEROFFSET = 2, - DHCP_ROUTERS = 3, - DHCP_TIMESERVER = 4, - DHCP_NAMESERVER = 5, - DHCP_DNSSERVER = 6, - DHCP_LOGSERVER = 7, - DHCP_COOKIESERVER = 8, - DHCP_HOSTNAME = 12, - DHCP_DNSDOMAIN = 15, - DHCP_ROOTPATH = 17, - DHCP_DEFAULTIPTTL = 23, - DHCP_MTU = 26, - DHCP_BROADCAST = 28, - DHCP_MASKDISCOVERY = 29, - DHCP_ROUTERDISCOVERY = 31, - DHCP_STATICROUTE = 33, - DHCP_NISDOMAIN = 40, - DHCP_NISSERVER = 41, - DHCP_NTPSERVER = 42, - DHCP_ADDRESS = 50, - DHCP_LEASETIME = 51, - DHCP_OPTIONSOVERLOADED = 52, - DHCP_MESSAGETYPE = 53, - DHCP_SERVERIDENTIFIER = 54, - DHCP_PARAMETERREQUESTLIST = 55, - DHCP_MESSAGE = 56, - DHCP_MAXMESSAGESIZE = 57, - DHCP_RENEWALTIME = 58, - DHCP_REBINDTIME = 59, - DHCP_CLASSID = 60, - DHCP_CLIENTID = 61, - DHCP_USERCLASS = 77, /* RFC 3004 */ - DHCP_FQDN = 81, - DHCP_DNSSEARCH = 119, /* RFC 3397 */ - DHCP_SIPSERVER = 120, /* RFC 3361 */ - DHCP_CSR = 121, /* RFC 3442 */ - DHCP_MSCSR = 249, /* MS code for RFC 3442 */ - DHCP_END = 255 + DHCP_PAD = 0, + DHCP_NETMASK = 1, + DHCP_TIMEROFFSET = 2, + DHCP_ROUTERS = 3, + DHCP_TIMESERVER = 4, + DHCP_NAMESERVER = 5, + DHCP_DNSSERVER = 6, + DHCP_LOGSERVER = 7, + DHCP_COOKIESERVER = 8, + DHCP_HOSTNAME = 12, + DHCP_DNSDOMAIN = 15, + DHCP_ROOTPATH = 17, + DHCP_DEFAULTIPTTL = 23, + DHCP_MTU = 26, + DHCP_BROADCAST = 28, + DHCP_MASKDISCOVERY = 29, + DHCP_ROUTERDISCOVERY = 31, + DHCP_STATICROUTE = 33, + DHCP_NISDOMAIN = 40, + DHCP_NISSERVER = 41, + DHCP_NTPSERVER = 42, + DHCP_ADDRESS = 50, + DHCP_LEASETIME = 51, + DHCP_OPTIONSOVERLOADED = 52, + DHCP_MESSAGETYPE = 53, + DHCP_SERVERIDENTIFIER = 54, + DHCP_PARAMETERREQUESTLIST = 55, + DHCP_MESSAGE = 56, + DHCP_MAXMESSAGESIZE = 57, + DHCP_RENEWALTIME = 58, + DHCP_REBINDTIME = 59, + DHCP_CLASSID = 60, + DHCP_CLIENTID = 61, + DHCP_USERCLASS = 77, /* RFC 3004 */ + DHCP_FQDN = 81, + DHCP_DNSSEARCH = 119, /* RFC 3397 */ + DHCP_SIPSERVER = 120, /* RFC 3361 */ + DHCP_CSR = 121, /* RFC 3442 */ + DHCP_MSCSR = 249, /* MS code for RFC 3442 */ + DHCP_END = 255 }; /* SetFQDNHostName values - lsnybble used in flags * byte (see buildmsg.c), hsnybble to create order * and to allow 0x00 to mean disable */ -enum FQQN { - FQDN_DISABLE = 0x00, - FQDN_NONE = 0x18, - FQDN_PTR = 0x20, - FQDN_BOTH = 0x31 +enum FQQN +{ + FQDN_DISABLE = 0x00, + FQDN_NONE = 0x18, + FQDN_PTR = 0x20, + FQDN_BOTH = 0x31 }; typedef struct fqdn_t { - uint8_t flags; - uint8_t r1; - uint8_t r2; - char *name; + uint8_t flags; + uint8_t r1; + uint8_t r2; + char *name; } fqdn_t; typedef struct dhcp_t { - char version[11]; + char version[11]; - struct in_addr serveraddress; - char serverhw[IF_NAMESIZE]; - char servername[64]; + struct in_addr serveraddress; + char serverhw[IF_NAMESIZE]; + char servername[64]; - struct in_addr address; - struct in_addr netmask; - struct in_addr broadcast; - unsigned short mtu; + struct in_addr address; + struct in_addr netmask; + struct in_addr broadcast; + unsigned short mtu; - uint32_t leasedfrom; - uint32_t leasetime; - uint32_t renewaltime; - uint32_t rebindtime; + uint32_t leasedfrom; + uint32_t leasetime; + uint32_t renewaltime; + uint32_t rebindtime; - struct route_head *routes; + struct route_head *routes; - char *hostname; - fqdn_t *fqdn; + char *hostname; + fqdn_t *fqdn; - struct address_head *dnsservers; - char *dnsdomain; - char *dnssearch; + struct address_head *dnsservers; + char *dnsdomain; + char *dnssearch; - struct address_head *ntpservers; + struct address_head *ntpservers; - struct address_head *nisservers; - char *nisdomain; + struct address_head *nisservers; + char *nisdomain; - char *sipservers; + char *sipservers; - char *message; - char *rootpath; + char *message; + char *rootpath; - bool frominfo; + bool frominfo; } dhcp_t; /* Sizes for DHCP options */ @@ -183,33 +184,33 @@ typedef struct dhcp_t typedef struct dhcpmessage_t { - unsigned char op; /* message type */ - unsigned char hwtype; /* hardware address type */ - unsigned char hwlen; /* hardware address length */ - unsigned char hwopcount; /* should be zero in client message */ - uint32_t xid; /* transaction id */ - uint16_t secs; /* elapsed time in sec. from boot */ - uint16_t flags; - uint32_t ciaddr; /* (previously allocated) client IP */ - uint32_t yiaddr; /* 'your' client IP address */ - uint32_t siaddr; /* should be zero in client's messages */ - uint32_t giaddr; /* should be zero in client's messages */ - unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ - unsigned char servername[SERVERNAME_LEN]; /* server host name */ - unsigned char bootfile[BOOTFILE_LEN]; /* boot file name */ - uint32_t cookie; - unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */ + unsigned char op; /* message type */ + unsigned char hwtype; /* hardware address type */ + unsigned char hwlen; /* hardware address length */ + unsigned char hwopcount; /* should be zero in client message */ + uint32_t xid; /* transaction id */ + uint16_t secs; /* elapsed time in sec. from boot */ + uint16_t flags; + uint32_t ciaddr; /* (previously allocated) client IP */ + uint32_t yiaddr; /* 'your' client IP address */ + uint32_t siaddr; /* should be zero in client's messages */ + uint32_t giaddr; /* should be zero in client's messages */ + unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ + unsigned char servername[SERVERNAME_LEN]; /* server host name */ + unsigned char bootfile[BOOTFILE_LEN]; /* boot file name */ + uint32_t cookie; + unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */ } dhcpmessage_t; struct udp_dhcp_packet { - struct ip ip; - struct udphdr udp; - dhcpmessage_t dhcp; + struct ip ip; + struct udphdr udp; + dhcpmessage_t dhcp; }; ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, - uint32_t xid, char type, const options_t *options); + uint32_t xid, char type, const options_t *options); void free_dhcp (dhcp_t *dhcp); int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message); #endif diff --git a/src/customdhcpcd/dhcpcd.c b/src/customdhcpcd/dhcpcd.c index d0ad5e7..31bfdcb 100644 --- a/src/customdhcpcd/dhcpcd.c +++ b/src/customdhcpcd/dhcpcd.c @@ -1,28 +1,28 @@ - /* dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples - * All rights reserved - - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ +/* dhcpcd - DHCP client daemon +* Copyright 2006-2008 Roy Marples +* All rights reserved + +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +* SUCH DAMAGE. +*/ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; @@ -55,42 +55,43 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; static int doversion = 0; static int dohelp = 0; #define EXTRA_OPTS -static const struct option longopts[] = { - {"arp", no_argument, NULL, 'a'}, - {"script", required_argument, NULL, 'c'}, - {"debug", no_argument, NULL, 'd'}, - {"hostname", optional_argument, NULL, 'h'}, - {"classid", optional_argument, NULL, 'i'}, - {"release", no_argument, NULL, 'k'}, - {"leasetime", required_argument, NULL, 'l'}, - {"metric", required_argument, NULL, 'm'}, - {"renew", no_argument, NULL, 'n'}, - {"persistent", no_argument, NULL, 'p'}, - {"qtsocketaddress", required_argument, NULL, 'q'}, - {"inform", optional_argument, NULL, 's'}, - {"request", optional_argument, NULL, 'r'}, - {"timeout", required_argument, NULL, 't'}, - {"userclass", required_argument, NULL, 'u'}, - {"exit", no_argument, NULL, 'x'}, - {"lastlease", no_argument, NULL, 'E'}, - {"fqdn", required_argument, NULL, 'F'}, - {"nogateway", no_argument, NULL, 'G'}, - {"sethostname", no_argument, NULL, 'H'}, - {"clientid", optional_argument, NULL, 'I'}, - {"noipv4ll", no_argument, NULL, 'L'}, - {"nomtu", no_argument, NULL, 'M'}, - {"nontp", no_argument, NULL, 'N'}, - {"nodns", no_argument, NULL, 'R'}, - {"msscr", no_argument, NULL, 'S'}, - {"test", no_argument, NULL, 'T'}, - {"nonis", no_argument, NULL, 'Y'}, - {"help", no_argument, &dohelp, 1}, - {"version", no_argument, &doversion, 1}, +static const struct option longopts[] = +{ + {"arp", no_argument, NULL, 'a'}, + {"script", required_argument, NULL, 'c'}, + {"debug", no_argument, NULL, 'd'}, + {"hostname", optional_argument, NULL, 'h'}, + {"classid", optional_argument, NULL, 'i'}, + {"release", no_argument, NULL, 'k'}, + {"leasetime", required_argument, NULL, 'l'}, + {"metric", required_argument, NULL, 'm'}, + {"renew", no_argument, NULL, 'n'}, + {"persistent", no_argument, NULL, 'p'}, + {"qtsocketaddress", required_argument, NULL, 'q'}, + {"inform", optional_argument, NULL, 's'}, + {"request", optional_argument, NULL, 'r'}, + {"timeout", required_argument, NULL, 't'}, + {"userclass", required_argument, NULL, 'u'}, + {"exit", no_argument, NULL, 'x'}, + {"lastlease", no_argument, NULL, 'E'}, + {"fqdn", required_argument, NULL, 'F'}, + {"nogateway", no_argument, NULL, 'G'}, + {"sethostname", no_argument, NULL, 'H'}, + {"clientid", optional_argument, NULL, 'I'}, + {"noipv4ll", no_argument, NULL, 'L'}, + {"nomtu", no_argument, NULL, 'M'}, + {"nontp", no_argument, NULL, 'N'}, + {"nodns", no_argument, NULL, 'R'}, + {"msscr", no_argument, NULL, 'S'}, + {"test", no_argument, NULL, 'T'}, + {"nonis", no_argument, NULL, 'Y'}, + {"help", no_argument, &dohelp, 1}, + {"version", no_argument, &doversion, 1}, #ifdef THERE_IS_NO_FORK - {"daemonised", no_argument, NULL, 'f'}, - {"skiproutes", required_argument, NULL, 'g'}, + {"daemonised", no_argument, NULL, 'f'}, + {"skiproutes", required_argument, NULL, 'g'}, #endif - {NULL, 0, NULL, 0} + {NULL, 0, NULL, 0} }; #ifdef THERE_IS_NO_FORK @@ -104,568 +105,616 @@ char *dhcpcd_skiproutes = NULL; static int atoint (const char *s) { - char *t; - long n; - - errno = 0; - n = strtol (s, &t, 0); - if ((errno != 0 && n == 0) || s == t || - (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))) - { - logger (LOG_ERR, "`%s' out of range", s); - return (-1); - } - - return ((int) n); + char *t; + long n; + + errno = 0; + n = strtol (s, &t, 0); + if ((errno != 0 && n == 0) || s == t || + (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))) + { + logger (LOG_ERR, "`%s' out of range", s); + return (-1); + } + + return ((int) n); } static pid_t read_pid (const char *pidfile) { - FILE *fp; - pid_t pid = 0; + FILE *fp; + pid_t pid = 0; - if ((fp = fopen (pidfile, "r")) == NULL) { - errno = ENOENT; - return 0; - } + if ((fp = fopen (pidfile, "r")) == NULL) + { + errno = ENOENT; + return 0; + } - fscanf (fp, "%d", &pid); - fclose (fp); + fscanf (fp, "%d", &pid); + fclose (fp); - return (pid); + return (pid); } static void usage (void) { - printf ("usage: "PACKAGE" [-adknpEGHMNRSTY] [-c script] [-h hostname] [-i classID]\n" - " [-l leasetime] [-m metric] [-r ipaddress] [-s ipaddress]\n" - " [-t timeout] [-u userclass] [-F none | ptr | both]\n" - " [-I clientID] [-q qtsocketaddress] \n"); + printf ("usage: "PACKAGE" [-adknpEGHMNRSTY] [-c script] [-h hostname] [-i classID]\n" + " [-l leasetime] [-m metric] [-r ipaddress] [-s ipaddress]\n" + " [-t timeout] [-u userclass] [-F none | ptr | both]\n" + " [-I clientID] [-q qtsocketaddress] \n"); } int main (int argc, char **argv) { - options_t *options; - int userclasses = 0; - int opt; - int option_index = 0; - char *prefix; - pid_t pid; - int debug = 0; - int i; - int pidfd = -1; - int sig = 0; - int retval = EXIT_FAILURE; - - /* Close any un-needed fd's */ - for (i = getdtablesize() - 1; i >= 3; --i) - close (i); - - openlog (PACKAGE, LOG_PID, LOG_LOCAL0); - - options = xzalloc (sizeof (*options)); - options->script = (char *) DEFAULT_SCRIPT; - snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", - PACKAGE, VERSION); - - options->doarp = true; - options->dodns = true; - options->domtu = true; - options->donis = true; - options->dontp = true; - options->dogateway = true; - options->daemonise = true; - options->doinform = false; - options->doipv4ll = true; - options->doduid = true; - options->timeout = DEFAULT_TIMEOUT; - /* added by Niklas Goby, additional field, storing the socket address path for - * communicating with Qt "server" - * defined in dhcpcd.h */ - strcpy(options->qtsocketaddress, DEFAULT_QTSOCKETADDRESS); - - gethostname (options->hostname, sizeof (options->hostname)); - if (strcmp (options->hostname, "(none)") == 0 || - strcmp (options->hostname, "localhost") == 0) - memset (options->hostname, 0, sizeof (options->hostname)); - - - /* Don't set any optional arguments here so we retain POSIX - * compatibility with getopt */ - while ((opt = getopt_long(argc, argv, EXTRA_OPTS - "c:dh:i:kl:m:npq:r:s:t:u:xAEF:GHI:LMNRSTY", - longopts, &option_index)) != -1) - { - switch (opt) { - case 0: - if (longopts[option_index].flag) - break; - logger (LOG_ERR, - "option `%s' should set a flag", - longopts[option_index].name); - goto abort; - case 'c': - options->script = optarg; - break; - case 'd': - debug++; - switch (debug) { - case 1: - setloglevel (LOG_DEBUG); - break; - case 2: - options->daemonise = false; - break; - } - break; - #ifdef THERE_IS_NO_FORK - case 'f': - options->daemonised = true; - close_fds (); - break; - case 'g': - dhcpcd_skiproutes = xstrdup (optarg); - break; - #endif - case 'h': - if (! optarg) - *options->hostname = '\0'; - else if (strlen (optarg) > MAXHOSTNAMELEN) { - logger (LOG_ERR, - "`%s' too long for HostName string, max is %d", - optarg, MAXHOSTNAMELEN); - goto abort; - } else - strlcpy (options->hostname, optarg, - sizeof (options->hostname)); - break; - case 'i': - if (! optarg) { - *options->classid = '\0'; - } else if (strlen (optarg) > CLASS_ID_MAX_LEN) { - logger (LOG_ERR, - "`%s' too long for ClassID string, max is %d", - optarg, CLASS_ID_MAX_LEN); - goto abort; - } else - strlcpy (options->classid, optarg, - sizeof (options->classid)); - break; - case 'k': - sig = SIGHUP; - break; - case 'l': - if (*optarg == '-') { - logger (LOG_ERR, - "leasetime must be a positive value"); - goto abort; - } - errno = 0; - options->leasetime = (uint32_t) strtol (optarg, NULL, 0); - if (errno == EINVAL || errno == ERANGE) { - logger (LOG_ERR, "`%s' out of range", optarg); - goto abort; - } - break; - case 'm': - options->metric = atoint (optarg); - if (options->metric < 0) { - logger (LOG_ERR, - "metric must be a positive value"); - goto abort; - } - break; - case 'n': - sig = SIGALRM; - break; - case 'p': - options->persistent = true; - break; - case 'q': - if (strlen(optarg) > QTSOCKETADDRESSLENGTH) { - logger(LOG_ERR, "`%s' too long for an socket address path (max=%d)", - optarg, QTSOCKETADDRESSLENGTH); - goto abort; - } - strlcpy(options->qtsocketaddress, optarg, sizeof(options->qtsocketaddress)); - break; - case 's': - options->doinform = true; - options->doarp = false; - if (! optarg || strlen (optarg) == 0) { - options->request_address.s_addr = 0; - break; - } else { - char *slash = strchr (optarg, '/'); - if (slash) { - int cidr; - /* nullify the slash, so the -r option can read the - * address */ - *slash++ = '\0'; - if (sscanf (slash, "%d", &cidr) != 1 || - inet_cidrtoaddr (cidr, &options->request_netmask) != 0) { - logger (LOG_ERR, "`%s' is not a valid CIDR", slash); - goto abort; - } - } - } - /* FALLTHROUGH */ - case 'r': - if (! options->doinform) - options->dorequest = true; - if (strlen (optarg) > 0 && - ! inet_aton (optarg, &options->request_address)) - { - logger (LOG_ERR, "`%s' is not a valid IP address", optarg); - goto abort; - } - break; - case 't': - options->timeout = atoint (optarg); - if (options->timeout < 0) { - logger (LOG_ERR, "timeout must be a positive value"); - goto abort; - } - break; - case 'u': - { - int offset = 0; - for (i = 0; i < userclasses; i++) - offset += (int) options->userclass[offset] + 1; - if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { - logger (LOG_ERR, "userclass overrun, max is %d", - USERCLASS_MAX_LEN); - goto abort; - } - userclasses++; - memcpy (options->userclass + offset + 1 , optarg, strlen (optarg)); - options->userclass[offset] = strlen (optarg); - options->userclass_len += (strlen (optarg)) + 1; - } - break; - case 'x': - sig = SIGTERM; - break; - case 'A': - #ifndef ENABLE_ARP - logger (LOG_ERR, - "arp not compiled into dhcpcd"); - goto abort; - #endif - options->doarp = false; - break; - case 'E': - #ifndef ENABLE_INFO - logger (LOG_ERR, - "info not compiled into dhcpcd"); - goto abort; - #endif - options->dolastlease = true; - break; - case 'F': - if (strncmp (optarg, "none", strlen (optarg)) == 0) - options->fqdn = FQDN_NONE; - else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) - options->fqdn = FQDN_PTR; - else if (strncmp (optarg, "both", strlen (optarg)) == 0) - options->fqdn = FQDN_BOTH; - else { - logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); - goto abort; - } - break; - case 'G': - options->dogateway = false; - break; - case 'H': - options->dohostname++; - break; - case 'I': - if (optarg) { - if (strlen (optarg) > CLIENT_ID_MAX_LEN) { - logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", - optarg, CLIENT_ID_MAX_LEN); - goto abort; - } - if (strlcpy (options->clientid, optarg, - sizeof (options->clientid)) == 0) - /* empty string disabled duid */ - options->doduid = false; - - } else { - memset (options->clientid, 0, sizeof (options->clientid)); - options->doduid = false; - } - break; - case 'L': - options->doipv4ll = false; - break; - case 'M': - options->domtu = false; - break; - case 'N': - options->dontp = false; - break; - case 'R': - options->dodns = false; - break; - case 'S': - options->domscsr++; - break; - case 'T': - #ifndef ENABLE_INFO - logger (LOG_ERR, "info support not compiled into dhcpcd"); - goto abort; - #endif - options->test = true; - options->persistent = true; - break; - case 'Y': - options->donis = false; - break; - case '?': - usage (); - goto abort; - default: - usage (); - goto abort; - } - } - if (doversion) { - printf (""PACKAGE" "VERSION"\n"); - printf ("Compile time options:" - #ifdef ENABLE_ARP - " ARP" - #endif - #ifdef ENABLE_DUID - " DUID" - #endif - #ifdef ENABLE_INFO - " INFO" - #endif - #ifdef ENABLE_INFO_COMPAT - " INFO_COMPAT" - #endif - #ifdef ENABLE_IPV4LL - " IPV4LL" - #endif - #ifdef ENABLE_NIS - " NIS" - #endif - #ifdef ENABLE_NTP - " NTP" - #endif - #ifdef SERVICE - " " SERVICE - #endif - #ifdef ENABLE_RESOLVCONF - " RESOLVCONF" - #endif - #ifdef THERE_IS_NO_FORK - " THERE_IS_NO_FORK" - #endif - "\n"); - } - - if (dohelp) - usage (); + options_t *options; + int userclasses = 0; + int opt; + int option_index = 0; + char *prefix; + pid_t pid; + int debug = 0; + int i; + int pidfd = -1; + int sig = 0; + int retval = EXIT_FAILURE; + + /* Close any un-needed fd's */ + for (i = getdtablesize() - 1; i >= 3; --i) + close (i); + + openlog (PACKAGE, LOG_PID, LOG_LOCAL0); + + options = xzalloc (sizeof (*options)); + options->script = (char *) DEFAULT_SCRIPT; + snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", + PACKAGE, VERSION); + + options->doarp = true; + options->dodns = true; + options->domtu = true; + options->donis = true; + options->dontp = true; + options->dogateway = true; + options->daemonise = true; + options->doinform = false; + options->doipv4ll = true; + options->doduid = true; + options->timeout = DEFAULT_TIMEOUT; + /* added by Niklas Goby, additional field, storing the socket address path for + * communicating with Qt "server" + * defined in dhcpcd.h */ + strcpy(options->qtsocketaddress, DEFAULT_QTSOCKETADDRESS); + + gethostname (options->hostname, sizeof (options->hostname)); + if (strcmp (options->hostname, "(none)") == 0 || + strcmp (options->hostname, "localhost") == 0) + memset (options->hostname, 0, sizeof (options->hostname)); + + + /* Don't set any optional arguments here so we retain POSIX + * compatibility with getopt */ + while ((opt = getopt_long(argc, argv, EXTRA_OPTS + "c:dh:i:kl:m:npq:r:s:t:u:xAEF:GHI:LMNRSTY", + longopts, &option_index)) != -1) + { + switch (opt) + { + case 0: + if (longopts[option_index].flag) + break; + logger (LOG_ERR, + "option `%s' should set a flag", + longopts[option_index].name); + goto abort; + case 'c': + options->script = optarg; + break; + case 'd': + debug++; + switch (debug) + { + case 1: + setloglevel (LOG_DEBUG); + break; + case 2: + options->daemonise = false; + break; + } + break; +#ifdef THERE_IS_NO_FORK + case 'f': + options->daemonised = true; + close_fds (); + break; + case 'g': + dhcpcd_skiproutes = xstrdup (optarg); + break; +#endif + case 'h': + if (! optarg) + *options->hostname = '\0'; + else if (strlen (optarg) > MAXHOSTNAMELEN) + { + logger (LOG_ERR, + "`%s' too long for HostName string, max is %d", + optarg, MAXHOSTNAMELEN); + goto abort; + } + else + strlcpy (options->hostname, optarg, + sizeof (options->hostname)); + break; + case 'i': + if (! optarg) + { + *options->classid = '\0'; + } + else if (strlen (optarg) > CLASS_ID_MAX_LEN) + { + logger (LOG_ERR, + "`%s' too long for ClassID string, max is %d", + optarg, CLASS_ID_MAX_LEN); + goto abort; + } + else + strlcpy (options->classid, optarg, + sizeof (options->classid)); + break; + case 'k': + sig = SIGHUP; + break; + case 'l': + if (*optarg == '-') + { + logger (LOG_ERR, + "leasetime must be a positive value"); + goto abort; + } + errno = 0; + options->leasetime = (uint32_t) strtol (optarg, NULL, 0); + if (errno == EINVAL || errno == ERANGE) + { + logger (LOG_ERR, "`%s' out of range", optarg); + goto abort; + } + break; + case 'm': + options->metric = atoint (optarg); + if (options->metric < 0) + { + logger (LOG_ERR, + "metric must be a positive value"); + goto abort; + } + break; + case 'n': + sig = SIGALRM; + break; + case 'p': + options->persistent = true; + break; + case 'q': + if (strlen(optarg) > QTSOCKETADDRESSLENGTH) + { + logger(LOG_ERR, "`%s' too long for an socket address path (max=%d)", + optarg, QTSOCKETADDRESSLENGTH); + goto abort; + } + strlcpy(options->qtsocketaddress, optarg, sizeof(options->qtsocketaddress)); + break; + case 's': + options->doinform = true; + options->doarp = false; + if (! optarg || strlen (optarg) == 0) + { + options->request_address.s_addr = 0; + break; + } + else + { + char *slash = strchr (optarg, '/'); + if (slash) + { + int cidr; + /* nullify the slash, so the -r option can read the + * address */ + *slash++ = '\0'; + if (sscanf (slash, "%d", &cidr) != 1 || + inet_cidrtoaddr (cidr, &options->request_netmask) != 0) + { + logger (LOG_ERR, "`%s' is not a valid CIDR", slash); + goto abort; + } + } + } + /* FALLTHROUGH */ + case 'r': + if (! options->doinform) + options->dorequest = true; + if (strlen (optarg) > 0 && + ! inet_aton (optarg, &options->request_address)) + { + logger (LOG_ERR, "`%s' is not a valid IP address", optarg); + goto abort; + } + break; + case 't': + options->timeout = atoint (optarg); + if (options->timeout < 0) + { + logger (LOG_ERR, "timeout must be a positive value"); + goto abort; + } + break; + case 'u': + { + int offset = 0; + for (i = 0; i < userclasses; i++) + offset += (int) options->userclass[offset] + 1; + if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) + { + logger (LOG_ERR, "userclass overrun, max is %d", + USERCLASS_MAX_LEN); + goto abort; + } + userclasses++; + memcpy (options->userclass + offset + 1 , optarg, strlen (optarg)); + options->userclass[offset] = strlen (optarg); + options->userclass_len += (strlen (optarg)) + 1; + } + break; + case 'x': + sig = SIGTERM; + break; + case 'A': +#ifndef ENABLE_ARP + logger (LOG_ERR, + "arp not compiled into dhcpcd"); + goto abort; +#endif + options->doarp = false; + break; + case 'E': +#ifndef ENABLE_INFO + logger (LOG_ERR, + "info not compiled into dhcpcd"); + goto abort; +#endif + options->dolastlease = true; + break; + case 'F': + if (strncmp (optarg, "none", strlen (optarg)) == 0) + options->fqdn = FQDN_NONE; + else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) + options->fqdn = FQDN_PTR; + else if (strncmp (optarg, "both", strlen (optarg)) == 0) + options->fqdn = FQDN_BOTH; + else + { + logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); + goto abort; + } + break; + case 'G': + options->dogateway = false; + break; + case 'H': + options->dohostname++; + break; + case 'I': + if (optarg) + { + if (strlen (optarg) > CLIENT_ID_MAX_LEN) + { + logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", + optarg, CLIENT_ID_MAX_LEN); + goto abort; + } + if (strlcpy (options->clientid, optarg, + sizeof (options->clientid)) == 0) + /* empty string disabled duid */ + options->doduid = false; + + } + else + { + memset (options->clientid, 0, sizeof (options->clientid)); + options->doduid = false; + } + break; + case 'L': + options->doipv4ll = false; + break; + case 'M': + options->domtu = false; + break; + case 'N': + options->dontp = false; + break; + case 'R': + options->dodns = false; + break; + case 'S': + options->domscsr++; + break; + case 'T': +#ifndef ENABLE_INFO + logger (LOG_ERR, "info support not compiled into dhcpcd"); + goto abort; +#endif + options->test = true; + options->persistent = true; + break; + case 'Y': + options->donis = false; + break; + case '?': + usage (); + goto abort; + default: + usage (); + goto abort; + } + } + if (doversion) + { + printf (""PACKAGE" "VERSION"\n"); + printf ("Compile time options:" +#ifdef ENABLE_ARP + " ARP" +#endif +#ifdef ENABLE_DUID + " DUID" +#endif +#ifdef ENABLE_INFO + " INFO" +#endif +#ifdef ENABLE_INFO_COMPAT + " INFO_COMPAT" +#endif +#ifdef ENABLE_IPV4LL + " IPV4LL" +#endif +#ifdef ENABLE_NIS + " NIS" +#endif +#ifdef ENABLE_NTP + " NTP" +#endif +#ifdef SERVICE + " " SERVICE +#endif +#ifdef ENABLE_RESOLVCONF + " RESOLVCONF" +#endif +#ifdef THERE_IS_NO_FORK + " THERE_IS_NO_FORK" +#endif + "\n"); + } + + if (dohelp) + usage (); #ifdef THERE_IS_NO_FORK - dhcpcd_argv = argv; - dhcpcd_argc = argc; - if (! realpath (argv[0], dhcpcd)) { - logger (LOG_ERR, "unable to resolve the path `%s': %s", - argv[0], strerror (errno)); - goto abort; - } + dhcpcd_argv = argv; + dhcpcd_argc = argc; + if (! realpath (argv[0], dhcpcd)) + { + logger (LOG_ERR, "unable to resolve the path `%s': %s", + argv[0], strerror (errno)); + goto abort; + } #endif - /* initializations for the ipc connection to qt*/ - setSocketName(options->qtsocketaddress); - if (initQtLoggerSocket() < 0) { - logger(LOG_ERR, "initialization Qt Logger failed: %s ", strerror (errno)); - goto abort; - } - - - if (optind < argc) { - if (strlen(argv[optind]) > IF_NAMESIZE) { - logger(LOG_ERR, "`%s' too long for an interface name (max=%d)", - argv[optind], IF_NAMESIZE); - goto abort; - } - strlcpy(options->interface, argv[optind], sizeof(options->interface)); - setInterfaceName(options->interface); - } else { - /* If only version was requested then exit now */ - if (doversion || dohelp) { - retval = 0; - goto abort; - } - - logger(LOG_ERR, "no interface specified"); - setInterfaceName("no_if"); - goto abort; - } - - if (strchr(options->hostname, '.')) { - if (options->fqdn == FQDN_DISABLE) - options->fqdn = FQDN_BOTH; - } else - options->fqdn = FQDN_DISABLE; - - if (options->request_address.s_addr == 0 && options->doinform) { - if ((options->request_address.s_addr = get_address(options->interface)) - != 0) - options->keep_address = true; - } - - if (IN_LINKLOCAL (ntohl (options->request_address.s_addr))) { - logger (LOG_ERR, - "you are not allowed to request a link local address"); - logToQt(LOG_ERR, -1, "you are not allowed to request a link local address"); - goto abort; - } - - if (geteuid ()) { - logger (LOG_WARNING, PACKAGE " will not work correctly unless" - " run as root"); - } - - prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3)); - snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface); - setlogprefix (prefix); - snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE, - options->interface); - free (prefix); - - chdir ("/"); - umask (022); - - if (mkdir (INFODIR, S_IRUSR | S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP - | S_IROTH | S_IXOTH) && errno != EEXIST) - { - logger (LOG_ERR, - "mkdir(\"%s\",0): %s\n", INFODIR, strerror (errno)); - goto abort; - } - - if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP - | S_IROTH | S_IXOTH) && errno != EEXIST) - { - logger (LOG_ERR, - "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); - goto abort; - } - - if (options->test) { - if (options->dorequest || options->doinform) { - logger (LOG_ERR, - "cannot test with --inform or --request"); - goto abort; - } - - if (options->dolastlease) { - logger (LOG_ERR, "cannot test with --lastlease"); - goto abort; - } - - if (sig != 0) { - logger (LOG_ERR, - "cannot test with --release or --renew"); - goto abort; - } - } - - if (sig != 0) { - int killed = -1; - pid = read_pid (options->pidfile); - if (pid != 0) - logger (LOG_INFO, "sending signal %d to pid %d", - sig, pid); - - if (! pid || (killed = kill (pid, sig))) - logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, - ""PACKAGE" not running"); - - if (pid != 0 && (sig != SIGALRM || killed != 0)) - unlink (options->pidfile); - - if (killed == 0) { - retval = EXIT_SUCCESS; - goto abort; - } - - if (sig != SIGALRM) - goto abort; - } - - if (! options->test && ! options->daemonised) { - if ((pid = read_pid (options->pidfile)) > 0 && - kill (pid, 0) == 0) - { - logger (LOG_ERR, ""PACKAGE - " already running on pid %d (%s)", - pid, options->pidfile); - goto abort; - } - - pidfd = open (options->pidfile, - O_WRONLY | O_CREAT | O_NONBLOCK, 0664); - if (pidfd == -1) { - logger (LOG_ERR, "open `%s': %s", - options->pidfile, strerror (errno)); - goto abort; - } - - /* Lock the file so that only one instance of dhcpcd runs - * on an interface */ - if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) { - logger (LOG_ERR, "flock `%s': %s", - options->pidfile, strerror (errno)); - goto abort; - } - - /* dhcpcd.sh should not interhit this fd */ - if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || - fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) - logger (LOG_ERR, "fcntl: %s", strerror (errno)); - - writepid (pidfd, getpid ()); - logger (LOG_INFO, PACKAGE " " VERSION " starting"); - } - - /* Seed random */ - srandomdev (); - - /* Massage our filters per platform */ - setup_packet_filters (); - - /* dhcp_run : defined in client.c */ - if (dhcp_run (options, &pidfd) == 0) - retval = EXIT_SUCCESS; + /* initializations for the ipc connection to qt*/ + setSocketName(options->qtsocketaddress); + if (initQtLoggerSocket() < 0) + { + logger(LOG_ERR, "initialization Qt Logger failed: %s ", strerror (errno)); + goto abort; + } + + + if (optind < argc) + { + if (strlen(argv[optind]) > IF_NAMESIZE) + { + logger(LOG_ERR, "`%s' too long for an interface name (max=%d)", + argv[optind], IF_NAMESIZE); + goto abort; + } + strlcpy(options->interface, argv[optind], sizeof(options->interface)); + setInterfaceName(options->interface); + } + else + { + /* If only version was requested then exit now */ + if (doversion || dohelp) + { + retval = 0; + goto abort; + } + + logger(LOG_ERR, "no interface specified"); + setInterfaceName("no_if"); + goto abort; + } + + if (strchr(options->hostname, '.')) + { + if (options->fqdn == FQDN_DISABLE) + options->fqdn = FQDN_BOTH; + } + else + options->fqdn = FQDN_DISABLE; + + if (options->request_address.s_addr == 0 && options->doinform) + { + if ((options->request_address.s_addr = get_address(options->interface)) + != 0) + options->keep_address = true; + } + + if (IN_LINKLOCAL (ntohl (options->request_address.s_addr))) + { + logger (LOG_ERR, + "you are not allowed to request a link local address"); + logToQt(LOG_ERR, -1, "you are not allowed to request a link local address"); + goto abort; + } + + if (geteuid ()) + { + logger (LOG_WARNING, PACKAGE " will not work correctly unless" + " run as root"); + } + + prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3)); + snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface); + setlogprefix (prefix); + snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE, + options->interface); + free (prefix); + + chdir ("/"); + umask (022); + + if (mkdir (INFODIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP + | S_IROTH | S_IXOTH) && errno != EEXIST) + { + logger (LOG_ERR, + "mkdir(\"%s\",0): %s\n", INFODIR, strerror (errno)); + goto abort; + } + + if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP + | S_IROTH | S_IXOTH) && errno != EEXIST) + { + logger (LOG_ERR, + "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); + goto abort; + } + + if (options->test) + { + if (options->dorequest || options->doinform) + { + logger (LOG_ERR, + "cannot test with --inform or --request"); + goto abort; + } + + if (options->dolastlease) + { + logger (LOG_ERR, "cannot test with --lastlease"); + goto abort; + } + + if (sig != 0) + { + logger (LOG_ERR, + "cannot test with --release or --renew"); + goto abort; + } + } + + if (sig != 0) + { + int killed = -1; + pid = read_pid (options->pidfile); + if (pid != 0) + logger (LOG_INFO, "sending signal %d to pid %d", + sig, pid); + + if (! pid || (killed = kill (pid, sig))) + logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, + ""PACKAGE" not running"); + + if (pid != 0 && (sig != SIGALRM || killed != 0)) + unlink (options->pidfile); + + if (killed == 0) + { + retval = EXIT_SUCCESS; + goto abort; + } + + if (sig != SIGALRM) + goto abort; + } + + if (! options->test && ! options->daemonised) + { + if ((pid = read_pid (options->pidfile)) > 0 && + kill (pid, 0) == 0) + { + logger (LOG_ERR, ""PACKAGE + " already running on pid %d (%s)", + pid, options->pidfile); + goto abort; + } + + pidfd = open (options->pidfile, + O_WRONLY | O_CREAT | O_NONBLOCK, 0664); + if (pidfd == -1) + { + logger (LOG_ERR, "open `%s': %s", + options->pidfile, strerror (errno)); + goto abort; + } + + /* Lock the file so that only one instance of dhcpcd runs + * on an interface */ + if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) + { + logger (LOG_ERR, "flock `%s': %s", + options->pidfile, strerror (errno)); + goto abort; + } + + /* dhcpcd.sh should not interhit this fd */ + if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || + fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) + logger (LOG_ERR, "fcntl: %s", strerror (errno)); + + writepid (pidfd, getpid ()); + logger (LOG_INFO, PACKAGE " " VERSION " starting"); + } + + /* Seed random */ + srandomdev (); + + /* Massage our filters per platform */ + setup_packet_filters (); + + /* dhcp_run : defined in client.c */ + if (dhcp_run (options, &pidfd) == 0) + retval = EXIT_SUCCESS; abort: - /* If we didn't daemonise then we need to punt the pidfile now */ - if (pidfd > -1) { - close (pidfd); - unlink (options->pidfile); - } + /* If we didn't daemonise then we need to punt the pidfile now */ + if (pidfd > -1) + { + close (pidfd); + unlink (options->pidfile); + } - free (options); + free (options); #ifdef THERE_IS_NO_FORK - /* There may have been an error before the dhcp_run function - * clears this, so just do it here to be safe */ - free (dhcpcd_skiproutes); + /* There may have been an error before the dhcp_run function + * clears this, so just do it here to be safe */ + free (dhcpcd_skiproutes); #endif - logger (LOG_INFO, "exiting"); - logToQt(LOG_INFO, DHCPCD_EXIT, "exiting due abort"); - closeQtLoggerSocket(); - exit (retval); - /* NOTREACHED */ + logger (LOG_INFO, "exiting"); + logToQt(LOG_INFO, DHCPCD_EXIT, "exiting due abort"); + closeQtLoggerSocket(); + exit (retval); + /* NOTREACHED */ } diff --git a/src/customdhcpcd/dhcpcd.h b/src/customdhcpcd/dhcpcd.h index 9219446..a600a8c 100644 --- a/src/customdhcpcd/dhcpcd.h +++ b/src/customdhcpcd/dhcpcd.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -52,55 +52,56 @@ #define CLIENT_ID_MAX_LEN 48 #define USERCLASS_MAX_LEN 255 -#ifdef THERE_IS_NO_FORK +#ifdef THERE_IS_NO_FORK extern char dhcpcd[PATH_MAX]; extern char **dhcpcd_argv; extern int dhcpcd_argc; extern char *dhcpcd_skiproutes; #endif -typedef struct options_t { - /* added by Niklas Goby, additional field, storing the socket address path for - * communicating with Qt "server" */ - char qtsocketaddress[QTSOCKETADDRESSLENGTH]; - /*----*/ - char interface[IF_NAMESIZE]; - char hostname[MAXHOSTNAMELEN]; - int fqdn; - char classid[CLASS_ID_MAX_LEN]; - char clientid[CLIENT_ID_MAX_LEN]; - char userclass[USERCLASS_MAX_LEN]; - size_t userclass_len; - uint32_t leasetime; - time_t timeout; - int metric; - - bool doarp; - bool dodns; - bool dodomainname; - bool dogateway; - int dohostname; - bool domtu; - bool donis; - bool dontp; - bool dolastlease; - bool doinform; - bool dorequest; - bool doipv4ll; - bool doduid; - int domscsr; - - struct in_addr request_address; - struct in_addr request_netmask; - - bool persistent; - bool keep_address; - bool daemonise; - bool daemonised; - bool test; - - char *script; - char pidfile[PATH_MAX]; +typedef struct options_t +{ + /* added by Niklas Goby, additional field, storing the socket address path for + * communicating with Qt "server" */ + char qtsocketaddress[QTSOCKETADDRESSLENGTH]; + /*----*/ + char interface[IF_NAMESIZE]; + char hostname[MAXHOSTNAMELEN]; + int fqdn; + char classid[CLASS_ID_MAX_LEN]; + char clientid[CLIENT_ID_MAX_LEN]; + char userclass[USERCLASS_MAX_LEN]; + size_t userclass_len; + uint32_t leasetime; + time_t timeout; + int metric; + + bool doarp; + bool dodns; + bool dodomainname; + bool dogateway; + int dohostname; + bool domtu; + bool donis; + bool dontp; + bool dolastlease; + bool doinform; + bool dorequest; + bool doipv4ll; + bool doduid; + int domscsr; + + struct in_addr request_address; + struct in_addr request_netmask; + + bool persistent; + bool keep_address; + bool daemonise; + bool daemonised; + bool test; + + char *script; + char pidfile[PATH_MAX]; } options_t; int nd_main (char *ifname); diff --git a/src/customdhcpcd/duid.c b/src/customdhcpcd/duid.c index e4dd83b..c51503d 100644 --- a/src/customdhcpcd/duid.c +++ b/src/customdhcpcd/duid.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -45,74 +45,81 @@ size_t get_duid (unsigned char *duid, const interface_t *iface) { - FILE *f; - uint16_t type = 0; - uint16_t hw = 0; - uint32_t ul; - time_t t; - int x = 0; - unsigned char *p = duid; - size_t len = 0; - - if (! iface) - return (0); - - /* If we already have a DUID then use it as it's never supposed - * to change once we have one even if the interfaces do */ - if ((f = fopen (DUIDFILE, "r"))) { - char *line = get_line (f); - if (line) { - len = hwaddr_aton (NULL, line); - if (len && len <= DUID_LEN) - hwaddr_aton (duid, line); - free (line); - } - fclose (f); - if (len) - return (len); - } else { - if (errno != ENOENT) { - logger (LOG_ERR, "fopen `%s': %s", - DUIDFILE, strerror (errno)); - return (0); - } - } - - /* No file? OK, lets make one based on our interface */ - type = htons (1); /* DUI-D-LLT */ - memcpy (p, &type, 2); - p += 2; - - hw = htons (iface->family); - memcpy (p, &hw, 2); - p += 2; - - /* time returns seconds from jan 1 1970, but DUID-LLT is - * seconds from jan 1 2000 modulo 2^32 */ - t = time (NULL) - THIRTY_YEARS_IN_SECONDS; - ul = htonl (t & 0xffffffff); - memcpy (p, &ul, 4); - p += 4; - - /* Finally, add the MAC address of the interface */ - memcpy (p, iface->hwaddr, iface->hwlen); - p += iface->hwlen; - - len = p - duid; - - if (! (f = fopen (DUIDFILE, "w"))) - logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); - else { - x = fprintf (f, "%s\n", hwaddr_ntoa (duid, len)); - fclose (f); - } - - /* Failed to write the duid? scrub it, we cannot use it */ - if (x < 1) { - len = 0; - unlink (DUIDFILE); - } - - return (len); + FILE *f; + uint16_t type = 0; + uint16_t hw = 0; + uint32_t ul; + time_t t; + int x = 0; + unsigned char *p = duid; + size_t len = 0; + + if (! iface) + return (0); + + /* If we already have a DUID then use it as it's never supposed + * to change once we have one even if the interfaces do */ + if ((f = fopen (DUIDFILE, "r"))) + { + char *line = get_line (f); + if (line) + { + len = hwaddr_aton (NULL, line); + if (len && len <= DUID_LEN) + hwaddr_aton (duid, line); + free (line); + } + fclose (f); + if (len) + return (len); + } + else + { + if (errno != ENOENT) + { + logger (LOG_ERR, "fopen `%s': %s", + DUIDFILE, strerror (errno)); + return (0); + } + } + + /* No file? OK, lets make one based on our interface */ + type = htons (1); /* DUI-D-LLT */ + memcpy (p, &type, 2); + p += 2; + + hw = htons (iface->family); + memcpy (p, &hw, 2); + p += 2; + + /* time returns seconds from jan 1 1970, but DUID-LLT is + * seconds from jan 1 2000 modulo 2^32 */ + t = time (NULL) - THIRTY_YEARS_IN_SECONDS; + ul = htonl (t & 0xffffffff); + memcpy (p, &ul, 4); + p += 4; + + /* Finally, add the MAC address of the interface */ + memcpy (p, iface->hwaddr, iface->hwlen); + p += iface->hwlen; + + len = p - duid; + + if (! (f = fopen (DUIDFILE, "w"))) + logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); + else + { + x = fprintf (f, "%s\n", hwaddr_ntoa (duid, len)); + fclose (f); + } + + /* Failed to write the duid? scrub it, we cannot use it */ + if (x < 1) + { + len = 0; + unlink (DUIDFILE); + } + + return (len); } #endif diff --git a/src/customdhcpcd/duid.h b/src/customdhcpcd/duid.h index 1492990..f264c26 100644 --- a/src/customdhcpcd/duid.h +++ b/src/customdhcpcd/duid.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved diff --git a/src/customdhcpcd/info.c b/src/customdhcpcd/info.c index 8369b43..5d933dc 100644 --- a/src/customdhcpcd/info.c +++ b/src/customdhcpcd/info.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -48,424 +48,469 @@ * so the contents work in a shell */ static char *cleanmetas (const char *cstr) { - const char *p = cstr; - char *new; - char *n; - size_t len; - - if (cstr == NULL || (len = strlen (cstr)) == 0) - return (xstrdup ("")); - - n = new = xmalloc (sizeof (char) * len + 2); - do - if (*p == '\'') { - size_t pos = n - new; - len += 4; - new = xrealloc (new, sizeof (char) * len + 1); - n = new + pos; - *n++ = '\''; - *n++ = '\\'; - *n++ = '\''; - *n++ = '\''; - } else - *n++ = *p; - while (*p++); - - /* Terminate the sucker */ - *n = '\0'; - - return (new); + const char *p = cstr; + char *new; + char *n; + size_t len; + + if (cstr == NULL || (len = strlen (cstr)) == 0) + return (xstrdup ("")); + + n = new = xmalloc (sizeof (char) * len + 2); + do + if (*p == '\'') + { + size_t pos = n - new; + len += 4; + new = xrealloc (new, sizeof (char) * len + 1); + n = new + pos; + *n++ = '\''; + *n++ = '\\'; + *n++ = '\''; + *n++ = '\''; + } + else + *n++ = *p; + while (*p++); + + /* Terminate the sucker */ + *n = '\0'; + + return (new); } static void print_addresses (FILE *f, const struct address_head *addresses) { - const address_t *addr; - - STAILQ_FOREACH (addr, addresses, entries) { - fprintf (f, "%s", inet_ntoa (addr->address)); - if (STAILQ_NEXT (addr, entries)) - fprintf (f, " "); - } + const address_t *addr; + + STAILQ_FOREACH (addr, addresses, entries) + { + fprintf (f, "%s", inet_ntoa (addr->address)); + if (STAILQ_NEXT (addr, entries)) + fprintf (f, " "); + } } static void print_clean (FILE *f, const char *name, const char *value) { - char *clean; + char *clean; - if (! value) - return; + if (! value) + return; - clean = cleanmetas (value); - fprintf (f, "%s='%s'\n", name, clean); - free (clean); + clean = cleanmetas (value); + fprintf (f, "%s='%s'\n", name, clean); + free (clean); } bool write_info(const interface_t *iface, const dhcp_t *dhcp, - const options_t *options, bool overwrite) + const options_t *options, bool overwrite) { - FILE *f; - route_t *route; - struct stat sb; - - if (options->test) - f = stdout; - else { - if (! overwrite && stat (iface->infofile, &sb) == 0) - return (true); - - logger (LOG_DEBUG, "writing %s", iface->infofile); - if ((f = fopen (iface->infofile, "w")) == NULL) { - logger (LOG_ERR, "fopen `%s': %s", - iface->infofile, strerror (errno)); - return (false); - } - } - - if (dhcp->address.s_addr) { - struct in_addr n; - n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; - fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); - fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); - fprintf (f, "NETWORK='%s'\n", inet_ntoa (n)); - fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); - } - if (dhcp->mtu > 0) - fprintf (f, "MTU='%d'\n", dhcp->mtu); - - if (dhcp->routes) { - bool doneone = false; - fprintf (f, "ROUTES='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr != 0) { - if (doneone) - fprintf (f, " "); - fprintf (f, "%s", inet_ntoa (route->destination)); - fprintf (f, ",%s", inet_ntoa (route->netmask)); - fprintf (f, ",%s", inet_ntoa (route->gateway)); - doneone = true; - } - } - fprintf (f, "'\n"); - - doneone = false; - fprintf (f, "GATEWAYS='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr == 0) { - if (doneone) - fprintf (f, " "); - fprintf (f, "%s", inet_ntoa (route->gateway)); - doneone = true; - } - } - fprintf (f, "'\n"); - } - - print_clean (f, "HOSTNAME", dhcp->hostname); - print_clean (f, "DNSDOMAIN", dhcp->dnsdomain); - print_clean (f, "DNSSEARCH", dhcp->dnssearch); - - if (dhcp->dnsservers) { - fprintf (f, "DNSSERVERS='"); - print_addresses (f, dhcp->dnsservers); - fprintf (f, "'\n"); - } - - if (dhcp->fqdn) { - fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags); - fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1); - fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2); - print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name); - } - - if (dhcp->ntpservers) { - fprintf (f, "NTPSERVERS='"); - print_addresses (f, dhcp->ntpservers); - fprintf (f, "'\n"); - } - - print_clean (f, "NISDOMAIN", dhcp->nisdomain); - if (dhcp->nisservers) { - fprintf (f, "NISSERVERS='"); - print_addresses (f, dhcp->nisservers); - fprintf (f, "'\n"); - } - - print_clean (f, "ROOTPATH", dhcp->rootpath); - print_clean (f, "SIPSERVERS", dhcp->sipservers); - - if (dhcp->serveraddress.s_addr) - fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); - if (dhcp->servername[0]) - print_clean (f, "DHCPSNAME", dhcp->servername); - - if (! options->doinform && dhcp->address.s_addr) { - if (! options->test) - fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom); - fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); - fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); - fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); - } - print_clean (f, "INTERFACE", iface->name); - print_clean (f, "CLASSID", options->classid); - if (iface->clientid_len > 0) { - fprintf (f, "CLIENTID='%s'\n", - hwaddr_ntoa (iface->clientid, iface->clientid_len)); - } - fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, - iface->hwlen)); + FILE *f; + route_t *route; + struct stat sb; + + if (options->test) + f = stdout; + else + { + if (! overwrite && stat (iface->infofile, &sb) == 0) + return (true); + + logger (LOG_DEBUG, "writing %s", iface->infofile); + if ((f = fopen (iface->infofile, "w")) == NULL) + { + logger (LOG_ERR, "fopen `%s': %s", + iface->infofile, strerror (errno)); + return (false); + } + } + + if (dhcp->address.s_addr) + { + struct in_addr n; + n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; + fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); + fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); + fprintf (f, "NETWORK='%s'\n", inet_ntoa (n)); + fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); + } + if (dhcp->mtu > 0) + fprintf (f, "MTU='%d'\n", dhcp->mtu); + + if (dhcp->routes) + { + bool doneone = false; + fprintf (f, "ROUTES='"); + STAILQ_FOREACH (route, dhcp->routes, entries) + { + if (route->destination.s_addr != 0) + { + if (doneone) + fprintf (f, " "); + fprintf (f, "%s", inet_ntoa (route->destination)); + fprintf (f, ",%s", inet_ntoa (route->netmask)); + fprintf (f, ",%s", inet_ntoa (route->gateway)); + doneone = true; + } + } + fprintf (f, "'\n"); + + doneone = false; + fprintf (f, "GATEWAYS='"); + STAILQ_FOREACH (route, dhcp->routes, entries) + { + if (route->destination.s_addr == 0) + { + if (doneone) + fprintf (f, " "); + fprintf (f, "%s", inet_ntoa (route->gateway)); + doneone = true; + } + } + fprintf (f, "'\n"); + } + + print_clean (f, "HOSTNAME", dhcp->hostname); + print_clean (f, "DNSDOMAIN", dhcp->dnsdomain); + print_clean (f, "DNSSEARCH", dhcp->dnssearch); + + if (dhcp->dnsservers) + { + fprintf (f, "DNSSERVERS='"); + print_addresses (f, dhcp->dnsservers); + fprintf (f, "'\n"); + } + + if (dhcp->fqdn) + { + fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags); + fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1); + fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2); + print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name); + } + + if (dhcp->ntpservers) + { + fprintf (f, "NTPSERVERS='"); + print_addresses (f, dhcp->ntpservers); + fprintf (f, "'\n"); + } + + print_clean (f, "NISDOMAIN", dhcp->nisdomain); + if (dhcp->nisservers) + { + fprintf (f, "NISSERVERS='"); + print_addresses (f, dhcp->nisservers); + fprintf (f, "'\n"); + } + + print_clean (f, "ROOTPATH", dhcp->rootpath); + print_clean (f, "SIPSERVERS", dhcp->sipservers); + + if (dhcp->serveraddress.s_addr) + fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); + if (dhcp->servername[0]) + print_clean (f, "DHCPSNAME", dhcp->servername); + + if (! options->doinform && dhcp->address.s_addr) + { + if (! options->test) + fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom); + fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); + fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); + fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); + } + print_clean (f, "INTERFACE", iface->name); + print_clean (f, "CLASSID", options->classid); + if (iface->clientid_len > 0) + { + fprintf (f, "CLIENTID='%s'\n", + hwaddr_ntoa (iface->clientid, iface->clientid_len)); + } + fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, + iface->hwlen)); #ifdef ENABLE_INFO_COMPAT - /* Support the old .info settings if we need to */ - fprintf (f, "\n# dhcpcd-1.x and 2.x compatible variables\n"); - if (dhcp->dnsservers) { - address_t *addr; - - fprintf (f, "DNS='"); - STAILQ_FOREACH (addr, dhcp->dnsservers, entries) { - fprintf (f, "%s", inet_ntoa (addr->address)); - if (STAILQ_NEXT (addr, entries)) - fprintf (f, ","); - } - fprintf (f, "'\n"); - } - - if (dhcp->routes) { - bool doneone = false; - fprintf (f, "GATEWAY='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr == 0) { - if (doneone) - fprintf (f, ","); - fprintf (f, "%s", inet_ntoa (route->gateway)); - doneone = true; - } - } - fprintf (f, "'\n"); - } + /* Support the old .info settings if we need to */ + fprintf (f, "\n# dhcpcd-1.x and 2.x compatible variables\n"); + if (dhcp->dnsservers) + { + address_t *addr; + + fprintf (f, "DNS='"); + STAILQ_FOREACH (addr, dhcp->dnsservers, entries) + { + fprintf (f, "%s", inet_ntoa (addr->address)); + if (STAILQ_NEXT (addr, entries)) + fprintf (f, ","); + } + fprintf (f, "'\n"); + } + + if (dhcp->routes) + { + bool doneone = false; + fprintf (f, "GATEWAY='"); + STAILQ_FOREACH (route, dhcp->routes, entries) + { + if (route->destination.s_addr == 0) + { + if (doneone) + fprintf (f, ","); + fprintf (f, "%s", inet_ntoa (route->gateway)); + doneone = true; + } + } + fprintf (f, "'\n"); + } #endif - if (! options->test) - fclose (f); - return (true); + if (! options->test) + fclose (f); + return (true); } static bool parse_address (struct in_addr *addr, - const char *value, const char *var) + const char *value, const char *var) { - if (inet_aton (value, addr) == 0) { - logger (LOG_ERR, "%s `%s': %s", var, value, - strerror (errno)); - return (false); - } - return (true); + if (inet_aton (value, addr) == 0) + { + logger (LOG_ERR, "%s `%s': %s", var, value, + strerror (errno)); + return (false); + } + return (true); } static bool parse_uint (unsigned int *i, - const char *value, const char *var) + const char *value, const char *var) { - if (sscanf (value, "%u", i) != 1) { - logger (LOG_ERR, "%s `%s': not a valid number", - var, value); - return (false); - } - return (true); + if (sscanf (value, "%u", i) != 1) + { + logger (LOG_ERR, "%s `%s': not a valid number", + var, value); + return (false); + } + return (true); } static bool parse_ushort (unsigned short *s, - const char *value, const char *var) + const char *value, const char *var) { - if (sscanf (value, "%hu", s) != 1) { - logger (LOG_ERR, "%s `%s': not a valid number", - var, value); - return (false); - } - return (true); + if (sscanf (value, "%hu", s) != 1) + { + logger (LOG_ERR, "%s `%s': not a valid number", + var, value); + return (false); + } + return (true); } static struct address_head *parse_addresses (char *value, const char *var) { - char *token; - char *p = value; - struct address_head *head = NULL; - - while ((token = strsep (&p, " "))) { - address_t *a = xzalloc (sizeof (*a)); - - if (inet_aton (token, &a->address) == 0) { - logger (LOG_ERR, "%s: invalid address `%s'", var, token); - free_address (head); - free (a); - return (NULL); - } - - if (! head) { - head = xmalloc (sizeof (*head)); - STAILQ_INIT (head); - } - STAILQ_INSERT_TAIL (head, a, entries); - } - - return (head); + char *token; + char *p = value; + struct address_head *head = NULL; + + while ((token = strsep (&p, " "))) + { + address_t *a = xzalloc (sizeof (*a)); + + if (inet_aton (token, &a->address) == 0) + { + logger (LOG_ERR, "%s: invalid address `%s'", var, token); + free_address (head); + free (a); + return (NULL); + } + + if (! head) + { + head = xmalloc (sizeof (*head)); + STAILQ_INIT (head); + } + STAILQ_INSERT_TAIL (head, a, entries); + } + + return (head); } bool read_info (const interface_t *iface, dhcp_t *dhcp) { - FILE *fp; - char *line; - char *var; - char *value; - char *p; - struct stat sb; - - if (stat (iface->infofile, &sb) != 0) { - logger (LOG_ERR, "lease information file `%s' does not exist", - iface->infofile); - return (false); - } - - if (! (fp = fopen (iface->infofile, "r"))) { - logger (LOG_ERR, "fopen `%s': %s", - iface->infofile, strerror (errno)); - return (false); - } - - dhcp->frominfo = true; - - while ((line = get_line (fp))) { - var = line; - - /* Strip leading spaces/tabs */ - while ((*var == ' ') || (*var == '\t')) - var++; - - /* Trim trailing \n */ - p = var + strlen (var) - 1; - if (*p == '\n') - *p = 0; - - /* Skip comments */ - if (*var == '#') - goto next; - - /* If we don't have an equals sign then skip it */ - if (! (p = strchr (var, '='))) - goto next; - - /* Terminate the = so we have two strings */ - *p = 0; - - value = p + 1; - /* Strip leading and trailing quotes if present */ - if (*value == '\'' || *value == '"') - value++; - p = value + strlen (value) - 1; - if (*p == '\'' || *p == '"') - *p = 0; - - /* Don't process null vars or values */ - if (! *var || ! *value) - goto next; - - if (strcmp (var, "IPADDR") == 0) - parse_address (&dhcp->address, value, "IPADDR"); - else if (strcmp (var, "NETMASK") == 0) - parse_address (&dhcp->netmask, value, "NETMASK"); - else if (strcmp (var, "BROADCAST") == 0) - parse_address (&dhcp->broadcast, value, "BROADCAST"); - else if (strcmp (var, "MTU") == 0) - parse_ushort (&dhcp->mtu, value, "MTU"); - else if (strcmp (var, "ROUTES") == 0) { - p = value; - while ((value = strsep (&p, " "))) { - char *pp = value; - char *dest = strsep (&pp, ","); - char *net = strsep (&pp, ","); - char *gate = strsep (&pp, ","); - route_t *route; - - if (! dest || ! net || ! gate) { - logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route", - dest, net, gate); - goto next; - } - - /* See if we can create a route */ - route = xzalloc (sizeof (*route)); - if (inet_aton (dest, &route->destination) == 0) { - logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address", - dest); - free (route); - goto next; - } - if (inet_aton (dest, &route->netmask) == 0) { - logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address", - net); - free (route); - goto next; - } - if (inet_aton (dest, &route->gateway) == 0) { - logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address", - gate); - free (route); - goto next; - } - - /* OK, now add our route */ - if (! dhcp->routes) { - dhcp->routes = xmalloc (sizeof (*dhcp->routes)); - STAILQ_INIT (dhcp->routes); - } - STAILQ_INSERT_TAIL (dhcp->routes, route, entries); - } - } else if (strcmp (var, "GATEWAYS") == 0) { - p = value; - while ((value = strsep (&p, " "))) { - route_t *route = xzalloc (sizeof (*route)); - if (parse_address (&route->gateway, value, "GATEWAYS")) { - if (! dhcp->routes) { - dhcp->routes = xmalloc (sizeof (*dhcp->routes)); - STAILQ_INIT (dhcp->routes); - } - STAILQ_INSERT_TAIL (dhcp->routes, route, entries); - } else - free (route); - } - } else if (strcmp (var, "HOSTNAME") == 0) - dhcp->hostname = xstrdup (value); - else if (strcmp (var, "DNSDOMAIN") == 0) - dhcp->dnsdomain = xstrdup (value); - else if (strcmp (var, "DNSSEARCH") == 0) - dhcp->dnssearch = xstrdup (value); - else if (strcmp (var, "DNSSERVERS") == 0) - dhcp->dnsservers = parse_addresses (value, "DNSSERVERS"); - else if (strcmp (var, "NTPSERVERS") == 0) - dhcp->ntpservers = parse_addresses (value, "NTPSERVERS"); - else if (strcmp (var, "NISDOMAIN") == 0) - dhcp->nisdomain = xstrdup (value); - else if (strcmp (var, "NISSERVERS") == 0) - dhcp->nisservers = parse_addresses (value, "NISSERVERS"); - else if (strcmp (var, "ROOTPATH") == 0) - dhcp->rootpath = xstrdup (value); - else if (strcmp (var, "DHCPSID") == 0) - parse_address (&dhcp->serveraddress, value, "DHCPSID"); - else if (strcmp (var, "DHCPSNAME") == 0) - strlcpy (dhcp->servername, value, sizeof (dhcp->servername)); - else if (strcmp (var, "LEASEDFROM") == 0) - parse_uint (&dhcp->leasedfrom, value, "LEASEDFROM"); - else if (strcmp (var, "LEASETIME") == 0) - parse_uint (&dhcp->leasetime, value, "LEASETIME"); - else if (strcmp (var, "RENEWALTIME") == 0) - parse_uint (&dhcp->renewaltime, value, "RENEWALTIME"); - else if (strcmp (var, "REBINDTIME") == 0) - parse_uint (&dhcp->rebindtime, value, "REBINDTIME"); + FILE *fp; + char *line; + char *var; + char *value; + char *p; + struct stat sb; + + if (stat (iface->infofile, &sb) != 0) + { + logger (LOG_ERR, "lease information file `%s' does not exist", + iface->infofile); + return (false); + } + + if (! (fp = fopen (iface->infofile, "r"))) + { + logger (LOG_ERR, "fopen `%s': %s", + iface->infofile, strerror (errno)); + return (false); + } + + dhcp->frominfo = true; + + while ((line = get_line (fp))) + { + var = line; + + /* Strip leading spaces/tabs */ + while ((*var == ' ') || (*var == '\t')) + var++; + + /* Trim trailing \n */ + p = var + strlen (var) - 1; + if (*p == '\n') + *p = 0; + + /* Skip comments */ + if (*var == '#') + goto next; + + /* If we don't have an equals sign then skip it */ + if (! (p = strchr (var, '='))) + goto next; + + /* Terminate the = so we have two strings */ + *p = 0; + + value = p + 1; + /* Strip leading and trailing quotes if present */ + if (*value == '\'' || *value == '"') + value++; + p = value + strlen (value) - 1; + if (*p == '\'' || *p == '"') + *p = 0; + + /* Don't process null vars or values */ + if (! *var || ! *value) + goto next; + + if (strcmp (var, "IPADDR") == 0) + parse_address (&dhcp->address, value, "IPADDR"); + else if (strcmp (var, "NETMASK") == 0) + parse_address (&dhcp->netmask, value, "NETMASK"); + else if (strcmp (var, "BROADCAST") == 0) + parse_address (&dhcp->broadcast, value, "BROADCAST"); + else if (strcmp (var, "MTU") == 0) + parse_ushort (&dhcp->mtu, value, "MTU"); + else if (strcmp (var, "ROUTES") == 0) + { + p = value; + while ((value = strsep (&p, " "))) + { + char *pp = value; + char *dest = strsep (&pp, ","); + char *net = strsep (&pp, ","); + char *gate = strsep (&pp, ","); + route_t *route; + + if (! dest || ! net || ! gate) + { + logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route", + dest, net, gate); + goto next; + } + + /* See if we can create a route */ + route = xzalloc (sizeof (*route)); + if (inet_aton (dest, &route->destination) == 0) + { + logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address", + dest); + free (route); + goto next; + } + if (inet_aton (dest, &route->netmask) == 0) + { + logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address", + net); + free (route); + goto next; + } + if (inet_aton (dest, &route->gateway) == 0) + { + logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address", + gate); + free (route); + goto next; + } + + /* OK, now add our route */ + if (! dhcp->routes) + { + dhcp->routes = xmalloc (sizeof (*dhcp->routes)); + STAILQ_INIT (dhcp->routes); + } + STAILQ_INSERT_TAIL (dhcp->routes, route, entries); + } + } + else if (strcmp (var, "GATEWAYS") == 0) + { + p = value; + while ((value = strsep (&p, " "))) + { + route_t *route = xzalloc (sizeof (*route)); + if (parse_address (&route->gateway, value, "GATEWAYS")) + { + if (! dhcp->routes) + { + dhcp->routes = xmalloc (sizeof (*dhcp->routes)); + STAILQ_INIT (dhcp->routes); + } + STAILQ_INSERT_TAIL (dhcp->routes, route, entries); + } + else + free (route); + } + } + else if (strcmp (var, "HOSTNAME") == 0) + dhcp->hostname = xstrdup (value); + else if (strcmp (var, "DNSDOMAIN") == 0) + dhcp->dnsdomain = xstrdup (value); + else if (strcmp (var, "DNSSEARCH") == 0) + dhcp->dnssearch = xstrdup (value); + else if (strcmp (var, "DNSSERVERS") == 0) + dhcp->dnsservers = parse_addresses (value, "DNSSERVERS"); + else if (strcmp (var, "NTPSERVERS") == 0) + dhcp->ntpservers = parse_addresses (value, "NTPSERVERS"); + else if (strcmp (var, "NISDOMAIN") == 0) + dhcp->nisdomain = xstrdup (value); + else if (strcmp (var, "NISSERVERS") == 0) + dhcp->nisservers = parse_addresses (value, "NISSERVERS"); + else if (strcmp (var, "ROOTPATH") == 0) + dhcp->rootpath = xstrdup (value); + else if (strcmp (var, "DHCPSID") == 0) + parse_address (&dhcp->serveraddress, value, "DHCPSID"); + else if (strcmp (var, "DHCPSNAME") == 0) + strlcpy (dhcp->servername, value, sizeof (dhcp->servername)); + else if (strcmp (var, "LEASEDFROM") == 0) + parse_uint (&dhcp->leasedfrom, value, "LEASEDFROM"); + else if (strcmp (var, "LEASETIME") == 0) + parse_uint (&dhcp->leasetime, value, "LEASETIME"); + else if (strcmp (var, "RENEWALTIME") == 0) + parse_uint (&dhcp->renewaltime, value, "RENEWALTIME"); + else if (strcmp (var, "REBINDTIME") == 0) + parse_uint (&dhcp->rebindtime, value, "REBINDTIME"); next: - free (line); - } + free (line); + } - fclose (fp); - return (true); + fclose (fp); + return (true); } #endif diff --git a/src/customdhcpcd/info.h b/src/customdhcpcd/info.h index 22966db..2b4a90e 100644 --- a/src/customdhcpcd/info.h +++ b/src/customdhcpcd/info.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -34,7 +34,7 @@ #ifdef ENABLE_INFO bool write_info (const interface_t *iface, const dhcp_t *dhcp, - const options_t *options, bool overwrite); + const options_t *options, bool overwrite); bool read_info (const interface_t *iface, dhcp_t *dhcp); #endif diff --git a/src/customdhcpcd/interface.c b/src/customdhcpcd/interface.c index d2ff8d6..818a2f0 100644 --- a/src/customdhcpcd/interface.c +++ b/src/customdhcpcd/interface.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -63,438 +63,478 @@ void free_address (struct address_head *addresses) { - address_t *p; - address_t *n; - - if (! addresses) - return; - - p = STAILQ_FIRST (addresses); - while (p) { - n = STAILQ_NEXT (p, entries); - free (p); - p = n; - } - free (addresses); + address_t *p; + address_t *n; + + if (! addresses) + return; + + p = STAILQ_FIRST (addresses); + while (p) + { + n = STAILQ_NEXT (p, entries); + free (p); + p = n; + } + free (addresses); } void free_route (struct route_head *routes) { - route_t *p; - route_t *n; - - if (! routes) - return; - - p = STAILQ_FIRST (routes); - while (p) { - n = STAILQ_NEXT (p, entries); - free (p); - p = n; - } - free (routes); + route_t *p; + route_t *n; + + if (! routes) + return; + + p = STAILQ_FIRST (routes); + while (p) + { + n = STAILQ_NEXT (p, entries); + free (p); + p = n; + } + free (routes); } int inet_ntocidr (struct in_addr address) { - int cidr = 0; - uint32_t mask = htonl (address.s_addr); + int cidr = 0; + uint32_t mask = htonl (address.s_addr); - while (mask) { - cidr++; - mask <<= 1; - } + while (mask) + { + cidr++; + mask <<= 1; + } - return (cidr); + return (cidr); } -int inet_cidrtoaddr (int cidr, struct in_addr *addr) { - int ocets; - - if (cidr < 0 || cidr > 32) { - errno = EINVAL; - return (-1); - } - ocets = (cidr + 7) / 8; - - memset (addr, 0, sizeof (*addr)); - if (ocets > 0) { - memset (&addr->s_addr, 255, (size_t) ocets - 1); - memset ((unsigned char *) &addr->s_addr + (ocets - 1), - (256 - (1 << (32 - cidr) % 8)), 1); - } - - return (0); +int inet_cidrtoaddr (int cidr, struct in_addr *addr) +{ + int ocets; + + if (cidr < 0 || cidr > 32) + { + errno = EINVAL; + return (-1); + } + ocets = (cidr + 7) / 8; + + memset (addr, 0, sizeof (*addr)); + if (ocets > 0) + { + memset (&addr->s_addr, 255, (size_t) ocets - 1); + memset ((unsigned char *) &addr->s_addr + (ocets - 1), + (256 - (1 << (32 - cidr) % 8)), 1); + } + + return (0); } uint32_t get_netmask (uint32_t addr) { - uint32_t dst; + uint32_t dst; - if (addr == 0) - return (0); + if (addr == 0) + return (0); - dst = htonl (addr); - if (IN_CLASSA (dst)) - return (ntohl (IN_CLASSA_NET)); - if (IN_CLASSB (dst)) - return (ntohl (IN_CLASSB_NET)); - if (IN_CLASSC (dst)) - return (ntohl (IN_CLASSC_NET)); + dst = htonl (addr); + if (IN_CLASSA (dst)) + return (ntohl (IN_CLASSA_NET)); + if (IN_CLASSB (dst)) + return (ntohl (IN_CLASSB_NET)); + if (IN_CLASSC (dst)) + return (ntohl (IN_CLASSC_NET)); - return (0); + return (0); } char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen) { - static char buffer[(HWADDR_LEN * 3) + 1]; - char *p = buffer; - size_t i; + static char buffer[(HWADDR_LEN * 3) + 1]; + char *p = buffer; + size_t i; - for (i = 0; i < hwlen && i < HWADDR_LEN; i++) { - if (i > 0) - *p ++= ':'; - p += snprintf (p, 3, "%.2x", hwaddr[i]); - } + for (i = 0; i < hwlen && i < HWADDR_LEN; i++) + { + if (i > 0) + *p ++ = ':'; + p += snprintf (p, 3, "%.2x", hwaddr[i]); + } - *p ++= '\0'; + *p ++ = '\0'; - return (buffer); + return (buffer); } size_t hwaddr_aton (unsigned char *buffer, const char *addr) { - char c[3]; - const char *p = addr; - unsigned char *bp = buffer; - size_t len = 0; - - c[2] = '\0'; - while (*p) { - c[0] = *p++; - c[1] = *p++; - /* Ensure that next data is EOL or a seperator with data */ - if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) { - errno = EINVAL; - return (0); - } - /* Ensure that digits are hex */ - if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) { - errno = EINVAL; - return (0); - } - p++; - if (bp) - *bp++ = (unsigned char) strtol (c, NULL, 16); - else - len++; - } - - if (bp) - return (bp - buffer); - return (len); + char c[3]; + const char *p = addr; + unsigned char *bp = buffer; + size_t len = 0; + + c[2] = '\0'; + while (*p) + { + c[0] = *p++; + c[1] = *p++; + /* Ensure that next data is EOL or a seperator with data */ + if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) + { + errno = EINVAL; + return (0); + } + /* Ensure that digits are hex */ + if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) + { + errno = EINVAL; + return (0); + } + p++; + if (bp) + *bp++ = (unsigned char) strtol (c, NULL, 16); + else + len++; + } + + if (bp) + return (bp - buffer); + return (len); } static int _do_interface (const char *ifname, - _unused unsigned char *hwaddr, _unused size_t *hwlen, - struct in_addr *addr, - bool flush, bool get) + _unused unsigned char *hwaddr, _unused size_t *hwlen, + struct in_addr *addr, + bool flush, bool get) { - int s; - struct ifconf ifc; - int retval = 0; - int len = 10 * sizeof (struct ifreq); - int lastlen = 0; - char *p; - - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - /* Not all implementations return the needed buffer size for - * SIOGIFCONF so we loop like so for all until it works */ - memset (&ifc, 0, sizeof (ifc)); - for (;;) { - ifc.ifc_len = len; - ifc.ifc_buf = xmalloc ((size_t) len); - if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { - if (errno != EINVAL || lastlen != 0) { - logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", - strerror (errno)); - close (s); - free (ifc.ifc_buf); - return -1; - } - } else { - if (ifc.ifc_len == lastlen) - break; - lastlen = ifc.ifc_len; - } - - free (ifc.ifc_buf); - ifc.ifc_buf = NULL; - len *= 2; - } - - for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) { - union { - char *buffer; - struct ifreq *ifr; - } ifreqs; - struct sockaddr_in address; - struct ifreq *ifr; - - /* Cast the ifc buffer to an ifreq cleanly */ - ifreqs.buffer = p; - ifr = ifreqs.ifr; + int s; + struct ifconf ifc; + int retval = 0; + int len = 10 * sizeof (struct ifreq); + int lastlen = 0; + char *p; + + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + /* Not all implementations return the needed buffer size for + * SIOGIFCONF so we loop like so for all until it works */ + memset (&ifc, 0, sizeof (ifc)); + for (;;) + { + ifc.ifc_len = len; + ifc.ifc_buf = xmalloc ((size_t) len); + if (ioctl (s, SIOCGIFCONF, &ifc) == -1) + { + if (errno != EINVAL || lastlen != 0) + { + logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", + strerror (errno)); + close (s); + free (ifc.ifc_buf); + return -1; + } + } + else + { + if (ifc.ifc_len == lastlen) + break; + lastlen = ifc.ifc_len; + } + + free (ifc.ifc_buf); + ifc.ifc_buf = NULL; + len *= 2; + } + + for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) + { + union + { + char *buffer; + struct ifreq *ifr; + } ifreqs; + struct sockaddr_in address; + struct ifreq *ifr; + + /* Cast the ifc buffer to an ifreq cleanly */ + ifreqs.buffer = p; + ifr = ifreqs.ifr; #ifdef __linux__ - p += sizeof (*ifr); + p += sizeof (*ifr); #else - p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len; + p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len; #endif - if (strcmp (ifname, ifr->ifr_name) != 0) - continue; + if (strcmp (ifname, ifr->ifr_name) != 0) + continue; #ifdef AF_LINK - if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) { - struct sockaddr_dl sdl; - - memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl)); - *hwlen = sdl.sdl_alen; - memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, - (size_t) sdl.sdl_alen); - retval = 1; - break; - } + if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) + { + struct sockaddr_dl sdl; + + memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl)); + *hwlen = sdl.sdl_alen; + memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, + (size_t) sdl.sdl_alen); + retval = 1; + break; + } #endif - if (ifr->ifr_addr.sa_family == AF_INET) { - memcpy (&address, &ifr->ifr_addr, sizeof (address)); - if (flush) { - struct sockaddr_in netmask; - - if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) { - logger (LOG_ERR, - "ioctl SIOCGIFNETMASK: %s", - strerror (errno)); - continue; - } - memcpy (&netmask, &ifr->ifr_addr, - sizeof (netmask)); - - if (del_address (ifname, - address.sin_addr, - netmask.sin_addr) == -1) - retval = -1; - } else if (get) { - addr->s_addr = address.sin_addr.s_addr; - retval = 1; - break; - } else if (address.sin_addr.s_addr == addr->s_addr) { - retval = 1; - break; - } - } - - } - - close (s); - free (ifc.ifc_buf); - return retval; + if (ifr->ifr_addr.sa_family == AF_INET) + { + memcpy (&address, &ifr->ifr_addr, sizeof (address)); + if (flush) + { + struct sockaddr_in netmask; + + if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) + { + logger (LOG_ERR, + "ioctl SIOCGIFNETMASK: %s", + strerror (errno)); + continue; + } + memcpy (&netmask, &ifr->ifr_addr, + sizeof (netmask)); + + if (del_address (ifname, + address.sin_addr, + netmask.sin_addr) == -1) + retval = -1; + } + else if (get) + { + addr->s_addr = address.sin_addr.s_addr; + retval = 1; + break; + } + else if (address.sin_addr.s_addr == addr->s_addr) + { + retval = 1; + break; + } + } + + } + + close (s); + free (ifc.ifc_buf); + return retval; } interface_t *read_interface (const char *ifname, _unused int metric) { - int s; - struct ifreq ifr; - interface_t *iface = NULL; - unsigned char *hwaddr = NULL; - size_t hwlen = 0; - sa_family_t family = 0; - unsigned short mtu; + int s; + struct ifreq ifr; + interface_t *iface = NULL; + unsigned char *hwaddr = NULL; + size_t hwlen = 0; + sa_family_t family = 0; + unsigned short mtu; #ifdef __linux__ - char *p; + char *p; #endif - if (! ifname) - return NULL; + if (! ifname) + return NULL; - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return NULL; - } + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return NULL; + } #ifdef __linux__ - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); - goto exit; - } - - switch (ifr.ifr_hwaddr.sa_family) { - case ARPHRD_ETHER: - case ARPHRD_IEEE802: - hwlen = ETHER_ADDR_LEN; - break; - case ARPHRD_IEEE1394: - hwlen = EUI64_ADDR_LEN; - case ARPHRD_INFINIBAND: - hwlen = INFINIBAND_ADDR_LEN; - break; - default: - logger (LOG_ERR, - "interface is not Ethernet, FireWire, " \ - "InfiniBand or Token Ring"); - goto exit; - } - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); - family = ifr.ifr_hwaddr.sa_family; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); + goto exit; + } + + switch (ifr.ifr_hwaddr.sa_family) + { + case ARPHRD_ETHER: + case ARPHRD_IEEE802: + hwlen = ETHER_ADDR_LEN; + break; + case ARPHRD_IEEE1394: + hwlen = EUI64_ADDR_LEN; + case ARPHRD_INFINIBAND: + hwlen = INFINIBAND_ADDR_LEN; + break; + default: + logger (LOG_ERR, + "interface is not Ethernet, FireWire, " \ + "InfiniBand or Token Ring"); + goto exit; + } + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); + family = ifr.ifr_hwaddr.sa_family; #else - ifr.ifr_metric = metric; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); - goto exit; - } - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) { - logger (LOG_ERR, "could not find interface %s", ifname); - goto exit; - } - - family = ARPHRD_ETHER; + ifr.ifr_metric = metric; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); + goto exit; + } + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) + { + logger (LOG_ERR, "could not find interface %s", ifname); + goto exit; + } + + family = ARPHRD_ETHER; #endif - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCGIFMTU, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - goto exit; - } - - if (ifr.ifr_mtu < MTU_MIN) { - logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", - ifr.ifr_mtu, MTU_MIN); - ifr.ifr_mtu = MTU_MIN; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCSIFMTU, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", - strerror (errno)); - goto exit; - } - } - mtu = ifr.ifr_mtu; - - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCGIFMTU, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); + goto exit; + } + + if (ifr.ifr_mtu < MTU_MIN) + { + logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", + ifr.ifr_mtu, MTU_MIN); + ifr.ifr_mtu = MTU_MIN; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCSIFMTU, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", + strerror (errno)); + goto exit; + } + } + mtu = ifr.ifr_mtu; + + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); #ifdef __linux__ - /* We can only bring the real interface up */ - if ((p = strchr (ifr.ifr_name, ':'))) - *p = '\0'; + /* We can only bring the real interface up */ + if ((p = strchr (ifr.ifr_name, ':'))) + * p = '\0'; #endif - if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); - goto exit; - } - - if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) { - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) { - logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", - strerror (errno)); - goto exit; - } - } - - iface = xzalloc (sizeof (*iface)); - strlcpy (iface->name, ifname, IF_NAMESIZE); + if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); + goto exit; + } + + if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) + { + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) + { + logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", + strerror (errno)); + goto exit; + } + } + + iface = xzalloc (sizeof (*iface)); + strlcpy (iface->name, ifname, IF_NAMESIZE); #ifdef ENABLE_INFO - snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); + snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); #endif - memcpy (&iface->hwaddr, hwaddr, hwlen); - iface->hwlen = hwlen; + memcpy (&iface->hwaddr, hwaddr, hwlen); + iface->hwlen = hwlen; - iface->family = family; - iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)); - iface->mtu = iface->previous_mtu = mtu; + iface->family = family; + iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)); + iface->mtu = iface->previous_mtu = mtu; - logger (LOG_INFO, "hardware address = %s", - hwaddr_ntoa (iface->hwaddr, iface->hwlen)); + logger (LOG_INFO, "hardware address = %s", + hwaddr_ntoa (iface->hwaddr, iface->hwlen)); - /* 0 is a valid fd, so init to -1 */ - iface->fd = -1; + /* 0 is a valid fd, so init to -1 */ + iface->fd = -1; #ifdef __linux__ - iface->listen_fd = -1; + iface->listen_fd = -1; #endif exit: - close (s); - free (hwaddr); - return iface; + close (s); + free (hwaddr); + return iface; } int get_mtu (const char *ifname) { - struct ifreq ifr; - int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - r = ioctl (s, SIOCGIFMTU, &ifr); - close (s); - - if (r == -1) { - logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - return (-1); - } - - return (ifr.ifr_mtu); + struct ifreq ifr; + int r; + int s; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + r = ioctl (s, SIOCGIFMTU, &ifr); + close (s); + + if (r == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); + return (-1); + } + + return (ifr.ifr_mtu); } int set_mtu (const char *ifname, short int mtu) { - struct ifreq ifr; - int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (ifr)); - logger (LOG_DEBUG, "setting MTU to %d", mtu); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - ifr.ifr_mtu = mtu; - r = ioctl (s, SIOCSIFMTU, &ifr); - close (s); - - if (r == -1) - logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); - - return (r == 0 ? 0 : -1); + struct ifreq ifr; + int r; + int s; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (ifr)); + logger (LOG_DEBUG, "setting MTU to %d", mtu); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + ifr.ifr_mtu = mtu; + r = ioctl (s, SIOCSIFMTU, &ifr); + close (s); + + if (r == -1) + logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); + + return (r == 0 ? 0 : -1); } static void log_route (struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - _unused int metric, - int change, int del) + struct in_addr netmask, + struct in_addr gateway, + _unused int metric, + int change, int del) { - char *dstd = xstrdup (inet_ntoa (destination)); + char *dstd = xstrdup (inet_ntoa (destination)); #ifdef __linux__ #define METRIC " metric %d" @@ -502,34 +542,34 @@ static void log_route (struct in_addr destination, #define METRIC "" #endif - if (gateway.s_addr == destination.s_addr || - gateway.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s route to %s/%d" METRIC, - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask) + if (gateway.s_addr == destination.s_addr || + gateway.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s route to %s/%d" METRIC, + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask) #ifdef __linux__ - , metric + , metric #endif - ); - else if (destination.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s default route via %s" METRIC, - change ? "changing" : del ? "removing" : "adding", - inet_ntoa (gateway) + ); + else if (destination.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s default route via %s" METRIC, + change ? "changing" : del ? "removing" : "adding", + inet_ntoa (gateway) #ifdef __linux__ - , metric + , metric #endif - ); - else - logger (LOG_INFO, "%s route to %s/%d via %s" METRIC, - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask), inet_ntoa (gateway) + ); + else + logger (LOG_INFO, "%s route to %s/%d via %s" METRIC, + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask), inet_ntoa (gateway) #ifdef __linux__ - , metric + , metric #endif - ); + ); - free (dstd); + free (dstd); } #if defined(BSD) || defined(__FreeBSD_kernel__) @@ -543,22 +583,23 @@ static void log_route (struct in_addr destination, #endif static int do_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast, - int del) + struct in_addr netmask, struct in_addr broadcast, + int del) { - int s; - struct ifaliasreq ifa; + int s; + struct ifaliasreq ifa; - if (! ifname) - return -1; + if (! ifname) + return -1; - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } - memset (&ifa, 0, sizeof (ifa)); - strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name)); + memset (&ifa, 0, sizeof (ifa)); + strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name)); #define ADDADDR(_var, _addr) { \ union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \ @@ -568,70 +609,73 @@ static int do_address (const char *ifname, struct in_addr address, memcpy (&_s.sin->sin_addr, &_addr, sizeof (_s.sin->sin_addr)); \ } - ADDADDR (ifa.ifra_addr, address); - ADDADDR (ifa.ifra_mask, netmask); -if (! del) - ADDADDR (ifa.ifra_broadaddr, broadcast); + ADDADDR (ifa.ifra_addr, address); + ADDADDR (ifa.ifra_mask, netmask); + if (! del) + ADDADDR (ifa.ifra_broadaddr, broadcast); #undef ADDADDR - if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) { - logger (LOG_ERR, "ioctl %s: %s", - del ? "SIOCDIFADDR" : "SIOCAIFADDR", - strerror (errno)); - close (s); - return -1; - } - -close (s); -return 0; + if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) + { + logger (LOG_ERR, "ioctl %s: %s", + del ? "SIOCDIFADDR" : "SIOCAIFADDR", + strerror (errno)); + close (s); + return -1; + } + + close (s); + return 0; } static int do_route (const char *ifname, - struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - int metric, - int change, int del) + struct in_addr destination, + struct in_addr netmask, + struct in_addr gateway, + int metric, + int change, int del) { - int s; - static int seq; - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; + int s; + static int seq; + union sockunion + { + struct sockaddr sa; + struct sockaddr_in sin; #ifdef INET6 - struct sockaddr_in6 sin6; + struct sockaddr_in6 sin6; #endif - struct sockaddr_dl sdl; - struct sockaddr_storage ss; - } su; - struct rtm - { - struct rt_msghdr hdr; - char buffer[sizeof (su) * 3]; - } rtm; - char *bp = rtm.buffer; - size_t l; - - if (! ifname) - return -1; - - log_route (destination, netmask, gateway, metric, change, del); - - if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&rtm, 0, sizeof (rtm)); - - rtm.hdr.rtm_version = RTM_VERSION; - rtm.hdr.rtm_seq = ++seq; - rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; - rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC; - - /* This order is important */ - rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; + struct sockaddr_dl sdl; + struct sockaddr_storage ss; + } su; + struct rtm + { + struct rt_msghdr hdr; + char buffer[sizeof (su) * 3]; + } rtm; + char *bp = rtm.buffer; + size_t l; + + if (! ifname) + return -1; + + log_route (destination, netmask, gateway, metric, change, del); + + if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&rtm, 0, sizeof (rtm)); + + rtm.hdr.rtm_version = RTM_VERSION; + rtm.hdr.rtm_seq = ++seq; + rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; + rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC; + + /* This order is important */ + rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; #define ADDADDR(_addr) \ memset (&su, 0, sizeof (su)); \ @@ -642,52 +686,55 @@ static int do_route (const char *ifname, memcpy (bp, &(su), l); \ bp += l; - ADDADDR (destination); - - if (netmask.s_addr == INADDR_BROADCAST || - gateway.s_addr == INADDR_ANY) - { - /* Make us a link layer socket */ - unsigned char *hwaddr; - size_t hwlen = 0; - - if (netmask.s_addr == INADDR_BROADCAST) - rtm.hdr.rtm_flags |= RTF_HOST; - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); - memset (&su, 0, sizeof (su)); - su.sdl.sdl_len = sizeof (su.sdl); - su.sdl.sdl_family = AF_LINK; - su.sdl.sdl_nlen = strlen (ifname); - memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen); - su.sdl.sdl_alen = hwlen; - memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, - hwaddr, (size_t) su.sdl.sdl_alen); - - l = SA_SIZE (&(su.sa)); - memcpy (bp, &su, l); - bp += l; - free (hwaddr); - } else { - rtm.hdr.rtm_flags |= RTF_GATEWAY; - ADDADDR (gateway); - } - - ADDADDR (netmask); + ADDADDR (destination); + + if (netmask.s_addr == INADDR_BROADCAST || + gateway.s_addr == INADDR_ANY) + { + /* Make us a link layer socket */ + unsigned char *hwaddr; + size_t hwlen = 0; + + if (netmask.s_addr == INADDR_BROADCAST) + rtm.hdr.rtm_flags |= RTF_HOST; + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); + memset (&su, 0, sizeof (su)); + su.sdl.sdl_len = sizeof (su.sdl); + su.sdl.sdl_family = AF_LINK; + su.sdl.sdl_nlen = strlen (ifname); + memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen); + su.sdl.sdl_alen = hwlen; + memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, + hwaddr, (size_t) su.sdl.sdl_alen); + + l = SA_SIZE (&(su.sa)); + memcpy (bp, &su, l); + bp += l; + free (hwaddr); + } + else + { + rtm.hdr.rtm_flags |= RTF_GATEWAY; + ADDADDR (gateway); + } + + ADDADDR (netmask); #undef ADDADDR - rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; - if (write (s, &rtm, l) == -1) { - /* Don't report error about routes already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } - - close (s); - return 0; + rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; + if (write (s, &rtm, l) == -1) + { + /* Don't report error about routes already existing */ + if (errno != EEXIST) + logger (LOG_ERR, "write: %s", strerror (errno)); + close (s); + return -1; + } + + close (s); + return 0; } #elif __linux__ @@ -698,363 +745,381 @@ static int do_route (const char *ifname, #define BUFFERLEN 256 int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg) { - int s; - pid_t mypid = getpid (); - struct sockaddr_nl nl; - struct iovec iov; - struct msghdr msg; - static unsigned int seq; - char *buffer; - ssize_t bytes; - union - { - char *buffer; - struct nlmsghdr *nlm; - } h; - - if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&nl, 0, sizeof (nl)); - nl.nl_family = AF_NETLINK; - if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (s); - return -1; - } - - memset (&iov, 0, sizeof (iov)); - iov.iov_base = hdr; - iov.iov_len = hdr->nlmsg_len; - - memset (&msg, 0, sizeof (msg)); - msg.msg_name = &nl; - msg.msg_namelen = sizeof (nl); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - /* Request a reply */ - hdr->nlmsg_flags |= NLM_F_ACK; - hdr->nlmsg_seq = ++seq; - - if (sendmsg (s, &msg, 0) == -1) { - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } - - buffer = xzalloc (sizeof (char) * BUFFERLEN); - iov.iov_base = buffer; - - for (;;) { - iov.iov_len = BUFFERLEN; - bytes = recvmsg (s, &msg, 0); - - if (bytes == -1) { - if (errno != EINTR) - logger (LOG_ERR, "recvmsg: %s", - strerror (errno)); - continue; - } - - if (bytes == 0) { - logger (LOG_ERR, "netlink: EOF"); - goto eexit; - } - - if (msg.msg_namelen != sizeof (nl)) { - logger (LOG_ERR, - "netlink: sender address length mismatch"); - goto eexit; - } - - for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) { - int len = h.nlm->nlmsg_len; - int l = len - sizeof (*h.nlm); - struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); - - if (l < 0 || len > bytes) { - if (msg.msg_flags & MSG_TRUNC) - logger (LOG_ERR, "netlink: truncated message"); - else - logger (LOG_ERR, "netlink: malformed message"); - goto eexit; - } - - /* Ensure it's our message */ - if (nl.nl_pid != 0 || - (pid_t) h.nlm->nlmsg_pid != mypid || - h.nlm->nlmsg_seq != seq) - { - /* Next Message */ - bytes -= NLMSG_ALIGN (len); - h.buffer += NLMSG_ALIGN (len); - continue; - } - - /* We get an NLMSG_ERROR back with a code of zero for success */ - if (h.nlm->nlmsg_type != NLMSG_ERROR) { - logger (LOG_ERR, "netlink: unexpected reply %d", - h.nlm->nlmsg_type); - goto eexit; - } - - if ((unsigned) l < sizeof (*err)) { - logger (LOG_ERR, "netlink: error truncated"); - goto eexit; - } - - if (err->error == 0) { - int retval = 0; - - close (s); - if (callback) { - if ((retval = callback (hdr, arg)) == -1) - logger (LOG_ERR, "netlink: callback failed"); - } - free (buffer); - return (retval); - } - - errno = -err->error; - /* Don't report on something already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "netlink: %s", - strerror (errno)); - goto eexit; - } - } + int s; + pid_t mypid = getpid (); + struct sockaddr_nl nl; + struct iovec iov; + struct msghdr msg; + static unsigned int seq; + char *buffer; + ssize_t bytes; + union + { + char *buffer; + struct nlmsghdr *nlm; + } h; + + if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&nl, 0, sizeof (nl)); + nl.nl_family = AF_NETLINK; + if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) + { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (s); + return -1; + } + + memset (&iov, 0, sizeof (iov)); + iov.iov_base = hdr; + iov.iov_len = hdr->nlmsg_len; + + memset (&msg, 0, sizeof (msg)); + msg.msg_name = &nl; + msg.msg_namelen = sizeof (nl); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + /* Request a reply */ + hdr->nlmsg_flags |= NLM_F_ACK; + hdr->nlmsg_seq = ++seq; + + if (sendmsg (s, &msg, 0) == -1) + { + logger (LOG_ERR, "write: %s", strerror (errno)); + close (s); + return -1; + } + + buffer = xzalloc (sizeof (char) * BUFFERLEN); + iov.iov_base = buffer; + + for (;;) + { + iov.iov_len = BUFFERLEN; + bytes = recvmsg (s, &msg, 0); + + if (bytes == -1) + { + if (errno != EINTR) + logger (LOG_ERR, "recvmsg: %s", + strerror (errno)); + continue; + } + + if (bytes == 0) + { + logger (LOG_ERR, "netlink: EOF"); + goto eexit; + } + + if (msg.msg_namelen != sizeof (nl)) + { + logger (LOG_ERR, + "netlink: sender address length mismatch"); + goto eexit; + } + + for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) + { + int len = h.nlm->nlmsg_len; + int l = len - sizeof (*h.nlm); + struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); + + if (l < 0 || len > bytes) + { + if (msg.msg_flags & MSG_TRUNC) + logger (LOG_ERR, "netlink: truncated message"); + else + logger (LOG_ERR, "netlink: malformed message"); + goto eexit; + } + + /* Ensure it's our message */ + if (nl.nl_pid != 0 || + (pid_t) h.nlm->nlmsg_pid != mypid || + h.nlm->nlmsg_seq != seq) + { + /* Next Message */ + bytes -= NLMSG_ALIGN (len); + h.buffer += NLMSG_ALIGN (len); + continue; + } + + /* We get an NLMSG_ERROR back with a code of zero for success */ + if (h.nlm->nlmsg_type != NLMSG_ERROR) + { + logger (LOG_ERR, "netlink: unexpected reply %d", + h.nlm->nlmsg_type); + goto eexit; + } + + if ((unsigned) l < sizeof (*err)) + { + logger (LOG_ERR, "netlink: error truncated"); + goto eexit; + } + + if (err->error == 0) + { + int retval = 0; + + close (s); + if (callback) + { + if ((retval = callback (hdr, arg)) == -1) + logger (LOG_ERR, "netlink: callback failed"); + } + free (buffer); + return (retval); + } + + errno = -err->error; + /* Don't report on something already existing */ + if (errno != EEXIST) + logger (LOG_ERR, "netlink: %s", + strerror (errno)); + goto eexit; + } + } eexit: - close (s); - free (buffer); - return -1; + close (s); + free (buffer); + return -1; } #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) static int add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type, - const void *data, int alen) + const void *data, int alen) { - int len = RTA_LENGTH(alen); - struct rtattr *rta; - - if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) { - logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", - maxlen); - return -1; - } - - rta = NLMSG_TAIL (n); - rta->rta_type = type; - rta->rta_len = len; - memcpy (RTA_DATA (rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len); - - return 0; + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) + { + logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", + maxlen); + return -1; + } + + rta = NLMSG_TAIL (n); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA (rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len); + + return 0; } static int add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, - uint32_t data) + uint32_t data) { - int len = RTA_LENGTH (sizeof (data)); - struct rtattr *rta; - - if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) { - logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", - maxlen); - return -1; - } - - rta = NLMSG_TAIL (n); - rta->rta_type = type; - rta->rta_len = len; - memcpy (RTA_DATA (rta), &data, sizeof (data)); - n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; - - return 0; + int len = RTA_LENGTH (sizeof (data)); + struct rtattr *rta; + + if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) + { + logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", + maxlen); + return -1; + } + + rta = NLMSG_TAIL (n); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA (rta), &data, sizeof (data)); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; } struct nlma { - struct nlmsghdr hdr; - struct ifaddrmsg ifa; - char buffer[64]; + struct nlmsghdr hdr; + struct ifaddrmsg ifa; + char buffer[64]; }; struct nlmr { - struct nlmsghdr hdr; - struct rtmsg rt; - char buffer[256]; + struct nlmsghdr hdr; + struct rtmsg rt; + char buffer[256]; }; static int do_address(const char *ifname, - struct in_addr address, struct in_addr netmask, - struct in_addr broadcast, int del) + struct in_addr address, struct in_addr netmask, + struct in_addr broadcast, int del) { - struct nlma *nlm; - int retval; - - if (!ifname) - return -1; - - nlm = xzalloc (sizeof (*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); - nlm->hdr.nlmsg_flags = NLM_F_REQUEST; - if (! del) - nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; - if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - ifname); - free (nlm); - return -1; - } - nlm->ifa.ifa_family = AF_INET; - - nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); - - /* This creates the aliased interface */ - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL, - ifname, strlen (ifname) + 1); - - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL, - &address.s_addr, sizeof (address.s_addr)); - if (! del) - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, - &broadcast.s_addr, sizeof (broadcast.s_addr)); - - retval = send_netlink (&nlm->hdr, NULL, NULL); - free (nlm); - return retval; + struct nlma *nlm; + int retval; + + if (!ifname) + return -1; + + nlm = xzalloc (sizeof (*nlm)); + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); + nlm->hdr.nlmsg_flags = NLM_F_REQUEST; + if (! del) + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; + nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; + if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) + { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + ifname); + free (nlm); + return -1; + } + nlm->ifa.ifa_family = AF_INET; + + nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); + + /* This creates the aliased interface */ + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL, + ifname, strlen (ifname) + 1); + + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL, + &address.s_addr, sizeof (address.s_addr)); + if (! del) + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, + &broadcast.s_addr, sizeof (broadcast.s_addr)); + + retval = send_netlink (&nlm->hdr, NULL, NULL); + free (nlm); + return retval; } static int do_route (const char *ifname, - struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - int metric, int change, int del) + struct in_addr destination, + struct in_addr netmask, + struct in_addr gateway, + int metric, int change, int del) { - struct nlmr *nlm; - unsigned int ifindex; - int retval; - - if (! ifname) - return -1; - - log_route (destination, netmask, gateway, metric, change, del); - - if (! (ifindex = if_nametoindex (ifname))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - ifname); - return -1; - } - - nlm = xzalloc (sizeof (*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - if (change) - nlm->hdr.nlmsg_flags = NLM_F_REPLACE; - else if (! del) - nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; - nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; - nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; - nlm->rt.rtm_family = AF_INET; - nlm->rt.rtm_table = RT_TABLE_MAIN; - - if (del) - nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; - else { - nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; - nlm->rt.rtm_protocol = RTPROT_BOOT; - if (netmask.s_addr == INADDR_BROADCAST || - gateway.s_addr == INADDR_ANY) - nlm->rt.rtm_scope = RT_SCOPE_LINK; - else - nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; - nlm->rt.rtm_type = RTN_UNICAST; - } - - nlm->rt.rtm_dst_len = inet_ntocidr (netmask); - add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST, - &destination.s_addr, sizeof (destination.s_addr)); - if (netmask.s_addr != INADDR_BROADCAST && - destination.s_addr != gateway.s_addr) - add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY, - &gateway.s_addr, sizeof (gateway.s_addr)); - - add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); - add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); - - retval = send_netlink (&nlm->hdr, NULL, NULL); - free (nlm); - return retval; + struct nlmr *nlm; + unsigned int ifindex; + int retval; + + if (! ifname) + return -1; + + log_route (destination, netmask, gateway, metric, change, del); + + if (! (ifindex = if_nametoindex (ifname))) + { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + ifname); + return -1; + } + + nlm = xzalloc (sizeof (*nlm)); + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + if (change) + nlm->hdr.nlmsg_flags = NLM_F_REPLACE; + else if (! del) + nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; + nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; + nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; + nlm->rt.rtm_family = AF_INET; + nlm->rt.rtm_table = RT_TABLE_MAIN; + + if (del) + nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; + else + { + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + nlm->rt.rtm_protocol = RTPROT_BOOT; + if (netmask.s_addr == INADDR_BROADCAST || + gateway.s_addr == INADDR_ANY) + nlm->rt.rtm_scope = RT_SCOPE_LINK; + else + nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; + nlm->rt.rtm_type = RTN_UNICAST; + } + + nlm->rt.rtm_dst_len = inet_ntocidr (netmask); + add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST, + &destination.s_addr, sizeof (destination.s_addr)); + if (netmask.s_addr != INADDR_BROADCAST && + destination.s_addr != gateway.s_addr) + add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY, + &gateway.s_addr, sizeof (gateway.s_addr)); + + add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); + add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); + + retval = send_netlink (&nlm->hdr, NULL, NULL); + free (nlm); + return retval; } #else - #error "Platform not supported!" - #error "We currently support BPF and Linux sockets." - #error "Other platforms may work using BPF. If yours does, please let me know" - #error "so I can add it to our list." +#error "Platform not supported!" +#error "We currently support BPF and Linux sockets." +#error "Other platforms may work using BPF. If yours does, please let me know" +#error "so I can add it to our list." #endif int add_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast) + struct in_addr netmask, struct in_addr broadcast) { - logger (LOG_INFO, "adding IP address %s/%d", - inet_ntoa (address), inet_ntocidr (netmask)); + logger (LOG_INFO, "adding IP address %s/%d", + inet_ntoa (address), inet_ntocidr (netmask)); - return (do_address (ifname, address, netmask, broadcast, 0)); + return (do_address (ifname, address, netmask, broadcast, 0)); } int del_address (const char *ifname, - struct in_addr address, struct in_addr netmask) + struct in_addr address, struct in_addr netmask) { - struct in_addr t; + struct in_addr t; - logger (LOG_INFO, "removing IP address %s/%d", - inet_ntoa (address), inet_ntocidr (netmask)); + logger (LOG_INFO, "removing IP address %s/%d", + inet_ntoa (address), inet_ntocidr (netmask)); - memset (&t, 0, sizeof (t)); - return (do_address (ifname, address, netmask, t, 1)); + memset (&t, 0, sizeof (t)); + return (do_address (ifname, address, netmask, t, 1)); } int add_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) + struct in_addr netmask, struct in_addr gateway, int metric) { - return (do_route (ifname, destination, netmask, gateway, metric, 0, 0)); + return (do_route (ifname, destination, netmask, gateway, metric, 0, 0)); } int change_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) + struct in_addr netmask, struct in_addr gateway, int metric) { - return (do_route (ifname, destination, netmask, gateway, metric, 1, 0)); + return (do_route (ifname, destination, netmask, gateway, metric, 1, 0)); } int del_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) + struct in_addr netmask, struct in_addr gateway, int metric) { - return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); + return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); } int flush_addresses (const char *ifname) { - return (_do_interface (ifname, NULL, NULL, NULL, true, false)); + return (_do_interface (ifname, NULL, NULL, NULL, true, false)); } in_addr_t get_address (const char *ifname) { - struct in_addr address; - if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) - return (address.s_addr); - return (0); + struct in_addr address; + if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) + return (address.s_addr); + return (0); } int has_address (const char *ifname, struct in_addr address) { - return (_do_interface (ifname, NULL, NULL, &address, false, false)); + return (_do_interface (ifname, NULL, NULL, &address, false, false)); } diff --git a/src/customdhcpcd/interface.h b/src/customdhcpcd/interface.h index 8215d48..8431080 100644 --- a/src/customdhcpcd/interface.h +++ b/src/customdhcpcd/interface.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -93,48 +93,48 @@ typedef struct route_t { - struct in_addr destination; - struct in_addr netmask; - struct in_addr gateway; - STAILQ_ENTRY (route_t) entries; + struct in_addr destination; + struct in_addr netmask; + struct in_addr gateway; + STAILQ_ENTRY (route_t) entries; } route_t; STAILQ_HEAD (route_head, route_t); typedef struct address_t { - struct in_addr address; - STAILQ_ENTRY (address_t) entries; + struct in_addr address; + STAILQ_ENTRY (address_t) entries; } address_t; STAILQ_HEAD (address_head, address_t); typedef struct interface_t { - char name[IF_NAMESIZE]; - sa_family_t family; - unsigned char hwaddr[HWADDR_LEN]; - size_t hwlen; - bool arpable; - unsigned short mtu; + char name[IF_NAMESIZE]; + sa_family_t family; + unsigned char hwaddr[HWADDR_LEN]; + size_t hwlen; + bool arpable; + unsigned short mtu; - int fd; - size_t buffer_length; + int fd; + size_t buffer_length; #ifdef __linux__ - int listen_fd; - int socket_protocol; + int listen_fd; + int socket_protocol; #endif - char infofile[PATH_MAX]; + char infofile[PATH_MAX]; - unsigned short previous_mtu; - struct in_addr previous_address; - struct in_addr previous_netmask; - struct route_head *previous_routes; + unsigned short previous_mtu; + struct in_addr previous_address; + struct in_addr previous_netmask; + struct route_head *previous_routes; - time_t start_uptime; + time_t start_uptime; - unsigned char *clientid; - size_t clientid_len; + unsigned char *clientid; + size_t clientid_len; } interface_t; void free_address (struct address_head *addresses); @@ -148,20 +148,20 @@ int get_mtu (const char *ifname); int set_mtu (const char *ifname, short int mtu); int add_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast); + struct in_addr netmask, struct in_addr broadcast); int del_address (const char *ifname, struct in_addr address, - struct in_addr netmask); + struct in_addr netmask); int flush_addresses (const char *ifname); in_addr_t get_address (const char *ifname); int has_address (const char *ifname, struct in_addr address); int add_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric); + struct in_addr netmask, struct in_addr gateway, int metric); int change_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric); + struct in_addr netmask, struct in_addr gateway, int metric); int del_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric); + struct in_addr netmask, struct in_addr gateway, int metric); int inet_ntocidr (struct in_addr address); int inet_cidrtoaddr (int cidr, struct in_addr *addr); diff --git a/src/customdhcpcd/ipv4ll.c b/src/customdhcpcd/ipv4ll.c index 9742b9a..c8ce8b8 100644 --- a/src/customdhcpcd/ipv4ll.c +++ b/src/customdhcpcd/ipv4ll.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -35,36 +35,38 @@ #ifdef ENABLE_IPV4LL #ifndef ENABLE_ARP - # error IPV4LL requires ARP +# error IPV4LL requires ARP #endif -#define IPV4LL_LEASETIME 20 +#define IPV4LL_LEASETIME 20 -int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp) { - struct in_addr addr; +int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp) +{ + struct in_addr addr; - for (;;) { - addr.s_addr = htonl (LINKLOCAL_ADDR | - (((uint32_t) abs ((int) random ()) - % 0xFD00) + 0x0100)); - errno = 0; - if (! arp_claim (iface, addr)) - break; - /* Our ARP may have been interrupted */ - if (errno) - return (-1); - } + for (;;) + { + addr.s_addr = htonl (LINKLOCAL_ADDR | + (((uint32_t) abs ((int) random ()) + % 0xFD00) + 0x0100)); + errno = 0; + if (! arp_claim (iface, addr)) + break; + /* Our ARP may have been interrupted */ + if (errno) + return (-1); + } - dhcp->address.s_addr = addr.s_addr; - dhcp->netmask.s_addr = htonl (LINKLOCAL_MASK); - dhcp->broadcast.s_addr = htonl (LINKLOCAL_BRDC); + dhcp->address.s_addr = addr.s_addr; + dhcp->netmask.s_addr = htonl (LINKLOCAL_MASK); + dhcp->broadcast.s_addr = htonl (LINKLOCAL_BRDC); - /* Finally configure some DHCP like lease times */ - dhcp->leasetime = IPV4LL_LEASETIME; - dhcp->renewaltime = (dhcp->leasetime * 0.5); - dhcp->rebindtime = (dhcp->leasetime * 0.875); + /* Finally configure some DHCP like lease times */ + dhcp->leasetime = IPV4LL_LEASETIME; + dhcp->renewaltime = (dhcp->leasetime * 0.5); + dhcp->rebindtime = (dhcp->leasetime * 0.875); - return (0); + return (0); } #endif diff --git a/src/customdhcpcd/ipv4ll.h b/src/customdhcpcd/ipv4ll.h index 4fa8943..2dfc266 100644 --- a/src/customdhcpcd/ipv4ll.h +++ b/src/customdhcpcd/ipv4ll.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved diff --git a/src/customdhcpcd/logger.c b/src/customdhcpcd/logger.c index 2c8431d..48e6fa6 100644 --- a/src/customdhcpcd/logger.c +++ b/src/customdhcpcd/logger.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -46,109 +46,114 @@ static int loglevel = LOG_WARNING; static char logprefix[12] = { 0 }; -int logtolevel(const char *priority) { - CODE *c; +int logtolevel(const char *priority) +{ + CODE *c; - if (isdigit ((int) *priority)) - return (atoi(priority)); + if (isdigit ((int) *priority)) + return (atoi(priority)); - for (c = prioritynames; c->c_name; c++) - if (!strcasecmp(priority, c->c_name)) - return (c->c_val); + for (c = prioritynames; c->c_name; c++) + if (!strcasecmp(priority, c->c_name)) + return (c->c_val); - return (-1); + return (-1); } -static const char *leveltolog(int level) { - CODE *c; +static const char *leveltolog(int level) +{ + CODE *c; - for (c = prioritynames; c->c_name; c++) - if (c->c_val == level) - return (c->c_name); + for (c = prioritynames; c->c_name; c++) + if (c->c_val == level) + return (c->c_name); - return (NULL); + return (NULL); } -void setloglevel(int level) { - loglevel = level; +void setloglevel(int level) +{ + loglevel = level; } -void setlogprefix(const char *prefix) { - snprintf(logprefix, sizeof(logprefix), "%s", prefix); +void setlogprefix(const char *prefix) +{ + snprintf(logprefix, sizeof(logprefix), "%s", prefix); } -void logger(int level, const char *fmt, ...) { - va_list p; - //va_list p2; -// FILE *f = stderr; - FILE *f; - FILE *f2; - char* path = "/tmp/cdhcpcd.log"; - char* msgpath = "/tmp/cdhcpcd-msg.log"; - int size = 512; - char *msg = (char *) malloc (size); - - - f = fopen(path,"a"); - f2 = fopen(msgpath,"a"); - va_start (p, fmt); - //va_copy (p2, p); - - - vsnprintf (msg, size, fmt, p); - strcat(msg,"\n"); - logToQt(level, DHCPCD_LOG, msg); - - fprintf(f2, "%s, %s", leveltolog(level), logprefix); - fprintf(f2, "%s", msg); - fputc('\n', f2); - - fprintf(f, "%s, %s", leveltolog(level), logprefix); - vfprintf(f, fmt, p); - fputc('\n', f); - - /* stdout, stderr may be re-directed to some kind of buffer. - * So we always flush to ensure it's written. */ - fflush(f); - -// //logLoggerToQt(level, fmt, p); -// if (level <= LOG_ERR || level <= loglevel) { -// -// /* new function by Niklas Goby -// * send the log message also to our Qt programm. -// * implemented in logwriter.c -// * */ -// //logLoggerToQt(level, fmt, p); -// -// if (level == LOG_DEBUG || level == LOG_INFO) -// f = stdout; -// fprintf(f, "%s, %s", leveltolog(level), logprefix); -// vfprintf(f, fmt, p); -// fputc('\n', f); -// -// /* stdout, stderr may be re-directed to some kind of buffer. -// * So we always flush to ensure it's written. */ -// fflush(f); -// } -// if (level < LOG_DEBUG || level <= loglevel) { -// size_t len = strlen(logprefix); -// size_t fmt2len = strlen(fmt) + len + 1; -// char *fmt2 = malloc(sizeof(char) * fmt2len); -// char *pf = fmt2; -// if (fmt2) { -// memcpy(pf, logprefix, len); -// pf += len; -// strlcpy(pf, fmt, fmt2len - len); -// vsyslog(level, fmt2, p2); -// free(fmt2); -// } else { -// vsyslog(level, fmt, p2); -// syslog(LOG_ERR, "logger: memory exhausted"); -// exit(EXIT_FAILURE); -// } -// } - - //va_end (p2); - va_end (p); +void logger(int level, const char *fmt, ...) +{ + va_list p; + //va_list p2; + // FILE *f = stderr; + FILE *f; + FILE *f2; + char* path = "/tmp/cdhcpcd.log"; + char* msgpath = "/tmp/cdhcpcd-msg.log"; + int size = 512; + char *msg = (char *) malloc (size); + + + f = fopen(path, "a"); + f2 = fopen(msgpath, "a"); + va_start (p, fmt); + //va_copy (p2, p); + + + vsnprintf (msg, size, fmt, p); + strcat(msg, "\n"); + logToQt(level, DHCPCD_LOG, msg); + + fprintf(f2, "%s, %s", leveltolog(level), logprefix); + fprintf(f2, "%s", msg); + fputc('\n', f2); + + fprintf(f, "%s, %s", leveltolog(level), logprefix); + vfprintf(f, fmt, p); + fputc('\n', f); + + /* stdout, stderr may be re-directed to some kind of buffer. + * So we always flush to ensure it's written. */ + fflush(f); + + // //logLoggerToQt(level, fmt, p); + // if (level <= LOG_ERR || level <= loglevel) { + // + // /* new function by Niklas Goby + // * send the log message also to our Qt programm. + // * implemented in logwriter.c + // * */ + // //logLoggerToQt(level, fmt, p); + // + // if (level == LOG_DEBUG || level == LOG_INFO) + // f = stdout; + // fprintf(f, "%s, %s", leveltolog(level), logprefix); + // vfprintf(f, fmt, p); + // fputc('\n', f); + // + // /* stdout, stderr may be re-directed to some kind of buffer. + // * So we always flush to ensure it's written. */ + // fflush(f); + // } + // if (level < LOG_DEBUG || level <= loglevel) { + // size_t len = strlen(logprefix); + // size_t fmt2len = strlen(fmt) + len + 1; + // char *fmt2 = malloc(sizeof(char) * fmt2len); + // char *pf = fmt2; + // if (fmt2) { + // memcpy(pf, logprefix, len); + // pf += len; + // strlcpy(pf, fmt, fmt2len - len); + // vsyslog(level, fmt2, p2); + // free(fmt2); + // } else { + // vsyslog(level, fmt, p2); + // syslog(LOG_ERR, "logger: memory exhausted"); + // exit(EXIT_FAILURE); + // } + // } + + //va_end (p2); + va_end (p); } diff --git a/src/customdhcpcd/logger.h b/src/customdhcpcd/logger.h index 70e2ed5..52552f6 100644 --- a/src/customdhcpcd/logger.h +++ b/src/customdhcpcd/logger.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved diff --git a/src/customdhcpcd/logwriter.c b/src/customdhcpcd/logwriter.c index ee8bb1d..e3316cb 100644 --- a/src/customdhcpcd/logwriter.c +++ b/src/customdhcpcd/logwriter.c @@ -25,236 +25,260 @@ int retval = -1; char socketName[QTSOCKETADDRESSLENGTH]; char interfaceName[IF_NAMESIZE]; -void setSocketName(const char * sn) { - snprintf(socketName, sizeof(socketName), "%s", sn); +void setSocketName(const char * sn) +{ + snprintf(socketName, sizeof(socketName), "%s", sn); } -void setInterfaceName(const char * in) { - snprintf(interfaceName, sizeof(interfaceName), "%s", in); +void setInterfaceName(const char * in) +{ + snprintf(interfaceName, sizeof(interfaceName), "%s", in); } -int initQtLoggerSocket() { - /** - * new code. seems to be right. - */ - - struct sockaddr_un serv_addr; - fprintf(stdout, "start init \n"); - sockfd = socket(AF_UNIX, SOCK_STREAM, 0); - if (sockfd < 0) { - fprintf(stdout, "ERROR opening socket \n"); - retval = sockfd; - return sockfd; - } - serv_addr.sun_family = AF_UNIX; - strcpy(serv_addr.sun_path, socketName); - - retval = connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); - if (retval < 0) - fprintf(stdout, "ERROR connecting \n"); - fprintf(stdout, "init Qt Logger Socket done \n"); - return retval; +int initQtLoggerSocket() +{ + /** + * new code. seems to be right. + */ + + struct sockaddr_un serv_addr; + fprintf(stdout, "start init \n"); + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd < 0) + { + fprintf(stdout, "ERROR opening socket \n"); + retval = sockfd; + return sockfd; + } + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, socketName); + + retval = connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)); + if (retval < 0) + fprintf(stdout, "ERROR connecting \n"); + fprintf(stdout, "init Qt Logger Socket done \n"); + return retval; } -void closeQtLoggerSocket() { - close(sockfd); +void closeQtLoggerSocket() +{ + close(sockfd); } -void sendToQt(log_msg * msg) { - int n = -1; - int t; - int ret; - const char *tpl = "%s;%d;%d;%s\n"; - char outbuf[DHCP_MESSAGE_SIZE]; - char ack[ACK_SIZE]; - /* - size_t outbuf_size = sizeof(char) * 4 + // ";" *3 + newline - sizeof(int) * 2 + // status, substatus - sizeof(msg->device) + // devicename - sizeof(msg->msg); // msg - outbuf = malloc(outbuf_size); - memset(outbuf, 0, outbuf_size); - snprintf(outbuf, sizeof(char) * 3 + sizeof(int) * 2 + sizeof(msg->device) - + sizeof(msg->msg), tpl, msg->device, msg->status, msg->substatus, - msg->msg); - */ - memset(outbuf, '\0', DHCP_MESSAGE_SIZE); - ret = snprintf(outbuf, DHCP_MESSAGE_SIZE, tpl, msg->device, msg->status, - msg->substatus, msg->msg); - if (ret < 1) { - log ger(LOG_INFO, "[fbgui] ERROR filling message buffer"); - //syslog(LOG_INFO, "[fbgui] ERROR filling message buffer"); - return; - } - if (outbuf != NULL) { - n = send(sockfd, outbuf, DHCP_MESSAGE_SIZE, 0); - } - syslog(LOG_INFO, "[fbgui] INFO writing to socket: [%d:%d] %s (%s)", - msg->status, msg->substatus, msg->msg, msg->device); - - if (n <= 0) { - logger(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", - msg->status, msg->substatus, msg->msg, msg->device); - //syslog(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", - // msg->status, msg->substatus, msg->msg, msg->device); - } - /* - memset(ack, 0, ACK_SIZE); - if ((t = recv(sockfd, ack, ACK_SIZE, 0)) > 0) { - syslog(LOG_ERR, "[fbgui] recv ack echo> %s", ack); - printf("received: %s\n", ack); - } else { - if (t < 0) - syslog(LOG_ERR, "[fbgui] ERROR receiving from socket"); - else - syslog(LOG_ERR, "[fbgui] ERROR Server closed"); - } - */ +void sendToQt(log_msg * msg) +{ + int n = -1; + int t; + int ret; + const char *tpl = "%s;%d;%d;%s\n"; + char outbuf[DHCP_MESSAGE_SIZE]; + char ack[ACK_SIZE]; + /* + size_t outbuf_size = sizeof(char) * 4 + // ";" *3 + newline + sizeof(int) * 2 + // status, substatus + sizeof(msg->device) + // devicename + sizeof(msg->msg); // msg + outbuf = malloc(outbuf_size); + memset(outbuf, 0, outbuf_size); + snprintf(outbuf, sizeof(char) * 3 + sizeof(int) * 2 + sizeof(msg->device) + + sizeof(msg->msg), tpl, msg->device, msg->status, msg->substatus, + msg->msg); + */ + memset(outbuf, '\0', DHCP_MESSAGE_SIZE); + ret = snprintf(outbuf, DHCP_MESSAGE_SIZE, tpl, msg->device, msg->status, + msg->substatus, msg->msg); + if (ret < 1) + { + log ger(LOG_INFO, "[fbgui] ERROR filling message buffer"); + //syslog(LOG_INFO, "[fbgui] ERROR filling message buffer"); + return; + } + if (outbuf != NULL) + { + n = send(sockfd, outbuf, DHCP_MESSAGE_SIZE, 0); + } + syslog(LOG_INFO, "[fbgui] INFO writing to socket: [%d:%d] %s (%s)", + msg->status, msg->substatus, msg->msg, msg->device); + + if (n <= 0) + { + logger(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", + msg->status, msg->substatus, msg->msg, msg->device); + //syslog(LOG_ERR, "[fbgui] ERROR writing to socket: [%d:%d] %s (%s)", + // msg->status, msg->substatus, msg->msg, msg->device); + } + /* + memset(ack, 0, ACK_SIZE); + if ((t = recv(sockfd, ack, ACK_SIZE, 0)) > 0) { + syslog(LOG_ERR, "[fbgui] recv ack echo> %s", ack); + printf("received: %s\n", ack); + } else { + if (t < 0) + syslog(LOG_ERR, "[fbgui] ERROR receiving from socket"); + else + syslog(LOG_ERR, "[fbgui] ERROR Server closed"); + } + */ } -void logToQt(int status, int substatus, const char * msg) { - if (retval >= 0) { - log_msg lm; - lm.status = status; - lm.substatus = substatus; - snprintf(lm.msg, sizeof(lm.msg), "%s", msg); - snprintf(lm.device, sizeof(lm.device), "%s", interfaceName); - sendToQt(&lm); - } +void logToQt(int status, int substatus, const char * msg) +{ + if (retval >= 0) + { + log_msg lm; + lm.status = status; + lm.substatus = substatus; + snprintf(lm.msg, sizeof(lm.msg), "%s", msg); + snprintf(lm.device, sizeof(lm.device), "%s", interfaceName); + sendToQt(&lm); + } } -void logSendToQt(int type) { - switch (type) { - case DHCP_DISCOVER: - logToQt(LOG_INFO, DHCP_DISCOVER, "send discover"); - break; - case DHCP_OFFER: - logToQt(LOG_INFO, DHCP_OFFER, "send offer"); - break; - case DHCP_REQUEST: - logToQt(LOG_INFO, DHCP_REQUEST, "send request"); - break; - case DHCP_DECLINE: - logToQt(LOG_INFO, DHCP_DECLINE, "send decline"); - break; - case DHCP_ACK: - logToQt(LOG_INFO, DHCP_ACK, "send ack"); - break; - case DHCP_NAK: - logToQt(LOG_INFO, DHCP_NAK, "send nak"); - break; - case DHCP_RELEASE: - logToQt(LOG_INFO, DHCP_RELEASE, "send release"); - break; - case DHCP_INFORM: - logToQt(LOG_INFO, DHCP_INFORM, "send inform"); - break; - default: - break; - } +void logSendToQt(int type) +{ + switch (type) + { + case DHCP_DISCOVER: + logToQt(LOG_INFO, DHCP_DISCOVER, "send discover"); + break; + case DHCP_OFFER: + logToQt(LOG_INFO, DHCP_OFFER, "send offer"); + break; + case DHCP_REQUEST: + logToQt(LOG_INFO, DHCP_REQUEST, "send request"); + break; + case DHCP_DECLINE: + logToQt(LOG_INFO, DHCP_DECLINE, "send decline"); + break; + case DHCP_ACK: + logToQt(LOG_INFO, DHCP_ACK, "send ack"); + break; + case DHCP_NAK: + logToQt(LOG_INFO, DHCP_NAK, "send nak"); + break; + case DHCP_RELEASE: + logToQt(LOG_INFO, DHCP_RELEASE, "send release"); + break; + case DHCP_INFORM: + logToQt(LOG_INFO, DHCP_INFORM, "send inform"); + break; + default: + break; + } } static void print_addresses (FILE *f, const struct address_head *addresses) { - const address_t *addr; - - STAILQ_FOREACH (addr, addresses, entries) { - fprintf (f, "%s", inet_ntoa (addr->address)); - if (STAILQ_NEXT (addr, entries)) - fprintf (f, " "); - } + const address_t *addr; + + STAILQ_FOREACH (addr, addresses, entries) + { + fprintf (f, "%s", inet_ntoa (addr->address)); + if (STAILQ_NEXT (addr, entries)) + fprintf (f, " "); + } } -void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp) { - /*void logGatewayToFile(const interface_t iface, const dhcp_t *dhcp, - const options_t options)*/ - //char path[QTSOCKETADDRESSLENGTH]; - - /* - strcpy(path, DEFAULT_GATEWAY_INFO_LOCATION); - strcat(path, iface.name); - strcpy(iface.infofile, path); - options.test = false; - syslog(LOG_INFO, "[fbgui] try to open file: %s", iface.infofile); - write_info(&iface, dhcp, &options, true); - */ - FILE *f; - route_t *route; - char path[QTSOCKETADDRESSLENGTH]; - - strcpy(path, DEFAULT_INTERFACE_CONF_LOCATION); - strcat(path, iface->name); - - syslog(LOG_INFO, "[fbgui] try to open file: %s", path); - - logger(LOG_DEBUG, "writing %s", iface->infofile); - if ((f = fopen(path, "w")) == NULL) { - logger(LOG_ERR, "fopen `%s': %s", path, strerror(errno)); - //TODO: exit/return .. - return; - } - - if (dhcp->address.s_addr) { - struct in_addr n; - n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; - fprintf(f, "IPADDR='%s'\n", inet_ntoa(dhcp->address)); - fprintf(f, "NETMASK='%s'\n", inet_ntoa(dhcp->netmask)); - fprintf(f, "NETWORK='%s'\n", inet_ntoa(n)); - fprintf(f, "BROADCAST='%s'\n", inet_ntoa(dhcp->broadcast)); - } - - if (dhcp->routes) { - bool doneone = false; - fprintf(f, "ROUTES='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr != 0) { - if (doneone) - fprintf(f, " "); - fprintf(f, "%s", inet_ntoa(route->destination)); - fprintf(f, ",%s", inet_ntoa(route->netmask)); - fprintf(f, ",%s", inet_ntoa(route->gateway)); - doneone = true; - } - } - fprintf(f, "'\n"); - - doneone = false; - fprintf(f, "GATEWAYS='"); - STAILQ_FOREACH (route, dhcp->routes, entries) { - if (route->destination.s_addr == 0) { - if (doneone) - fprintf(f, " "); - fprintf(f, "%s", inet_ntoa(route->gateway)); - doneone = true; - } - } - fprintf(f, "'\n"); - } - - fprintf(f, "HOSTNAME='%s", dhcp->hostname); - fprintf(f, "'\n"); - fprintf(f, "DNSSEARCH='%s", dhcp->dnssearch); - fprintf(f, "'\n"); - - if (dhcp->dnsservers) { - fprintf(f, "DNSSERVERS='"); - print_addresses(f, dhcp->dnsservers); - fprintf(f, "'\n"); - } - fprintf(f, "INTERFACE='%s", iface->name); - fprintf(f, "'\n"); - if (iface->clientid_len > 0) { - fprintf(f, "CLIENTID='%s'\n", hwaddr_ntoa(iface->clientid, - iface->clientid_len)); - } - fprintf(f, "DHCPCHADDR='%s'\n", hwaddr_ntoa(iface->hwaddr, iface->hwlen)); - fclose(f); +void logGatewayToFile(const interface_t *iface, const dhcp_t *dhcp) +{ + /*void logGatewayToFile(const interface_t iface, const dhcp_t *dhcp, + const options_t options)*/ + //char path[QTSOCKETADDRESSLENGTH]; + + /* + strcpy(path, DEFAULT_GATEWAY_INFO_LOCATION); + strcat(path, iface.name); + strcpy(iface.infofile, path); + options.test = false; + syslog(LOG_INFO, "[fbgui] try to open file: %s", iface.infofile); + write_info(&iface, dhcp, &options, true); + */ + FILE *f; + route_t *route; + char path[QTSOCKETADDRESSLENGTH]; + + strcpy(path, DEFAULT_INTERFACE_CONF_LOCATION); + strcat(path, iface->name); + + syslog(LOG_INFO, "[fbgui] try to open file: %s", path); + + logger(LOG_DEBUG, "writing %s", iface->infofile); + if ((f = fopen(path, "w")) == NULL) + { + logger(LOG_ERR, "fopen `%s': %s", path, strerror(errno)); + //TODO: exit/return .. + return; + } + + if (dhcp->address.s_addr) + { + struct in_addr n; + n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; + fprintf(f, "IPADDR='%s'\n", inet_ntoa(dhcp->address)); + fprintf(f, "NETMASK='%s'\n", inet_ntoa(dhcp->netmask)); + fprintf(f, "NETWORK='%s'\n", inet_ntoa(n)); + fprintf(f, "BROADCAST='%s'\n", inet_ntoa(dhcp->broadcast)); + } + + if (dhcp->routes) + { + bool doneone = false; + fprintf(f, "ROUTES='"); + STAILQ_FOREACH (route, dhcp->routes, entries) + { + if (route->destination.s_addr != 0) + { + if (doneone) + fprintf(f, " "); + fprintf(f, "%s", inet_ntoa(route->destination)); + fprintf(f, ",%s", inet_ntoa(route->netmask)); + fprintf(f, ",%s", inet_ntoa(route->gateway)); + doneone = true; + } + } + fprintf(f, "'\n"); + + doneone = false; + fprintf(f, "GATEWAYS='"); + STAILQ_FOREACH (route, dhcp->routes, entries) + { + if (route->destination.s_addr == 0) + { + if (doneone) + fprintf(f, " "); + fprintf(f, "%s", inet_ntoa(route->gateway)); + doneone = true; + } + } + fprintf(f, "'\n"); + } + + fprintf(f, "HOSTNAME='%s", dhcp->hostname); + fprintf(f, "'\n"); + fprintf(f, "DNSSEARCH='%s", dhcp->dnssearch); + fprintf(f, "'\n"); + + if (dhcp->dnsservers) + { + fprintf(f, "DNSSERVERS='"); + print_addresses(f, dhcp->dnsservers); + fprintf(f, "'\n"); + } + fprintf(f, "INTERFACE='%s", iface->name); + fprintf(f, "'\n"); + if (iface->clientid_len > 0) + { + fprintf(f, "CLIENTID='%s'\n", hwaddr_ntoa(iface->clientid, + iface->clientid_len)); + } + fprintf(f, "DHCPCHADDR='%s'\n", hwaddr_ntoa(iface->hwaddr, iface->hwlen)); + fclose(f); } diff --git a/src/customdhcpcd/logwriter.h b/src/customdhcpcd/logwriter.h index 43f35fa..9d7af47 100644 --- a/src/customdhcpcd/logwriter.h +++ b/src/customdhcpcd/logwriter.h @@ -16,11 +16,12 @@ #define LOG_MSG_SIZE 1024 typedef struct _log_msg log_msg; -struct _log_msg { - int status; - int substatus; - char device[IF_NAMESIZE]; - char msg[LOG_MSG_SIZE]; +struct _log_msg +{ + int status; + int substatus; + char device[IF_NAMESIZE]; + char msg[LOG_MSG_SIZE]; }; /** diff --git a/src/customdhcpcd/signal.c b/src/customdhcpcd/signal.c index 9055c9f..297d8b2 100644 --- a/src/customdhcpcd/signal.c +++ b/src/customdhcpcd/signal.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -40,44 +40,45 @@ static int signal_pipe[2]; static int signals[5]; -static const int handle_sigs[] = { - SIGHUP, - SIGALRM, - SIGTERM, - SIGINT +static const int handle_sigs[] = +{ + SIGHUP, + SIGALRM, + SIGTERM, + SIGINT }; static void signal_handler (int sig) { - unsigned int i = 0; - int serrno = errno; - - /* Add a signal to our stack */ - while (signals[i]) - i++; - if (i > sizeof (signals) / sizeof (signals[0])) - logger (LOG_ERR, "signal buffer overrun"); - else - signals[i] = sig; - - if (write (signal_pipe[1], &sig, sizeof (sig)) == -1) - logger (LOG_ERR, "Could not send signal: %s", strerror (errno)); - - /* Restore errno */ - errno = serrno; + unsigned int i = 0; + int serrno = errno; + + /* Add a signal to our stack */ + while (signals[i]) + i++; + if (i > sizeof (signals) / sizeof (signals[0])) + logger (LOG_ERR, "signal buffer overrun"); + else + signals[i] = sig; + + if (write (signal_pipe[1], &sig, sizeof (sig)) == -1) + logger (LOG_ERR, "Could not send signal: %s", strerror (errno)); + + /* Restore errno */ + errno = serrno; } int signal_fd (void) { - return (signal_pipe[0]); + return (signal_pipe[0]); } /* Check if we have a signal or not */ int signal_exists (const struct pollfd *fd) { - if (signals[0] || (fd && fd->revents & POLLIN)) - return (0); - return (-1); + if (signals[0] || (fd && fd->revents & POLLIN)) + return (0); + return (-1); } /* Read a signal from the signal pipe. Returns 0 if there is @@ -85,99 +86,106 @@ int signal_exists (const struct pollfd *fd) * your signal on success */ int signal_read (struct pollfd *fd) { - int sig = -1; - - /* Pop a signal off the our stack */ - if (signals[0]) { - unsigned int i = 0; - sig = signals[0]; - while (i < (sizeof (signals) / sizeof (signals[0])) - 1) { - signals[i] = signals[i + 1]; - if (! signals[++i]) - break; - } - } - - if (fd && fd->revents & POLLIN) { - char buf[16]; - size_t bytes; - - memset (buf, 0, sizeof (buf)); - bytes = read (signal_pipe[0], buf, sizeof (buf)); - - if (bytes >= sizeof (sig)) - memcpy (&sig, buf, sizeof (sig)); - - /* We need to clear us from rset if nothing left in the buffer - * in case we are called many times */ - if (bytes == sizeof (sig)) - fd->revents = 0; - } - - return (sig); + int sig = -1; + + /* Pop a signal off the our stack */ + if (signals[0]) + { + unsigned int i = 0; + sig = signals[0]; + while (i < (sizeof (signals) / sizeof (signals[0])) - 1) + { + signals[i] = signals[i + 1]; + if (! signals[++i]) + break; + } + } + + if (fd && fd->revents & POLLIN) + { + char buf[16]; + size_t bytes; + + memset (buf, 0, sizeof (buf)); + bytes = read (signal_pipe[0], buf, sizeof (buf)); + + if (bytes >= sizeof (sig)) + memcpy (&sig, buf, sizeof (sig)); + + /* We need to clear us from rset if nothing left in the buffer + * in case we are called many times */ + if (bytes == sizeof (sig)) + fd->revents = 0; + } + + return (sig); } /* Call this before doing anything else. Sets up the socket pair * and installs the signal handler */ int signal_init (void) { - struct sigaction sa; - - if (pipe (signal_pipe) == -1) { - logger (LOG_ERR, "pipe: %s", strerror (errno)); - return (-1); - } - - /* Stop any scripts from inheriting us */ - close_on_exec (signal_pipe[0]); - close_on_exec (signal_pipe[1]); - - /* Ignore child signals and don't make zombies. - * Because we do this, we don't need to be in signal_setup */ - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = SIG_DFL; - sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT; - if (sigaction (SIGCHLD, &sa, NULL) == -1) { - logger (LOG_ERR, "sigaction: %s", strerror (errno)); - return (-1); - } - - memset (signals, 0, sizeof (signals)); - return (0); + struct sigaction sa; + + if (pipe (signal_pipe) == -1) + { + logger (LOG_ERR, "pipe: %s", strerror (errno)); + return (-1); + } + + /* Stop any scripts from inheriting us */ + close_on_exec (signal_pipe[0]); + close_on_exec (signal_pipe[1]); + + /* Ignore child signals and don't make zombies. + * Because we do this, we don't need to be in signal_setup */ + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = SIG_DFL; + sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT; + if (sigaction (SIGCHLD, &sa, NULL) == -1) + { + logger (LOG_ERR, "sigaction: %s", strerror (errno)); + return (-1); + } + + memset (signals, 0, sizeof (signals)); + return (0); } int signal_setup (void) { - unsigned int i; - struct sigaction sa; - - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = signal_handler; - sigemptyset (&sa.sa_mask); - - for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) - if (sigaction (handle_sigs[i], &sa, NULL) == -1) { - logger (LOG_ERR, "sigaction: %s", strerror (errno)); - return (-1); - } - - return (0); + unsigned int i; + struct sigaction sa; + + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = signal_handler; + sigemptyset (&sa.sa_mask); + + for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) + if (sigaction (handle_sigs[i], &sa, NULL) == -1) + { + logger (LOG_ERR, "sigaction: %s", strerror (errno)); + return (-1); + } + + return (0); } int signal_reset (void) { - struct sigaction sa; - unsigned int i; + struct sigaction sa; + unsigned int i; - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = SIG_DFL; - sigemptyset (&sa.sa_mask); + memset (&sa, 0, sizeof (sa)); + sa.sa_handler = SIG_DFL; + sigemptyset (&sa.sa_mask); - for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) - if (sigaction (handle_sigs[i], &sa, NULL) == -1) { - logger (LOG_ERR, "sigaction: %s", strerror (errno)); - return (-1); - } + for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) + if (sigaction (handle_sigs[i], &sa, NULL) == -1) + { + logger (LOG_ERR, "sigaction: %s", strerror (errno)); + return (-1); + } - return (0); + return (0); } diff --git a/src/customdhcpcd/signal.h b/src/customdhcpcd/signal.h index 63a5906..1c29f80 100644 --- a/src/customdhcpcd/signal.h +++ b/src/customdhcpcd/signal.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved diff --git a/src/customdhcpcd/socket.c b/src/customdhcpcd/socket.c index 58ad6c5..9cb1227 100644 --- a/src/customdhcpcd/socket.c +++ b/src/customdhcpcd/socket.c @@ -65,583 +65,629 @@ #endif /* Broadcast address for IPoIB */ -static const uint8_t ipv4_bcast_addr[] = { - 0x00, 0xff, 0xff, 0xff, - 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff +static const uint8_t ipv4_bcast_addr[] = +{ + 0x00, 0xff, 0xff, 0xff, + 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }; /* Credit where credit is due :) * The below BPF filter is taken from ISC DHCP */ -static struct bpf_insn dhcp_bpf_filter [] = { - /* Make sure this is an IP packet... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), +static struct bpf_insn dhcp_bpf_filter [] = +{ + /* Make sure this is an IP packet... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), - /* Make sure it's a UDP packet... */ - BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), + /* Make sure it's a UDP packet... */ + BPF_STMT (BPF_LD + BPF_B + BPF_ABS, 23), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6), - /* Make sure this isn't a fragment... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), + /* Make sure this isn't a fragment... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), + BPF_JUMP (BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0), - /* Get the IP header length... */ - BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), + /* Get the IP header length... */ + BPF_STMT (BPF_LDX + BPF_B + BPF_MSH, 14), - /* Make sure it's to the right port... */ - BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1), + /* Make sure it's to the right port... */ + BPF_STMT (BPF_LD + BPF_H + BPF_IND, 16), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, DHCP_CLIENT_PORT, 0, 1), - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT (BPF_RET + BPF_K, ~0U), + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT (BPF_RET + BPF_K, ~0U), - /* Otherwise, drop it. */ - BPF_STMT (BPF_RET + BPF_K, 0), + /* Otherwise, drop it. */ + BPF_STMT (BPF_RET + BPF_K, 0), }; -static struct bpf_insn arp_bpf_filter [] = { - /* Make sure this is an ARP packet... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3), +static struct bpf_insn arp_bpf_filter [] = +{ + /* Make sure this is an ARP packet... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3), - /* Make sure this is an ARP REPLY... */ - BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), + /* Make sure this is an ARP REPLY... */ + BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), + BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT (BPF_RET + BPF_K, ~0U), + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT (BPF_RET + BPF_K, ~0U), - /* Otherwise, drop it. */ - BPF_STMT (BPF_RET + BPF_K, 0), + /* Otherwise, drop it. */ + BPF_STMT (BPF_RET + BPF_K, 0), }; void setup_packet_filters (void) { #ifdef __linux__ - /* We need to massage the filters for Linux cooked packets */ - dhcp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ - dhcp_bpf_filter[2].k -= ETH_HLEN; - dhcp_bpf_filter[4].k -= ETH_HLEN; - dhcp_bpf_filter[6].k -= ETH_HLEN; - dhcp_bpf_filter[7].k -= ETH_HLEN; - - arp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ - arp_bpf_filter[2].k -= ETH_HLEN; + /* We need to massage the filters for Linux cooked packets */ + dhcp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ + dhcp_bpf_filter[2].k -= ETH_HLEN; + dhcp_bpf_filter[4].k -= ETH_HLEN; + dhcp_bpf_filter[6].k -= ETH_HLEN; + dhcp_bpf_filter[7].k -= ETH_HLEN; + + arp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ + arp_bpf_filter[2].k -= ETH_HLEN; #endif } static uint16_t checksum (unsigned char *addr, uint16_t len) { - uint32_t sum = 0; - union - { - unsigned char *addr; - uint16_t *i; - } p; - uint16_t nleft = len; - - p.addr = addr; - while (nleft > 1) { - sum += *p.i++; - nleft -= 2; - } - - if (nleft == 1) { - uint8_t a = 0; - memcpy (&a, p.i, 1); - sum += ntohs (a) << 8; - } - - sum = (sum >> 16) + (sum & 0xffff); - sum += (sum >> 16); - - return ~sum; + uint32_t sum = 0; + union + { + unsigned char *addr; + uint16_t *i; + } p; + uint16_t nleft = len; + + p.addr = addr; + while (nleft > 1) + { + sum += *p.i++; + nleft -= 2; + } + + if (nleft == 1) + { + uint8_t a = 0; + memcpy (&a, p.i, 1); + sum += ntohs (a) << 8; + } + + sum = (sum >> 16) + (sum & 0xffff); + sum += (sum >> 16); + + return ~sum; } void make_dhcp_packet(struct udp_dhcp_packet *packet, - const unsigned char *data, size_t length, - struct in_addr source, struct in_addr dest) + const unsigned char *data, size_t length, + struct in_addr source, struct in_addr dest) { - struct ip *ip = &packet->ip; - struct udphdr *udp = &packet->udp; - - /* OK, this is important :) - * We copy the data to our packet and then create a small part of the - * ip structure and an invalid ip_len (basically udp length). - * We then fill the udp structure and put the checksum - * of the whole packet into the udp checksum. - * Finally we complete the ip structure and ip checksum. - * If we don't do the ordering like so then the udp checksum will be - * broken, so find another way of doing it! */ - - memcpy (&packet->dhcp, data, length); - - ip->ip_p = IPPROTO_UDP; - ip->ip_src.s_addr = source.s_addr; - if (dest.s_addr == 0) - ip->ip_dst.s_addr = INADDR_BROADCAST; - else - ip->ip_dst.s_addr = dest.s_addr; - - udp->uh_sport = htons (DHCP_CLIENT_PORT); - udp->uh_dport = htons (DHCP_SERVER_PORT); - udp->uh_ulen = htons (sizeof (*udp) + length); - ip->ip_len = udp->uh_ulen; - udp->uh_sum = checksum ((unsigned char *) packet, sizeof (*packet)); - - ip->ip_v = IPVERSION; - ip->ip_hl = 5; - ip->ip_id = 0; - ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = htons (sizeof (*ip) + sizeof (*udp) + length); - ip->ip_id = 0; - ip->ip_off = htons (IP_DF); /* Don't fragment */ - ip->ip_ttl = IPDEFTTL; - - ip->ip_sum = checksum ((unsigned char *) ip, sizeof (*ip)); + struct ip *ip = &packet->ip; + struct udphdr *udp = &packet->udp; + + /* OK, this is important :) + * We copy the data to our packet and then create a small part of the + * ip structure and an invalid ip_len (basically udp length). + * We then fill the udp structure and put the checksum + * of the whole packet into the udp checksum. + * Finally we complete the ip structure and ip checksum. + * If we don't do the ordering like so then the udp checksum will be + * broken, so find another way of doing it! */ + + memcpy (&packet->dhcp, data, length); + + ip->ip_p = IPPROTO_UDP; + ip->ip_src.s_addr = source.s_addr; + if (dest.s_addr == 0) + ip->ip_dst.s_addr = INADDR_BROADCAST; + else + ip->ip_dst.s_addr = dest.s_addr; + + udp->uh_sport = htons (DHCP_CLIENT_PORT); + udp->uh_dport = htons (DHCP_SERVER_PORT); + udp->uh_ulen = htons (sizeof (*udp) + length); + ip->ip_len = udp->uh_ulen; + udp->uh_sum = checksum ((unsigned char *) packet, sizeof (*packet)); + + ip->ip_v = IPVERSION; + ip->ip_hl = 5; + ip->ip_id = 0; + ip->ip_tos = IPTOS_LOWDELAY; + ip->ip_len = htons (sizeof (*ip) + sizeof (*udp) + length); + ip->ip_id = 0; + ip->ip_off = htons (IP_DF); /* Don't fragment */ + ip->ip_ttl = IPDEFTTL; + + ip->ip_sum = checksum ((unsigned char *) ip, sizeof (*ip)); } static int valid_dhcp_packet (unsigned char *data) { - union - { - unsigned char *data; - struct udp_dhcp_packet *packet; - } d; - uint16_t bytes; - uint16_t ipsum; - uint16_t iplen; - uint16_t udpsum; - struct in_addr source; - struct in_addr dest; - int retval = 0; - - d.data = data; - bytes = ntohs (d.packet->ip.ip_len); - ipsum = d.packet->ip.ip_sum; - iplen = d.packet->ip.ip_len; - udpsum = d.packet->udp.uh_sum; - - d.data = data; - d.packet->ip.ip_sum = 0; - if (ipsum != checksum ((unsigned char *) &d.packet->ip, - sizeof (d.packet->ip))) - { - logger (LOG_DEBUG, "bad IP header checksum, ignoring"); - retval = -1; - goto eexit; - } - - memcpy (&source, &d.packet->ip.ip_src, sizeof (d.packet->ip.ip_src)); - memcpy (&dest, &d.packet->ip.ip_dst, sizeof (d.packet->ip.ip_dst)); - memset (&d.packet->ip, 0, sizeof (d.packet->ip)); - d.packet->udp.uh_sum = 0; - - d.packet->ip.ip_p = IPPROTO_UDP; - memcpy (&d.packet->ip.ip_src, &source, sizeof (d.packet->ip.ip_src)); - memcpy (&d.packet->ip.ip_dst, &dest, sizeof (d.packet->ip.ip_dst)); - d.packet->ip.ip_len = d.packet->udp.uh_ulen; - if (udpsum && udpsum != checksum (d.data, bytes)) { - logger (LOG_ERR, "bad UDP checksum, ignoring"); - retval = -1; - } + union + { + unsigned char *data; + struct udp_dhcp_packet *packet; + } d; + uint16_t bytes; + uint16_t ipsum; + uint16_t iplen; + uint16_t udpsum; + struct in_addr source; + struct in_addr dest; + int retval = 0; + + d.data = data; + bytes = ntohs (d.packet->ip.ip_len); + ipsum = d.packet->ip.ip_sum; + iplen = d.packet->ip.ip_len; + udpsum = d.packet->udp.uh_sum; + + d.data = data; + d.packet->ip.ip_sum = 0; + if (ipsum != checksum ((unsigned char *) &d.packet->ip, + sizeof (d.packet->ip))) + { + logger (LOG_DEBUG, "bad IP header checksum, ignoring"); + retval = -1; + goto eexit; + } + + memcpy (&source, &d.packet->ip.ip_src, sizeof (d.packet->ip.ip_src)); + memcpy (&dest, &d.packet->ip.ip_dst, sizeof (d.packet->ip.ip_dst)); + memset (&d.packet->ip, 0, sizeof (d.packet->ip)); + d.packet->udp.uh_sum = 0; + + d.packet->ip.ip_p = IPPROTO_UDP; + memcpy (&d.packet->ip.ip_src, &source, sizeof (d.packet->ip.ip_src)); + memcpy (&d.packet->ip.ip_dst, &dest, sizeof (d.packet->ip.ip_dst)); + d.packet->ip.ip_len = d.packet->udp.uh_ulen; + if (udpsum && udpsum != checksum (d.data, bytes)) + { + logger (LOG_ERR, "bad UDP checksum, ignoring"); + retval = -1; + } eexit: - d.packet->ip.ip_sum = ipsum; - d.packet->ip.ip_len = iplen; - d.packet->udp.uh_sum = udpsum; + d.packet->ip.ip_sum = ipsum; + d.packet->ip.ip_len = iplen; + d.packet->udp.uh_sum = udpsum; - return retval; + return retval; } #if defined(BSD) || defined(__FreeBSD_kernel__) int open_socket (interface_t *iface, int protocol) { - int n = 0; - int fd = -1; - char *device; - int flags; - struct ifreq ifr; - int buf = 0; - struct bpf_program pf; - - device = xmalloc (sizeof (char) * PATH_MAX); - do { - snprintf (device, PATH_MAX, "/dev/bpf%d", n++); - fd = open (device, O_RDWR); - } while (fd == -1 && errno == EBUSY); - free (device); - - if (fd == -1) { - logger (LOG_ERR, "unable to open a BPF device"); - return -1; - } - - close_on_exec (fd); - - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); - if (ioctl (fd, BIOCSETIF, &ifr) == -1) { - logger (LOG_ERR, - "cannot attach interface `%s' to bpf device `%s': %s", - iface->name, device, strerror (errno)); - close (fd); - return -1; - } - - /* Get the required BPF buffer length from the kernel. */ - if (ioctl (fd, BIOCGBLEN, &buf) == -1) { - logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno)); - close (fd); - return -1; - } - iface->buffer_length = buf; - - flags = 1; - if (ioctl (fd, BIOCIMMEDIATE, &flags) == -1) { - logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno)); - close (fd); - return -1; - } - - /* Install the DHCP filter */ - if (protocol == ETHERTYPE_ARP) { - pf.bf_insns = arp_bpf_filter; - pf.bf_len = sizeof (arp_bpf_filter) - / sizeof (arp_bpf_filter[0]); - } else { - pf.bf_insns = dhcp_bpf_filter; - pf.bf_len = sizeof (dhcp_bpf_filter) - / sizeof (dhcp_bpf_filter[0]); - } - if (ioctl (fd, BIOCSETF, &pf) == -1) { - logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno)); - close (fd); - return -1; - } - - if (iface->fd > -1) - close (iface->fd); - iface->fd = fd; - - return fd; + int n = 0; + int fd = -1; + char *device; + int flags; + struct ifreq ifr; + int buf = 0; + struct bpf_program pf; + + device = xmalloc (sizeof (char) * PATH_MAX); + do + { + snprintf (device, PATH_MAX, "/dev/bpf%d", n++); + fd = open (device, O_RDWR); + } + while (fd == -1 && errno == EBUSY); + free (device); + + if (fd == -1) + { + logger (LOG_ERR, "unable to open a BPF device"); + return -1; + } + + close_on_exec (fd); + + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); + if (ioctl (fd, BIOCSETIF, &ifr) == -1) + { + logger (LOG_ERR, + "cannot attach interface `%s' to bpf device `%s': %s", + iface->name, device, strerror (errno)); + close (fd); + return -1; + } + + /* Get the required BPF buffer length from the kernel. */ + if (ioctl (fd, BIOCGBLEN, &buf) == -1) + { + logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno)); + close (fd); + return -1; + } + iface->buffer_length = buf; + + flags = 1; + if (ioctl (fd, BIOCIMMEDIATE, &flags) == -1) + { + logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno)); + close (fd); + return -1; + } + + /* Install the DHCP filter */ + if (protocol == ETHERTYPE_ARP) + { + pf.bf_insns = arp_bpf_filter; + pf.bf_len = sizeof (arp_bpf_filter) + / sizeof (arp_bpf_filter[0]); + } + else + { + pf.bf_insns = dhcp_bpf_filter; + pf.bf_len = sizeof (dhcp_bpf_filter) + / sizeof (dhcp_bpf_filter[0]); + } + if (ioctl (fd, BIOCSETF, &pf) == -1) + { + logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno)); + close (fd); + return -1; + } + + if (iface->fd > -1) + close (iface->fd); + iface->fd = fd; + + return fd; } ssize_t send_packet (const interface_t *iface, int type, - const unsigned char *data, size_t len) + const unsigned char *data, size_t len) { - ssize_t retval = -1; - struct iovec iov[2]; - - if (iface->family == ARPHRD_ETHER) { - struct ether_header hw; - memset (&hw, 0, sizeof (hw)); - memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); - hw.ether_type = htons (type); - - iov[0].iov_base = &hw; - iov[0].iov_len = sizeof (hw); - } else { - logger (LOG_ERR, "unsupported interace type %d", iface->family); - return -1; - } - iov[1].iov_base = (unsigned char *) data; - iov[1].iov_len = len; - - if ((retval = writev(iface->fd, iov, 2)) == -1) - logger (LOG_ERR, "writev: %s", strerror (errno)); - - return retval; + ssize_t retval = -1; + struct iovec iov[2]; + + if (iface->family == ARPHRD_ETHER) + { + struct ether_header hw; + memset (&hw, 0, sizeof (hw)); + memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); + hw.ether_type = htons (type); + + iov[0].iov_base = &hw; + iov[0].iov_len = sizeof (hw); + } + else + { + logger (LOG_ERR, "unsupported interace type %d", iface->family); + return -1; + } + iov[1].iov_base = (unsigned char *) data; + iov[1].iov_len = len; + + if ((retval = writev(iface->fd, iov, 2)) == -1) + logger (LOG_ERR, "writev: %s", strerror (errno)); + + return retval; } /* BPF requires that we read the entire buffer. * So we pass the buffer in the API so we can loop on >1 dhcp packet. */ ssize_t get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, - size_t *buffer_len, size_t *buffer_pos) + unsigned char *buffer, + size_t *buffer_len, size_t *buffer_pos) { - union - { - unsigned char *buffer; - struct bpf_hdr *packet; - } bpf; - - bpf.buffer = buffer; - - if (*buffer_pos < 1) { - memset (bpf.buffer, 0, iface->buffer_length); - *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length); - *buffer_pos = 0; - if (*buffer_len < 1) { - struct timespec ts; - logger (LOG_ERR, "read: %s", strerror (errno)); - ts.tv_sec = 3; - ts.tv_nsec = 0; - nanosleep (&ts, NULL); - return (-1); - } - } else - bpf.buffer += *buffer_pos; - - while (bpf.packet) { - size_t len = 0; - union - { - unsigned char *buffer; - struct ether_header *hw; - } hdr; - unsigned char *payload; - bool have_data = false; - - /* Ensure that the entire packet is in our buffer */ - if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen - > (unsigned) *buffer_len) - break; - - hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen; - payload = hdr.buffer + sizeof (*hdr.hw); - - /* If it's an ARP reply, then just send it back */ - if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) { - len = bpf.packet->bh_caplen - - sizeof (*hdr.hw); - memcpy (data, payload, len); - have_data = true; - } else { - if (valid_dhcp_packet (payload) >= 0) { - union - { - unsigned char *buffer; - struct udp_dhcp_packet *packet; - } pay; - pay.buffer = payload; - len = ntohs (pay.packet->ip.ip_len) - - sizeof (pay.packet->ip) - - sizeof (pay.packet->udp); - memcpy (data, &pay.packet->dhcp, len); - have_data = true; - } - } - - /* Update the buffer_pos pointer */ - bpf.buffer += BPF_WORDALIGN (bpf.packet->bh_hdrlen + - bpf.packet->bh_caplen); - if ((unsigned) (bpf.buffer - buffer) < *buffer_len) - *buffer_pos = bpf.buffer - buffer; - else - *buffer_pos = 0; - - if (have_data) - return len; - - if (*buffer_pos == 0) - break; - } - - /* No valid packets left, so return */ - *buffer_pos = 0; - return -1; + union + { + unsigned char *buffer; + struct bpf_hdr *packet; + } bpf; + + bpf.buffer = buffer; + + if (*buffer_pos < 1) + { + memset (bpf.buffer, 0, iface->buffer_length); + *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length); + *buffer_pos = 0; + if (*buffer_len < 1) + { + struct timespec ts; + logger (LOG_ERR, "read: %s", strerror (errno)); + ts.tv_sec = 3; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); + return (-1); + } + } + else + bpf.buffer += *buffer_pos; + + while (bpf.packet) + { + size_t len = 0; + union + { + unsigned char *buffer; + struct ether_header *hw; + } hdr; + unsigned char *payload; + bool have_data = false; + + /* Ensure that the entire packet is in our buffer */ + if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen + > (unsigned) *buffer_len) + break; + + hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen; + payload = hdr.buffer + sizeof (*hdr.hw); + + /* If it's an ARP reply, then just send it back */ + if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) + { + len = bpf.packet->bh_caplen - + sizeof (*hdr.hw); + memcpy (data, payload, len); + have_data = true; + } + else + { + if (valid_dhcp_packet (payload) >= 0) + { + union + { + unsigned char *buffer; + struct udp_dhcp_packet *packet; + } pay; + pay.buffer = payload; + len = ntohs (pay.packet->ip.ip_len) - + sizeof (pay.packet->ip) - + sizeof (pay.packet->udp); + memcpy (data, &pay.packet->dhcp, len); + have_data = true; + } + } + + /* Update the buffer_pos pointer */ + bpf.buffer += BPF_WORDALIGN (bpf.packet->bh_hdrlen + + bpf.packet->bh_caplen); + if ((unsigned) (bpf.buffer - buffer) < *buffer_len) + *buffer_pos = bpf.buffer - buffer; + else + *buffer_pos = 0; + + if (have_data) + return len; + + if (*buffer_pos == 0) + break; + } + + /* No valid packets left, so return */ + *buffer_pos = 0; + return -1; } #elif __linux__ int open_socket (interface_t *iface, int protocol) { - int fd; - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_ll sll; - struct sockaddr_storage ss; - } su; - struct sock_fprog pf; - struct ifreq ifr; - int n = 1; - - /* We need to bind to a port, otherwise Linux generate ICMP messages - * that cannot contect the port when we have an address. - * We don't actually use this fd at all, instead using our packet - * filter socket. */ - if (iface->listen_fd == -1 && protocol == ETHERTYPE_IP) { - if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - } else { - memset (&su, 0, sizeof (su)); - su.sin.sin_family = AF_INET; - su.sin.sin_port = htons (DHCP_CLIENT_PORT); - if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, - &n, sizeof (n)) == -1) - logger (LOG_ERR, "SO_REUSEADDR: %s", - strerror (errno)); - if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, - &n, sizeof (n)) == -1) - logger (LOG_ERR, "SO_RCVBUF: %s", - strerror (errno)); - memset (&ifr, 0, sizeof (ifr)); - strncpy (ifr.ifr_name, iface->name, - sizeof (ifr.ifr_name)); - if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, - &ifr, sizeof (ifr)) == -1) - logger (LOG_ERR, "SO_SOBINDTODEVICE: %s", - strerror (errno)); - if (bind (fd, &su.sa, sizeof (su)) == -1) { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (fd); - } else { - iface->listen_fd = fd; - close_on_exec (fd); - } - } - } - - if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (protocol))) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - close_on_exec (fd); - - memset (&su, 0, sizeof (su)); - su.sll.sll_family = PF_PACKET; - su.sll.sll_protocol = htons (protocol); - if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { - logger (LOG_ERR, - "if_nametoindex: no index for interface `%s'", - iface->name); - close (fd); - return (-1); - } - - /* Install the DHCP filter */ - memset (&pf, 0, sizeof (pf)); - if (protocol == ETHERTYPE_ARP) { - pf.filter = arp_bpf_filter; - pf.len = sizeof (arp_bpf_filter) / sizeof (arp_bpf_filter[0]); - } else { - pf.filter = dhcp_bpf_filter; - pf.len = sizeof (dhcp_bpf_filter) / sizeof (dhcp_bpf_filter[0]); - } - if (setsockopt (fd, SOL_SOCKET, SO_ATTACH_FILTER, - &pf, sizeof (pf)) != 0) - { - logger (LOG_ERR, "SO_ATTACH_FILTER: %s", strerror (errno)); - close (fd); - return (-1); - } - - if (bind (fd, &su.sa, sizeof (su)) == -1) { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (fd); - return (-1); - } - - if (iface->fd > -1) - close (iface->fd); - iface->fd = fd; - iface->socket_protocol = protocol; - iface->buffer_length = BUFFER_LENGTH; - - return (fd); + int fd; + union sockunion + { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_ll sll; + struct sockaddr_storage ss; + } su; + struct sock_fprog pf; + struct ifreq ifr; + int n = 1; + + /* We need to bind to a port, otherwise Linux generate ICMP messages + * that cannot contect the port when we have an address. + * We don't actually use this fd at all, instead using our packet + * filter socket. */ + if (iface->listen_fd == -1 && protocol == ETHERTYPE_IP) + { + if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + } + else + { + memset (&su, 0, sizeof (su)); + su.sin.sin_family = AF_INET; + su.sin.sin_port = htons (DHCP_CLIENT_PORT); + if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, + &n, sizeof (n)) == -1) + logger (LOG_ERR, "SO_REUSEADDR: %s", + strerror (errno)); + if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, + &n, sizeof (n)) == -1) + logger (LOG_ERR, "SO_RCVBUF: %s", + strerror (errno)); + memset (&ifr, 0, sizeof (ifr)); + strncpy (ifr.ifr_name, iface->name, + sizeof (ifr.ifr_name)); + if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, + &ifr, sizeof (ifr)) == -1) + logger (LOG_ERR, "SO_SOBINDTODEVICE: %s", + strerror (errno)); + if (bind (fd, &su.sa, sizeof (su)) == -1) + { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (fd); + } + else + { + iface->listen_fd = fd; + close_on_exec (fd); + } + } + } + + if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (protocol))) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + close_on_exec (fd); + + memset (&su, 0, sizeof (su)); + su.sll.sll_family = PF_PACKET; + su.sll.sll_protocol = htons (protocol); + if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) + { + logger (LOG_ERR, + "if_nametoindex: no index for interface `%s'", + iface->name); + close (fd); + return (-1); + } + + /* Install the DHCP filter */ + memset (&pf, 0, sizeof (pf)); + if (protocol == ETHERTYPE_ARP) + { + pf.filter = arp_bpf_filter; + pf.len = sizeof (arp_bpf_filter) / sizeof (arp_bpf_filter[0]); + } + else + { + pf.filter = dhcp_bpf_filter; + pf.len = sizeof (dhcp_bpf_filter) / sizeof (dhcp_bpf_filter[0]); + } + if (setsockopt (fd, SOL_SOCKET, SO_ATTACH_FILTER, + &pf, sizeof (pf)) != 0) + { + logger (LOG_ERR, "SO_ATTACH_FILTER: %s", strerror (errno)); + close (fd); + return (-1); + } + + if (bind (fd, &su.sa, sizeof (su)) == -1) + { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (fd); + return (-1); + } + + if (iface->fd > -1) + close (iface->fd); + iface->fd = fd; + iface->socket_protocol = protocol; + iface->buffer_length = BUFFER_LENGTH; + + return (fd); } ssize_t send_packet (const interface_t *iface, int type, - const unsigned char *data, size_t len) + const unsigned char *data, size_t len) { - union sockunion { - struct sockaddr sa; - struct sockaddr_ll sll; - struct sockaddr_storage ss; - } su; - ssize_t retval; - - if (! iface) - return (-1); - - memset (&su, 0, sizeof (su)); - su.sll.sll_family = AF_PACKET; - su.sll.sll_protocol = htons (type); - - if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - iface->name); - return (-1); - } - - su.sll.sll_hatype = htons (iface->family); - su.sll.sll_halen = iface->hwlen; - if (iface->family == ARPHRD_INFINIBAND) - memcpy (&su.sll.sll_addr, - &ipv4_bcast_addr, sizeof (ipv4_bcast_addr)); - else - memset (&su.sll.sll_addr, 0xff, iface->hwlen); - - if ((retval = sendto (iface->fd, data, len, 0, &su.sa, - sizeof (su))) == -1) - - logger (LOG_ERR, "sendto: %s", strerror (errno)); - return (retval); + union sockunion + { + struct sockaddr sa; + struct sockaddr_ll sll; + struct sockaddr_storage ss; + } su; + ssize_t retval; + + if (! iface) + return (-1); + + memset (&su, 0, sizeof (su)); + su.sll.sll_family = AF_PACKET; + su.sll.sll_protocol = htons (type); + + if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) + { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + iface->name); + return (-1); + } + + su.sll.sll_hatype = htons (iface->family); + su.sll.sll_halen = iface->hwlen; + if (iface->family == ARPHRD_INFINIBAND) + memcpy (&su.sll.sll_addr, + &ipv4_bcast_addr, sizeof (ipv4_bcast_addr)); + else + memset (&su.sll.sll_addr, 0xff, iface->hwlen); + + if ((retval = sendto (iface->fd, data, len, 0, &su.sa, + sizeof (su))) == -1) + + logger (LOG_ERR, "sendto: %s", strerror (errno)); + return (retval); } /* Linux has no need for the buffer as we can read as much as we want. * We only have the buffer listed to keep the same API. */ ssize_t get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, - size_t *buffer_len, size_t *buffer_pos) + unsigned char *buffer, + size_t *buffer_len, size_t *buffer_pos) { - ssize_t bytes; - union - { - unsigned char *buffer; - struct udp_dhcp_packet *packet; - } pay; - - /* We don't use the given buffer, but we need to rewind the position */ - *buffer_pos = 0; - - memset (buffer, 0, iface->buffer_length); - bytes = read (iface->fd, buffer, iface->buffer_length); - - if (bytes == -1) { - struct timespec ts; - logger (LOG_ERR, "read: %s", strerror (errno)); - ts.tv_sec = 3; - ts.tv_nsec = 0; - nanosleep (&ts, NULL); - return (-1); - } - - *buffer_len = bytes; - /* If it's an ARP reply, then just send it back */ - if (iface->socket_protocol == ETHERTYPE_ARP) { - memcpy (data, buffer, bytes); - return (bytes); - } - - if ((unsigned) bytes < (sizeof (pay.packet->ip) + - sizeof (pay.packet->udp))) - { - logger (LOG_DEBUG, "message too short, ignoring"); - return (-1); - } - - pay.buffer = buffer; - if (bytes < ntohs (pay.packet->ip.ip_len)) { - logger (LOG_DEBUG, "truncated packet, ignoring"); - return (-1); - } - - if (valid_dhcp_packet (buffer) == -1) - return (-1); - - bytes = ntohs (pay.packet->ip.ip_len) - - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)); - memcpy (data, &pay.packet->dhcp, bytes); - return (bytes); + ssize_t bytes; + union + { + unsigned char *buffer; + struct udp_dhcp_packet *packet; + } pay; + + /* We don't use the given buffer, but we need to rewind the position */ + *buffer_pos = 0; + + memset (buffer, 0, iface->buffer_length); + bytes = read (iface->fd, buffer, iface->buffer_length); + + if (bytes == -1) + { + struct timespec ts; + logger (LOG_ERR, "read: %s", strerror (errno)); + ts.tv_sec = 3; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); + return (-1); + } + + *buffer_len = bytes; + /* If it's an ARP reply, then just send it back */ + if (iface->socket_protocol == ETHERTYPE_ARP) + { + memcpy (data, buffer, bytes); + return (bytes); + } + + if ((unsigned) bytes < (sizeof (pay.packet->ip) + + sizeof (pay.packet->udp))) + { + logger (LOG_DEBUG, "message too short, ignoring"); + return (-1); + } + + pay.buffer = buffer; + if (bytes < ntohs (pay.packet->ip.ip_len)) + { + logger (LOG_DEBUG, "truncated packet, ignoring"); + return (-1); + } + + if (valid_dhcp_packet (buffer) == -1) + return (-1); + + bytes = ntohs (pay.packet->ip.ip_len) - + (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)); + memcpy (data, &pay.packet->dhcp, bytes); + return (bytes); } #else - #error "Platform not supported!" - #error "We currently support BPF and Linux sockets." - #error "Other platforms may work using BPF. If yours does, please let me know" - #error "so I can add it to our list." +#error "Platform not supported!" +#error "We currently support BPF and Linux sockets." +#error "Other platforms may work using BPF. If yours does, please let me know" +#error "so I can add it to our list." #endif diff --git a/src/customdhcpcd/socket.h b/src/customdhcpcd/socket.h index bdf26d0..1ab53ab 100644 --- a/src/customdhcpcd/socket.h +++ b/src/customdhcpcd/socket.h @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved @@ -35,12 +35,12 @@ void setup_packet_filters (void); void make_dhcp_packet(struct udp_dhcp_packet *packet, - const unsigned char *data, size_t length, - struct in_addr source, struct in_addr dest); + const unsigned char *data, size_t length, + struct in_addr source, struct in_addr dest); int open_socket (interface_t *iface, int protocol); ssize_t send_packet (const interface_t *iface, int type, - const unsigned char *data, size_t len); + const unsigned char *data, size_t len); ssize_t get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos); + unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos); #endif -- cgit v1.2.3-55-g7522