From 378dcbd5d580b197dbcd4f1c2fc84bf41c28e032 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Wed, 11 Apr 2007 13:18:33 +0000 Subject: [PATCH] Cuddle up to LKML style C --- arp.c | 218 ++++---- client.c | 1026 +++++++++++++++++------------------ common.c | 85 ++- configure.c | 1097 ++++++++++++++++++------------------- configure.h | 4 +- dhcp.c | 1234 ++++++++++++++++++++---------------------- dhcp.h | 198 +++---- dhcpcd.c | 655 +++++++++++----------- dhcpcd.h | 50 +- interface.c | 1502 +++++++++++++++++++++++++-------------------------- interface.h | 54 +- logger.c | 106 ++-- signals.c | 67 ++- socket.c | 908 +++++++++++++++---------------- socket.h | 8 +- 15 files changed, 3470 insertions(+), 3742 deletions(-) diff --git a/arp.c b/arp.c index 0dc04ebc..12e32cbc 100644 --- a/arp.c +++ b/arp.c @@ -48,124 +48,118 @@ #define ar_sha(ap) (((unsigned char *) ((ap) + 1)) + 0) #define ar_spa(ap) (((unsigned char *) ((ap) + 1)) + (ap)->ar_hln) #define ar_tha(ap) (((unsigned char *) ((ap) + 1)) + \ - (ap)->ar_hln + (ap)->ar_pln) + (ap)->ar_hln + (ap)->ar_pln) #define ar_tpa(ap) (((unsigned char *) ((ap) + 1)) + \ - 2 * (ap)->ar_hln + (ap)->ar_pln) + 2 * (ap)->ar_hln + (ap)->ar_pln) #define arphdr_len2(ar_hln, ar_pln) (sizeof (struct arphdr) + \ - 2 * (ar_hln) + 2 * (ar_pln)) + 2 * (ar_hln) + 2 * (ar_pln)) #define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln)) #endif int arp_check (interface_t *iface, struct in_addr address) { - union - { - unsigned char buffer[iface->buffer_length]; - struct arphdr ah; - } arp; - - int bytes; - struct timeval tv; - long timeout = 0; - fd_set rset; - - if (! iface->arpable) - { - logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable", - iface->name); - return 0; - } - - memset (arp.buffer, 0, sizeof (arp.buffer)); - - arp.ah.ar_hrd = htons (iface->family); - arp.ah.ar_pro = htons (ETHERTYPE_IP); - arp.ah.ar_hln = iface->hwlen; - arp.ah.ar_pln = sizeof (struct in_addr); - arp.ah.ar_op = htons (ARPOP_REQUEST); - memcpy (ar_sha (&arp.ah), &iface->hwaddr, arp.ah.ar_hln); - memcpy (ar_tpa (&arp.ah), &address, arp.ah.ar_pln); - - logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa - (address)); - - open_socket (iface, true); - send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &arp.buffer, - arphdr_len (&arp.ah)); - - timeout = uptime() + TIMEOUT; - while (1) - { - int buflen = sizeof (arp.buffer); - int bufpos = -1; - - tv.tv_sec = timeout - uptime (); - tv.tv_usec = 0; - - if (tv.tv_sec < 1) - break; /* Time out */ - - FD_ZERO (&rset); - FD_SET (iface->fd, &rset); - - if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0) - break; - - if (! FD_ISSET (iface->fd, &rset)) - continue; - - memset (arp.buffer, 0, sizeof (arp.buffer)); - - while (bufpos != 0) - { - union - { - unsigned char buffer[buflen]; - struct arphdr hdr; - } reply; - union - { - unsigned char *c; - struct in_addr *a; - } rp; - union - { - unsigned char *c; - struct ether_addr *a; - } rh; - memset (reply.buffer, 0, sizeof (reply.buffer)); - if ((bytes = get_packet (iface, reply.buffer, arp.buffer, - &buflen, &bufpos)) < 0) - break; - - /* Only these types are recognised */ - if (reply.hdr.ar_op != htons(ARPOP_REPLY)) - continue; - - /* Protocol must be IP. */ - if (reply.hdr.ar_pro != htons (ETHERTYPE_IP)) - continue; - if (reply.hdr.ar_pln != sizeof (struct in_addr)) - continue; - - if (reply.hdr.ar_hln != ETHER_ADDR_LEN) - continue; - if ((unsigned) bytes < sizeof (reply.hdr) + - 2 * (4 + reply.hdr.ar_hln)) - continue; - - rp.c = (unsigned char *) ar_spa (&reply.hdr); - rh.c = (unsigned char *) ar_sha (&reply.hdr); - logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", - inet_ntoa (*rp.a), ether_ntoa (rh.a)); - close (iface->fd); - iface->fd = -1; - return 1; - } - } - - close (iface->fd); - iface->fd = -1; - return 0; + union { + unsigned char buffer[iface->buffer_length]; + struct arphdr ah; + } arp; + + int bytes; + struct timeval tv; + long timeout = 0; + fd_set rset; + + if (! iface->arpable) { + logger (LOG_DEBUG, "arp_check: interface `%s' is not ARPable", + iface->name); + return 0; + } + + memset (arp.buffer, 0, sizeof (arp.buffer)); + + arp.ah.ar_hrd = htons (iface->family); + arp.ah.ar_pro = htons (ETHERTYPE_IP); + arp.ah.ar_hln = iface->hwlen; + arp.ah.ar_pln = sizeof (struct in_addr); + arp.ah.ar_op = htons (ARPOP_REQUEST); + memcpy (ar_sha (&arp.ah), &iface->hwaddr, arp.ah.ar_hln); + memcpy (ar_tpa (&arp.ah), &address, arp.ah.ar_pln); + + logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa + (address)); + + open_socket (iface, true); + send_packet (iface, ETHERTYPE_ARP, (unsigned char *) &arp.buffer, + arphdr_len (&arp.ah)); + + timeout = uptime() + TIMEOUT; + while (1) { + int buflen = sizeof (arp.buffer); + int bufpos = -1; + + tv.tv_sec = timeout - uptime (); + tv.tv_usec = 0; + + if (tv.tv_sec < 1) + break; /* Time out */ + + FD_ZERO (&rset); + FD_SET (iface->fd, &rset); + + if (select (iface->fd + 1, &rset, NULL, NULL, &tv) == 0) + break; + + if (! FD_ISSET (iface->fd, &rset)) + continue; + + memset (arp.buffer, 0, sizeof (arp.buffer)); + + while (bufpos != 0) { + union { + unsigned char buffer[buflen]; + struct arphdr hdr; + } reply; + union { + unsigned char *c; + struct in_addr *a; + } rp; + union { + unsigned char *c; + struct ether_addr *a; + } rh; + + memset (reply.buffer, 0, sizeof (reply.buffer)); + if ((bytes = get_packet (iface, reply.buffer, arp.buffer, + &buflen, &bufpos)) < 0) + break; + + /* Only these types are recognised */ + if (reply.hdr.ar_op != htons(ARPOP_REPLY)) + continue; + + /* Protocol must be IP. */ + if (reply.hdr.ar_pro != htons (ETHERTYPE_IP)) + continue; + if (reply.hdr.ar_pln != sizeof (struct in_addr)) + continue; + + if (reply.hdr.ar_hln != ETHER_ADDR_LEN) + continue; + if ((unsigned) bytes < sizeof (reply.hdr) + + 2 * (4 + reply.hdr.ar_hln)) + continue; + + rp.c = (unsigned char *) ar_spa (&reply.hdr); + rh.c = (unsigned char *) ar_sha (&reply.hdr); + logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", + inet_ntoa (*rp.a), ether_ntoa (rh.a)); + close (iface->fd); + iface->fd = -1; + return 1; + } + } + + close (iface->fd); + iface->fd = -1; + return 0; } diff --git a/client.c b/client.c index 71039811..0e9a51c1 100644 --- a/client.c +++ b/client.c @@ -69,571 +69,519 @@ #define SOCKET_CLOSED 0 #define SOCKET_OPEN 1 -#define SOCKET_MODE(_mode) \ -{ \ - if (iface->fd >= 0) close (iface->fd); \ - iface->fd = -1; \ - if (_mode == SOCKET_OPEN) \ - if (open_socket (iface, false) < 0) { retval = -1; goto eexit; } \ - mode = _mode; \ +#define SOCKET_MODE(_mode) { \ + if (iface->fd >= 0) close (iface->fd); \ + iface->fd = -1; \ + if (_mode == SOCKET_OPEN) \ + if (open_socket (iface, false) < 0) { retval = -1; goto eexit; } \ + mode = _mode; \ } -#define SEND_MESSAGE(_type) \ -{ \ - last_type = _type; \ - last_send = uptime (); \ - send_message (iface, dhcp, xid, _type, options); \ +#define SEND_MESSAGE(_type) { \ + last_type = _type; \ + last_send = uptime (); \ + send_message (iface, dhcp, xid, _type, options); \ } -#define DROP_CONFIG \ -{ \ - memset (&dhcp->address, 0, sizeof (struct in_addr)); \ - if (iface->previous_address.s_addr != 0 && ! options->persistent) \ - configure (options, iface, dhcp); \ - free_dhcp (dhcp); \ - memset (dhcp, 0, sizeof (dhcp_t)); \ +#define DROP_CONFIG { \ + memset (&dhcp->address, 0, sizeof (struct in_addr)); \ + if (iface->previous_address.s_addr != 0 && ! options->persistent) \ + configure (options, iface, dhcp); \ + free_dhcp (dhcp); \ + memset (dhcp, 0, sizeof (dhcp_t)); \ } static int daemonise (const char *pidfile) { - logger (LOG_DEBUG, "forking to background"); - if (daemon (0, 0) < 0) - { - logger (LOG_ERR, "daemon: %s", strerror (errno)); - return -1; - } + logger (LOG_DEBUG, "forking to background"); + if (daemon (0, 0) < 0) { + logger (LOG_ERR, "daemon: %s", strerror (errno)); + return -1; + } - make_pid (pidfile); + make_pid (pidfile); - return 0; + return 0; } static unsigned long random_xid (void) { - static int initialized; - - if (! initialized) - { - int fd; - unsigned long seed; - - fd = open ("/dev/urandom", 0); - if (fd < 0 || read (fd, &seed, sizeof(seed)) < 0) - { - logger (LOG_WARNING, "Could not load seed from /dev/urandom: %s", - strerror (errno)); - seed = time (0); - } - if (fd >= 0) - close(fd); - - srand(seed); - initialized++; - } - - return rand(); + static int initialized; + + if (! initialized) { + int fd; + unsigned long seed; + + fd = open ("/dev/urandom", 0); + if (fd < 0 || read (fd, &seed, sizeof(seed)) < 0) { + logger (LOG_WARNING, "Could not load seed from /dev/urandom: %s", + strerror (errno)); + seed = time (0); + } + if (fd >= 0) + close(fd); + + srand(seed); + initialized++; + } + + return rand(); } /* This state machine is based on the one from udhcpc written by Russ Dill */ int dhcp_run (const options_t *options) { - interface_t *iface; - int mode = SOCKET_CLOSED; - int state = STATE_INIT; - struct timeval tv; - int xid = 0; - long timeout = 0; - fd_set rset; - int maxfd; - int retval; - dhcpmessage_t message; - dhcp_t *dhcp; - int type = DHCP_DISCOVER; - int last_type = DHCP_DISCOVER; - bool daemonised = false; - unsigned long start = 0; - unsigned long last_send = 0; - int sig; - unsigned char *buffer = NULL; - int buffer_len = 0; - int buffer_pos = 0; - - if (! options || (iface = (read_interface (options->interface, - options->metric))) == NULL) - return -1; - - /* 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. */ - flush_addresses (iface->name); - - dhcp = xmalloc (sizeof (dhcp_t)); - memset (dhcp, 0, sizeof (dhcp_t)); - - if (options->requestaddress.s_addr != 0) - dhcp->address.s_addr = options->requestaddress.s_addr; - - signal_setup (); - - while (1) - { - if (timeout > 0 || (options->timeout == 0 && - (state != STATE_INIT || xid))) - { - if (options->timeout == 0 || - (dhcp->leasetime == (unsigned) -1 && state == STATE_BOUND)) - { - int retry = 0; - logger (LOG_DEBUG, "waiting on select for infinity"); - retval = 0; - while (retval == 0) - { - maxfd = signal_fd_set (&rset, iface->fd); - if (iface->fd == -1) - retval = select (maxfd + 1, &rset, NULL, NULL, NULL); - else - { - /* Slow down our requests */ - if (retry < TIMEOUT_MINI_INF) - retry += TIMEOUT_MINI; - else if (retry > TIMEOUT_MINI_INF) - retry = TIMEOUT_MINI_INF; - - tv.tv_sec = retry; - tv.tv_usec = 0; - retval = select (maxfd + 1, &rset, NULL, NULL, &tv); - if (retval == 0) - SEND_MESSAGE (last_type); - } - } - } - else - { - /* Resend our message if we're getting loads of packets - that aren't for us. This mainly happens on Linux as it - doesn't have a nice BPF filter. */ - if (iface->fd > -1 && uptime () - last_send >= TIMEOUT_MINI) - SEND_MESSAGE (last_type); - - logger (LOG_DEBUG, "waiting on select for %ld seconds", - 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 (timeout > 0 && retval == 0) - { - if (iface->fd == -1) - tv.tv_sec = SELECT_MAX; - else - tv.tv_sec = TIMEOUT_MINI; - if (timeout < tv.tv_sec) - tv.tv_sec = timeout; - tv.tv_usec = 0; - start = uptime (); - maxfd = signal_fd_set (&rset, iface->fd); - retval = select (maxfd + 1, &rset, NULL, NULL, &tv); - timeout -= uptime () - start; - if (retval == 0 && iface->fd != -1 && timeout > 0) - SEND_MESSAGE (last_type); - } - } - } - else - retval = 0; - - /* We should always handle our signals first */ - if (retval > 0 && (sig = signal_read (&rset))) - { - switch (sig) - { - case SIGINT: - logger (LOG_INFO, "received SIGINT, stopping"); - retval = (! daemonised); - goto eexit; - - case SIGTERM: - logger (LOG_INFO, "received SIGTERM, stopping"); - retval = (! daemonised); - goto eexit; - - case SIGALRM: - - logger (LOG_INFO, "received SIGALRM, renewing lease"); - switch (state) - { - case STATE_BOUND: - case STATE_RENEWING: - case STATE_REBINDING: - state = STATE_RENEW_REQUESTED; - break; - case STATE_RENEW_REQUESTED: - case STATE_REQUESTING: - case STATE_RELEASED: - state = STATE_INIT; - break; - } - - timeout = 0; - xid = 0; - break; - - case SIGHUP: - if (state == STATE_BOUND || state == STATE_RENEWING - || state == STATE_REBINDING) - { - logger (LOG_INFO, "received SIGHUP, releasing lease"); - SOCKET_MODE (SOCKET_OPEN); - xid = random_xid (); - if ((open_socket (iface, false)) >= 0) - SEND_MESSAGE (DHCP_RELEASE); - SOCKET_MODE (SOCKET_CLOSED); - unlink (iface->infofile); - } - else - logger (LOG_ERR, - "received SIGHUP, but no we have lease to release"); - retval = 0; - goto eexit; - - default: - logger (LOG_ERR, - "received signal %d, but don't know what to do with it", - sig); - } - } - else if (retval == 0) /* timed out */ - { - switch (state) - { - case STATE_INIT: - if (iface->previous_address.s_addr != 0) - { - logger (LOG_ERR, "lost lease"); - xid = 0; - SOCKET_MODE (SOCKET_CLOSED); - if (! options->persistent) - DROP_CONFIG; - } - - if (xid == 0) - xid = random_xid (); - else - { - logger (LOG_ERR, "timed out"); - if (! daemonised) - { - retval = -1; - goto eexit; - } - } - - SOCKET_MODE (SOCKET_OPEN); - timeout = options->timeout; - iface->start_uptime = uptime (); - if (dhcp->address.s_addr == 0) - { - logger (LOG_INFO, "broadcasting for a lease"); - SEND_MESSAGE (DHCP_DISCOVER); - } - else - { - logger (LOG_INFO, "broadcasting for a lease of %s", - inet_ntoa (dhcp->address)); - SEND_MESSAGE (DHCP_REQUEST); - state = STATE_REQUESTING; - } - - break; - case STATE_BOUND: - case STATE_RENEW_REQUESTED: - state = STATE_RENEWING; - xid = random_xid (); - case STATE_RENEWING: - iface->start_uptime = uptime (); - logger (LOG_INFO, "renewing lease of %s", inet_ntoa - (dhcp->address)); - SOCKET_MODE (SOCKET_OPEN); - SEND_MESSAGE (DHCP_REQUEST); - timeout = dhcp->rebindtime - dhcp->renewaltime; - state = STATE_REBINDING; - break; - case STATE_REBINDING: - logger (LOG_ERR, "lost lease, attemping to rebind"); - memset (&dhcp->address, 0, sizeof (struct in_addr)); - SOCKET_MODE (SOCKET_OPEN); - SEND_MESSAGE (DHCP_REQUEST); - timeout = dhcp->leasetime - dhcp->rebindtime; - state = STATE_REQUESTING; - break; - case STATE_REQUESTING: - if (iface->previous_address.s_addr != 0) - logger (LOG_ERR, "lost lease"); - else - logger (LOG_ERR, "timed out"); - if (! daemonised && options->daemonise) - goto eexit; - - state = STATE_INIT; - SOCKET_MODE (SOCKET_CLOSED); - timeout = 0; - xid = 0; - DROP_CONFIG; - break; - - case STATE_RELEASED: - dhcp->leasetime = -1; - break; - } - } - else if (retval > 0 && mode != SOCKET_CLOSED && FD_ISSET(iface->fd, &rset)) - { - int valid = 0; - struct dhcp_t *new_dhcp; - - /* 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 (! buffer) - buffer = xmalloc (iface->buffer_length); - buffer_len = iface->buffer_length; - buffer_pos = -1; - - /* 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 (struct dhcpmessage_t)); - new_dhcp = xmalloc (sizeof (dhcp_t)); - - while (buffer_pos != 0) - { - if (get_packet (iface, (unsigned char *) &message, buffer, - &buffer_len, &buffer_pos) < 0) - break; - - if (xid != message.xid) - { - logger (LOG_ERR, - "ignoring packet with xid 0x%x as it's not ours (0x%x)", - message.xid, xid); - continue; - } - - logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid); - memset (new_dhcp, 0, sizeof (dhcp_t)); - if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0) - { - logger (LOG_ERR, "failed to parse packet"); - free_dhcp (new_dhcp); - continue; - } - - /* 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 = 1; - break; - } - - /* No packets for us, so wait until we get one */ - if (! valid) - { - free (new_dhcp); - continue; - } - - /* new_dhcp is now our master DHCP message */ - free_dhcp (dhcp); - free (dhcp); - dhcp = new_dhcp; - new_dhcp = NULL; - - /* We should restart on a NAK */ - if (type == DHCP_NAK) - { - logger (LOG_INFO, "received NAK: %s", dhcp->message); - state = STATE_INIT; - timeout = 0; - xid = 0; - DROP_CONFIG; - continue; - } - - switch (state) - { - case STATE_INIT: - if (type == DHCP_OFFER) - { - 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); - - SEND_MESSAGE (DHCP_REQUEST); - state = STATE_REQUESTING; - } - break; - - case STATE_RENEW_REQUESTED: - case STATE_REQUESTING: - case STATE_RENEWING: - case STATE_REBINDING: - if (type == DHCP_ACK) - { - SOCKET_MODE (SOCKET_CLOSED); - if (options->doarp && iface->previous_address.s_addr != - dhcp->address.s_addr) - { - if (arp_check (iface, dhcp->address)) - { - SOCKET_MODE (SOCKET_OPEN); - SEND_MESSAGE (DHCP_DECLINE); - SOCKET_MODE (SOCKET_CLOSED); - DROP_CONFIG; - - xid = 0; - timeout = 0; - state = STATE_INIT; - /* RFC 2131 says that we should wait for 10 seconds - before doing anything else */ - logger (LOG_INFO, "sleeping for 10 seconds"); - tv.tv_sec = 10; - tv.tv_usec = 0; - select (0, NULL, NULL, NULL, &tv); - continue; - } - } - - if (dhcp->leasetime == (unsigned) -1) - { - dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; - timeout = 1; /* So we select on infinity */ - logger (LOG_INFO, "leased %s for infinity", - inet_ntoa (dhcp->address)); - } - 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); - - timeout = dhcp->renewaltime; - } - - state = STATE_BOUND; - xid = 0; - - if (configure (options, iface, dhcp) < 0 && ! daemonised) - { - retval = -1; - goto eexit; - } - - if (! daemonised && options->daemonise) - { - if ((daemonise (options->pidfile)) < 0 ) - { - retval = -1; - goto eexit; - } - daemonised = true; - } - } - else if (type == DHCP_OFFER) - logger (LOG_INFO, "got subsequent offer of %s, ignoring ", - inet_ntoa (dhcp->address)); - else - logger (LOG_ERR, - "no idea what to do with DHCP type %d at this point", - type); - break; - } - } - else if (retval == -1 && errno == EINTR) - { - /* The interupt will be handled above */ - } - else - { - /* An error occured. As we heavily depend on select, we abort. */ - logger (LOG_ERR, "error on select: %s", strerror (errno)); - retval = -1; - goto eexit; - } - } + interface_t *iface; + int mode = SOCKET_CLOSED; + int state = STATE_INIT; + struct timeval tv; + int xid = 0; + long timeout = 0; + fd_set rset; + int maxfd; + int retval; + dhcpmessage_t message; + dhcp_t *dhcp; + int type = DHCP_DISCOVER; + int last_type = DHCP_DISCOVER; + bool daemonised = false; + unsigned long start = 0; + unsigned long last_send = 0; + int sig; + unsigned char *buffer = NULL; + int buffer_len = 0; + int buffer_pos = 0; + + if (! options || (iface = (read_interface (options->interface, + options->metric))) == NULL) + return -1; + + /* 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. */ + flush_addresses (iface->name); + + dhcp = xmalloc (sizeof (dhcp_t)); + memset (dhcp, 0, sizeof (dhcp_t)); + + if (options->requestaddress.s_addr != 0) + dhcp->address.s_addr = options->requestaddress.s_addr; + + signal_setup (); + + while (1) { + if (timeout > 0 || (options->timeout == 0 && + (state != STATE_INIT || xid))) + { + if (options->timeout == 0 || + (dhcp->leasetime == (unsigned) -1 && state == STATE_BOUND)) + { + int retry = 0; + logger (LOG_DEBUG, "waiting on select for infinity"); + retval = 0; + while (retval == 0) { + maxfd = signal_fd_set (&rset, iface->fd); + if (iface->fd == -1) + retval = select (maxfd + 1, &rset, NULL, NULL, NULL); + else { + /* Slow down our requests */ + if (retry < TIMEOUT_MINI_INF) + retry += TIMEOUT_MINI; + else if (retry > TIMEOUT_MINI_INF) + retry = TIMEOUT_MINI_INF; + + tv.tv_sec = retry; + tv.tv_usec = 0; + retval = select (maxfd + 1, &rset, NULL, NULL, &tv); + if (retval == 0) + SEND_MESSAGE (last_type); + } + } + } else { + /* Resend our message if we're getting loads of packets + that aren't for us. This mainly happens on Linux as it + doesn't have a nice BPF filter. */ + if (iface->fd > -1 && uptime () - last_send >= TIMEOUT_MINI) + SEND_MESSAGE (last_type); + + logger (LOG_DEBUG, "waiting on select for %ld seconds", + 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 (timeout > 0 && retval == 0) { + if (iface->fd == -1) + tv.tv_sec = SELECT_MAX; + else + tv.tv_sec = TIMEOUT_MINI; + if (timeout < tv.tv_sec) + tv.tv_sec = timeout; + tv.tv_usec = 0; + start = uptime (); + maxfd = signal_fd_set (&rset, iface->fd); + retval = select (maxfd + 1, &rset, NULL, NULL, &tv); + timeout -= uptime () - start; + if (retval == 0 && iface->fd != -1 && timeout > 0) + SEND_MESSAGE (last_type); + } + } + } else + retval = 0; + + /* We should always handle our signals first */ + if (retval > 0 && (sig = signal_read (&rset))) { + switch (sig) { + case SIGINT: + logger (LOG_INFO, "received SIGINT, stopping"); + retval = (! daemonised); + goto eexit; + + case SIGTERM: + logger (LOG_INFO, "received SIGTERM, stopping"); + retval = (! daemonised); + goto eexit; + + case SIGALRM: + + logger (LOG_INFO, "received SIGALRM, renewing lease"); + switch (state) { + case STATE_BOUND: + case STATE_RENEWING: + case STATE_REBINDING: + state = STATE_RENEW_REQUESTED; + break; + case STATE_RENEW_REQUESTED: + case STATE_REQUESTING: + case STATE_RELEASED: + state = STATE_INIT; + break; + } + + timeout = 0; + xid = 0; + break; + + case SIGHUP: + if (state == STATE_BOUND || state == STATE_RENEWING + || state == STATE_REBINDING) + { + logger (LOG_INFO, "received SIGHUP, releasing lease"); + SOCKET_MODE (SOCKET_OPEN); + xid = random_xid (); + if ((open_socket (iface, false)) >= 0) + SEND_MESSAGE (DHCP_RELEASE); + SOCKET_MODE (SOCKET_CLOSED); + unlink (iface->infofile); + } + else + logger (LOG_ERR, + "received SIGHUP, but no we have lease to release"); + retval = 0; + goto eexit; + + default: + logger (LOG_ERR, + "received signal %d, but don't know what to do with it", + sig); + } + } else if (retval == 0) { + /* timed out */ + switch (state) { + case STATE_INIT: + if (iface->previous_address.s_addr != 0) { + logger (LOG_ERR, "lost lease"); + xid = 0; + SOCKET_MODE (SOCKET_CLOSED); + if (! options->persistent) + DROP_CONFIG; + } + + if (xid == 0) + xid = random_xid (); + else { + logger (LOG_ERR, "timed out"); + if (! daemonised) { + retval = -1; + goto eexit; + } + } + + SOCKET_MODE (SOCKET_OPEN); + timeout = options->timeout; + iface->start_uptime = uptime (); + if (dhcp->address.s_addr == 0) { + logger (LOG_INFO, "broadcasting for a lease"); + SEND_MESSAGE (DHCP_DISCOVER); + } else { + logger (LOG_INFO, "broadcasting for a lease of %s", + inet_ntoa (dhcp->address)); + SEND_MESSAGE (DHCP_REQUEST); + state = STATE_REQUESTING; + } + + break; + case STATE_BOUND: + case STATE_RENEW_REQUESTED: + state = STATE_RENEWING; + xid = random_xid (); + case STATE_RENEWING: + iface->start_uptime = uptime (); + logger (LOG_INFO, "renewing lease of %s", inet_ntoa + (dhcp->address)); + SOCKET_MODE (SOCKET_OPEN); + SEND_MESSAGE (DHCP_REQUEST); + timeout = dhcp->rebindtime - dhcp->renewaltime; + state = STATE_REBINDING; + break; + case STATE_REBINDING: + logger (LOG_ERR, "lost lease, attemping to rebind"); + memset (&dhcp->address, 0, sizeof (struct in_addr)); + SOCKET_MODE (SOCKET_OPEN); + SEND_MESSAGE (DHCP_REQUEST); + timeout = dhcp->leasetime - dhcp->rebindtime; + state = STATE_REQUESTING; + break; + case STATE_REQUESTING: + if (iface->previous_address.s_addr != 0) + logger (LOG_ERR, "lost lease"); + else + logger (LOG_ERR, "timed out"); + if (! daemonised && options->daemonise) + goto eexit; + + state = STATE_INIT; + SOCKET_MODE (SOCKET_CLOSED); + timeout = 0; + xid = 0; + DROP_CONFIG; + break; + + case STATE_RELEASED: + dhcp->leasetime = -1; + break; + } + } else if (retval > 0 && + mode != SOCKET_CLOSED && + FD_ISSET(iface->fd, &rset)) + { + int valid = 0; + struct dhcp_t *new_dhcp; + + /* 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 (! buffer) + buffer = xmalloc (iface->buffer_length); + buffer_len = iface->buffer_length; + buffer_pos = -1; + + /* 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 (struct dhcpmessage_t)); + new_dhcp = xmalloc (sizeof (dhcp_t)); + + while (buffer_pos != 0) { + if (get_packet (iface, (unsigned char *) &message, buffer, + &buffer_len, &buffer_pos) < 0) + break; + + if (xid != message.xid) { + logger (LOG_ERR, + "ignoring packet with xid 0x%x as it's not ours (0x%x)", + message.xid, xid); + continue; + } + + logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid); + memset (new_dhcp, 0, sizeof (dhcp_t)); + if ((type = parse_dhcpmessage (new_dhcp, &message)) < 0) { + logger (LOG_ERR, "failed to parse packet"); + free_dhcp (new_dhcp); + continue; + } + + /* 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 = 1; + break; + } + + /* No packets for us, so wait until we get one */ + if (! valid) { + free (new_dhcp); + continue; + } + + /* new_dhcp is now our master DHCP message */ + free_dhcp (dhcp); + free (dhcp); + dhcp = new_dhcp; + new_dhcp = NULL; + + /* We should restart on a NAK */ + if (type == DHCP_NAK) { + logger (LOG_INFO, "received NAK: %s", dhcp->message); + state = STATE_INIT; + timeout = 0; + xid = 0; + DROP_CONFIG; + continue; + } + + switch (state) { + case STATE_INIT: + if (type == DHCP_OFFER) { + 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); + + SEND_MESSAGE (DHCP_REQUEST); + state = STATE_REQUESTING; + } + break; + + case STATE_RENEW_REQUESTED: + case STATE_REQUESTING: + case STATE_RENEWING: + case STATE_REBINDING: + if (type == DHCP_ACK) { + SOCKET_MODE (SOCKET_CLOSED); + if (options->doarp && iface->previous_address.s_addr != + dhcp->address.s_addr) + { + if (arp_check (iface, dhcp->address)) { + SOCKET_MODE (SOCKET_OPEN); + SEND_MESSAGE (DHCP_DECLINE); + SOCKET_MODE (SOCKET_CLOSED); + DROP_CONFIG; + + xid = 0; + timeout = 0; + state = STATE_INIT; + /* RFC 2131 says that we should wait for 10 seconds + before doing anything else */ + logger (LOG_INFO, "sleeping for 10 seconds"); + tv.tv_sec = 10; + tv.tv_usec = 0; + select (0, NULL, NULL, NULL, &tv); + continue; + } + } + + if (dhcp->leasetime == (unsigned) -1) { + dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; + timeout = 1; /* So we select on infinity */ + logger (LOG_INFO, "leased %s for infinity", + inet_ntoa (dhcp->address)); + } 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); + + timeout = dhcp->renewaltime; + } + + state = STATE_BOUND; + xid = 0; + + if (configure (options, iface, dhcp) < 0 && ! daemonised) { + retval = -1; + goto eexit; + } + + if (! daemonised && options->daemonise) { + if ((daemonise (options->pidfile)) < 0 ) { + retval = -1; + goto eexit; + } + daemonised = true; + } + } else if (type == DHCP_OFFER) + logger (LOG_INFO, "got subsequent offer of %s, ignoring ", + inet_ntoa (dhcp->address)); + else + logger (LOG_ERR, + "no idea what to do with DHCP type %d at this point", + type); + break; + } + } else if (retval == -1 && errno == EINTR) { + /* The interupt will be handled above */ + } else { + /* An error occured. As we heavily depend on select, we abort. */ + logger (LOG_ERR, "error on select: %s", strerror (errno)); + retval = -1; + goto eexit; + } + } eexit: - SOCKET_MODE (SOCKET_CLOSED); - DROP_CONFIG; - free (dhcp); + SOCKET_MODE (SOCKET_CLOSED); + DROP_CONFIG; + free (dhcp); - if (iface) - { - if (iface->previous_routes) - free_route (iface->previous_routes); - free (iface); - } + if (iface) { + if (iface->previous_routes) + free_route (iface->previous_routes); + free (iface); + } - if (buffer) - free (buffer); + if (buffer) + free (buffer); - logger (LOG_INFO, "exiting"); + logger (LOG_INFO, "exiting"); - /* Unlink our pidfile */ - unlink (options->pidfile); + /* Unlink our pidfile */ + unlink (options->pidfile); - return retval; + return retval; } diff --git a/common.c b/common.c index d232de04..bbddf3cd 100644 --- a/common.c +++ b/common.c @@ -32,26 +32,23 @@ # if ! defined(__UCLIBC__) && ! defined (__dietlibc__) 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 #endif @@ -61,54 +58,52 @@ size_t strlcpy (char *dst, const char *src, size_t size) #include long uptime (void) { - struct sysinfo info; + struct sysinfo info; - sysinfo (&info); - return info.uptime; + sysinfo (&info); + return info.uptime; } #elif __APPLE__ /* Darwin doesn't appear to have an uptime, so try and make one ourselves */ #include long uptime (void) { - struct timeval tv; - static long start = 0; + struct timeval tv; + static long start = 0; - if (gettimeofday (&tv, NULL) == -1) - { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return -1; - } + if (gettimeofday (&tv, NULL) == -1) { + logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); + return -1; + } - if (start == 0) - start = tv.tv_sec; + if (start == 0) + start = tv.tv_sec; - return tv.tv_sec - start; + return tv.tv_sec - start; } #else #include long uptime (void) { - struct timespec tp; + struct timespec tp; - if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) - { - logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); - return -1; - } + if (clock_gettime(CLOCK_MONOTONIC, &tp) == -1) { + logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); + return -1; + } - return tp.tv_sec; + return tp.tv_sec; } #endif void *xmalloc (size_t size) { - void *value = malloc (size); + void *value = malloc (size); - if (value) - return value; + if (value) + return value; - logger (LOG_ERR, "memory exhausted"); - exit (1); + logger (LOG_ERR, "memory exhausted"); + exit (1); } diff --git a/configure.c b/configure.c index 92a2f5c7..c539e9d7 100644 --- a/configure.c +++ b/configure.c @@ -50,670 +50,619 @@ /* IMPORTANT: Ensure that the last parameter is NULL when calling */ static int exec_cmd (const char *cmd, const char *args, ...) { - va_list va; - pid_t pid; - char **argv; - int n = 1; - - va_start (va, args); - while (va_arg (va, char *) != NULL) - n++; - va_end (va); - argv = alloca ((n + 1) * sizeof (*argv)); - if (argv == NULL) - { - errno = ENOMEM; - return -1; - } - - 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); - - if ((pid = fork ()) == 0) - { - if (execv (cmd, argv) && errno != ENOENT) - logger (LOG_ERR, "error executing \"%s\": %s", - cmd, strerror (errno)); - exit (0); - } - else if (pid == -1) - logger (LOG_ERR, "fork: %s", strerror (errno)); - - return 0; + va_list va; + pid_t pid; + char **argv; + int n = 1; + + va_start (va, args); + while (va_arg (va, char *) != NULL) + n++; + va_end (va); + argv = alloca ((n + 1) * sizeof (*argv)); + if (argv == NULL) { + errno = ENOMEM; + return -1; + } + + 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); + + if ((pid = fork ()) == 0) { + if (execv (cmd, argv) && errno != ENOENT) + logger (LOG_ERR, "error executing \"%s\": %s", + cmd, strerror (errno)); + exit (0); + } else if (pid == -1) + logger (LOG_ERR, "fork: %s", strerror (errno)); + + return 0; } static void exec_script (const char *script, const char *infofile, - const char *arg) + const char *arg) { - struct stat buf; + struct stat buf; #ifdef ENABLE_INFO - if (! script || ! infofile || ! arg) - return; + if (! script || ! infofile || ! arg) + return; #else - if (! script || ! arg) - return ; + if (! script || ! arg) + return ; #endif - if (stat (script, &buf) < 0) - { - if (strcmp (script, DEFAULT_SCRIPT) != 0) - logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT)); - return; - } + if (stat (script, &buf) < 0) { + 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, infofile, arg); - exec_cmd (script, infofile, "", arg, (char *) NULL); + logger (LOG_DEBUG, "exec \"%s \"\" %s\"", script, infofile, arg); + exec_cmd (script, infofile, "", arg, (char *) NULL); #endif } static int make_resolv (const char *ifname, const dhcp_t *dhcp) { - FILE *f; - struct stat buf; - char resolvconf[PATH_MAX] = {0}; - address_t *address; + FILE *f; + struct stat buf; + char resolvconf[PATH_MAX] = {0}; + address_t *address; #ifdef RESOLVCONF - if (stat (RESOLVCONF, &buf) == 0) - { - logger (LOG_DEBUG, "sending DNS information to resolvconf"); - snprintf (resolvconf, PATH_MAX, RESOLVCONF" -a %s", ifname); - f = popen (resolvconf, "w"); - - if (! f) - logger (LOG_ERR, "popen: %s", strerror (errno)); - } - else + if (stat (RESOLVCONF, &buf) == 0) { + logger (LOG_DEBUG, "sending DNS information to resolvconf"); + snprintf (resolvconf, PATH_MAX, RESOLVCONF" -a %s", ifname); + f = popen (resolvconf, "w"); + + if (! f) + logger (LOG_ERR, "popen: %s", strerror (errno)); + } else #endif - { - logger (LOG_DEBUG, "writing "RESOLVFILE); - if (! (f = fopen(RESOLVFILE, "w"))) - logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno)); - } - - if (f) - { - 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); - } - - for (address = dhcp->dnsservers; address; address = address->next) - fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); - - if (*resolvconf) - pclose (f); - else - fclose (f); - } - else - return -1; - - /* Refresh the local resolver */ - res_init (); - return 0; + { + logger (LOG_DEBUG, "writing "RESOLVFILE); + if (! (f = fopen(RESOLVFILE, "w"))) + logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno)); + } + + if (f) { + 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); + } + + for (address = dhcp->dnsservers; address; address = address->next) + fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); + + if (*resolvconf) + pclose (f); + else + fclose (f); + } else + return -1; + + /* Refresh the local resolver */ + res_init (); + return 0; } static void restore_resolv(const char *ifname) { #ifdef RESOLVCONF - struct stat buf; + struct stat buf; - if (stat (RESOLVCONF, &buf) < 0) - return; + if (stat (RESOLVCONF, &buf) < 0) + return; - logger (LOG_DEBUG, "removing information from resolvconf"); - exec_cmd (RESOLVCONF, "-d", ifname, (char *) NULL); + logger (LOG_DEBUG, "removing information from resolvconf"); + exec_cmd (RESOLVCONF, "-d", ifname, (char *) NULL); #endif } #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 buffer[1024]; - int tomatch = 0; - char *token; - bool ntp = false; - - for (address = dhcp->ntpservers; address; address = address->next) - 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 - { - memset (buffer, 0, sizeof (buffer)); - while (fgets (buffer, sizeof (buffer), f)) - { - a = buffer; - token = strsep (&a, " "); - if (! token || strcmp (token, "server") != 0) - continue; - - if ((token = strsep (&a, " \n")) == NULL) - continue; - - for (address = dhcp->ntpservers; address; address = address->next) - if (strcmp (token, inet_ntoa (address->address)) == 0) - { - tomatch--; - break; - } - - if (tomatch == 0) - break; - } - 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); + FILE *f; + address_t *address; + char *a; + char buffer[1024]; + int tomatch = 0; + char *token; + bool ntp = false; + + for (address = dhcp->ntpservers; address; address = address->next) + 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 { + memset (buffer, 0, sizeof (buffer)); + while (fgets (buffer, sizeof (buffer), f)) { + a = buffer; + token = strsep (&a, " "); + if (! token || strcmp (token, "server") != 0) + continue; + + if ((token = strsep (&a, " \n")) == NULL) + continue; + + for (address = dhcp->ntpservers; address; address = address->next) + if (strcmp (token, inet_ntoa (address->address)) == 0) { + tomatch--; + break; + } + + if (tomatch == 0) + break; + } + 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"); - } + if (strcmp (file, NTPFILE) == 0) { + ntp = true; + fprintf (f, "restrict default noquery notrust nomodify\n"); + fprintf (f, "restrict 127.0.0.1\n"); + } #endif - for (address = dhcp->ntpservers; address; address = address->next) - { - a = inet_ntoa (address->address); - if (ntp) - fprintf (f, "restrict %s nomodify notrap noquery\n", a); - fprintf (f, "server %s\n", a); - } - - if (ntp) - { - fprintf (f, "driftfile " NTPDRIFTFILE "\n"); - fprintf (f, "logfile " NTPLOGFILE "\n"); - } - fclose (f); - - return 1; + for (address = dhcp->ntpservers; address; address = address->next) { + a = inet_ntoa (address->address); + if (ntp) + fprintf (f, "restrict %s nomodify notrap noquery\n", a); + fprintf (f, "server %s\n", a); + } + + if (ntp) { + fprintf (f, "driftfile " NTPDRIFTFILE "\n"); + fprintf (f, "logfile " NTPLOGFILE "\n"); + } + 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) - retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, (char *) NULL); + if (restart_ntp) + retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, (char *) NULL); #endif #if defined (NTPSERVICE) && defined (OPENNTPSERVICE) - if (restart_openntp && - (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp)) - retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL); + if (restart_openntp && + (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp)) + retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL); #elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE) - if (restart_openntp) - retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL); + if (restart_openntp) + retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL); #endif - return retval; + return retval; } #endif #ifdef ENABLE_NIS static int make_nis (const char *ifname, const dhcp_t *dhcp) { - FILE *f; - address_t *address; - char prefix[256] = {0}; - - logger (LOG_DEBUG, "writing "NISFILE); - if (! (f = fopen(NISFILE, "w"))) - { - logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno)); - return -1; - } - - fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); - if (dhcp->nisdomain) - { - setdomainname (dhcp->nisdomain, strlen (dhcp->nisdomain)); - - if (dhcp->nisservers) - snprintf (prefix, sizeof (prefix), "domain %s server", dhcp->nisdomain); - else - fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); - } - else - snprintf (prefix, sizeof (prefix), "%s", "ypserver"); - - for (address = dhcp->nisservers; address; address = address->next) - fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); - - fclose (f); - - exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); - return 0; + FILE *f; + address_t *address; + char prefix[256] = {0}; + + logger (LOG_DEBUG, "writing "NISFILE); + if (! (f = fopen(NISFILE, "w"))) { + logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno)); + return -1; + } + + fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); + if (dhcp->nisdomain) { + setdomainname (dhcp->nisdomain, strlen (dhcp->nisdomain)); + + if (dhcp->nisservers) + snprintf (prefix, sizeof (prefix), "domain %s server", dhcp->nisdomain); + else + fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); + } + else + snprintf (prefix, sizeof (prefix), "%s", "ypserver"); + + for (address = dhcp->nisservers; address; address = address->next) + fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); + + fclose (f); + + exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); + return 0; } #endif #ifdef ENABLE_INFO static char *cleanmetas (const char *cstr) { - /* The largest single element we can have is 256 bytes according to the RFC, - so this buffer size should be safe even if it's all ' */ - static char buffer[1024]; - char *b = buffer; - - memset (buffer, 0, sizeof (buffer)); - if (cstr == NULL || strlen (cstr) == 0) - return b; - - do - if (*cstr == 39) - { - *b++ = '\''; - *b++ = '\\'; - *b++ = '\''; - *b++ = '\''; - } - else - *b++ = *cstr; - while (*cstr++); - - *b++ = 0; - b = buffer; - - return b; + /* The largest single element we can have is 256 bytes according to the RFC, + so this buffer size should be safe even if it's all ' */ + static char buffer[1024]; + char *b = buffer; + + memset (buffer, 0, sizeof (buffer)); + if (cstr == NULL || strlen (cstr) == 0) + return b; + + do + if (*cstr == 39) { + *b++ = '\''; + *b++ = '\\'; + *b++ = '\''; + *b++ = '\''; + } else + *b++ = *cstr; + while (*cstr++); + + *b++ = 0; + b = buffer; + + return b; } static int write_info(const interface_t *iface, const dhcp_t *dhcp, - const options_t *options) + const options_t *options) { - FILE *f; - route_t *route; - address_t *address; - - 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 -1; - } - - fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); - fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); - fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); - if (dhcp->mtu > 0) - fprintf (f, "MTU='%d'\n", dhcp->mtu); - - if (dhcp->routes) - { - fprintf (f, "ROUTES='"); - for (route = dhcp->routes; route; route = route->next) - { - fprintf (f, "%s", inet_ntoa (route->destination)); - fprintf (f, ",%s", inet_ntoa (route->netmask)); - fprintf (f, ",%s", inet_ntoa (route->gateway)); - if (route->next) - fprintf (f, " "); - } - fprintf (f, "'\n"); - } - - if (dhcp->hostname) - fprintf (f, "HOSTNAME='%s'\n", cleanmetas (dhcp->hostname)); - - if (dhcp->dnsdomain) - fprintf (f, "DNSDOMAIN='%s'\n", cleanmetas (dhcp->dnsdomain)); - - if (dhcp->dnssearch) - fprintf (f, "DNSSEARCH='%s'\n", cleanmetas (dhcp->dnssearch)); - - if (dhcp->dnsservers) - { - fprintf (f, "DNSSERVERS='"); - for (address = dhcp->dnsservers; address; address = address->next) - { - fprintf (f, "%s", inet_ntoa (address->address)); - if (address->next) - fprintf (f, " "); - } - 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); - fprintf (f, "FQDNHOSTNAME='%s'\n", dhcp->fqdn->name); - } - - if (dhcp->ntpservers) - { - fprintf (f, "NTPSERVERS='"); - for (address = dhcp->ntpservers; address; address = address->next) - { - fprintf (f, "%s", inet_ntoa (address->address)); - if (address->next) - fprintf (f, " "); - } - fprintf (f, "'\n"); - } - - if (dhcp->nisdomain) - fprintf (f, "NISDOMAIN='%s'\n", cleanmetas (dhcp->nisdomain)); - - if (dhcp->nisservers) - { - fprintf (f, "NISSERVERS='"); - for (address = dhcp->nisservers; address; address = address->next) - { - fprintf (f, "%s", inet_ntoa (address->address)); - if (address->next) - fprintf (f, " "); - } - fprintf (f, "'\n"); - } - - if (dhcp->rootpath) - fprintf (f, "ROOTPATH='%s'\n", cleanmetas (dhcp->rootpath)); - - fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); - fprintf (f, "DHCPSNAME='%s'\n", cleanmetas (dhcp->servername)); - fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); - fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); - fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); - fprintf (f, "INTERFACE='%s'\n", iface->name); - fprintf (f, "CLASSID='%s'\n", cleanmetas (options->classid)); - if (options->clientid[0]) - fprintf (f, "CLIENTID='%s'\n", cleanmetas (options->clientid)); - else - fprintf (f, "CLIENTID='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen)); - fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen)); - fclose (f); - return 0; + FILE *f; + route_t *route; + address_t *address; + + 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 -1; + } + + fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); + fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); + fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); + if (dhcp->mtu > 0) + fprintf (f, "MTU='%d'\n", dhcp->mtu); + + if (dhcp->routes) { + fprintf (f, "ROUTES='"); + for (route = dhcp->routes; route; route = route->next) { + fprintf (f, "%s", inet_ntoa (route->destination)); + fprintf (f, ",%s", inet_ntoa (route->netmask)); + fprintf (f, ",%s", inet_ntoa (route->gateway)); + if (route->next) + fprintf (f, " "); + } + fprintf (f, "'\n"); + } + + if (dhcp->hostname) + fprintf (f, "HOSTNAME='%s'\n", cleanmetas (dhcp->hostname)); + + if (dhcp->dnsdomain) + fprintf (f, "DNSDOMAIN='%s'\n", cleanmetas (dhcp->dnsdomain)); + + if (dhcp->dnssearch) + fprintf (f, "DNSSEARCH='%s'\n", cleanmetas (dhcp->dnssearch)); + + if (dhcp->dnsservers) { + fprintf (f, "DNSSERVERS='"); + for (address = dhcp->dnsservers; address; address = address->next) { + fprintf (f, "%s", inet_ntoa (address->address)); + if (address->next) + fprintf (f, " "); + } + 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); + fprintf (f, "FQDNHOSTNAME='%s'\n", dhcp->fqdn->name); + } + + if (dhcp->ntpservers) { + fprintf (f, "NTPSERVERS='"); + for (address = dhcp->ntpservers; address; address = address->next) { + fprintf (f, "%s", inet_ntoa (address->address)); + if (address->next) + fprintf (f, " "); + } + fprintf (f, "'\n"); + } + + if (dhcp->nisdomain) + fprintf (f, "NISDOMAIN='%s'\n", cleanmetas (dhcp->nisdomain)); + + if (dhcp->nisservers) { + fprintf (f, "NISSERVERS='"); + for (address = dhcp->nisservers; address; address = address->next) { + fprintf (f, "%s", inet_ntoa (address->address)); + if (address->next) + fprintf (f, " "); + } + fprintf (f, "'\n"); + } + + if (dhcp->rootpath) + fprintf (f, "ROOTPATH='%s'\n", cleanmetas (dhcp->rootpath)); + + fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); + fprintf (f, "DHCPSNAME='%s'\n", cleanmetas (dhcp->servername)); + fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); + fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); + fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); + fprintf (f, "INTERFACE='%s'\n", iface->name); + fprintf (f, "CLASSID='%s'\n", cleanmetas (options->classid)); + if (options->clientid[0]) + fprintf (f, "CLIENTID='%s'\n", cleanmetas (options->clientid)); + else + fprintf (f, "CLIENTID='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen)); + fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen)); + fclose (f); + return 0; } #endif int configure (const options_t *options, interface_t *iface, - const dhcp_t *dhcp) + const dhcp_t *dhcp) { - route_t *route = NULL; - route_t *new_route = NULL; - route_t *old_route = NULL; - struct hostent *he = NULL; - char newhostname[HOSTNAME_MAX_LEN] = {0}; - char curhostname[HOSTNAME_MAX_LEN] = {0}; - char *dname = NULL; - int dnamel = 0; - - if (! options || ! iface || ! dhcp) - return -1; - - /* 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 */ - if (iface->previous_routes) - { - for (route = iface->previous_routes; route; route = route->next) - if (route->destination.s_addr || options->dogateway) - { - int have = 0; - if (dhcp->address.s_addr != 0) - for (new_route = dhcp->routes; new_route; new_route = new_route->next) - if (new_route->destination.s_addr == route->destination.s_addr - && new_route->netmask.s_addr == route->netmask.s_addr - && new_route->gateway.s_addr == route->gateway.s_addr) - { - have = 1; - break; - } - if (! have) - del_route (iface->name, route->destination, route->netmask, - route->gateway, options->metric); - } - } - - /* If we don't have an address, then return */ - if (dhcp->address.s_addr == 0) - { - 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; - } - - /* Only reset things if we had set them before */ - if (iface->previous_address.s_addr != 0) - { - del_address (iface->name, iface->previous_address, - iface->previous_netmask); - memset (&iface->previous_address, 0, sizeof (struct in_addr)); - memset (&iface->previous_netmask, 0, sizeof (struct in_addr)); - - restore_resolv (iface->name); - - /* we currently don't have a resolvconf style programs for ntp/nis */ - 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; - } - } - - if (add_address (iface->name, dhcp->address, dhcp->netmask, - dhcp->broadcast) < 0 && errno != EEXIST) - return -1; - - /* Now delete the old address if different */ - if (iface->previous_address.s_addr != dhcp->address.s_addr - && iface->previous_address.s_addr != 0) - del_address (iface->name, iface->previous_address, iface->previous_netmask); + route_t *route = NULL; + route_t *new_route = NULL; + route_t *old_route = NULL; + struct hostent *he = NULL; + char newhostname[HOSTNAME_MAX_LEN] = {0}; + char curhostname[HOSTNAME_MAX_LEN] = {0}; + char *dname = NULL; + int dnamel = 0; + + if (! options || ! iface || ! dhcp) + return -1; + + /* 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 */ + if (iface->previous_routes) { + for (route = iface->previous_routes; route; route = route->next) + if (route->destination.s_addr || options->dogateway) { + int have = 0; + if (dhcp->address.s_addr != 0) + for (new_route = dhcp->routes; new_route; new_route = new_route->next) + if (new_route->destination.s_addr == route->destination.s_addr + && new_route->netmask.s_addr == route->netmask.s_addr + && new_route->gateway.s_addr == route->gateway.s_addr) + { + have = 1; + break; + } + if (! have) + del_route (iface->name, route->destination, route->netmask, + route->gateway, options->metric); + } + } + + /* If we don't have an address, then return */ + if (dhcp->address.s_addr == 0) { + 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; + } + + /* Only reset things if we had set them before */ + if (iface->previous_address.s_addr != 0) { + del_address (iface->name, iface->previous_address, + iface->previous_netmask); + memset (&iface->previous_address, 0, sizeof (struct in_addr)); + memset (&iface->previous_netmask, 0, sizeof (struct in_addr)); + + restore_resolv (iface->name); + + /* we currently don't have a resolvconf style programs for ntp/nis */ + 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; + } + } + + if (add_address (iface->name, dhcp->address, dhcp->netmask, + dhcp->broadcast) < 0 && errno != EEXIST) + return -1; + + /* Now delete the old address if different */ + if (iface->previous_address.s_addr != dhcp->address.s_addr + && iface->previous_address.s_addr != 0) + 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 - /* Remember added routes */ - if (dhcp->routes) - { - route_t *new_routes = NULL; - int remember; - - for (route = dhcp->routes; route; route = route->next) - { - /* 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) - for (old_route = iface->previous_routes; old_route; - old_route = old_route->next) - if (old_route->destination.s_addr == route->destination.s_addr - && old_route->netmask.s_addr == route->netmask.s_addr - && old_route->gateway.s_addr == route->gateway.s_addr) - { - remember = 1; - break; - } - - if (remember >= 0) - { - if (! new_routes) - { - new_routes = xmalloc (sizeof (route_t)); - memset (new_routes, 0, sizeof (route_t)); - new_route = new_routes; - } - else - { - new_route->next = xmalloc (sizeof (route_t)); - new_route = new_route->next; - } - memcpy (new_route, route, sizeof (route_t)); - new_route -> next = NULL; - } - } - - if (iface->previous_routes) - free_route (iface->previous_routes); - - iface->previous_routes = new_routes; - } - - if (options->dodns && dhcp->dnsservers) - make_resolv(iface->name, dhcp); - else - logger (LOG_DEBUG, "no dns information to write"); + /* Remember added routes */ + if (dhcp->routes) { + route_t *new_routes = NULL; + int remember; + + for (route = dhcp->routes; route; route = route->next) { + /* 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) + for (old_route = iface->previous_routes; old_route; + old_route = old_route->next) + if (old_route->destination.s_addr == route->destination.s_addr + && old_route->netmask.s_addr == route->netmask.s_addr + && old_route->gateway.s_addr == route->gateway.s_addr) + { + remember = 1; + break; + } + + if (remember >= 0) { + if (! new_routes) { + new_routes = xmalloc (sizeof (route_t)); + memset (new_routes, 0, sizeof (route_t)); + new_route = new_routes; + } else { + new_route->next = xmalloc (sizeof (route_t)); + new_route = new_route->next; + } + memcpy (new_route, route, sizeof (route_t)); + new_route -> next = NULL; + } + } + + if (iface->previous_routes) + free_route (iface->previous_routes); + + iface->previous_routes = new_routes; + } + + 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 - /* Now we have made a resolv.conf we can obtain a hostname if we need one */ - if (options->dohostname && ! dhcp->hostname) - { - he = gethostbyaddr (inet_ntoa (dhcp->address), - sizeof (struct in_addr), AF_INET); - if (he) - { - dname = he->h_name; - while (*dname > 32) - dname++; - dnamel = dname - he->h_name; - memcpy (newhostname, he->h_name, dnamel); - newhostname[dnamel] = 0; - } - } - - gethostname (curhostname, sizeof (curhostname)); - - if (options->dohostname - || strlen (curhostname) == 0 - || strcmp (curhostname, "(none)") == 0 - || strcmp (curhostname, "localhost") == 0) - { - if (dhcp->hostname) - strlcpy (newhostname, dhcp->hostname, sizeof (newhostname)); - - if (*newhostname) - { - logger (LOG_INFO, "setting hostname to `%s'", newhostname); - sethostname (newhostname, strlen (newhostname)); - } - } + /* Now we have made a resolv.conf we can obtain a hostname if we need one */ + if (options->dohostname && ! dhcp->hostname) { + he = gethostbyaddr (inet_ntoa (dhcp->address), + sizeof (struct in_addr), AF_INET); + if (he) { + dname = he->h_name; + while (*dname > 32) + dname++; + dnamel = dname - he->h_name; + memcpy (newhostname, he->h_name, dnamel); + newhostname[dnamel] = 0; + } + } + + gethostname (curhostname, sizeof (curhostname)); + + if (options->dohostname + || strlen (curhostname) == 0 + || strcmp (curhostname, "(none)") == 0 + || strcmp (curhostname, "localhost") == 0) + { + if (dhcp->hostname) + strlcpy (newhostname, dhcp->hostname, sizeof (newhostname)); + + if (*newhostname) { + logger (LOG_INFO, "setting hostname to `%s'", newhostname); + sethostname (newhostname, strlen (newhostname)); + } + } #ifdef ENABLE_INFO - write_info (iface, dhcp, options); + write_info (iface, dhcp, options); #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 (struct in_addr)); - memcpy (&iface->previous_netmask, - &dhcp->netmask, sizeof (struct in_addr)); - exec_script (options->script, iface->infofile, "new"); - } - else - exec_script (options->script, iface->infofile, "up"); - - return 0; + 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 (struct in_addr)); + memcpy (&iface->previous_netmask, + &dhcp->netmask, sizeof (struct in_addr)); + exec_script (options->script, iface->infofile, "new"); + } else + exec_script (options->script, iface->infofile, "up"); + + return 0; } diff --git a/configure.h b/configure.h index 4d766d26..1daa07d3 100644 --- a/configure.h +++ b/configure.h @@ -24,7 +24,7 @@ /* If you disable all 3 options you can shrink the binary by around 5-10k unstripped depending on platform and CFLAGS -*/ + */ #define ENABLE_NTP #define ENABLE_NIS #define ENABLE_INFO @@ -34,6 +34,6 @@ #include "dhcp.h" int configure (const options_t *options, interface_t *iface, - const dhcp_t *dhcp); + const dhcp_t *dhcp); #endif diff --git a/dhcp.c b/dhcp.c index 7df70ea7..2f58e77c 100644 --- a/dhcp.c +++ b/dhcp.c @@ -41,262 +41,243 @@ #define BROADCAST_FLAG 0x8000 static const char *dhcp_message[] = { - [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", - [DHCP_INFORM + 1] = NULL + [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", + [DHCP_INFORM + 1] = NULL }; size_t send_message (const interface_t *iface, const dhcp_t *dhcp, - unsigned long xid, char type, - const options_t *options) + unsigned long xid, char type, + const options_t *options) { - dhcpmessage_t message; - struct udp_dhcp_packet packet; - unsigned char *m = (unsigned char *) &message; - unsigned char *p = (unsigned char *) &message.options; - unsigned char *n_params = NULL; - unsigned long l; - struct in_addr from; - struct in_addr to; - long up = uptime() - iface->start_uptime; - uint32_t ul; - uint16_t sz; - unsigned int message_length; - - 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; - - memset (&message, 0, sizeof (dhcpmessage_t)); - - if (type == DHCP_INFORM || - type == DHCP_RELEASE || - type == DHCP_REQUEST) - { - message.ciaddr = iface->previous_address.s_addr; - from.s_addr = iface->previous_address.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: - if (message.ciaddr == 0) - message.flags = htons (BROADCAST_FLAG); - message.hwlen = 0; - break; - default: - logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family); - } - - if (up < 0 || up > UINT16_MAX) - message.secs = htons ((short) 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; - } - -#define PUTADDR(_type, _val) \ - { \ - *p++ = _type; \ - *p++ = 4; \ - memcpy (p, &_val.s_addr, 4); \ - p += 4; \ - } - if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0 - && type != DHCP_RELEASE) - PUTADDR (DHCP_ADDRESS, dhcp->address); - - if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 && - (iface->previous_address.s_addr == 0 || type == DHCP_RELEASE)) - PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress); + dhcpmessage_t message; + struct udp_dhcp_packet packet; + unsigned char *m = (unsigned char *) &message; + unsigned char *p = (unsigned char *) &message.options; + unsigned char *n_params = NULL; + unsigned long l; + struct in_addr from; + struct in_addr to; + long up = uptime() - iface->start_uptime; + uint32_t ul; + uint16_t sz; + unsigned int message_length; + + 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; + + memset (&message, 0, sizeof (dhcpmessage_t)); + + if (type == DHCP_INFORM || + type == DHCP_RELEASE || + type == DHCP_REQUEST) + { + message.ciaddr = iface->previous_address.s_addr; + from.s_addr = iface->previous_address.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: + if (message.ciaddr == 0) + message.flags = htons (BROADCAST_FLAG); + message.hwlen = 0; + break; + default: + logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family); + } + + if (up < 0 || up > UINT16_MAX) + message.secs = htons ((short) 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; + } + +#define PUTADDR(_type, _val) { \ + *p++ = _type; \ + *p++ = 4; \ + memcpy (p, &_val.s_addr, 4); \ + p += 4; \ + } + if (dhcp->address.s_addr != 0 && iface->previous_address.s_addr == 0 + && type != DHCP_RELEASE) + PUTADDR (DHCP_ADDRESS, dhcp->address); + + if (dhcp->serveraddress.s_addr != 0 && dhcp->address.s_addr !=0 && + (iface->previous_address.s_addr == 0 || type == DHCP_RELEASE)) + PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress); #undef PUTADDR - if (type == DHCP_REQUEST || type == DHCP_DISCOVER) - { - 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) - { - *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 we can safely do this. */ - - if (type == DHCP_DISCOVER) - *p++ = DHCP_DNSSERVER; - else - { - *p++ = DHCP_RENEWALTIME; - *p++ = DHCP_REBINDTIME; - *p++ = DHCP_NETMASK; - *p++ = DHCP_BROADCAST; - *p++ = DHCP_CSR; - /* 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; - *p++ = DHCP_NISDOMAIN; - *p++ = DHCP_NISSERVER; - *p++ = DHCP_NTPSERVER; - *p++ = DHCP_MTU; - /* These parameters were requested by dhcpcd-2.0 and earlier - but we never did anything with them */ - /* *p++ = DHCP_DEFAULTIPTTL; - *p++ = DHCP_MASKDISCOVERY; - *p++ = DHCP_ROUTERDISCOVERY; */ - } - - *n_params = p - n_params - 1; - - if (*options->hostname) - { - 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; /* rcode1, response from DNS server for PTR RR */ - *p++ = 0; /* rcode2, response from DNS server for A RR if S=1 */ - memcpy (p, options->hostname, l); - p += l; - } - } - } - - 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; - } - - *p++ = DHCP_CLASSID; - *p++ = l = strlen (options->classid); - memcpy (p, options->classid, l); - p += l; - } - - *p++ = DHCP_CLIENTID; - if (options->clientid[0]) - { - l = strlen (options->clientid); - *p++ = l + 1; - *p++ = 0; /* string */ - memcpy (p, options, l); - p += l; - } - else - { - *p++ = iface->hwlen + 1; - *p++ = iface->family; - memcpy (p, &iface->hwaddr, iface->hwlen); - p += iface->hwlen; - } - - *p++ = DHCP_END; - - message_length = p - m; - - memset (&packet, 0, sizeof (struct udp_dhcp_packet)); - make_dhcp_packet (&packet, (unsigned char *) &message, message_length, - from, to); - - logger (LOG_DEBUG, "sending %s with xid 0x%lx", dhcp_message[(int) type], xid); - return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet, - message_length + sizeof (struct ip) + - sizeof (struct udphdr)); + if (type == DHCP_REQUEST || type == DHCP_DISCOVER) { + 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) { + *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 we can safely do this. */ + + if (type == DHCP_DISCOVER) + *p++ = DHCP_DNSSERVER; + else { + *p++ = DHCP_RENEWALTIME; + *p++ = DHCP_REBINDTIME; + *p++ = DHCP_NETMASK; + *p++ = DHCP_BROADCAST; + *p++ = DHCP_CSR; + /* 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; + *p++ = DHCP_NISDOMAIN; + *p++ = DHCP_NISSERVER; + *p++ = DHCP_NTPSERVER; + *p++ = DHCP_MTU; + /* These parameters were requested by dhcpcd-2.0 and earlier + but we never did anything with them */ + /* *p++ = DHCP_DEFAULTIPTTL; + *p++ = DHCP_MASKDISCOVERY; + *p++ = DHCP_ROUTERDISCOVERY; */ + } + + *n_params = p - n_params - 1; + + if (*options->hostname) { + 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; /* rcode1, response from DNS server for PTR RR */ + *p++ = 0; /* rcode2, response from DNS server for A RR if S=1 */ + memcpy (p, options->hostname, l); + p += l; + } + } + } + + 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; + } + + *p++ = DHCP_CLASSID; + *p++ = l = strlen (options->classid); + memcpy (p, options->classid, l); + p += l; + } + + *p++ = DHCP_CLIENTID; + if (options->clientid[0]) { + l = strlen (options->clientid); + *p++ = l + 1; + *p++ = 0; /* string */ + memcpy (p, options, l); + p += l; + } else { + *p++ = iface->hwlen + 1; + *p++ = iface->family; + memcpy (p, &iface->hwaddr, iface->hwlen); + p += iface->hwlen; + } + + *p++ = DHCP_END; + + message_length = p - m; + + memset (&packet, 0, sizeof (struct udp_dhcp_packet)); + make_dhcp_packet (&packet, (unsigned char *) &message, message_length, + from, to); + + logger (LOG_DEBUG, "sending %s with xid 0x%lx", dhcp_message[(int) type], xid); + return send_packet (iface, ETHERTYPE_IP, (unsigned char *) &packet, + message_length + sizeof (struct ip) + + sizeof (struct udphdr)); } static unsigned long getnetmask (unsigned long ip_in) { - unsigned long t, p = ntohl (ip_in); - - 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); + unsigned long t, p = ntohl (ip_in); + + 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); } /* Decode an RFC3397 DNS search order option into a space @@ -305,316 +286,293 @@ static unsigned long getnetmask (unsigned long ip_in) 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 route_t *decodeCSR(const unsigned char *p, int len) { - const unsigned char *q = p; - int cidr; - int ocets; - route_t *first; - route_t *route; - - /* Minimum is 5 -first is CIDR and a router length of 4 */ - if (len < 5) - return NULL; - - first = xmalloc (sizeof (route_t)); - route = first; - - while (q - p < len) - { - memset (route, 0, sizeof (route_t)); - - cidr = *q++; - if (cidr == 0) - ocets = 0; - else if (cidr < 9) - ocets = 1; - else if (cidr < 17) - ocets = 2; - else if (cidr < 25) - ocets = 3; - else - ocets = 4; - - if (ocets > 0) - { - memcpy (&route->destination.s_addr, q, ocets); - q += ocets; - } - - /* Now enter the netmask */ - if (ocets > 0) - { - memset (&route->netmask.s_addr, 255, 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; - - /* We have another route */ - if (q - p < len) - { - route->next = xmalloc (sizeof (route_t)); - route = route->next; - } - } - - return first; + const unsigned char *q = p; + int cidr; + int ocets; + route_t *first; + route_t *route; + + /* Minimum is 5 -first is CIDR and a router length of 4 */ + if (len < 5) + return NULL; + + first = xmalloc (sizeof (route_t)); + route = first; + + while (q - p < len) { + memset (route, 0, sizeof (route_t)); + + cidr = *q++; + if (cidr == 0) + ocets = 0; + else if (cidr < 9) + ocets = 1; + else if (cidr < 17) + ocets = 2; + else if (cidr < 25) + ocets = 3; + else + ocets = 4; + + if (ocets > 0) { + memcpy (&route->destination.s_addr, q, ocets); + q += ocets; + } + + /* Now enter the netmask */ + if (ocets > 0) { + memset (&route->netmask.s_addr, 255, 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; + + /* We have another route */ + if (q - p < len) { + route->next = xmalloc (sizeof (route_t)); + route = route->next; + } + } + + return first; } void free_dhcp (dhcp_t *dhcp) { - if (! dhcp) - return; - - if (dhcp->routes) - free_route (dhcp->routes); - - if (dhcp->hostname) - free (dhcp->hostname); - - if (dhcp->dnsservers) - free_address (dhcp->dnsservers); - if (dhcp->dnsdomain) - free (dhcp->dnsdomain); - if (dhcp->dnssearch) - free (dhcp->dnssearch); - - if (dhcp->ntpservers) - free_address (dhcp->ntpservers); - - if (dhcp->nisdomain) - free (dhcp->nisdomain); - if (dhcp->nisservers) - free_address (dhcp->nisservers); - - if (dhcp->rootpath) - free (dhcp->rootpath); - - if (dhcp->fqdn) - { - if (dhcp->fqdn->name) - free (dhcp->fqdn->name); - free (dhcp->fqdn); - } + if (! dhcp) + return; + + if (dhcp->routes) + free_route (dhcp->routes); + + if (dhcp->hostname) + free (dhcp->hostname); + + if (dhcp->dnsservers) + free_address (dhcp->dnsservers); + if (dhcp->dnsdomain) + free (dhcp->dnsdomain); + if (dhcp->dnssearch) + free (dhcp->dnssearch); + + if (dhcp->ntpservers) + free_address (dhcp->ntpservers); + + if (dhcp->nisdomain) + free (dhcp->nisdomain); + if (dhcp->nisservers) + free_address (dhcp->nisservers); + + if (dhcp->rootpath) + free (dhcp->rootpath); + + if (dhcp->fqdn) { + if (dhcp->fqdn->name) + free (dhcp->fqdn->name); + free (dhcp->fqdn); + } } static bool dhcp_add_address(address_t **address, const unsigned char *data, int length) { - int i; - address_t *p = *address; - - for (i = 0; i < length; i += 4) - { - if (*address == NULL) - { - *address = xmalloc (sizeof (address_t)); - p = *address; - } - else - { - p->next = xmalloc (sizeof (address_t)); - p = p->next; - } - memset (p, 0, sizeof (address_t)); - - /* Sanity check */ - if (i + 4 > length) - { - logger (LOG_ERR, "invalid address length"); - return (false); - } - - memcpy (&p->address.s_addr, data + i, 4); - } - - return (true); + int i; + address_t *p = *address; + + for (i = 0; i < length; i += 4) { + if (*address == NULL) { + *address = xmalloc (sizeof (address_t)); + p = *address; + } else { + p->next = xmalloc (sizeof (address_t)); + p = p->next; + } + memset (p, 0, sizeof (address_t)); + + /* Sanity check */ + if (i + 4 > length) { + logger (LOG_ERR, "invalid address length"); + return (false); + } + + memcpy (&p->address.s_addr, data + i, 4); + } + + return (true); } 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 i; - int retval = -1; - route_t *first_route = xmalloc (sizeof (route_t)); - route_t *route = first_route; - route_t *last_route = NULL; - route_t *csr = NULL; - - end += sizeof (message->options); - - memset (first_route, 0, sizeof (route_t)); - - dhcp->address.s_addr = message->yiaddr; - strlcpy (dhcp->servername, message->servername, - sizeof (dhcp->servername)); - -#define LEN_ERR \ - { \ - logger (LOG_ERR, "invalid length %d for option %d", length, option); \ - p += length; \ - continue; \ - } - - while (p < end) - { - option = *p++; - if (!option) - continue; - - length = *p++; - - if (p + length >= end) - { - logger (LOG_ERR, "dhcp option exceeds message length"); - retval = -1; - goto eexit; - } - - switch (option) - { - case DHCP_END: - goto eexit; - - case DHCP_MESSAGETYPE: - retval = (int) *p; - p += length; - continue; - - default: - if (length == 0) - { - logger (LOG_DEBUG, "option %d has zero length, skipping", - option); - continue; - } - } + 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 i; + int retval = -1; + route_t *first_route = xmalloc (sizeof (route_t)); + route_t *route = first_route; + route_t *last_route = NULL; + route_t *csr = NULL; + + end += sizeof (message->options); + + memset (first_route, 0, sizeof (route_t)); + + dhcp->address.s_addr = message->yiaddr; + strlcpy (dhcp->servername, message->servername, + sizeof (dhcp->servername)); + +#define LEN_ERR { \ + logger (LOG_ERR, "invalid length %d for option %d", length, option); \ + p += length; \ + continue; \ + } + + while (p < end) { + option = *p++; + if (!option) + continue; + + length = *p++; + + if (p + length >= end) { + logger (LOG_ERR, "dhcp option exceeds message length"); + retval = -1; + goto eexit; + } + + switch (option) { + case DHCP_END: + goto eexit; + + 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) \ - LEN_ERR; + if (length != _length) \ + LEN_ERR; #define MIN_LENGTH(_length) \ - if (length < _length) \ - LEN_ERR; + if (length < _length) \ + LEN_ERR; #define MULT_LENGTH(_mult) \ - if (length % _mult != 0) \ - LEN_ERR; + if (length % _mult != 0) \ + LEN_ERR; #define GET_UINT8(_val) \ - LENGTH (sizeof (uint8_t)); \ - memcpy (&_val, p, sizeof (uint8_t)); + LENGTH (sizeof (uint8_t)); \ + memcpy (&_val, p, sizeof (uint8_t)); #define GET_UINT16(_val) \ - LENGTH (sizeof (uint16_t)); \ - memcpy (&_val, p, sizeof (uint16_t)); + LENGTH (sizeof (uint16_t)); \ + memcpy (&_val, p, sizeof (uint16_t)); #define GET_UINT32(_val) \ - LENGTH (sizeof (uint32_t)); \ - memcpy (&_val, p, sizeof (uint32_t)); + LENGTH (sizeof (uint32_t)); \ + memcpy (&_val, p, sizeof (uint32_t)); #define GET_UINT16_H(_val) \ - GET_UINT16 (_val); \ - _val = ntohs (_val); + GET_UINT16 (_val); \ + _val = ntohs (_val); #define GET_UINT32_H(_val) \ - 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 (minimum maximum message size) */ - if (dhcp->mtu < MTU_MIN) - { - logger (LOG_DEBUG, "MTU %d is too low, minium is %d; ignoring", dhcp->mtu, MTU_MIN); - dhcp->mtu = 0; - } - break; + 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 (minimum maximum message size) */ + if (dhcp->mtu < MTU_MIN) { + logger (LOG_DEBUG, "MTU %d is too low, minium is %d; ignoring", dhcp->mtu, MTU_MIN); + dhcp->mtu = 0; + } + break; #undef GET_UINT32_H #undef GET_UINT32 @@ -623,131 +581,123 @@ int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message) #undef GET_UINT8 #define GETSTR(_var) \ - MIN_LENGTH (sizeof (char)); \ - if (_var) free (_var); \ - _var = xmalloc (length + 1); \ - memcpy (_var, p, 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_ROOTPATH: - GETSTR (dhcp->rootpath); - break; - case DHCP_NISDOMAIN: - GETSTR (dhcp->nisdomain); - break; + MIN_LENGTH (sizeof (char)); \ + if (_var) free (_var); \ + _var = xmalloc (length + 1); \ + memcpy (_var, p, 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_ROOTPATH: + GETSTR (dhcp->rootpath); + break; + case DHCP_NISDOMAIN: + GETSTR (dhcp->nisdomain); + break; #undef GETSTR #define GETADDR(_var) \ - MULT_LENGTH (4); \ - if (! dhcp_add_address (&_var, p, length)) \ - { \ - retval = -1; \ - goto eexit; \ - } - case DHCP_DNSSERVER: - GETADDR (dhcp->dnsservers); - break; - case DHCP_NTPSERVER: - GETADDR (dhcp->ntpservers); - break; - case DHCP_NISSERVER: - GETADDR (dhcp->nisservers); - break; + MULT_LENGTH (4); \ + if (! dhcp_add_address (&_var, p, length)) \ + { \ + retval = -1; \ + goto eexit; \ + } + case DHCP_DNSSERVER: + GETADDR (dhcp->dnsservers); + break; + case DHCP_NTPSERVER: + GETADDR (dhcp->ntpservers); + break; + case DHCP_NISSERVER: + GETADDR (dhcp->nisservers); + break; #undef GETADDR - case DHCP_DNSSEARCH: - MIN_LENGTH (1); - if (dhcp->dnssearch) - free (dhcp->dnssearch); - if ((len = decode_search (p, length, NULL)) > 0) - { - dhcp->dnssearch = xmalloc (len); - decode_search (p, length, dhcp->dnssearch); - } - break; - - case DHCP_CSR: - MIN_LENGTH (5); - if (csr) - free_route (csr); - csr = decodeCSR (p, length); - break; - - case DHCP_STATICROUTE: - MULT_LENGTH (8); - for (i = 0; i < length; i += 8) - { - memcpy (&route->destination.s_addr, p + i, 4); - memcpy (&route->gateway.s_addr, p + i + 4, 4); - route->netmask.s_addr = getnetmask (route->destination.s_addr); - last_route = route; - route->next = xmalloc (sizeof (route_t)); - route = route->next; - memset (route, 0, sizeof (route_t)); - } - break; - - case DHCP_ROUTERS: - MULT_LENGTH (4); - for (i = 0; i < length; i += 4) - { - memcpy (&route->gateway.s_addr, p + i, 4); - last_route = route; - route->next = xmalloc (sizeof (route_t)); - route = route->next; - memset (route, 0, sizeof (route_t)); - } - break; + case DHCP_DNSSEARCH: + MIN_LENGTH (1); + if (dhcp->dnssearch) + free (dhcp->dnssearch); + if ((len = decode_search (p, length, NULL)) > 0) { + dhcp->dnssearch = xmalloc (len); + decode_search (p, length, dhcp->dnssearch); + } + break; + + case DHCP_CSR: + MIN_LENGTH (5); + if (csr) + free_route (csr); + csr = decodeCSR (p, length); + break; + + case DHCP_STATICROUTE: + MULT_LENGTH (8); + for (i = 0; i < length; i += 8) { + memcpy (&route->destination.s_addr, p + i, 4); + memcpy (&route->gateway.s_addr, p + i + 4, 4); + route->netmask.s_addr = getnetmask (route->destination.s_addr); + last_route = route; + route->next = xmalloc (sizeof (route_t)); + route = route->next; + memset (route, 0, sizeof (route_t)); + } + break; + + case DHCP_ROUTERS: + MULT_LENGTH (4); + for (i = 0; i < length; i += 4) + { + memcpy (&route->gateway.s_addr, p + i, 4); + last_route = route; + route->next = xmalloc (sizeof (route_t)); + route = route->next; + memset (route, 0, sizeof (route_t)); + } + 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: - /* Fill in any missing fields */ - if (! dhcp->netmask.s_addr) - dhcp->netmask.s_addr = getnetmask (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 (first_route); - } - else - { - dhcp->routes = first_route; - if (last_route) - { - free (last_route->next); - last_route->next = NULL; - } - else - { - free_route (dhcp->routes); - dhcp->routes = NULL; - } - } - - return retval; + /* Fill in any missing fields */ + if (! dhcp->netmask.s_addr) + dhcp->netmask.s_addr = getnetmask (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 (first_route); + } else { + dhcp->routes = first_route; + if (last_route) { + free (last_route->next); + last_route->next = NULL; + } else { + free_route (dhcp->routes); + dhcp->routes = NULL; + } + } + + return retval; } diff --git a/dhcp.h b/dhcp.h index 111b3eba..95ac66df 100644 --- a/dhcp.h +++ b/dhcp.h @@ -59,43 +59,43 @@ /* 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_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_CSR = 121, /* 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_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_CSR = 121, /* RFC 3442 */ + DHCP_END = 255 }; /* SetFQDNHostName values - lsnybble used in flags @@ -103,53 +103,53 @@ enum DHCP_OPTIONS * and to allow 0x00 to mean disable */ enum FQQN { - FQDN_DISABLE = 0x00, - FQDN_NONE = 0x18, - FQDN_PTR = 0x20, - FQDN_BOTH = 0x31 + 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]; - - 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; - - unsigned int leasetime; - unsigned int renewaltime; - unsigned int rebindtime; - - route_t *routes; - - char *hostname; - fqdn_t *fqdn; - - address_t *dnsservers; - char *dnsdomain; - char *dnssearch; - - address_t *ntpservers; - - address_t *nisservers; - char *nisdomain; - - char *message; - char *rootpath; + char version[11]; + + 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; + + unsigned int leasetime; + unsigned int renewaltime; + unsigned int rebindtime; + + route_t *routes; + + char *hostname; + fqdn_t *fqdn; + + address_t *dnsservers; + char *dnsdomain; + char *dnssearch; + + address_t *ntpservers; + + address_t *nisservers; + char *nisdomain; + + char *message; + char *rootpath; } dhcp_t; /* Sizes for DHCP options */ @@ -160,40 +160,40 @@ typedef struct dhcp_t #define DHCP_BASE_LEN (4 + 4 + 2 + 2 + 4 + 4 + 4 + 4 + 4) #define DHCP_RESERVE_LEN (4 + 4 + 4 + 4 + 2) #define DHCP_FIXED_LEN (DHCP_BASE_LEN + DHCP_CHADDR_LEN + \ - + SERVERNAME_LEN + BOOTFILE_LEN) + + SERVERNAME_LEN + BOOTFILE_LEN) #define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \ - - DHCP_RESERVE_LEN) + - DHCP_RESERVE_LEN) 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's message */ - int32_t xid; /* transaction id */ - int16_t secs; /* elapsed time in sec. from trying to boot */ - int16_t flags; - int32_t ciaddr; /* (previously allocated) client IP address */ - int32_t yiaddr; /* 'your' client IP address */ - int32_t siaddr; /* should be zero in client's messages */ - int32_t giaddr; /* should be zero in client's messages */ - unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ - char servername[SERVERNAME_LEN]; /* server host name, null terminated string */ - char bootfile[BOOTFILE_LEN]; /* boot file name, null terminated string */ - 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's message */ + int32_t xid; /* transaction id */ + int16_t secs; /* elapsed time in sec. from trying to boot */ + int16_t flags; + int32_t ciaddr; /* (previously allocated) client IP address */ + int32_t yiaddr; /* 'your' client IP address */ + int32_t siaddr; /* should be zero in client's messages */ + int32_t giaddr; /* should be zero in client's messages */ + unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ + char servername[SERVERNAME_LEN]; /* server host name, null terminated string */ + char bootfile[BOOTFILE_LEN]; /* boot file name, null terminated string */ + 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; }; size_t send_message (const interface_t *iface, const dhcp_t *dhcp, - unsigned long xid, char type, - const options_t *options); + unsigned long xid, char type, + const options_t *options); void free_dhcp (dhcp_t *dhcp); int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message); diff --git a/dhcpcd.c b/dhcpcd.c index 071dd6d0..d8e6a45d 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -49,365 +49,340 @@ #define PACKAGE "dhcpcd" #define STRINGINT(_string, _int) { \ - char *_tmp; \ - long _number = strtol (_string, &_tmp, 0); \ - errno = 0; \ - if ((errno != 0 && _number == 0) || _string == _tmp || \ - (errno == ERANGE && (_number == LONG_MAX || _number == LONG_MIN))) \ - { \ - logger (LOG_ERR, "`%s' out of range", _string);; \ - exit (EXIT_FAILURE); \ - } \ - else \ - _int = (int) _number; \ + char *_tmp; \ + long _number = strtol (_string, &_tmp, 0); \ + errno = 0; \ + if ((errno != 0 && _number == 0) || _string == _tmp || \ + (errno == ERANGE && (_number == LONG_MAX || _number == LONG_MIN))) \ + { \ + logger (LOG_ERR, "`%s' out of range", _string);; \ + exit (EXIT_FAILURE); \ + } \ + else \ + _int = (int) _number; \ } static pid_t read_pid(const char *pidfile) { - FILE *fp; - pid_t pid; + FILE *fp; + pid_t pid; - 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; } void make_pid (const char *pidfile) { - FILE *fp; + FILE *fp; - if ((fp = fopen (pidfile, "w")) == NULL) - { - logger (LOG_ERR, "fopen `%s': %s", pidfile, strerror (errno)); - return; - } + if ((fp = fopen (pidfile, "w")) == NULL) { + logger (LOG_ERR, "fopen `%s': %s", pidfile, strerror (errno)); + return; + } - fprintf (fp, "%u\n", getpid ()); - fclose (fp); + fprintf (fp, "%u\n", getpid ()); + fclose (fp); } static void usage () { - printf ("usage: "PACKAGE" [-adknpGHMNRY] [-c script] [-h hostame] [-i classID]\n" - " [-l leasetime] [-m metric] [-s ipaddress] [-t timeout]\n" - " [-u userclass] [-F [none | ptr | both]] [-I clientID]\n"); + printf ("usage: "PACKAGE" [-adknpGHMNRY] [-c script] [-h hostame] [-i classID]\n" + " [-l leasetime] [-m metric] [-s ipaddress] [-t timeout]\n" + " [-u userclass] [-F [none | ptr | both]] [-I clientID]\n"); } int main(int argc, char **argv) { - options_t options; - int doversion = 0; - int dohelp = 0; - int userclasses = 0; - int ch; - int option_index = 0; - char prefix[IF_NAMESIZE + 3]; - pid_t pid; - int debug = 0; - - const struct option longopts[] = - { - {"arp", no_argument, NULL, 'a'}, - {"script",required_argument, NULL, 'c'}, - {"debug", no_argument, NULL, 'd'}, - {"hostname", required_argument, NULL, 'h'}, - {"classid", required_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'}, - {"request", required_argument, NULL, 's'}, - {"timeout", required_argument, NULL, 't'}, - {"userclass", required_argument, NULL, 'u'}, - {"fqdn", optional_argument, NULL, 'F'}, - {"nogateway", no_argument, NULL, 'G'}, - {"sethostname", no_argument, NULL, 'H'}, - {"clientid", required_argument, NULL, 'I'}, - {"nomtu", no_argument, NULL, 'M'}, - {"nontp", no_argument, NULL, 'N'}, - {"nodns", no_argument, NULL, 'R'}, - {"nonis", no_argument, NULL, 'Y'}, - {"help", no_argument, &dohelp, 1}, - {"version", no_argument, &doversion, 1}, - {NULL, 0, NULL, 0} - }; - - /* Sanitize our fd's */ - int zero; - if ((zero = open (_PATH_DEVNULL, O_RDWR, 0)) >= 0) - { - while (zero < 3) - zero = dup (zero); - close(zero); - } - - openlog (PACKAGE, LOG_PID, LOG_LOCAL0); - - memset (&options, 0, sizeof (options_t)); - options.script = (char *) DEFAULT_SCRIPT; - snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); - - options.doarp = false; - options.dodns = true; - options.domtu = true; - options.donis = true; - options.dontp = true; - options.dogateway = true; - options.daemonise = true; - gethostname (options.hostname, sizeof (options.hostname)); - if (strcmp (options.hostname, "(none)") == 0 || - strcmp (options.hostname, "localhost") == 0) - memset (options.hostname, 0, sizeof (options.hostname)); - options.timeout = DEFAULT_TIMEOUT; - - while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:F:GHI:MNRY", longopts, - &option_index)) != -1) - switch (ch) - { - case 0: - if (longopts[option_index].flag) - break; - logger (LOG_ERR, "option `%s' should set a flag", - longopts[option_index].name); - exit (EXIT_FAILURE); - break; - - case 'a': - options.doarp = true; - break; - case 'c': - options.script = optarg; - break; - case 'd': - debug++; - switch (debug) - { - case 1: - setloglevel(LOG_DEBUG); - break; - case 2: - options.daemonise = false; - break; - } - break; - case 'h': - if (strlen (optarg) > HOSTNAME_MAX_LEN) - { - logger (LOG_ERR, "`%s' too long for HostName string, max is %d", - optarg, HOSTNAME_MAX_LEN); - exit (EXIT_FAILURE); - } - else - strlcpy (options.hostname, optarg, sizeof (options.hostname)); - break; - case 'i': - if (strlen (optarg) > CLASS_ID_MAX_LEN) - { - logger (LOG_ERR, "`%s' too long for ClassID string, max is %d", - optarg, CLASS_ID_MAX_LEN); - exit (EXIT_FAILURE); - } - else - strlcpy (options.classid, optarg, sizeof (options.classid)); - break; - case 'k': - options.signal = SIGHUP; - break; - case 'l': - STRINGINT (optarg, options.leasetime); - if (options.leasetime <= 0) - { - logger (LOG_ERR, "leasetime must be a positive value"); - exit (EXIT_FAILURE); - } - break; - case 'm': - STRINGINT (optarg, options.metric); - break; - case 'n': - options.signal = SIGALRM; - break; - case 'p': - options.persistent = true; - break; - case 's': - if (! inet_aton (optarg, &options.requestaddress)) - { - logger (LOG_ERR, "`%s' is not a valid IP address", optarg); - exit (EXIT_FAILURE); - } - break; - case 't': - STRINGINT (optarg, options.timeout); - if (options.timeout < 0) - { - logger (LOG_ERR, "timeout must be a positive value"); - exit (EXIT_FAILURE); - } - break; - case 'u': - { - int i; - 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); - exit (EXIT_FAILURE); - } - userclasses++; - memcpy (options.userclass + offset + 1 , optarg, strlen (optarg)); - options.userclass[offset] = strlen (optarg); - options.userclass_len += (strlen (optarg)) + 1; - } - break; - case 'F': - if (strcmp (optarg, "none") == 0) - options.fqdn = FQDN_NONE; - else if (strcmp (optarg, "ptr") == 0) - options.fqdn = FQDN_PTR; - else if (strcmp (optarg, "both") == 0) - options.fqdn = FQDN_BOTH; - else - { - logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); - exit (EXIT_FAILURE); - } - break; - case 'G': - options.dogateway = false; - break; - case 'H': - options.dohostname = true; - break; - case 'I': - if (strlen (optarg) > CLIENT_ID_MAX_LEN) - { - logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", - optarg, CLIENT_ID_MAX_LEN); - exit (EXIT_FAILURE); - } - else - strlcpy (options.clientid, optarg, sizeof (options.clientid)); - break; - case 'M': - options.domtu = false; - break; - case 'N': - options.dontp = false; - break; - case 'R': - options.dodns = false; - break; - case 'Y': - options.donis = false; - break; - case '?': - usage (); - exit (EXIT_FAILURE); - default: - usage (); - exit (EXIT_FAILURE); - } - - if (doversion) - printf (""PACKAGE" "VERSION"\n"); - - if (dohelp) - usage (); - - if (optind < argc) - { - if (strlen (argv[optind]) > IF_NAMESIZE) - { - logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)", - argv[optind], IF_NAMESIZE); - exit (EXIT_FAILURE); - } - strlcpy (options.interface, argv[optind], - sizeof (options.interface)); - } - else - { - /* If only version was requested then exit now */ - if (doversion || dohelp) - exit (EXIT_SUCCESS); - - logger (LOG_ERR, "no interface specified"); - exit (EXIT_FAILURE); - } - - if (geteuid ()) - { - logger (LOG_ERR, "you need to be root to run "PACKAGE); - exit (EXIT_FAILURE); - } - - snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface); - setlogprefix (prefix); - snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE, - options.interface); - - if (options.signal != 0) - { - int killed = -1; - pid = read_pid (options.pidfile); - if (pid != 0) - logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid); - - if (! pid || (killed = kill (pid, options.signal))) - logger (options.signal == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); - - if (pid != 0 && (options.signal != SIGALRM || killed != 0)) - unlink (options.pidfile); - - if (killed == 0) - exit (EXIT_SUCCESS); - - if (options.signal != SIGALRM) - exit (EXIT_FAILURE); - } - - umask (022); - - if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP - | S_IROTH | S_IXOTH) && errno != EEXIST ) - { - logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno)); - exit (EXIT_FAILURE); - } - - 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)); - exit (EXIT_FAILURE); - } - - if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) - { - logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile); - exit (EXIT_FAILURE); - } - - make_pid (options.pidfile); - - logger (LOG_INFO, PACKAGE " " VERSION " starting"); - if (dhcp_run (&options)) - { - unlink (options.pidfile); - exit (EXIT_FAILURE); - } - - exit (EXIT_SUCCESS); + options_t options; + int doversion = 0; + int dohelp = 0; + int userclasses = 0; + int ch; + int option_index = 0; + char prefix[IF_NAMESIZE + 3]; + pid_t pid; + int debug = 0; + + const struct option longopts[] = { + {"arp", no_argument, NULL, 'a'}, + {"script",required_argument, NULL, 'c'}, + {"debug", no_argument, NULL, 'd'}, + {"hostname", required_argument, NULL, 'h'}, + {"classid", required_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'}, + {"request", required_argument, NULL, 's'}, + {"timeout", required_argument, NULL, 't'}, + {"userclass", required_argument, NULL, 'u'}, + {"fqdn", optional_argument, NULL, 'F'}, + {"nogateway", no_argument, NULL, 'G'}, + {"sethostname", no_argument, NULL, 'H'}, + {"clientid", required_argument, NULL, 'I'}, + {"nomtu", no_argument, NULL, 'M'}, + {"nontp", no_argument, NULL, 'N'}, + {"nodns", no_argument, NULL, 'R'}, + {"nonis", no_argument, NULL, 'Y'}, + {"help", no_argument, &dohelp, 1}, + {"version", no_argument, &doversion, 1}, + {NULL, 0, NULL, 0} + }; + + /* Sanitize our fd's */ + int zero; + if ((zero = open (_PATH_DEVNULL, O_RDWR, 0)) >= 0) { + while (zero < 3) + zero = dup (zero); + close(zero); + } + + openlog (PACKAGE, LOG_PID, LOG_LOCAL0); + + memset (&options, 0, sizeof (options_t)); + options.script = (char *) DEFAULT_SCRIPT; + snprintf (options.classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); + + options.doarp = false; + options.dodns = true; + options.domtu = true; + options.donis = true; + options.dontp = true; + options.dogateway = true; + options.daemonise = true; + gethostname (options.hostname, sizeof (options.hostname)); + if (strcmp (options.hostname, "(none)") == 0 || + strcmp (options.hostname, "localhost") == 0) + memset (options.hostname, 0, sizeof (options.hostname)); + options.timeout = DEFAULT_TIMEOUT; + + while ((ch = getopt_long(argc, argv, "ac:dh:i:kl:m:nps:t:u:F:GHI:MNRY", longopts, + &option_index)) != -1) + switch (ch) { + case 0: + if (longopts[option_index].flag) + break; + logger (LOG_ERR, "option `%s' should set a flag", + longopts[option_index].name); + exit (EXIT_FAILURE); + break; + + case 'a': + options.doarp = true; + break; + case 'c': + options.script = optarg; + break; + case 'd': + debug++; + switch (debug) { + case 1: + setloglevel (LOG_DEBUG); + break; + case 2: + options.daemonise = false; + break; + } + break; + case 'h': + if (strlen (optarg) > HOSTNAME_MAX_LEN) { + logger (LOG_ERR, "`%s' too long for HostName string, max is %d", + optarg, HOSTNAME_MAX_LEN); + exit (EXIT_FAILURE); + } else + strlcpy (options.hostname, optarg, sizeof (options.hostname)); + break; + case 'i': + if (strlen (optarg) > CLASS_ID_MAX_LEN) { + logger (LOG_ERR, "`%s' too long for ClassID string, max is %d", + optarg, CLASS_ID_MAX_LEN); + exit (EXIT_FAILURE); + } else + strlcpy (options.classid, optarg, sizeof (options.classid)); + break; + case 'k': + options.signal = SIGHUP; + break; + case 'l': + STRINGINT (optarg, options.leasetime); + if (options.leasetime <= 0) { + logger (LOG_ERR, "leasetime must be a positive value"); + exit (EXIT_FAILURE); + } + break; + case 'm': + STRINGINT (optarg, options.metric); + break; + case 'n': + options.signal = SIGALRM; + break; + case 'p': + options.persistent = true; + break; + case 's': + if (! inet_aton (optarg, &options.requestaddress)) { + logger (LOG_ERR, "`%s' is not a valid IP address", optarg); + exit (EXIT_FAILURE); + } + break; + case 't': + STRINGINT (optarg, options.timeout); + if (options.timeout < 0) { + logger (LOG_ERR, "timeout must be a positive value"); + exit (EXIT_FAILURE); + } + break; + case 'u': + { + int i; + 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); + exit (EXIT_FAILURE); + } + userclasses++; + memcpy (options.userclass + offset + 1 , optarg, strlen (optarg)); + options.userclass[offset] = strlen (optarg); + options.userclass_len += (strlen (optarg)) + 1; + } + break; + case 'F': + if (strcmp (optarg, "none") == 0) + options.fqdn = FQDN_NONE; + else if (strcmp (optarg, "ptr") == 0) + options.fqdn = FQDN_PTR; + else if (strcmp (optarg, "both") == 0) + options.fqdn = FQDN_BOTH; + else { + logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); + exit (EXIT_FAILURE); + } + break; + case 'G': + options.dogateway = false; + break; + case 'H': + options.dohostname = true; + break; + case 'I': + if (strlen (optarg) > CLIENT_ID_MAX_LEN) { + logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", + optarg, CLIENT_ID_MAX_LEN); + exit (EXIT_FAILURE); + } else + strlcpy (options.clientid, optarg, sizeof (options.clientid)); + break; + case 'M': + options.domtu = false; + break; + case 'N': + options.dontp = false; + break; + case 'R': + options.dodns = false; + break; + case 'Y': + options.donis = false; + break; + case '?': + usage (); + exit (EXIT_FAILURE); + default: + usage (); + exit (EXIT_FAILURE); + } + + if (doversion) + printf (""PACKAGE" "VERSION"\n"); + + if (dohelp) + usage (); + + if (optind < argc) { + if (strlen (argv[optind]) > IF_NAMESIZE) { + logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)", + argv[optind], IF_NAMESIZE); + exit (EXIT_FAILURE); + } + strlcpy (options.interface, argv[optind], + sizeof (options.interface)); + } else { + /* If only version was requested then exit now */ + if (doversion || dohelp) + exit (EXIT_SUCCESS); + + logger (LOG_ERR, "no interface specified"); + exit (EXIT_FAILURE); + } + + if (geteuid ()) { + logger (LOG_ERR, "you need to be root to run "PACKAGE); + exit (EXIT_FAILURE); + } + + snprintf (prefix, IF_NAMESIZE, "%s: ", options.interface); + setlogprefix (prefix); + snprintf (options.pidfile, sizeof (options.pidfile), PIDFILE, + options.interface); + + if (options.signal != 0) { + int killed = -1; + pid = read_pid (options.pidfile); + if (pid != 0) + logger (LOG_INFO, "sending signal %d to pid %d", options.signal, pid); + + if (! pid || (killed = kill (pid, options.signal))) + logger (options.signal == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); + + if (pid != 0 && (options.signal != SIGALRM || killed != 0)) + unlink (options.pidfile); + + if (killed == 0) + exit (EXIT_SUCCESS); + + if (options.signal != SIGALRM) + exit (EXIT_FAILURE); + } + + umask (022); + + if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP + | S_IROTH | S_IXOTH) && errno != EEXIST ) + { + logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", CONFIGDIR, strerror (errno)); + exit (EXIT_FAILURE); + } + + 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)); + exit (EXIT_FAILURE); + } + + if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) { + logger (LOG_ERR, ""PACKAGE" already running (%s)", options.pidfile); + exit (EXIT_FAILURE); + } + + make_pid (options.pidfile); + + logger (LOG_INFO, PACKAGE " " VERSION " starting"); + if (dhcp_run (&options)) { + unlink (options.pidfile); + exit (EXIT_FAILURE); + } + + exit (EXIT_SUCCESS); } diff --git a/dhcpcd.h b/dhcpcd.h index e86b4e6f..f3738e64 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -38,33 +38,33 @@ #define USERCLASS_MAX_LEN 255 typedef struct options_t { - char interface[IF_NAMESIZE]; - char hostname[HOSTNAME_MAX_LEN]; - int fqdn; - char classid[CLASS_ID_MAX_LEN]; - char clientid[CLIENT_ID_MAX_LEN]; - char userclass[USERCLASS_MAX_LEN]; - int userclass_len; - unsigned leasetime; - time_t timeout; - int metric; - struct in_addr requestaddress; + char interface[IF_NAMESIZE]; + char hostname[HOSTNAME_MAX_LEN]; + int fqdn; + char classid[CLASS_ID_MAX_LEN]; + char clientid[CLIENT_ID_MAX_LEN]; + char userclass[USERCLASS_MAX_LEN]; + int userclass_len; + unsigned leasetime; + time_t timeout; + int metric; + struct in_addr requestaddress; - bool doarp; - bool dodns; - bool dodomainname; - bool dogateway; - bool dohostname; - bool domtu; - bool donis; - bool dontp; - - int signal; - bool persistent; - bool daemonise; + bool doarp; + bool dodns; + bool dodomainname; + bool dogateway; + bool dohostname; + bool domtu; + bool donis; + bool dontp; - char *script; - char pidfile[PATH_MAX]; + int signal; + bool persistent; + bool daemonise; + + char *script; + char pidfile[PATH_MAX]; } options_t; void make_pid (const char *pidfile); diff --git a/interface.c b/interface.c index f35c222b..5a46181a 100644 --- a/interface.c +++ b/interface.c @@ -42,7 +42,7 @@ #endif #else #include /*dietlibc requires this - normally from - netinet/ether.h */ + netinet/ether.h */ #include #include #include @@ -66,461 +66,433 @@ void free_address (address_t *addresses) { - address_t *p = addresses; - address_t *n = NULL; - - if (! addresses) - return; - - while (p) - { - n = p->next; - free (p); - p = n; - } + address_t *p = addresses; + address_t *n = NULL; + + if (! addresses) + return; + + while (p) { + n = p->next; + free (p); + p = n; + } } void free_route (route_t *routes) { - route_t *p = routes; - route_t *n = NULL; - - if (!routes) - return; - - while (p) - { - n = p->next; - free (p); - p = n; - } + route_t *p = routes; + route_t *n = NULL; + + if (!routes) + return; + + while (p) { + n = p->next; + free (p); + p = n; + } } 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); } char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen) { - static char buffer[128]; - char *p = buffer; - int i; - - for (i = 0; i < hwlen && i < 125; i++) - { - if (i > 0) - *p ++= ':'; - p += snprintf (p, 3, "%.2x", hwaddr[i]); - } - *p ++= '\0'; - - return (buffer); + static char buffer[128]; + char *p = buffer; + int i; + + for (i = 0; i < hwlen && i < 125; i++) { + if (i > 0) + *p ++= ':'; + p += snprintf (p, 3, "%.2x", hwaddr[i]); + } + *p ++= '\0'; + + return (buffer); } interface_t *read_interface (const char *ifname, int metric) { - int s; - struct ifreq ifr; - interface_t *iface; - unsigned char hwaddr[16]; - int hwlen = 0; - sa_family_t family = 0; - unsigned short mtu; + int s; + struct ifreq ifr; + interface_t *iface; + unsigned char hwaddr[16]; + int hwlen = 0; + sa_family_t family = 0; + unsigned short mtu; #ifndef __linux__ - struct ifaddrs *ifap; - struct ifaddrs *p; + struct ifaddrs *ifap; + struct ifaddrs *p; #endif - if (! ifname) - return NULL; + if (! ifname) + return NULL; - memset (hwaddr, sizeof (hwaddr), 0); + memset (hwaddr, sizeof (hwaddr), 0); #ifndef __linux__ - if (getifaddrs (&ifap) != 0) - return NULL; - - for (p = ifap; p; p = p->ifa_next) - { - union - { - struct sockaddr *sa; - struct sockaddr_dl *sdl; - } us; - - if (strcmp (p->ifa_name, ifname) != 0) - continue; - - us.sa = p->ifa_addr; - - if (p->ifa_addr->sa_family != AF_LINK - || (us.sdl->sdl_type != IFT_ETHER)) - /* - && us.sdl->sdl_type != IFT_ISO88025)) - */ - { - logger (LOG_ERR, "interface is not Ethernet"); - freeifaddrs (ifap); - return NULL; - } - - memcpy (hwaddr, us.sdl->sdl_data + us.sdl->sdl_nlen, ETHER_ADDR_LEN); - family = ARPHRD_ETHER; - hwlen = ETHER_ADDR_LEN; - break; - } - freeifaddrs (ifap); - - if (!p) - { - logger (LOG_ERR, "could not find interface %s", ifname); - return NULL; - } + if (getifaddrs (&ifap) != 0) + return NULL; + + for (p = ifap; p; p = p->ifa_next) { + union { + struct sockaddr *sa; + struct sockaddr_dl *sdl; + } us; + + if (strcmp (p->ifa_name, ifname) != 0) + continue; + + us.sa = p->ifa_addr; + + if (p->ifa_addr->sa_family != AF_LINK + || (us.sdl->sdl_type != IFT_ETHER)) + /* + && us.sdl->sdl_type != IFT_ISO88025)) + */ + { + logger (LOG_ERR, "interface is not Ethernet"); + freeifaddrs (ifap); + return NULL; + } + + memcpy (hwaddr, us.sdl->sdl_data + us.sdl->sdl_nlen, ETHER_ADDR_LEN); + family = ARPHRD_ETHER; + hwlen = ETHER_ADDR_LEN; + break; + } + freeifaddrs (ifap); + + if (! p) { + logger (LOG_ERR, "could not find interface %s", ifname); + return NULL; + } #endif - memset (&ifr, 0, sizeof (struct ifreq)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return NULL; - } + memset (&ifr, 0, sizeof (struct ifreq)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return NULL; + } #ifdef __linux__ - /* Do something with the metric parameter to satisfy the compiler warning */ - metric = 0; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCGIFHWADDR, &ifr) <0) - { - logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); - close (s); - return NULL; - } - 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"); - close (s); - return NULL; - } - memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); - family = ifr.ifr_hwaddr.sa_family; + /* Do something with the metric parameter to satisfy the compiler warning */ + metric = 0; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCGIFHWADDR, &ifr) <0) { + logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); + close (s); + return NULL; + } + + 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"); + close (s); + return NULL; + } + + 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) < 0) - { - logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); - close (s); - return NULL; - } + ifr.ifr_metric = metric; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCSIFMETRIC, &ifr) < 0) { + logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); + close (s); + return NULL; + } #endif - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(s, SIOCGIFMTU, &ifr) < 0) - { - logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - close (s); - return NULL; - } - 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) < 0) - { - logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", strerror (errno)); - close (s); - return NULL; - } - } - mtu = ifr.ifr_mtu; - - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) - { - logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); - close (s); - return NULL; - } - - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) - { - logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno)); - close (s); - return NULL; - } - - close (s); - - iface = xmalloc (sizeof (interface_t)); - memset (iface, 0, sizeof (interface_t)); - strlcpy (iface->name, ifname, IF_NAMESIZE); - snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); - 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; - - logger (LOG_INFO, "hardware address = %s", - hwaddr_ntoa (iface->hwaddr, iface->hwlen)); - - /* 0 is a valid fd, so init to -1 */ - iface->fd = -1; - - return iface; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { + logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); + close (s); + return NULL; + } + + 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) < 0) { + logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", strerror (errno)); + close (s); + return NULL; + } + } + mtu = ifr.ifr_mtu; + + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { + logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); + close (s); + return NULL; + } + + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) { + logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno)); + close (s); + return NULL; + } + + close (s); + + iface = xmalloc (sizeof (interface_t)); + memset (iface, 0, sizeof (interface_t)); + strlcpy (iface->name, ifname, IF_NAMESIZE); + snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); + 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; + + logger (LOG_INFO, "hardware address = %s", + hwaddr_ntoa (iface->hwaddr, iface->hwlen)); + + /* 0 is a valid fd, so init to -1 */ + iface->fd = -1; + + return iface; } int get_mtu (const char *ifname) { - struct ifreq ifr; - int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (struct ifreq)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - r = ioctl (s, SIOCGIFMTU, &ifr); - close (s); - - if (r < 0) - { - 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)) < 0) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (struct ifreq)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + r = ioctl (s, SIOCGIFMTU, &ifr); + close (s); + + if (r < 0) { + 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)) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (struct ifreq)); - 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 < 0) - 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)) < 0) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (struct ifreq)); + 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 < 0) + logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); + + return (r == 0 ? 0 : -1); } #if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) \ || defined(__APPLE__) 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)) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + 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; \ - _s.sa = &_var; \ - _s.sin->sin_family = AF_INET; \ - _s.sin->sin_len = sizeof (struct sockaddr_in); \ - memcpy (&_s.sin->sin_addr, &_addr, sizeof (struct in_addr)); \ - } - - ADDADDR (ifa.ifra_addr, address); - ADDADDR (ifa.ifra_mask, netmask); - if (! del) - { - ADDADDR (ifa.ifra_broadaddr, broadcast); - } +#define ADDADDR(_var, _addr) { \ + union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \ + _s.sa = &_var; \ + _s.sin->sin_family = AF_INET; \ + _s.sin->sin_len = sizeof (struct sockaddr_in); \ + memcpy (&_s.sin->sin_addr, &_addr, sizeof (struct in_addr)); \ + } + + 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; - } + 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; + 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; - char *dstd; - struct rtm - { - struct rt_msghdr hdr; - struct sockaddr_in destination; - union - { - struct sockaddr sa; - struct sockaddr_in sin; - struct sockaddr_dl sdl; - struct sockaddr_storage sss; /* added to avoid memory overrun */ - } gateway; - struct sockaddr_in netmask; - } rtm; - static int seq; - - if (! ifname) - return -1; - - /* Do something with metric to satisfy compiler warnings */ - metric = 0; - - dstd = strdup (inet_ntoa (destination)); - if (gateway.s_addr == destination.s_addr) - logger (LOG_INFO, "%s route to %s/%d", - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask)); - else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s default route via %s", - change ? "changing" : del ? "removing" : "adding", - inet_ntoa (gateway)); - else - logger (LOG_INFO, "%s route to %s/%d via %s", - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask), inet_ntoa (gateway)); - if (dstd) - free (dstd); - - if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&rtm, 0, sizeof (struct 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; - if (netmask.s_addr == INADDR_BROADCAST) - rtm.hdr.rtm_flags |= RTF_HOST; - else - rtm.hdr.rtm_flags |= RTF_GATEWAY; - - rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; + int s; + char *dstd; + struct rtm + { + struct rt_msghdr hdr; + struct sockaddr_in destination; + union + { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_dl sdl; + struct sockaddr_storage sss; /* added to avoid memory overrun */ + } gateway; + struct sockaddr_in netmask; + } rtm; + static int seq; + + if (! ifname) + return -1; + + /* Do something with metric to satisfy compiler warnings */ + metric = 0; + + dstd = strdup (inet_ntoa (destination)); + if (gateway.s_addr == destination.s_addr) + logger (LOG_INFO, "%s route to %s/%d", + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask)); + else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s default route via %s", + change ? "changing" : del ? "removing" : "adding", + inet_ntoa (gateway)); + else + logger (LOG_INFO, "%s route to %s/%d via %s", + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask), inet_ntoa (gateway)); + if (dstd) + free (dstd); + + if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&rtm, 0, sizeof (struct 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; + if (netmask.s_addr == INADDR_BROADCAST) + rtm.hdr.rtm_flags |= RTF_HOST; + else + rtm.hdr.rtm_flags |= RTF_GATEWAY; + + rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; #define ADDADDR(_var, _addr) \ - _var.sin_family = AF_INET; \ - _var.sin_len = sizeof (struct sockaddr_in); \ - memcpy (&_var.sin_addr, &_addr, sizeof (struct in_addr)); - - ADDADDR (rtm.destination, destination); - if (netmask.s_addr == INADDR_BROADCAST) - { - struct ifaddrs *ifap, *ifa; - union - { - struct sockaddr *sa; - struct sockaddr_dl *sdl; - } us; - - if (getifaddrs (&ifap)) - { - logger (LOG_ERR, "getifaddrs: %s", strerror (errno)); - return -1; - } - - for (ifa = ifap; ifa; ifa = ifa->ifa_next) - { - if (ifa->ifa_addr->sa_family != AF_LINK) - continue; - - if (strcmp (ifname, ifa->ifa_name)) - continue; - - us.sa = ifa->ifa_addr; - memcpy (&rtm.gateway.sdl, us.sdl, us.sdl->sdl_len); - break; - } - freeifaddrs (ifap); - } - else - { - ADDADDR (rtm.gateway.sin, gateway); - } - - ADDADDR (rtm.netmask, netmask); + _var.sin_family = AF_INET; \ + _var.sin_len = sizeof (struct sockaddr_in); \ + memcpy (&_var.sin_addr, &_addr, sizeof (struct in_addr)); + + ADDADDR (rtm.destination, destination); + if (netmask.s_addr == INADDR_BROADCAST) { + struct ifaddrs *ifap, *ifa; + union + { + struct sockaddr *sa; + struct sockaddr_dl *sdl; + } us; + + if (getifaddrs (&ifap)) { + logger (LOG_ERR, "getifaddrs: %s", strerror (errno)); + return -1; + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + + if (strcmp (ifname, ifa->ifa_name)) + continue; + + us.sa = ifa->ifa_addr; + memcpy (&rtm.gateway.sdl, us.sdl, us.sdl->sdl_len); + break; + } + freeifaddrs (ifap); + } else { + ADDADDR (rtm.gateway.sin, gateway); + } + + ADDADDR (rtm.netmask, netmask); #undef ADDADDR - rtm.hdr.rtm_msglen = sizeof (rtm); + rtm.hdr.rtm_msglen = sizeof (rtm); - if (write(s, &rtm, sizeof (rtm)) < 0) - { - /* Don't report error about routes already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } + if (write(s, &rtm, sizeof (rtm)) < 0) { + /* 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; + close (s); + return 0; } #elif __linux__ @@ -535,318 +507,299 @@ static int do_route (const char *ifname, */ static int send_netlink(struct nlmsghdr *hdr) { - int s; - pid_t mypid = getpid (); - struct sockaddr_nl nl; - struct iovec iov; - struct msghdr msg; - static unsigned int seq; - char buffer[256]; - int bytes; - union - { - char *buffer; - struct nlmsghdr *nlm; - } h; - - if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&nl, 0, sizeof (struct sockaddr_nl)); - nl.nl_family = AF_NETLINK; - if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) < 0) - { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (s); - return -1; - } - - memset (&iov, 0, sizeof (struct iovec)); - iov.iov_base = hdr; - iov.iov_len = hdr->nlmsg_len; - - memset (&msg, 0, sizeof (struct msghdr)); - 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) < 0) - { - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } - - memset (buffer, 0, sizeof (buffer)); - iov.iov_base = buffer; - - while (1) - { - iov.iov_len = sizeof (buffer); - bytes = recvmsg(s, &msg, 0); - - if (bytes < 0) - { - if (errno != EINTR) - logger (LOG_ERR, "netlink: overrun"); - 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); - - 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; - } - - if (nl.nl_pid != 0 || - (pid_t) h.nlm->nlmsg_pid != mypid || - h.nlm->nlmsg_seq != seq) - /* Message isn't for us, so skip it */ - goto next; - - /* We get an NLMSG_ERROR back with a code of zero for success */ - if (h.nlm->nlmsg_type == NLMSG_ERROR) - { - struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); - if ((unsigned) l < sizeof (struct nlmsgerr)) - logger (LOG_ERR, "netlink: truncated error message"); - else - { - errno = -err->error; - if (errno == 0) - { - close (s); - return 0; - } - - /* Don't report on something already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "netlink: %s", strerror (errno)); - } - goto eexit; - } - - logger (LOG_ERR, "netlink: unexpected reply"); + int s; + pid_t mypid = getpid (); + struct sockaddr_nl nl; + struct iovec iov; + struct msghdr msg; + static unsigned int seq; + char buffer[256]; + int bytes; + union + { + char *buffer; + struct nlmsghdr *nlm; + } h; + + if ((s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&nl, 0, sizeof (struct sockaddr_nl)); + nl.nl_family = AF_NETLINK; + if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) < 0) { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (s); + return -1; + } + + memset (&iov, 0, sizeof (struct iovec)); + iov.iov_base = hdr; + iov.iov_len = hdr->nlmsg_len; + + memset (&msg, 0, sizeof (struct msghdr)); + 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) < 0) { + logger (LOG_ERR, "write: %s", strerror (errno)); + close (s); + return -1; + } + + memset (buffer, 0, sizeof (buffer)); + iov.iov_base = buffer; + + while (1) { + iov.iov_len = sizeof (buffer); + bytes = recvmsg(s, &msg, 0); + + if (bytes < 0) { + if (errno != EINTR) + logger (LOG_ERR, "netlink: overrun"); + 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); + + 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; + } + + if (nl.nl_pid != 0 || + (pid_t) h.nlm->nlmsg_pid != mypid || + h.nlm->nlmsg_seq != seq) + /* Message isn't for us, so skip it */ + goto next; + + /* We get an NLMSG_ERROR back with a code of zero for success */ + if (h.nlm->nlmsg_type == NLMSG_ERROR) { + struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); + if ((unsigned) l < sizeof (struct nlmsgerr)) + logger (LOG_ERR, "netlink: truncated error message"); + else { + errno = -err->error; + if (errno == 0) { + close (s); + return 0; + } + + /* Don't report on something already existing */ + if (errno != EEXIST) + logger (LOG_ERR, "netlink: %s", strerror (errno)); + } + goto eexit; + } + + logger (LOG_ERR, "netlink: unexpected reply"); next: - bytes -= NLMSG_ALIGN (len); - h.buffer += NLMSG_ALIGN (len); - } - - if (msg.msg_flags & MSG_TRUNC) - { - logger (LOG_ERR, "netlink: truncated message"); - continue; - } - - if (bytes) - { - logger (LOG_ERR, "netlink: remnant of size %d", bytes); - goto eexit; - } - } + bytes -= NLMSG_ALIGN (len); + h.buffer += NLMSG_ALIGN (len); + } + + if (msg.msg_flags & MSG_TRUNC) { + logger (LOG_ERR, "netlink: truncated message"); + continue; + } + + if (bytes) { + logger (LOG_ERR, "netlink: remnant of size %d", bytes); + goto eexit; + } + } eexit: - close (s); - return -1; + close (s); + return -1; } #define NLMSG_TAIL(nmsg) \ - ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) + ((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 (uint32_t)); - 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 (uint32_t)); - n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; - - return 0; + int len = RTA_LENGTH (sizeof (uint32_t)); + 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 (uint32_t)); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; } 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 - { - struct nlmsghdr hdr; - struct ifaddrmsg ifa; - char buffer[64]; - } - nlm; - - if (!ifname) - return -1; - - memset (&nlm, 0, 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: Couldn't find index for interface `%s'", - ifname); - return -1; - } - nlm.ifa.ifa_family = AF_INET; - - nlm.ifa.ifa_prefixlen = inet_ntocidr (netmask); - 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)); - - return send_netlink (&nlm.hdr); + struct + { + struct nlmsghdr hdr; + struct ifaddrmsg ifa; + char buffer[64]; + } + nlm; + + if (!ifname) + return -1; + + memset (&nlm, 0, 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: Couldn't find index for interface `%s'", + ifname); + return -1; + } + nlm.ifa.ifa_family = AF_INET; + + nlm.ifa.ifa_prefixlen = inet_ntocidr (netmask); + 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)); + + return send_netlink (&nlm.hdr); } 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) { - char *dstd; - char *gend; - unsigned int ifindex; - struct - { - struct nlmsghdr hdr; - struct rtmsg rt; - char buffer[256]; - } - nlm; - - if (! ifname) - return -1; - - dstd = strdup (inet_ntoa (destination)); - gend = strdup (inet_ntoa (netmask)); - if (gateway.s_addr == destination.s_addr) - logger (LOG_INFO, "%s route to %s (%s) metric %d", - change ? "changing" : del ? "removing" : "adding", - dstd, gend, metric); - else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s default route via %s metric %d", - change ? "changing" : del ? "removing" : "adding", - inet_ntoa (gateway), metric); - else - logger (LOG_INFO, "%s route to %s (%s) via %s metric %d", - change ? "changing" : del ? "removing" : "adding", - dstd, gend, inet_ntoa (gateway), metric); - if (dstd) - free (dstd); - if (gend) - free (gend); - - memset (&nlm, 0, 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 (gateway.s_addr == INADDR_ANY || - netmask.s_addr == INADDR_BROADCAST) - 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 (gateway.s_addr != INADDR_ANY && gateway.s_addr != destination.s_addr) - add_attr_l (&nlm.hdr, sizeof (nlm), RTA_GATEWAY, &gateway.s_addr, - sizeof (gateway.s_addr)); - - - if (! (ifindex = if_nametoindex (ifname))) - { - logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", - ifname); - return -1; - } - - add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_OIF, ifindex); - add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_PRIORITY, metric); - - return send_netlink (&nlm.hdr); + char *dstd; + char *gend; + unsigned int ifindex; + struct + { + struct nlmsghdr hdr; + struct rtmsg rt; + char buffer[256]; + } + nlm; + + if (! ifname) + return -1; + + dstd = strdup (inet_ntoa (destination)); + gend = strdup (inet_ntoa (netmask)); + if (gateway.s_addr == destination.s_addr) + logger (LOG_INFO, "%s route to %s (%s) metric %d", + change ? "changing" : del ? "removing" : "adding", + dstd, gend, metric); + else if (destination.s_addr == INADDR_ANY && netmask.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s default route via %s metric %d", + change ? "changing" : del ? "removing" : "adding", + inet_ntoa (gateway), metric); + else + logger (LOG_INFO, "%s route to %s (%s) via %s metric %d", + change ? "changing" : del ? "removing" : "adding", + dstd, gend, inet_ntoa (gateway), metric); + if (dstd) + free (dstd); + if (gend) + free (gend); + + memset (&nlm, 0, 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 (gateway.s_addr == INADDR_ANY || + netmask.s_addr == INADDR_BROADCAST) + 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 (gateway.s_addr != INADDR_ANY && gateway.s_addr != destination.s_addr) + add_attr_l (&nlm.hdr, sizeof (nlm), RTA_GATEWAY, &gateway.s_addr, + sizeof (gateway.s_addr)); + + + if (! (ifindex = if_nametoindex (ifname))) { + logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", + ifname); + return -1; + } + + add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_OIF, ifindex); + add_attr_32 (&nlm.hdr, sizeof (nlm), RTA_PRIORITY, metric); + + return send_netlink (&nlm.hdr); } #else @@ -858,130 +811,125 @@ static int do_route (const char *ifname, 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, "deleting IP address %s/%d", - inet_ntoa (address), inet_ntocidr (netmask)); + logger (LOG_INFO, "deleting 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)); } #ifdef HAVE_IFADDRS_H int flush_addresses (const char *ifname) { - struct ifaddrs *ifap; - struct ifaddrs *p; - int retval = 0; - - if (! ifname) - return -1; - if (getifaddrs (&ifap) != 0) - return -1; - - for (p = ifap; p; p = p->ifa_next) - { - union - { - struct sockaddr *sa; - struct sockaddr_in *sin; - } us_a, us_m; - - if (strcmp (p->ifa_name, ifname) != 0) - continue; - - us_a.sa = p->ifa_addr; - us_m.sa = p->ifa_netmask; - - if (us_a.sin->sin_family == AF_INET) - if (del_address (ifname, us_a.sin->sin_addr, us_m.sin->sin_addr) < 0) - retval = -1; - } - freeifaddrs (ifap); - - return retval; + struct ifaddrs *ifap; + struct ifaddrs *p; + int retval = 0; + + if (! ifname) + return -1; + if (getifaddrs (&ifap) != 0) + return -1; + + for (p = ifap; p; p = p->ifa_next) { + union + { + struct sockaddr *sa; + struct sockaddr_in *sin; + } us_a, us_m; + + if (strcmp (p->ifa_name, ifname) != 0) + continue; + + us_a.sa = p->ifa_addr; + us_m.sa = p->ifa_netmask; + + if (us_a.sin->sin_family == AF_INET) + if (del_address (ifname, us_a.sin->sin_addr, us_m.sin->sin_addr) < 0) + retval = -1; + } + freeifaddrs (ifap); + + return retval; } #else int flush_addresses (const char *ifname) { - int s; - struct ifconf ifc; - int retval = 0; - int i; - void *ifrs; - int nifs; - struct ifreq *ifr; - - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&ifc, 0, sizeof (struct ifconf)); - ifc.ifc_buf = NULL; - if (ioctl (s, SIOCGIFCONF, &ifc) < 0) - { - logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); - close (s); - } - - ifrs = xmalloc (ifc.ifc_len); - ifc.ifc_buf = ifrs; - if (ioctl (s, SIOCGIFCONF, &ifc) < 0) - { - logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); - close (s); - free (ifrs); - return -1; - } - - close (s); - - nifs = ifc.ifc_len / sizeof (struct ifreq); - ifr = ifrs; - for (i = 0; i < nifs; i++) - { - struct sockaddr_in *addr = (struct sockaddr_in *) &ifr->ifr_addr; - struct sockaddr_in *netm = (struct sockaddr_in *) &ifr->ifr_netmask; - - if (ifr->ifr_addr.sa_family == AF_INET - && strcmp (ifname, ifr->ifr_name) == 0) - if (del_address (ifname, addr->sin_addr, netm->sin_addr) < 0) - retval = -1; - ifr++; - } - - free (ifrs); - return retval; + int s; + struct ifconf ifc; + int retval = 0; + int i; + void *ifrs; + int nifs; + struct ifreq *ifr; + + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&ifc, 0, sizeof (struct ifconf)); + ifc.ifc_buf = NULL; + if (ioctl (s, SIOCGIFCONF, &ifc) < 0) { + logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); + close (s); + } + + ifrs = xmalloc (ifc.ifc_len); + ifc.ifc_buf = ifrs; + if (ioctl (s, SIOCGIFCONF, &ifc) < 0) { + logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); + close (s); + free (ifrs); + return -1; + } + + close (s); + + nifs = ifc.ifc_len / sizeof (struct ifreq); + ifr = ifrs; + for (i = 0; i < nifs; i++) { + struct sockaddr_in *addr = (struct sockaddr_in *) &ifr->ifr_addr; + struct sockaddr_in *netm = (struct sockaddr_in *) &ifr->ifr_netmask; + + if (ifr->ifr_addr.sa_family == AF_INET + && strcmp (ifname, ifr->ifr_name) == 0) + if (del_address (ifname, addr->sin_addr, netm->sin_addr) < 0) + retval = -1; + ifr++; + } + + free (ifrs); + return retval; } #endif diff --git a/interface.h b/interface.h index 23615849..e3b25cf7 100644 --- a/interface.h +++ b/interface.h @@ -46,42 +46,42 @@ typedef struct route_t { - struct in_addr destination; - struct in_addr netmask; - struct in_addr gateway; - struct route_t *next; + struct in_addr destination; + struct in_addr netmask; + struct in_addr gateway; + struct route_t *next; } route_t; typedef struct address_t { - struct in_addr address; - struct address_t *next; + struct in_addr address; + struct address_t *next; } address_t; typedef struct interface_t { - char name[IF_NAMESIZE]; - sa_family_t family; - unsigned char hwaddr[20]; - int hwlen; - bool arpable; - unsigned short mtu; + char name[IF_NAMESIZE]; + sa_family_t family; + unsigned char hwaddr[20]; + int hwlen; + bool arpable; + unsigned short mtu; - int fd; - int buffer_length; + int fd; + int buffer_length; #ifdef __linux__ - int socket_protocol; + 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; - route_t *previous_routes; - - long start_uptime; + unsigned short previous_mtu; + struct in_addr previous_address; + struct in_addr previous_netmask; + route_t *previous_routes; + + long start_uptime; } interface_t; void free_address (address_t *addresses); @@ -91,17 +91,17 @@ 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); 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); char *hwaddr_ntoa (const unsigned char *hwaddr, int hwlen); diff --git a/logger.c b/logger.c index 221ea16f..6aa54cb9 100644 --- a/logger.c +++ b/logger.c @@ -32,83 +32,81 @@ static int loglevel = LOG_WARNING; static char logprefix[12] = {0}; static const char *syslog_level_msg[] = { - [LOG_EMERG] = "EMERGENCY!", - [LOG_ALERT] = "ALERT!", - [LOG_CRIT] = "Critical!", - [LOG_WARNING] = "Warning", - [LOG_ERR] = "Error", - [LOG_INFO] = "Info", - [LOG_DEBUG] = "Debug", - [LOG_DEBUG + 1] = NULL + [LOG_EMERG] = "EMERGENCY!", + [LOG_ALERT] = "ALERT!", + [LOG_CRIT] = "Critical!", + [LOG_WARNING] = "Warning", + [LOG_ERR] = "Error", + [LOG_INFO] = "Info", + [LOG_DEBUG] = "Debug", + [LOG_DEBUG + 1] = NULL }; static const char *syslog_level[] = { - [LOG_EMERG] = "LOG_EMERG", - [LOG_ALERT] = "LOG_ALERT", - [LOG_CRIT] = "LOG_CRIT", - [LOG_ERR] = "LOG_ERR", - [LOG_WARNING] = "LOG_WARNING", - [LOG_NOTICE] = "LOG_NOTICE", - [LOG_INFO] = "LOG_INFO", - [LOG_DEBUG] = "LOG_DEBUG", - [LOG_DEBUG + 1] = NULL + [LOG_EMERG] = "LOG_EMERG", + [LOG_ALERT] = "LOG_ALERT", + [LOG_CRIT] = "LOG_CRIT", + [LOG_ERR] = "LOG_ERR", + [LOG_WARNING] = "LOG_WARNING", + [LOG_NOTICE] = "LOG_NOTICE", + [LOG_INFO] = "LOG_INFO", + [LOG_DEBUG] = "LOG_DEBUG", + [LOG_DEBUG + 1] = NULL }; int logtolevel (const char *priority) { - int i = 0; + int i = 0; - while (syslog_level[i]) - { - if (!strcmp (priority, syslog_level[i])) - return i; - i++; - } - return -1; + while (syslog_level[i]) + { + if (!strcmp (priority, syslog_level[i])) + return i; + i++; + } + return -1; } void setloglevel (int level) { - loglevel = level; + loglevel = level; } void setlogprefix (const char *prefix) { - snprintf (logprefix, sizeof (logprefix), "%s", prefix); + snprintf (logprefix, sizeof (logprefix), "%s", prefix); } void logger(int level, const char *fmt, ...) { - va_list p; - va_list p2; - FILE *f = stderr; + va_list p; + va_list p2; + FILE *f = stderr; - va_start (p, fmt); - va_copy (p2, p); + va_start (p, fmt); + va_copy (p2, p); - if (level <= LOG_ERR || level <= loglevel) - { - if (level == LOG_DEBUG || level == LOG_INFO) - f = stdout; - fprintf (f, "%s, %s", syslog_level_msg[level], logprefix); - vfprintf (f, fmt, p); - fputc ('\n', f); - } + if (level <= LOG_ERR || level <= loglevel) { + if (level == LOG_DEBUG || level == LOG_INFO) + f = stdout; + fprintf (f, "%s, %s", syslog_level_msg[level], logprefix); + vfprintf (f, fmt, p); + fputc ('\n', f); + } - if (level < LOG_DEBUG || level <= loglevel) - { - int len = strlen (logprefix); - int fmt2len = strlen (fmt) + len + 1; - char *fmt2 = xmalloc (sizeof (char *) * fmt2len); - char *pf = fmt2; - memcpy (pf, logprefix, len); - pf += len; - strlcpy (pf, fmt, fmt2len - len); - vsyslog (level, fmt2, p2); - free (fmt2); - } + if (level < LOG_DEBUG || level <= loglevel) { + int len = strlen (logprefix); + int fmt2len = strlen (fmt) + len + 1; + char *fmt2 = xmalloc (sizeof (char *) * fmt2len); + char *pf = fmt2; + memcpy (pf, logprefix, len); + pf += len; + strlcpy (pf, fmt, fmt2len - len); + vsyslog (level, fmt2, p2); + free (fmt2); + } - va_end (p2); - va_end (p); + va_end (p2); + va_end (p); } diff --git a/signals.c b/signals.c index 3020d0f3..8a77bd8c 100644 --- a/signals.c +++ b/signals.c @@ -36,39 +36,38 @@ static int signal_pipe[2]; static void signal_handler (int sig) { - /* Silently ignore this signal and wait for it. This stops zombies. - We do this here instead of client.c so that we don't spam the log file - with "waiting on select messages" */ - if (sig == SIGCHLD) - { - wait (0); - return; - } + /* Silently ignore this signal and wait for it. This stops zombies. + We do this here instead of client.c so that we don't spam the log file + with "waiting on select messages" */ + if (sig == SIGCHLD) { + wait (0); + return; + } - if (send (signal_pipe[1], &sig, sizeof (sig), MSG_DONTWAIT) < 0) - logger (LOG_ERR, "Could not send signal: %s", strerror (errno)); + if (send (signal_pipe[1], &sig, sizeof (sig), MSG_DONTWAIT) < 0) + logger (LOG_ERR, "Could not send signal: %s", strerror (errno)); } /* Call this before doing anything else. Sets up the socket pair * and installs the signal handler */ void signal_setup(void) { - int i; - int flags; + int i; + int flags; - socketpair (AF_UNIX, SOCK_STREAM, 0, signal_pipe); + socketpair (AF_UNIX, SOCK_STREAM, 0, signal_pipe); - /* Stop any scripts from inheriting us */ - for (i = 0; i < 2; i++) - if ((flags = fcntl (signal_pipe[i], F_GETFD, 0)) < 0 || - fcntl (signal_pipe[i], F_SETFD, flags | FD_CLOEXEC) < 0) - logger (LOG_ERR ,"fcntl: %s", strerror (errno)); + /* Stop any scripts from inheriting us */ + for (i = 0; i < 2; i++) + if ((flags = fcntl (signal_pipe[i], F_GETFD, 0)) < 0 || + fcntl (signal_pipe[i], F_SETFD, flags | FD_CLOEXEC) < 0) + logger (LOG_ERR ,"fcntl: %s", strerror (errno)); - signal (SIGHUP, signal_handler); - signal (SIGALRM, signal_handler); - signal (SIGTERM, signal_handler); - signal (SIGINT, signal_handler); - signal (SIGCHLD, signal_handler); + signal (SIGHUP, signal_handler); + signal (SIGALRM, signal_handler); + signal (SIGTERM, signal_handler); + signal (SIGINT, signal_handler); + signal (SIGCHLD, signal_handler); } /* Quick little function to setup the rfds. Will return the @@ -76,11 +75,11 @@ void signal_setup(void) * one extra fd */ int signal_fd_set (fd_set *rfds, int extra_fd) { - FD_ZERO (rfds); - FD_SET (signal_pipe[0], rfds); - if (extra_fd >= 0) - FD_SET (extra_fd, rfds); - return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd; + FD_ZERO (rfds); + FD_SET (signal_pipe[0], rfds); + if (extra_fd >= 0) + FD_SET (extra_fd, rfds); + return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd; } /* Read a signal from the signal pipe. Returns 0 if there is @@ -88,14 +87,14 @@ int signal_fd_set (fd_set *rfds, int extra_fd) * your signal on success */ int signal_read (const fd_set *rfds) { - int sig; + int sig; - if (! FD_ISSET (signal_pipe[0], rfds)) - return 0; + if (! FD_ISSET (signal_pipe[0], rfds)) + return 0; - if (read (signal_pipe[0], &sig, sizeof (sig)) < 0) - return -1; + if (read (signal_pipe[0], &sig, sizeof (sig)) < 0) + return -1; - return sig; + return sig; } diff --git a/socket.c b/socket.c index 526e12c3..1428e3bd 100644 --- a/socket.c +++ b/socket.c @@ -56,384 +56,362 @@ 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, int length, - struct in_addr source, struct in_addr dest) + const unsigned char *data, int 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 (struct udphdr) + length); - ip->ip_len = udp->uh_ulen; - udp->uh_sum = checksum ((unsigned char *) packet, - sizeof (struct udp_dhcp_packet)); - - ip->ip_v = IPVERSION; - ip->ip_hl = 5; - ip->ip_id = 0; - ip->ip_tos = IPTOS_LOWDELAY; - ip->ip_len = htons (sizeof (struct ip) + sizeof (struct udphdr) + - length); - ip->ip_id = 0; - ip->ip_off = 0; - ip->ip_ttl = IPDEFTTL; - - ip->ip_sum = checksum ((unsigned char *) ip, sizeof (struct 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 (struct udphdr) + length); + ip->ip_len = udp->uh_ulen; + udp->uh_sum = checksum ((unsigned char *) packet, + sizeof (struct udp_dhcp_packet)); + + ip->ip_v = IPVERSION; + ip->ip_hl = 5; + ip->ip_id = 0; + ip->ip_tos = IPTOS_LOWDELAY; + ip->ip_len = htons (sizeof (struct ip) + sizeof (struct udphdr) + + length); + ip->ip_id = 0; + ip->ip_off = 0; + ip->ip_ttl = IPDEFTTL; + + ip->ip_sum = checksum ((unsigned char *) ip, sizeof (struct 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 (struct ip))) - { - logger (LOG_DEBUG, "bad IP header checksum, ignoring"); - retval = -1; - goto eexit; - } - - memcpy (&source, &d.packet->ip.ip_src, sizeof (struct in_addr)); - memcpy (&dest, &d.packet->ip.ip_dst, sizeof (struct in_addr)); - memset (&d.packet->ip, 0, sizeof (struct ip)); - d.packet->udp.uh_sum = 0; - - d.packet->ip.ip_p = IPPROTO_UDP; - memcpy (&d.packet->ip.ip_src, &source, sizeof (struct in_addr)); - memcpy (&d.packet->ip.ip_dst, &dest, sizeof (struct in_addr)); - 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 (struct ip))) + { + logger (LOG_DEBUG, "bad IP header checksum, ignoring"); + retval = -1; + goto eexit; + } + + memcpy (&source, &d.packet->ip.ip_src, sizeof (struct in_addr)); + memcpy (&dest, &d.packet->ip.ip_dst, sizeof (struct in_addr)); + memset (&d.packet->ip, 0, sizeof (struct ip)); + d.packet->udp.uh_sum = 0; + + d.packet->ip.ip_p = IPPROTO_UDP; + memcpy (&d.packet->ip.ip_src, &source, sizeof (struct in_addr)); + memcpy (&d.packet->ip.ip_dst, &dest, sizeof (struct in_addr)); + 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(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) \ - || defined(__APPLE__) + || defined(__APPLE__) /* Credit where credit is due :) The below BPF filter is taken from ISC DHCP */ # include 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 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, (u_int) - 1), + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT (BPF_RET+BPF_K, (u_int) - 1), - /* 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), + /* 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, (u_int) - 1), + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT (BPF_RET+BPF_K, (u_int) - 1), - /* Otherwise, drop it. */ - BPF_STMT (BPF_RET+BPF_K, 0), + /* Otherwise, drop it. */ + BPF_STMT (BPF_RET+BPF_K, 0), }; int open_socket (interface_t *iface, bool arp) { - int n = 0; - int fd = -1; - char device[PATH_MAX]; - int flags; - struct ifreq ifr; - int buf = 0; - struct bpf_program p; - - do - { - snprintf (device, PATH_MAX, "/dev/bpf%d", n++); - fd = open (device, O_RDWR); - } while (fd < 0 && errno == EBUSY); - - if (fd < 0) - { - logger (LOG_ERR, "unable to open a BPF device"); - return -1; - } - - if ((flags = fcntl (fd, F_GETFD, 0)) < 0 - || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0) - { - logger (LOG_ERR, "fcntl: %s", strerror (errno)); - close (fd); - return -1; - } - - memset (&ifr, 0, sizeof (struct ifreq)); - strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); - if (ioctl (fd, BIOCSETIF, &ifr) < 0) - { - 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) < 0) - { - logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno)); - close (fd); - return -1; - } - iface->buffer_length = buf; - - flags = 1; - if (ioctl (fd, BIOCIMMEDIATE, &flags) < 0) - { - logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno)); - close (fd); - return -1; - } - - /* Install the DHCP filter */ - if (arp) - { - p.bf_insns = arp_bpf_filter; - p.bf_len = sizeof (arp_bpf_filter) / sizeof (struct bpf_insn); - } - else - { - p.bf_insns = dhcp_bpf_filter; - p.bf_len = sizeof (dhcp_bpf_filter) / sizeof (struct bpf_insn); - } - if (ioctl (fd, BIOCSETF, &p) < 0) - { - 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[PATH_MAX]; + int flags; + struct ifreq ifr; + int buf = 0; + struct bpf_program p; + + do { + snprintf (device, PATH_MAX, "/dev/bpf%d", n++); + fd = open (device, O_RDWR); + } while (fd < 0 && errno == EBUSY); + + if (fd < 0) { + logger (LOG_ERR, "unable to open a BPF device"); + return -1; + } + + if ((flags = fcntl (fd, F_GETFD, 0)) < 0 + || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0) + { + logger (LOG_ERR, "fcntl: %s", strerror (errno)); + close (fd); + return -1; + } + + memset (&ifr, 0, sizeof (struct ifreq)); + strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); + if (ioctl (fd, BIOCSETIF, &ifr) < 0) { + 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) < 0) { + logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno)); + close (fd); + return -1; + } + iface->buffer_length = buf; + + flags = 1; + if (ioctl (fd, BIOCIMMEDIATE, &flags) < 0) { + logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno)); + close (fd); + return -1; + } + + /* Install the DHCP filter */ + if (arp) { + p.bf_insns = arp_bpf_filter; + p.bf_len = sizeof (arp_bpf_filter) / sizeof (struct bpf_insn); + } else { + p.bf_insns = dhcp_bpf_filter; + p.bf_len = sizeof (dhcp_bpf_filter) / sizeof (struct bpf_insn); + } + if (ioctl (fd, BIOCSETF, &p) < 0) { + 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 send_packet (const interface_t *iface, int type, - const unsigned char *data, int len) + const unsigned char *data, int len) { - int retval = -1; - struct iovec iov[2]; - - if (iface->family == ARPHRD_ETHER) - { - struct ether_header hw; - memset (&hw, 0, sizeof (struct ether_header)); - memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); - hw.ether_type = htons (type); - - iov[0].iov_base = &hw; - iov[0].iov_len = sizeof (struct ether_header); - } - 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; + int retval = -1; + struct iovec iov[2]; + + if (iface->family == ARPHRD_ETHER) { + struct ether_header hw; + memset (&hw, 0, sizeof (struct ether_header)); + memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); + hw.ether_type = htons (type); + + iov[0].iov_base = &hw; + iov[0].iov_len = sizeof (struct ether_header); + } 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. */ int get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, int *buffer_len, int *buffer_pos) + unsigned char *buffer, int *buffer_len, int *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 timeval tv; - logger (LOG_ERR, "read: %s", strerror (errno)); - tv.tv_sec = 3; - tv.tv_usec = 0; - select (0, NULL, NULL, NULL, &tv); - return -1; - } - } - else - bpf.buffer += *buffer_pos; - - while (bpf.packet) - { - int len = -1; - union - { - unsigned char *buffer; - struct ether_header *hw; - } hdr; - unsigned char *payload; - - /* 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 (struct ether_header); - - /* 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 (struct ether_header); - memcpy (data, payload, len); - } - 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 (struct ip) - - sizeof (struct udphdr); - memcpy (data, &pay.packet->dhcp, len); - } - } - - /* Update the buffer_pos pointer */ - bpf.buffer += - BPF_WORDALIGN (bpf.packet->bh_hdrlen + bpf.packet->bh_caplen); - if (bpf.buffer - buffer < *buffer_len) - *buffer_pos = bpf.buffer - buffer; - else - *buffer_pos = 0; - - if (len != -1) - 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 timeval tv; + logger (LOG_ERR, "read: %s", strerror (errno)); + tv.tv_sec = 3; + tv.tv_usec = 0; + select (0, NULL, NULL, NULL, &tv); + return -1; + } + } else + bpf.buffer += *buffer_pos; + + while (bpf.packet) { + int len = -1; + union + { + unsigned char *buffer; + struct ether_header *hw; + } hdr; + unsigned char *payload; + + /* 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 (struct ether_header); + + /* 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 (struct ether_header); + memcpy (data, payload, len); + } 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 (struct ip) - + sizeof (struct udphdr); + memcpy (data, &pay.packet->dhcp, len); + } + } + + /* Update the buffer_pos pointer */ + bpf.buffer += + BPF_WORDALIGN (bpf.packet->bh_hdrlen + bpf.packet->bh_caplen); + if (bpf.buffer - buffer < *buffer_len) + *buffer_pos = bpf.buffer - buffer; + else + *buffer_pos = 0; + + if (len != -1) + return len; + + if (*buffer_pos == 0) + break; + } + + /* No valid packets left, so return */ + *buffer_pos = 0; + return -1; } #elif __linux__ @@ -442,152 +420,146 @@ int get_packet (const interface_t *iface, unsigned char *data, int open_socket (interface_t *iface, bool arp) { - int fd; - int flags; - struct sockaddr_ll sll; - - if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP))) < 0) - { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - if ((flags = fcntl (fd, F_GETFD, 0)) < 0 - || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0) - { - logger (LOG_ERR, "fcntl: %s", strerror (errno)); - close (fd); - return -1; - } - - memset (&sll, 0, sizeof (struct sockaddr_ll)); - sll.sll_family = AF_PACKET; - if (arp) - sll.sll_protocol = htons (ETH_P_ARP); - else - sll.sll_protocol = htons (ETH_P_IP); - if (! (sll.sll_ifindex = if_nametoindex (iface->name))) - { - logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", - iface->name); - close (fd); - return -1; - } - - if (bind(fd, (struct sockaddr *) &sll, sizeof (struct sockaddr_ll)) == -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 = ntohs (sll.sll_protocol); - - iface->buffer_length = BUFFER_LENGTH; - - return fd; + int fd; + int flags; + struct sockaddr_ll sll; + + if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (ETH_P_IP))) < 0) { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + if ((flags = fcntl (fd, F_GETFD, 0)) < 0 + || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) < 0) + { + logger (LOG_ERR, "fcntl: %s", strerror (errno)); + close (fd); + return -1; + } + + memset (&sll, 0, sizeof (struct sockaddr_ll)); + sll.sll_family = AF_PACKET; + if (arp) + sll.sll_protocol = htons (ETH_P_ARP); + else + sll.sll_protocol = htons (ETH_P_IP); + if (! (sll.sll_ifindex = if_nametoindex (iface->name))) { + logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", + iface->name); + close (fd); + return -1; + } + + if (bind (fd, (struct sockaddr *) &sll, + sizeof (struct sockaddr_ll)) == -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 = ntohs (sll.sll_protocol); + + iface->buffer_length = BUFFER_LENGTH; + + return fd; } int send_packet (const interface_t *iface, const int type, - const unsigned char *data, const int len) + const unsigned char *data, const int len) { - struct sockaddr_ll sll; - int retval; - - if (! iface) - return -1; - - memset (&sll, 0, sizeof (struct sockaddr_ll)); - sll.sll_family = AF_PACKET; - sll.sll_protocol = htons (type); - if (! (sll.sll_ifindex = if_nametoindex (iface->name))) - { - logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", - iface->name); - return -1; - } - sll.sll_halen = ETHER_ADDR_LEN; - memset(sll.sll_addr, 0xff, sizeof (sll.sll_addr)); - - if ((retval = sendto (iface->fd, data, len, 0, (struct sockaddr *) &sll, - sizeof (struct sockaddr_ll))) < 0) - - logger (LOG_ERR, "sendto: %s", strerror (errno)); - return retval; + struct sockaddr_ll sll; + int retval; + + if (! iface) + return -1; + + memset (&sll, 0, sizeof (struct sockaddr_ll)); + sll.sll_family = AF_PACKET; + sll.sll_protocol = htons (type); + if (! (sll.sll_ifindex = if_nametoindex (iface->name))) { + logger (LOG_ERR, "if_nametoindex: Couldn't find index for interface `%s'", + iface->name); + return -1; + } + sll.sll_halen = ETHER_ADDR_LEN; + memset(sll.sll_addr, 0xff, sizeof (sll.sll_addr)); + + if ((retval = sendto (iface->fd, data, len, 0, (struct sockaddr *) &sll, + sizeof (struct sockaddr_ll))) < 0) + + 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. */ int get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, int *buffer_len, int *buffer_pos) + unsigned char *buffer, int *buffer_len, int *buffer_pos) { - long 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 < 0) - { - struct timeval tv; - logger (LOG_ERR, "read: %s", strerror (errno)); - tv.tv_sec = 3; - tv.tv_usec = 0; - select (0, NULL, NULL, NULL, &tv); - return -1; - } - - *buffer_len = bytes; - /* If it's an ARP reply, then just send it back */ - if (iface->socket_protocol == ETH_P_ARP) - { - memcpy (data, buffer, bytes); - return bytes; - } - - if ((unsigned) bytes < (sizeof (struct ip) + sizeof (struct udphdr))) - { - 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; - } - - bytes = ntohs (pay.packet->ip.ip_len); - - /* This is like our BPF filter above */ - if (pay.packet->ip.ip_p != IPPROTO_UDP || pay.packet->ip.ip_v != IPVERSION || - pay.packet->ip.ip_hl != sizeof (pay.packet->ip) >> 2 || - pay.packet->udp.uh_dport != htons (DHCP_CLIENT_PORT) || - bytes > (int) sizeof (struct udp_dhcp_packet) || - ntohs (pay.packet->udp.uh_ulen) - != (uint16_t) (bytes - sizeof (pay.packet->ip))) - { - return -1; - } - - if (valid_dhcp_packet (buffer) < 0) - return -1; - - memcpy(data, &pay.packet->dhcp, - bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp))); - - return bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)); + long 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 < 0) { + struct timeval tv; + logger (LOG_ERR, "read: %s", strerror (errno)); + tv.tv_sec = 3; + tv.tv_usec = 0; + select (0, NULL, NULL, NULL, &tv); + return -1; + } + + *buffer_len = bytes; + /* If it's an ARP reply, then just send it back */ + if (iface->socket_protocol == ETH_P_ARP) { + memcpy (data, buffer, bytes); + return bytes; + } + + if ((unsigned) bytes < (sizeof (struct ip) + sizeof (struct udphdr))) { + 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; + } + + bytes = ntohs (pay.packet->ip.ip_len); + + /* This is like our BPF filter above */ + if (pay.packet->ip.ip_p != IPPROTO_UDP || pay.packet->ip.ip_v != IPVERSION || + pay.packet->ip.ip_hl != sizeof (pay.packet->ip) >> 2 || + pay.packet->udp.uh_dport != htons (DHCP_CLIENT_PORT) || + bytes > (int) sizeof (struct udp_dhcp_packet) || + ntohs (pay.packet->udp.uh_ulen) + != (uint16_t) (bytes - sizeof (pay.packet->ip))) + { + return -1; + } + + if (valid_dhcp_packet (buffer) < 0) + return -1; + + memcpy(data, &pay.packet->dhcp, + bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp))); + + return bytes - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)); } #else diff --git a/socket.h b/socket.h index beb60f48..932f8dab 100644 --- a/socket.h +++ b/socket.h @@ -29,12 +29,12 @@ #include "interface.h" void make_dhcp_packet(struct udp_dhcp_packet *packet, - const unsigned char *data, int length, - struct in_addr source, struct in_addr dest); + const unsigned char *data, int length, + struct in_addr source, struct in_addr dest); int open_socket (interface_t *iface, bool arp); int send_packet (const interface_t *iface, int type, - const unsigned char *data, int len); + const unsigned char *data, int len); int get_packet (const interface_t *iface, unsigned char *data, - unsigned char *buffer, int *buffer_len, int *buffer_pos); + unsigned char *buffer, int *buffer_len, int *buffer_pos); #endif -- 2.47.3