dhcpcd-3.2.3.orig/0000755000076400001440000000000010760476043012434 5ustar srkusersdhcpcd-3.2.3.orig/.gitignore0000644000076400001440000000005310760476043014422 0ustar srkusers*.o version.h dhcpcd dhcpcd.8 dhcpcd-*.bz2 dhcpcd-3.2.3.orig/Makefile0000644000076400001440000000141610760476043014076 0ustar srkusers# Makefile based on BSD's pmake. # Our mk stubs also work with GNU make. # Copyright 2008 Roy Marples PROG= dhcpcd SRCS= arp.c client.c common.c configure.c dhcp.c dhcpcd.c duid.c \ info.c interface.c ipv4ll.c logger.c signal.c socket.c MAN= dhcpcd.8 VERSION= 3.2.3 CLEANFILES= version.h dhcpcd.8 BINDIR= ${PREFIX}/sbin .SUFFIXES: .in MK= mk include ${MK}/os.mk include ${MK}/cc.mk include ${MK}/prog.mk # os.mk should define this, but heh INFOD?= /var/db LDADD+= ${LIBRESOLV} ${LIBRT} CFLAGS+= -DINFODIR=\"${INFOD}\" ${FORK} ${RC} # As version.h is generated by us, hardcode the depend correctly. ${SRCS}: version.h version.h: echo "#define VERSION \"${VERSION}\""> version.h .in: sed 's:@PREFIX@:${PREFIX}:g; s:@INFODIR@:${INFOD}:g' $< > $@ dhcpcd-3.2.3.orig/README0000644000076400001440000000273210760476043013320 0ustar srkusersdhcpcd-3 - DHCP client daemon Copyright 2006-2008 Roy Marples Installation ------------ Edit config.h to match your building requirements. Take special note of ENABLE_DUID and unset it if the target media is volatile, like say a LiveCD. Then just make; make install man dhcpcd for command line options Notes ----- If you're cross compiling you may need to send HAVE_FORK=yes or HAVE_FORK=no to the make command to avoid to automatic test. We try and detect how to restart ntp and ypbind, you can override this with HAVE_INIT=no or force one of these values OPENRC (OpenRC as used by Gentoo (forked from baselayout)) BSDRC (BSD RC system - /etc/rc.d/ntpd restart ) SERVICE (RedHat service command - service ntpd restart) SLACKRC (Slackware RC system - /etc/rc.d/rc.ntpd restart) SYSV (SYSV style - /etc/init.d/ntpd restart) You can change the default dir where dhcpcd stores it's .info files with INFODIR=/var/db We now default to using -std=c99. For 64-bit linux, this always works, but for 32-bit linux it requires either gnu99 or a patch to asm/types.h. Most distros patch linux headers so this should work fine. linux-2.6.24 finally ships with a working 32-bit header. If your linux headers are older, or your distro hasn't patched them you can set CSTD=gnu99 to work around this. ChangeLog --------- We no longer supply a ChangeLog. However, you're more than welcome to read the git commit comments at http://git.marples.name/?p=dhcpcd/.git;a=summary dhcpcd-3.2.3.orig/arp.c0000644000076400001440000001640510760476043013370 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #ifdef __linux__ #include #include #endif #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "arp.h" #include "interface.h" #include "logger.h" #include "signal.h" #include "socket.h" /* These are really for IPV4LL */ #define NPROBES 3 #define PROBE_INTERVAL 200 #define NCLAIMS 2 #define CLAIM_INTERVAL 200 /* Linux does not seem to define these handy macros */ #ifndef ar_sha #define ar_sha(ap) (((caddr_t) ((ap) + 1)) + 0) #define ar_spa(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln) #define ar_tha(ap) (((caddr_t) ((ap) + 1)) + (ap)->ar_hln + (ap)->ar_pln) #define ar_tpa(ap) (((caddr_t) ((ap) + 1)) + 2 * (ap)->ar_hln + (ap)->ar_pln) #endif #ifndef arphdr_len #define arphdr_len2(ar_hln, ar_pln) (sizeof (struct arphdr) + \ 2 * (ar_hln) + 2 * (ar_pln)) #define arphdr_len(ap) (arphdr_len2 ((ap)->ar_hln, (ap)->ar_pln)) #endif #ifdef ENABLE_ARP static int send_arp (const interface_t *iface, int op, struct in_addr sip, const unsigned char *taddr, struct in_addr tip) { struct arphdr *arp; size_t arpsize = arphdr_len2 (iface->hwlen, sizeof (sip)); caddr_t tha; int retval; arp = xzalloc (arpsize); arp->ar_hrd = htons (iface->family); arp->ar_pro = htons (ETHERTYPE_IP); arp->ar_hln = iface->hwlen; arp->ar_pln = sizeof (sip); arp->ar_op = htons (op); memcpy (ar_sha (arp), iface->hwaddr, (size_t) arp->ar_hln); memcpy (ar_spa (arp), &sip, (size_t) arp->ar_pln); if (taddr) { /* NetBSD can return NULL from ar_tha, which is probably wrong * but we still need to deal with it */ if (! (tha = ar_tha (arp))) { free (arp); errno = EINVAL; return (-1); } memcpy (tha, taddr, (size_t) arp->ar_hln); } memcpy (ar_tpa (arp), &tip, (size_t) arp->ar_pln); retval = send_packet (iface, ETHERTYPE_ARP, (unsigned char *) arp, arphdr_len (arp)); free (arp); return (retval); } int arp_claim (interface_t *iface, struct in_addr address) { struct arphdr *reply = NULL; long timeout = 0; unsigned char *buffer; int retval = -1; int nprobes = 0; int nclaims = 0; struct in_addr null_address; struct pollfd fds[] = { { -1, POLLIN, 0 }, { -1, POLLIN, 0 } }; if (! iface) return (-1); if (! iface->arpable) { logger (LOG_DEBUG, "interface `%s' is not ARPable", iface->name); return (0); } if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && ! IN_LINKLOCAL (ntohl (address.s_addr))) logger (LOG_INFO, "checking %s is available on attached networks", inet_ntoa (address)); if (! open_socket (iface, ETHERTYPE_ARP)) return (-1); fds[0].fd = signal_fd (); fds[1].fd = iface->fd; memset (&null_address, 0, sizeof (null_address)); buffer = xmalloc (iface->buffer_length); reply = xmalloc (iface->buffer_length); for (;;) { size_t bufpos = 0; size_t buflen = iface->buffer_length; int bytes; int s = 0; struct timeval stopat; struct timeval now; /* Only poll if we have a timeout */ if (timeout > 0) { s = poll (fds, 2, timeout); if (s == -1) { if (errno == EINTR) { if (signal_exists (NULL) == -1) { errno = 0; continue; } else break; } logger (LOG_ERR, "poll: `%s'", strerror (errno)); break; } } /* Timed out */ if (s == 0) { if (nprobes < NPROBES) { nprobes ++; timeout = PROBE_INTERVAL; logger (LOG_DEBUG, "sending ARP probe #%d", nprobes); if (send_arp (iface, ARPOP_REQUEST, null_address, NULL, address) == -1) break; /* IEEE1394 cannot set ARP target address * according to RFC2734 */ if (nprobes >= NPROBES && iface->family == ARPHRD_IEEE1394) nclaims = NCLAIMS; } else if (nclaims < NCLAIMS) { nclaims ++; timeout = CLAIM_INTERVAL; logger (LOG_DEBUG, "sending ARP claim #%d", nclaims); if (send_arp (iface, ARPOP_REQUEST, address, iface->hwaddr, address) == -1) break; } else { /* No replies, so done */ retval = 0; break; } /* Setup our stop time */ if (get_time (&stopat) != 0) break; stopat.tv_usec += timeout; continue; } /* We maybe ARP flooded, so check our time */ if (get_time (&now) != 0) break; if (timercmp (&now, &stopat, >)) { timeout = 0; continue; } if (! fds[1].revents & POLLIN) continue; memset (buffer, 0, buflen); do { union { unsigned char *c; struct in_addr *a; } rp; union { unsigned char *c; struct ether_addr *a; } rh; memset (reply, 0, iface->buffer_length); if ((bytes = get_packet (iface, (unsigned char *) reply, buffer, &buflen, &bufpos)) == -1) break; /* Only these types are recognised */ if (reply->ar_op != htons (ARPOP_REPLY)) continue; /* Protocol must be IP. */ if (reply->ar_pro != htons (ETHERTYPE_IP)) continue; if (reply->ar_pln != sizeof (address)) continue; if ((unsigned) bytes < sizeof (reply) + 2 * (4 + reply->ar_hln)) continue; rp.c = (unsigned char *) ar_spa (reply); rh.c = (unsigned char *) ar_sha (reply); /* Ensure the ARP reply is for the our address */ if (rp.a->s_addr != address.s_addr) continue; /* Some systems send a reply back from our hwaddress, * which is wierd */ if (reply->ar_hln == iface->hwlen && memcmp (rh.c, iface->hwaddr, iface->hwlen) == 0) continue; logger (LOG_ERR, "ARPOP_REPLY received from %s (%s)", inet_ntoa (*rp.a), hwaddr_ntoa (rh.c, (size_t) reply->ar_hln)); retval = -1; goto eexit; } while (bufpos != 0); } eexit: close (iface->fd); iface->fd = -1; free (buffer); free (reply); return (retval); } #endif dhcpcd-3.2.3.orig/arp.h0000644000076400001440000000304510760476043013371 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef ARP_H #define ARP_H #ifdef ENABLE_ARP #include #include "interface.h" int arp_claim (interface_t *iface, struct in_addr address); #endif #endif dhcpcd-3.2.3.orig/client.c0000644000076400001440000007120510760476043014063 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #ifdef __linux__ # include #endif #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #ifdef ENABLE_ARP # include "arp.h" #endif #include "client.h" #include "configure.h" #include "dhcp.h" #include "dhcpcd.h" #include "info.h" #include "interface.h" #ifdef ENABLE_IPV4LL # include "ipv4ll.h" #endif #include "logger.h" #include "signal.h" #include "socket.h" #ifdef ENABLE_DUID # include "duid.h" #endif #ifdef ENABLE_INFO # include "info.h" #endif #ifdef THERE_IS_NO_FORK # ifndef ENABLE_INFO # error "Non MMU requires ENABLE_INFO to work" # endif #endif /* Some platforms don't define INFTIM */ #ifndef INFTIM # define INFTIM -1 #endif /* This is out mini timeout. * Basically we resend the last request every TIMEOUT_MINI seconds. */ #define TIMEOUT_MINI 3 /* Except for an infinite timeout. We keep adding TIMEOUT_MINI to * ourself until TIMEOUT_MINI_INF is reached. */ #define TIMEOUT_MINI_INF 60 #define STATE_INIT 0 #define STATE_REQUESTING 1 #define STATE_BOUND 2 #define STATE_RENEWING 3 #define STATE_REBINDING 4 #define STATE_REBOOT 5 #define STATE_RENEW_REQUESTED 6 #define STATE_RELEASED 7 /* We should define a maximum for the NAK exponential backoff */ #define NAKOFF_MAX 60 #define SOCKET_CLOSED 0 #define SOCKET_OPEN 1 /* Indexes for pollfds */ #define POLLFD_SIGNAL 0 #define POLLFD_IFACE 1 typedef struct _state { int *pidfd; bool forked; int state; uint32_t xid; dhcp_t *dhcp; int socket; interface_t *interface; time_t start; time_t last_sent; time_t last_type; long timeout; time_t nakoff; bool daemonised; bool persistent; unsigned char *buffer; size_t buffer_len; size_t buffer_pos; } state_t; static pid_t daemonise (int *pidfd) { pid_t pid; sigset_t full; sigset_t old; #ifdef THERE_IS_NO_FORK char **argv; int i; #endif sigfillset (&full); sigprocmask (SIG_SETMASK, &full, &old); #ifndef THERE_IS_NO_FORK logger (LOG_DEBUG, "forking to background"); switch (pid = fork()) { case -1: logger (LOG_ERR, "fork: %s", strerror (errno)); exit (EXIT_FAILURE); /* NOT REACHED */ case 0: setsid (); close_fds (); break; default: /* Reset our signals as we're the parent about to exit. */ signal_reset (); break; } #else logger (LOG_INFO, "forking to background"); /* We need to add --daemonise to our options */ argv = xmalloc (sizeof (char *) * (dhcpcd_argc + 4)); argv[0] = dhcpcd; for (i = 1; i < dhcpcd_argc; i++) argv[i] = dhcpcd_argv[i]; argv[i] = (char *) "--daemonised"; if (dhcpcd_skiproutes) { argv[++i] = (char *) "--skiproutes"; argv[++i] = dhcpcd_skiproutes; } argv[i + 1] = NULL; switch (pid = vfork ()) { case -1: logger (LOG_ERR, "vfork: %s", strerror (errno)); _exit (EXIT_FAILURE); case 0: signal_reset (); sigprocmask (SIG_SETMASK, &old, NULL); execvp (dhcpcd, argv); logger (LOG_ERR, "execl `%s': %s", dhcpcd, strerror (errno)); _exit (EXIT_FAILURE); } free (argv); #endif /* Done with the fd now */ if (pid != 0) { writepid (*pidfd, pid); close (*pidfd); *pidfd = -1; } sigprocmask (SIG_SETMASK, &old, NULL); return (pid); } #ifdef ENABLE_INFO static bool get_old_lease (state_t *state, const options_t *options) { interface_t *iface = state->interface; dhcp_t *dhcp = state->dhcp; struct timeval tv; unsigned int offset = 0; if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) logger (LOG_INFO, "trying to use old lease in `%s'", iface->infofile); if (! read_info (iface, dhcp)) return (false); /* Vitaly important we remove the server information here */ memset (&dhcp->serveraddress, 0, sizeof (dhcp->serveraddress)); memset (dhcp->servername, 0, sizeof (dhcp->servername)); #ifdef ENABLE_ARP /* Check that no-one is using the address */ if ((options->dolastlease || (IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && (! options->doipv4ll || arp_claim (iface, dhcp->address))))) { memset (&dhcp->address, 0, sizeof (dhcp->address)); memset (&dhcp->netmask, 0, sizeof (dhcp->netmask)); memset (&dhcp->broadcast, 0, sizeof (dhcp->broadcast)); return (false); } /* Ok, lets use this */ if (IN_LINKLOCAL (dhcp->address.s_addr)) return (true); #endif /* Ensure that we can still use the lease */ if (gettimeofday (&tv, NULL) == -1) { logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); return (false); } offset = tv.tv_sec - dhcp->leasedfrom; if (dhcp->leasedfrom && tv.tv_sec - dhcp->leasedfrom > dhcp->leasetime) { logger (LOG_ERR, "lease expired %u seconds ago", offset + dhcp->leasetime); return (false); } if (dhcp->leasedfrom == 0) offset = 0; state->timeout = dhcp->renewaltime - offset; iface->start_uptime = uptime (); return (true); } #endif #ifdef THERE_IS_NO_FORK static void remove_skiproutes (dhcp_t *dhcp, interface_t *iface) { int i = -1; route_t *route; route_t *newroute; free_route (iface->previous_routes); iface->previous_routes = NULL; NSTAILQ_FOREACH (route, dhcp->routes, entries) { i++; /* Check that we did add this route or not */ if (dhcpcd_skiproutes) { char *sk = xstrdup (dhcpcd_skiproutes); char *skp = sk; char *token; bool found = false; while ((token = strsep (&skp, ","))) { if (isdigit (*token) && atoi (token) == i) { found = true; break; } } free (sk); if (found) continue; } if (! iface->previous_routes) { iface->previous_routes = xmalloc (sizeof (*iface->previous_routes)); STAILQ_INIT (iface->previous_routes); } newroute = xmalloc (sizeof (*newroute)); memcpy (newroute, route, sizeof (*newroute)); STAILQ_INSERT_TAIL (iface->previous_routes, newroute, entries); } /* We no longer need this argument */ free (dhcpcd_skiproutes); dhcpcd_skiproutes = NULL; } #endif static bool client_setup (state_t *state, const options_t *options) { dhcp_t *dhcp = state->dhcp; interface_t *iface = state->interface; state->state = STATE_INIT; state->last_type = DHCP_DISCOVER; state->nakoff = 1; state->daemonised = options->daemonised; state->persistent = options->persistent; if (options->request_address.s_addr == 0 && (options->doinform || options->dorequest || options->daemonised)) { #ifdef ENABLE_INFO if (! get_old_lease (state, options)) #endif { free (dhcp); return (false); } state->timeout = 0; if (! options->daemonised && IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) { logger (LOG_ERR, "cannot request a link local address"); return (false); } #ifdef THERE_IS_NO_FORK if (options->daemonised) { state->state = STATE_BOUND; state->timeout = dhcp->renewaltime; iface->previous_address = dhcp->address; iface->previous_netmask = dhcp->netmask; remove_skiproutes (dhcp, iface); } #endif } else { dhcp->address = options->request_address; dhcp->netmask = options->request_netmask; if (dhcp->netmask.s_addr == 0) dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); dhcp->broadcast.s_addr = dhcp->address.s_addr | ~dhcp->netmask.s_addr; } /* Remove all existing addresses. * After all, we ARE a DHCP client whose job it is to configure the * interface. We only do this on start, so persistent addresses * can be added afterwards by the user if needed. */ if (! options->test && ! options->daemonised) { if (! options->doinform) { flush_addresses (iface->name); } else { /* The inform address HAS to be configured for it to * work with most DHCP servers */ if (options->doinform && has_address (iface->name, dhcp->address) < 1) { add_address (iface->name, dhcp->address, dhcp->netmask, dhcp->broadcast); iface->previous_address = dhcp->address; iface->previous_netmask = dhcp->netmask; } } } if (*options->clientid) { /* Attempt to see if the ClientID is a hardware address */ iface->clientid_len = hwaddr_aton (NULL, options->clientid); if (iface->clientid_len) { iface->clientid = xmalloc (iface->clientid_len); hwaddr_aton (iface->clientid, options->clientid); } else { /* Nope, so mark it as-is */ iface->clientid_len = strlen (options->clientid) + 1; iface->clientid = xmalloc (iface->clientid_len); *iface->clientid = '\0'; memcpy (iface->clientid + 1, options->clientid, iface->clientid_len - 1); } } else { #ifdef ENABLE_DUID unsigned char *duid = NULL; size_t duid_len = 0; if (options->doduid) { duid = xmalloc (DUID_LEN); duid_len = get_duid (duid, iface); } if (duid_len > 0) { logger (LOG_INFO, "DUID = %s", hwaddr_ntoa (duid, duid_len)); iface->clientid_len = duid_len + 5; iface->clientid = xmalloc (iface->clientid_len); *iface->clientid = 255; /* RFC 4361 */ /* IAID is 4 bytes, so if the iface name is 4 bytes use it */ if (strlen (iface->name) == 4) { memcpy (iface->clientid + 1, iface->name, 4); } else { /* Name isn't 4 bytes, so use the index */ uint32_t ul = htonl (if_nametoindex (iface->name)); memcpy (iface->clientid + 1, &ul, 4); } memcpy (iface->clientid + 5, duid, duid_len); free (duid); } else { #else { #endif iface->clientid_len = iface->hwlen + 1; iface->clientid = xmalloc (iface->clientid_len); *iface->clientid = iface->family; memcpy (iface->clientid + 1, iface->hwaddr, iface->hwlen); } } return (true); } static bool do_socket (state_t *state, int mode) { if (state->interface->fd >= 0) close (state->interface->fd); #ifdef __linux if (mode == SOCKET_CLOSED && state->interface->listen_fd >= 0) { close (state->interface->listen_fd); state->interface->listen_fd = -1; } #endif state->interface->fd = -1; if (mode == SOCKET_OPEN) if (open_socket (state->interface, ETHERTYPE_IP) == -1) return (false); state->socket = mode; return (true); } static bool _send_message (state_t *state, int type, const options_t *options) { ssize_t retval; state->last_type = type; state->last_sent = uptime (); retval = send_message (state->interface, state->dhcp, state->xid, type, options); return (retval == -1 ? false : true); } static void drop_config (state_t *state, const options_t *options) { if (! state->persistent) configure (options, state->interface, state->dhcp, false); free_dhcp (state->dhcp); memset (state->dhcp, 0, sizeof (*state->dhcp)); } static int wait_for_packet (struct pollfd *fds, state_t *state, const options_t *options) { dhcp_t *dhcp = state->dhcp; interface_t *iface = state->interface; int timeout = 0; int retval = 0; if (! (state->timeout > 0 || (options->timeout == 0 && (state->state != STATE_INIT || state->xid)))) { /* We need to zero our signal fd, otherwise we will block * trying to read a signal. */ fds[POLLFD_SIGNAL].revents = 0; return (0); } fds[POLLFD_IFACE].fd = iface->fd; if ((options->timeout == 0 && state->xid) || (dhcp->leasetime == (unsigned) -1 && state->state == STATE_BOUND)) { logger (LOG_DEBUG, "waiting for infinity"); while (retval == 0) { if (iface->fd == -1) retval = poll (fds, 1, INFTIM); else { /* Slow down our requests */ if (timeout < TIMEOUT_MINI_INF) timeout += TIMEOUT_MINI; else if (timeout > TIMEOUT_MINI_INF) timeout = TIMEOUT_MINI_INF; retval = poll (fds, 2, timeout * 1000); if (retval == -1 && errno == EINTR) { /* If interupted, continue as normal as * the signal will be delivered down * the pipe */ retval = 0; continue; } if (retval == 0) _send_message (state, state->last_type, options); } } return (retval); } /* Resend our message if we're getting loads of packets. * As we use BPF or LPF, we shouldn't hit this as much, but it's * still nice to have. */ if (iface->fd > -1 && uptime () - state->last_sent >= TIMEOUT_MINI) _send_message (state, state->last_type, options); logger (LOG_DEBUG, "waiting for %ld seconds", (unsigned long) state->timeout); /* If we're waiting for a reply, then we re-send the last * DHCP request periodically in-case of a bad line */ retval = 0; while (state->timeout > 0 && retval == 0) { if (iface->fd == -1) timeout = (int) state->timeout; else { timeout = TIMEOUT_MINI; if (state->timeout < timeout) timeout = (int) state->timeout; } timeout *= 1000; state->start = uptime (); retval = poll (fds, iface->fd == -1 ? 1 : 2, timeout); state->timeout -= uptime () - state->start; if (retval == -1 && errno == EINTR) { /* If interupted, continue as normal as the signal * will be delivered down the pipe */ retval = 0; continue; } if (retval == 0 && iface->fd != -1 && state->timeout > 0) _send_message (state, state->last_type, options); } return (retval); } static bool handle_signal (int sig, state_t *state, const options_t *options) { switch (sig) { case SIGINT: logger (LOG_INFO, "received SIGINT, stopping"); return (false); case SIGTERM: logger (LOG_INFO, "received SIGTERM, stopping"); return (false); case SIGALRM: logger (LOG_INFO, "received SIGALRM, renewing lease"); switch (state->state) { case STATE_BOUND: case STATE_RENEWING: case STATE_REBINDING: state->state = STATE_RENEW_REQUESTED; break; case STATE_RENEW_REQUESTED: case STATE_REQUESTING: case STATE_RELEASED: state->state = STATE_INIT; break; } state->timeout = 0; state->xid = 0; return (true); case SIGHUP: if (state->state != STATE_BOUND && state->state != STATE_RENEWING && state->state != STATE_REBINDING) { logger (LOG_ERR, "received SIGHUP, but we no have lease to release"); return (false); } logger (LOG_INFO, "received SIGHUP, releasing lease"); if (! IN_LINKLOCAL (ntohl (state->dhcp->address.s_addr))) { do_socket (state, SOCKET_OPEN); state->xid = (uint32_t) random (); if ((open_socket (state->interface, false)) >= 0) _send_message (state, DHCP_RELEASE, options); do_socket (state, SOCKET_CLOSED); } unlink (state->interface->infofile); return (false); default: logger (LOG_ERR, "received signal %d, but don't know what to do with it", sig); } return (false); } static int handle_timeout (state_t *state, const options_t *options) { dhcp_t *dhcp = state->dhcp; interface_t *iface = state->interface; /* No NAK, so reset the backoff */ state->nakoff = 1; if (state->state == STATE_INIT && state->xid != 0) { if (iface->previous_address.s_addr != 0 && ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr)) && ! options->doinform) { logger (LOG_ERR, "lost lease"); if (! options->persistent) drop_config (state, options); } else if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) logger (LOG_ERR, "timed out"); do_socket (state, SOCKET_CLOSED); free_dhcp (dhcp); memset (dhcp, 0, sizeof (*dhcp)); #ifdef ENABLE_INFO if (! options->test && (options->doipv4ll || options->dolastlease)) { errno = 0; if (! get_old_lease (state, options)) { if (errno == EINTR) return (0); if (options->dolastlease) return (-1); free_dhcp (dhcp); memset (dhcp, 0, sizeof (*dhcp)); } else if (errno == EINTR) return (0); } #endif #ifdef ENABLE_IPV4LL if (! options->test && options->doipv4ll && (! dhcp->address.s_addr || (! IN_LINKLOCAL (ntohl (dhcp->address.s_addr)) && ! options->dolastlease))) { logger (LOG_INFO, "probing for an IPV4LL address"); free_dhcp (dhcp); memset (dhcp, 0, sizeof (*dhcp)); if (ipv4ll_get_address (iface, dhcp) == -1) { if (! state->daemonised) return (-1); /* start over */ state->xid = 0; return (0); } state->timeout = dhcp->renewaltime; } #endif #if defined (ENABLE_INFO) || defined (ENABLE_IPV4LL) if (dhcp->address.s_addr) { if (! state->daemonised && IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) logger (LOG_WARNING, "using IPV4LL address %s", inet_ntoa (dhcp->address)); if (configure (options, iface, dhcp, true) == -1 && ! state->daemonised) return (-1); state->state = STATE_BOUND; if (! state->daemonised && options->daemonise) { switch (daemonise (state->pidfd)) { case -1: return (-1); case 0: state->daemonised = true; return (0); default: state->persistent = true; state->forked = true; return (-1); } } state->timeout = dhcp->renewaltime; state->xid = 0; return (0); } #endif if (! state->daemonised) return (-1); } switch (state->state) { case STATE_INIT: state->xid = (uint32_t) random (); do_socket (state, SOCKET_OPEN); state->timeout = options->timeout; iface->start_uptime = uptime (); if (dhcp->address.s_addr == 0) { if (! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) logger (LOG_INFO, "broadcasting for a lease"); _send_message (state, DHCP_DISCOVER, options); } else if (options->doinform) { logger (LOG_INFO, "broadcasting inform for %s", inet_ntoa (dhcp->address)); _send_message (state, DHCP_INFORM, options); state->state = STATE_REQUESTING; } else { logger (LOG_INFO, "broadcasting for a lease of %s", inet_ntoa (dhcp->address)); _send_message (state, DHCP_REQUEST, options); state->state = STATE_REQUESTING; } break; case STATE_BOUND: case STATE_RENEW_REQUESTED: if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) { memset (&dhcp->address, 0, sizeof (dhcp->address)); state->state = STATE_INIT; state->xid = 0; break; } state->state = STATE_RENEWING; state->xid = (uint32_t) random (); /* FALLTHROUGH */ case STATE_RENEWING: iface->start_uptime = uptime (); logger (LOG_INFO, "renewing lease of %s", inet_ntoa (dhcp->address)); do_socket (state, SOCKET_OPEN); _send_message (state, DHCP_REQUEST, options); state->timeout = dhcp->rebindtime - dhcp->renewaltime; state->state = STATE_REBINDING; break; case STATE_REBINDING: logger (LOG_ERR, "lost lease, attemping to rebind"); memset (&dhcp->address, 0, sizeof (dhcp->address)); do_socket (state, SOCKET_OPEN); if (state->xid == 0) state->xid = (uint32_t) random (); dhcp->serveraddress.s_addr = 0; _send_message (state, DHCP_REQUEST, options); state->timeout = dhcp->leasetime - dhcp->rebindtime; state->state = STATE_REQUESTING; break; case STATE_REQUESTING: state->state = STATE_INIT; do_socket (state, SOCKET_CLOSED); state->timeout = 0; break; case STATE_RELEASED: dhcp->leasetime = 0; break; } return (0); } static int handle_dhcp (state_t *state, int type, const options_t *options) { struct timespec ts; interface_t *iface = state->interface; dhcp_t *dhcp = state->dhcp; /* We should restart on a NAK */ if (type == DHCP_NAK) { logger (LOG_INFO, "received NAK: %s", dhcp->message); state->state = STATE_INIT; state->timeout = 0; state->xid = 0; free_dhcp (dhcp); memset (dhcp, 0, sizeof (*dhcp)); /* If we constantly get NAKS then we should slowly back off */ if (state->nakoff > 0) { logger (LOG_DEBUG, "sleeping for %ld seconds", (long) state->nakoff); ts.tv_sec = state->nakoff; ts.tv_nsec = 0; state->nakoff *= 2; if (state->nakoff > NAKOFF_MAX) state->nakoff = NAKOFF_MAX; nanosleep (&ts, NULL); } return (0); } /* No NAK, so reset the backoff */ state->nakoff = 1; if (type == DHCP_OFFER && state->state == STATE_INIT) { char *addr = strdup (inet_ntoa (dhcp->address)); if (dhcp->servername[0]) logger (LOG_INFO, "offered %s from %s `%s'", addr, inet_ntoa (dhcp->serveraddress), dhcp->servername); else logger (LOG_INFO, "offered %s from %s", addr, inet_ntoa (dhcp->serveraddress)); free (addr); #ifdef ENABLE_INFO if (options->test) { write_info (iface, dhcp, options, false); errno = 0; return (-1); } #endif _send_message (state, DHCP_REQUEST, options); state->state = STATE_REQUESTING; return (0); } if (type == DHCP_OFFER) { logger (LOG_INFO, "got subsequent offer of %s, ignoring ", inet_ntoa (dhcp->address)); return (0); } /* We should only be dealing with acks */ if (type != DHCP_ACK) { logger (LOG_ERR, "%d not an ACK or OFFER", type); return (0); } switch (state->state) { case STATE_RENEW_REQUESTED: case STATE_REQUESTING: case STATE_RENEWING: case STATE_REBINDING: break; default: logger (LOG_ERR, "wrong state %d", state->state); } do_socket (state, SOCKET_CLOSED); #ifdef ENABLE_ARP if (options->doarp && iface->previous_address.s_addr != dhcp->address.s_addr) { errno = 0; if (arp_claim (iface, dhcp->address)) { do_socket (state, SOCKET_OPEN); _send_message (state, DHCP_DECLINE, options); do_socket (state, SOCKET_CLOSED); free_dhcp (dhcp); memset (dhcp, 0, sizeof (*dhcp)); state->xid = 0; state->timeout = 0; state->state = STATE_INIT; /* RFC 2131 says that we should wait for 10 seconds * before doing anything else */ logger (LOG_INFO, "sleeping for 10 seconds"); ts.tv_sec = 10; ts.tv_nsec = 0; nanosleep (&ts, NULL); return (0); } else if (errno == EINTR) return (0); } #endif if (options->doinform) { if (options->request_address.s_addr != 0) dhcp->address = options->request_address; else dhcp->address = iface->previous_address; logger (LOG_INFO, "received approval for %s", inet_ntoa (dhcp->address)); if (iface->previous_netmask.s_addr != dhcp->netmask.s_addr) { add_address (iface->name, dhcp->address, dhcp->netmask, dhcp->broadcast); iface->previous_netmask.s_addr = dhcp->netmask.s_addr; } state->timeout = options->leasetime; if (state->timeout == 0) state->timeout = DEFAULT_LEASETIME; state->state = STATE_INIT; } else if (dhcp->leasetime == (unsigned) -1) { dhcp->renewaltime = dhcp->rebindtime = dhcp->leasetime; state->timeout = 1; /* So we wait for infinity */ logger (LOG_INFO, "leased %s for infinity", inet_ntoa (dhcp->address)); state->state = STATE_BOUND; } else { if (! dhcp->leasetime) { dhcp->leasetime = DEFAULT_LEASETIME; logger(LOG_INFO, "no lease time supplied, assuming %d seconds", dhcp->leasetime); } logger (LOG_INFO, "leased %s for %u seconds", inet_ntoa (dhcp->address), dhcp->leasetime); if (dhcp->rebindtime >= dhcp->leasetime) { dhcp->rebindtime = (dhcp->leasetime * 0.875); logger (LOG_ERR, "rebind time greater than lease " "time, forcing to %u seconds", dhcp->rebindtime); } if (dhcp->renewaltime > dhcp->rebindtime) { dhcp->renewaltime = (dhcp->leasetime * 0.5); logger (LOG_ERR, "renewal time greater than rebind time, " "forcing to %u seconds", dhcp->renewaltime); } if (! dhcp->renewaltime) { dhcp->renewaltime = (dhcp->leasetime * 0.5); logger (LOG_INFO, "no renewal time supplied, assuming %d seconds", dhcp->renewaltime); } else logger (LOG_DEBUG, "renew in %u seconds", dhcp->renewaltime); if (! dhcp->rebindtime) { dhcp->rebindtime = (dhcp->leasetime * 0.875); logger (LOG_INFO, "no rebind time supplied, assuming %d seconds", dhcp->rebindtime); } else logger (LOG_DEBUG, "rebind in %u seconds", dhcp->rebindtime); state->timeout = dhcp->renewaltime; state->state = STATE_BOUND; } state->xid = 0; if (configure (options, iface, dhcp, true) == -1 && ! state->daemonised) return (-1); if (! state->daemonised && options->daemonise) { switch (daemonise (state->pidfd)) { case 0: state->daemonised = true; return (0); case -1: return (-1); default: state->persistent = true; state->forked = true; return (-1); } } return (0); } static int handle_packet (state_t *state, const options_t *options) { interface_t *iface = state->interface; bool valid = false; int type; struct dhcp_t *new_dhcp; dhcpmessage_t message; /* Allocate our buffer space for BPF. * We cannot do this until we have opened our socket as we don't * know how much of a buffer we need until then. */ if (! state->buffer) state->buffer = xmalloc (iface->buffer_length); state->buffer_len = iface->buffer_length; state->buffer_pos = 0; /* We loop through until our buffer is empty. * The benefit is that if we get >1 DHCP packet in our buffer and * the first one fails for any reason, we can use the next. */ memset (&message, 0, sizeof (message)); new_dhcp = xmalloc (sizeof (*new_dhcp)); do { if (get_packet (iface, (unsigned char *) &message, state->buffer, &state->buffer_len, &state->buffer_pos) == -1) break; if (state->xid != message.xid) { logger (LOG_DEBUG, "ignoring packet with xid 0x%x as it's not ours (0x%x)", message.xid, state->xid); continue; } logger (LOG_DEBUG, "got a packet with xid 0x%x", message.xid); memset (new_dhcp, 0, sizeof (*new_dhcp)); type = parse_dhcpmessage (new_dhcp, &message); if (type == -1) { logger (LOG_ERR, "failed to parse packet"); free_dhcp (new_dhcp); /* We don't abort on this, so return zero */ return (0); } /* If we got here then the DHCP packet is valid and appears to * be for us, so let's clear the buffer as we don't care about * any more DHCP packets at this point. */ valid = true; break; } while (state->buffer_pos != 0); /* No packets for us, so wait until we get one */ if (! valid) { free (new_dhcp); return (0); } /* new_dhcp is now our master DHCP message */ free_dhcp (state->dhcp); free (state->dhcp); state->dhcp = new_dhcp; new_dhcp = NULL; return (handle_dhcp (state, type, options)); } int dhcp_run (const options_t *options, int *pidfd) { interface_t *iface; state_t *state = NULL; struct pollfd fds[] = { { -1, POLLIN, 0 }, { -1, POLLIN, 0 } }; int retval = -1; int sig; if (! options) return (-1); iface = read_interface (options->interface, options->metric); if (! iface) goto eexit; state = xzalloc (sizeof (*state)); state->dhcp = xzalloc (sizeof (*state->dhcp)); state->pidfd = pidfd; state->interface = iface; if (! client_setup (state, options)) goto eexit; if (signal_init () == -1) goto eexit; if (signal_setup () == -1) goto eexit; fds[POLLFD_SIGNAL].fd = signal_fd (); for (;;) { retval = wait_for_packet (fds, state, options); /* We should always handle our signals first */ if ((sig = (signal_read (&fds[POLLFD_SIGNAL]))) != -1) { if (handle_signal (sig, state, options)) retval = 0; else retval = -1; } else if (retval == 0) retval = handle_timeout (state, options); else if (retval > 0 && state->socket != SOCKET_CLOSED && fds[POLLFD_IFACE].revents & POLLIN) retval = handle_packet (state, options); else if (retval == -1 && errno == EINTR) { /* The interupt will be handled above */ retval = 0; } else { logger (LOG_ERR, "poll: %s", strerror (errno)); retval = -1; } if (retval != 0) break; } eexit: if (iface) { do_socket (state, SOCKET_CLOSED); drop_config (state, options); free_route (iface->previous_routes); free (iface->clientid); free (iface); } if (state) { if (state->forked) retval = 0; if (state->daemonised) unlink (options->pidfile); free_dhcp (state->dhcp); free (state->dhcp); free (state->buffer); free (state); } return (retval); } dhcpcd-3.2.3.orig/client.h0000644000076400001440000000275710760476043014076 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CLIENT_H #define CLIENT_H #include "dhcpcd.h" int dhcp_run (const options_t *options, int *pidfd); #endif dhcpcd-3.2.3.orig/common.c0000644000076400001440000001261110760476043014071 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "common.h" #include "logger.h" /* Handy routine to read very long lines in text files. * This means we read the whole line and avoid any nasty buffer overflows. */ char *get_line (FILE *fp) { char *line = NULL; char *p; size_t len = 0; size_t last = 0; if (feof (fp)) return (NULL); do { len += BUFSIZ; line = xrealloc (line, sizeof (char) * len); p = line + last; memset (p, 0, BUFSIZ); fgets (p, BUFSIZ, fp); last += strlen (p); } while (! feof (fp) && line[last - 1] != '\n'); /* Trim the trailing newline */ if (*line && line[--last] == '\n') line[last] = '\0'; return (line); } /* OK, this should be in dhcpcd.c * It's here to make dhcpcd more readable */ #ifndef HAVE_SRANDOMDEV void srandomdev (void) { int fd; unsigned long seed; fd = open ("/dev/urandom", 0); if (fd == -1 || read (fd, &seed, sizeof (seed)) == -1) { logger (LOG_WARNING, "Could not read from /dev/urandom: %s", strerror (errno)); seed = time (0); } if (fd >= 0) close(fd); srandom (seed); } #endif /* strlcpy is nice, shame glibc does not define it */ #ifndef HAVE_STRLCPY size_t strlcpy (char *dst, const char *src, size_t size) { const char *s = src; size_t n = size; if (n && --n) do { if (! (*dst++ = *src++)) break; } while (--n); if (! n) { if (size) *dst = '\0'; while (*src++); } return (src - s - 1); } #endif /* Close our fd's */ int close_fds (void) { int fd; if ((fd = open ("/dev/null", O_RDWR)) == -1) { logger (LOG_ERR, "open `/dev/null': %s", strerror (errno)); return (-1); } dup2 (fd, fileno (stdin)); dup2 (fd, fileno (stdout)); dup2 (fd, fileno (stderr)); if (fd > 2) close (fd); return (0); } int close_on_exec (int fd) { int flags; if ((flags = fcntl (fd, F_GETFD, 0)) == -1 || fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1) { logger (LOG_ERR, "fcntl: %s", strerror (errno)); return (-1); } return (0); } /* Handy function to get the time. * We only care about time advancements, not the actual time itself * Which is why we use CLOCK_MONOTONIC, but it is not available on all * platforms. */ int get_time (struct timeval *tp) { #if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC) struct timespec ts; static clockid_t posix_clock; static int posix_clock_set = 0; if (! posix_clock_set) { if (sysconf (_SC_MONOTONIC_CLOCK) >= 0) posix_clock = CLOCK_MONOTONIC; else posix_clock = CLOCK_REALTIME; posix_clock_set = 1; } if (clock_gettime (posix_clock, &ts) == -1) { logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); return (-1); } tp->tv_sec = ts.tv_sec; tp->tv_usec = ts.tv_nsec / 1000; return (0); #else if (gettimeofday (tp, NULL) == -1) { logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); return (-1); } return (0); #endif } time_t uptime (void) { struct timeval tp; if (get_time (&tp) == -1) return (-1); return (tp.tv_sec); } void writepid (int fd, pid_t pid) { char spid[16]; if (ftruncate (fd, (off_t) 0) == -1) { logger (LOG_ERR, "ftruncate: %s", strerror (errno)); } else { ssize_t len; snprintf (spid, sizeof (spid), "%u", pid); len = pwrite (fd, spid, strlen (spid), (off_t) 0); if (len != (ssize_t) strlen (spid)) logger (LOG_ERR, "pwrite: %s", strerror (errno)); } } void *xmalloc (size_t s) { void *value = malloc (s); if (value) return (value); logger (LOG_ERR, "memory exhausted"); exit (EXIT_FAILURE); /* NOTREACHED */ } void *xzalloc (size_t s) { void *value = xmalloc (s); memset (value, 0, s); return (value); } void *xrealloc (void *ptr, size_t s) { void *value = realloc (ptr, s); if (value) return (value); logger (LOG_ERR, "memory exhausted"); exit (EXIT_FAILURE); /* NOTREACHED */ } char *xstrdup (const char *str) { char *value; if (! str) return (NULL); if ((value = strdup (str))) return (value); logger (LOG_ERR, "memory exhausted"); exit (EXIT_FAILURE); /* NOTREACHED */ } dhcpcd-3.2.3.orig/common.h0000644000076400001440000000446610760476043014107 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef COMMON_H #define COMMON_H /* string.h pulls in features.h so the below define checks work */ #include #include #include #if __GNUC__ > 2 || defined(__INTEL_COMPILER) # define _unused __attribute__((__unused__)) #else # define _unused #endif #define HAVE_STRLCPY /* Only GLIBC doesn't support strlcpy */ #ifdef __GLIBC__ # if ! defined(__UCLIBC__) && ! defined (__dietlibc__) # undef HAVE_STRLCPY size_t strlcpy (char *dst, const char *src, size_t size); # endif #endif #define HAVE_SRANDOMDEV #if defined(__GLIBC__) || defined(__NetBSD__) # undef HAVE_SRANDOMDEV void srandomdev (void); #endif int close_fds (void); int close_on_exec (int fd); char *get_line (FILE *fp); int get_time (struct timeval *tp); time_t uptime (void); void writepid (int fd, pid_t pid); void *xrealloc (void *ptr, size_t size); void *xmalloc (size_t size); void *xzalloc (size_t size); char *xstrdup (const char *str); #endif dhcpcd-3.2.3.orig/config.h0000644000076400001440000001116010760476043014051 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef CONFIG_H #define CONFIG_H /* You can enable/disable various chunks of optional code here. * You would only do this to try and shrink the end binary if dhcpcd * was running on a low memory device */ #define ENABLE_ARP #define ENABLE_NTP #define ENABLE_NIS #define ENABLE_INFO /* Define this to enable some compatability with 1.x and 2.x info files */ /* #define ENABLE_INFO_COMPAT */ /* IPV4LL, aka ZeroConf, aka APIPA, aka RFC 3927. * Needs ARP. */ #define ENABLE_IPV4LL /* We will auto create a DUID_LLT file if it doesn't exist. * You can always create your own DUID file that just contains the * hex string that represents the DUID. * See RFC 3315 for details on this. */ #define ENABLE_DUID /* resolvconf is framework for multiple interfaces to manage resolv.conf */ #define ENABLE_RESOLVCONF /* Some systems do not have a working fork. * The Makefile will attempt to work it out, but if it fails to feel free to * define it here. */ /* #define THERE_IS_NO_FORK */ /* Packname name and pathname definitions. */ #define PACKAGE "dhcpcd" #define ETCDIR "/etc" #define RESOLVFILE ETCDIR "/resolv.conf" #define NISFILE ETCDIR "/yp.conf" #define NTPFILE ETCDIR "/ntp.conf" #define NTPDRIFTFILE ETCDIR "/ntp.drift" #define NTPLOGFILE "/var/log/ntp.log" #define OPENNTPFILE ETCDIR "/ntpd.conf" #define DEFAULT_SCRIPT ETCDIR "/" PACKAGE ".sh" #define STATEDIR "/var" #define PIDFILE STATEDIR "/run/" PACKAGE "-%s.pid" #ifndef INFODIR # define INFODIR "/var/lib/dhcpcd" #endif #define INFOFILE INFODIR "/" PACKAGE "-%s.info" #define DUIDFILE INFODIR "/" PACKAGE ".duid" /* OPENRC is Open Run Control, forked from Gentoo's baselayout package * BSDRC is BSD style Run Control * SLACKRC is Slackware Run Control * SERVICE is RedHat service command * SYSV should cover everthing else */ #ifdef ENABLE_OPENRC # define SERVICE "OPENRC" # define NISSERVICE ETCDIR "/init.d/ypbind" # define NISRESTARTARGS "--nodeps", "--quiet", "conditionalrestart" # define NTPSERVICE ETCDIR "/init.d/ntpd" # define NTPRESTARTARGS "--nodeps", "--quiet", "conditionalrestart" #endif #if ENABLE_BSDRC # define SERVICE "BSDRC" # define NISSERVICE ETCDIR "/rc.d/ypbind" # define NISRESTARTARGS "restart" # define NTPSERVICE ETCDIR "/rc.d/ntpd" # define NTPRESTARTARGS "restart" #endif #if ENABLE_SLACKRC # define SERVICE "SLACKRC" # define NISSERVICE ETCDIR "/rc.d/rc.ypbind" # define NISRESTARTARGS "restart" # define NTPSERVICE ETCDIR "/rc.d/rc.ntpd" # define NTPRESTARTARGS "restart" #endif #if ENABLE_SERVICE # define SERVICE "SERVICE" # define NISSERVICE "service" # define NISRESTARTARGS "ypbind", "restart" # define NTPSERVICE "service" # define NTPRESTARTARGS "ntpd", "restart" #endif #if ENABLE_SYSV # define SERVICE "SYSV" # define NISSERVICE ETCDIR "/init.d/ypbind" # define NISRESTARTARGS "restart" # define NTPSERVICE ETCDIR "/init.d/ntpd" # define NTPRESTARTARGS "restart" #endif #ifndef NISSERVICE # undef ENABLE_NIS #endif #ifndef NTPSERVICE # undef ENABLE_NTP #endif #endif dhcpcd-3.2.3.orig/configure.c0000644000076400001440000004750610760476043014575 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #ifdef __linux__ # include #endif #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "configure.h" #include "dhcp.h" #ifdef ENABLE_INFO # include "info.h" #endif #include "interface.h" #include "dhcpcd.h" #include "logger.h" #include "signal.h" #include "socket.h" static int file_in_path (const char *file) { char *p = getenv ("PATH"); char *path; char *token; struct stat s; char mypath[PATH_MAX]; int retval = -1; if (! p) { errno = ENOENT; return (-1); } path = strdup (p); p = path; while ((token = strsep (&p, ":"))) { snprintf (mypath, PATH_MAX, "%s/%s", token, file); if (stat (mypath, &s) == 0) { retval = 0; break; } } free (path); return (retval); } /* IMPORTANT: Ensure that the last parameter is NULL when calling */ static int exec_cmd (const char *cmd, const char *args, ...) { va_list va; char **argv; int n = 1; int ret = 0; pid_t pid; sigset_t full; sigset_t old; va_start (va, args); while (va_arg (va, char *) != NULL) n++; va_end (va); argv = xmalloc (sizeof (char *) * (n + 2)); va_start (va, args); n = 2; argv[0] = (char *) cmd; argv[1] = (char *) args; while ((argv[n] = va_arg (va, char *)) != NULL) n++; va_end (va); /* OK, we need to block signals */ sigfillset (&full); sigprocmask (SIG_SETMASK, &full, &old); #ifdef THERE_IS_NO_FORK signal_reset (); pid = vfork (); #else pid = fork(); #endif switch (pid) { case -1: logger (LOG_ERR, "vfork: %s", strerror (errno)); ret = -1; break; case 0: #ifndef THERE_IS_NO_FORK signal_reset (); #endif sigprocmask (SIG_SETMASK, &old, NULL); if (execvp (cmd, argv) && errno != ENOENT) logger (LOG_ERR, "error executing \"%s\": %s", cmd, strerror (errno)); _exit (111); /* NOTREACHED */ } #ifdef THERE_IS_NO_FORK signal_setup (); #endif /* Restore our signals */ sigprocmask (SIG_SETMASK, &old, NULL); free (argv); return (ret); } static void exec_script (const char *script, const char *infofile, const char *arg) { struct stat buf; if (! script || ! infofile || ! arg) return; if (stat (script, &buf) == -1) { if (strcmp (script, DEFAULT_SCRIPT) != 0) logger (LOG_ERR, "`%s': %s", script, strerror (ENOENT)); return; } #ifdef ENABLE_INFO logger (LOG_DEBUG, "exec \"%s\" \"%s\" \"%s\"", script, infofile, arg); exec_cmd (script, infofile, arg, (char *) NULL); #else logger (LOG_DEBUG, "exec \"%s\" \"\" \"%s\"", script, arg); exec_cmd (script, "", arg, (char *) NULL); #endif } static int make_resolv (const char *ifname, const dhcp_t *dhcp) { FILE *f = NULL; address_t *address; #ifdef ENABLE_RESOLVCONF char *resolvconf = NULL; if (file_in_path ("resolvconf") == 0) { size_t len = strlen ("resolvconf -a ") + strlen (ifname) + 1; resolvconf = xmalloc (sizeof (char) * len); snprintf (resolvconf, len, "resolvconf -a %s", ifname); if ((f = popen (resolvconf , "w"))) logger (LOG_DEBUG, "sending DNS information to resolvconf"); else if (errno == EEXIST) logger (LOG_ERR, "popen: %s", strerror (errno)); if (ferror (f)) logger (LOG_ERR, "ferror"); free (resolvconf); } #endif if (! f) { logger (LOG_DEBUG, "writing "RESOLVFILE); if (! (f = fopen(RESOLVFILE, "w"))) logger (LOG_ERR, "fopen `%s': %s", RESOLVFILE, strerror (errno)); } if (! f) return (-1); fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); if (dhcp->dnssearch) fprintf (f, "search %s\n", dhcp->dnssearch); else if (dhcp->dnsdomain) { fprintf (f, "search %s\n", dhcp->dnsdomain); } STAILQ_FOREACH (address, dhcp->dnsservers, entries) fprintf (f, "nameserver %s\n", inet_ntoa (address->address)); #ifdef ENABLE_RESOLVCONF if (resolvconf) pclose (f); else #endif fclose (f); /* Refresh the local resolver */ res_init (); return (0); } static void restore_resolv (const char *ifname) { #ifdef ENABLE_RESOLVCONF if (file_in_path ("resolvconf") == 0) { logger (LOG_DEBUG, "removing information from resolvconf"); exec_cmd("resolvconf", "-d", ifname, (char *) NULL); } #endif } static bool in_addresses (const struct address_head *addresses, struct in_addr address) { const address_t *addr; STAILQ_FOREACH (addr, addresses, entries) if (addr->address.s_addr == address.s_addr) return (true); return (false); } static bool in_routes (const struct route_head *routes, route_t *route) { const route_t *r; if (! routes) return (false); STAILQ_FOREACH (r, routes, entries) if (r->destination.s_addr == route->destination.s_addr && r->netmask.s_addr == route->netmask.s_addr && r->gateway.s_addr == route->gateway.s_addr) return (true); return (false); } #ifdef ENABLE_NTP static int _make_ntp (const char *file, const char *ifname, const dhcp_t *dhcp) { FILE *f; address_t *address; char *a; char *line; int tomatch = 0; char *token; bool ntp = false; STAILQ_FOREACH (address, dhcp->ntpservers, entries) tomatch++; /* Check that we really need to update the servers. * We do this because ntp has to be restarted to * work with a changed config. */ if (! (f = fopen (file, "r"))) { if (errno != ENOENT) { logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno)); return (-1); } } else { while (tomatch != 0 && (line = get_line (f))) { struct in_addr addr; a = line; token = strsep (&a, " "); if (! token || strcmp (token, "server") != 0) goto next; if ((token = strsep (&a, " \n")) == NULL) goto next; if (inet_aton (token, &addr) == 1 && in_addresses (dhcp->ntpservers, addr)) tomatch--; next: free (line); } fclose (f); /* File has the same name servers that we do, * so no need to restart ntp */ if (tomatch == 0) { logger (LOG_DEBUG, "%s already configured, skipping", file); return (0); } } logger (LOG_DEBUG, "writing %s", file); if (! (f = fopen (file, "w"))) { logger (LOG_ERR, "fopen `%s': %s", file, strerror (errno)); return (-1); } fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); #ifdef NTPFILE if (strcmp (file, NTPFILE) == 0) { ntp = true; fprintf (f, "restrict default noquery notrust nomodify\n"); fprintf (f, "restrict 127.0.0.1\n"); } #endif STAILQ_FOREACH (address, dhcp->ntpservers, entries) { a = inet_ntoa (address->address); if (ntp) fprintf (f, "restrict %s nomodify notrap noquery\n", a); fprintf (f, "server %s\n", a); } fclose (f); return (1); } 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. */ bool restart_ntp = false; bool restart_openntp = false; int retval = 0; #ifdef NTPFILE if (_make_ntp (NTPFILE, ifname, dhcp) > 0) restart_ntp = true; #endif #ifdef OPENNTPFILE if (_make_ntp (OPENNTPFILE, ifname, dhcp) > 0) restart_openntp = true; #endif #ifdef NTPSERVICE if (restart_ntp) { #ifdef NTPCHECK if (system (NTPCHECK) == 0) #endif retval += exec_cmd (NTPSERVICE, NTPRESTARTARGS, (char *) NULL); } #endif #if defined (NTPSERVICE) && defined (OPENNTPSERVICE) if (restart_openntp && (strcmp (NTPSERVICE, OPENNTPSERVICE) != 0 || ! restart_ntp)) { #ifdef OPENNTPCHECK if (system (OPENNTPCHECK) == 0) #endif retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL); } #elif defined (OPENNTPSERVICE) && ! defined (NTPSERVICE) if (restart_openntp) { #ifdef OPENNTPCHECK if (system (OPENNTPCHECK) == 0) #endif retval += exec_cmd (OPENNTPSERVICE, OPENNTPRESTARTARGS, (char *) NULL); } #endif return (retval); } #endif #ifdef ENABLE_NIS #define PREFIXSIZE 256 static int make_nis (const char *ifname, const dhcp_t *dhcp) { FILE *f; address_t *address; char *prefix; logger (LOG_DEBUG, "writing "NISFILE); if (! (f = fopen(NISFILE, "w"))) { logger (LOG_ERR, "fopen `%s': %s", NISFILE, strerror (errno)); return (-1); } prefix = xmalloc (sizeof (char) * PREFIXSIZE); *prefix = '\0'; fprintf (f, "# Generated by dhcpcd for interface %s\n", ifname); if (dhcp->nisdomain) { setdomainname (dhcp->nisdomain, (int) strlen (dhcp->nisdomain)); if (dhcp->nisservers) snprintf (prefix, PREFIXSIZE, "domain %s server", dhcp->nisdomain); else fprintf (f, "domain %s broadcast\n", dhcp->nisdomain); } else snprintf (prefix, PREFIXSIZE, "%s", "ypserver"); NSTAILQ_FOREACH (address, dhcp->nisservers, entries) fprintf (f, "%s %s\n", prefix, inet_ntoa (address->address)); free (prefix); fclose (f); #ifdef NISCHECK if (system (NISCHECK) == 0) #endif exec_cmd (NISSERVICE, NISRESTARTARGS, (char *) NULL); return (0); } #endif static char *lookuphostname (char *hostname, const dhcp_t *dhcp, const options_t *options) { union { struct sockaddr sa; struct sockaddr_in sin; } su; socklen_t salen; char *addr; struct addrinfo hints; struct addrinfo *res = NULL; int result; char *p; logger (LOG_DEBUG, "Looking up hostname via DNS"); addr = xmalloc (sizeof (char) * NI_MAXHOST); salen = sizeof (su.sa); memset (&su.sa, 0, salen); su.sin.sin_family = AF_INET; memcpy (&su.sin.sin_addr, &dhcp->address, sizeof (su.sin.sin_addr)); if ((result = getnameinfo (&su.sa, salen, addr, NI_MAXHOST, NULL, 0, NI_NAMEREQD)) != 0) { logger (LOG_ERR, "Failed to lookup hostname via DNS: %s", gai_strerror (result)); free (addr); return (NULL); } /* Check for a malicious PTR record */ memset (&hints, 0, sizeof (hints)); hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_NUMERICHOST; result = getaddrinfo (addr, "0", &hints, &res); if (res) freeaddrinfo (res); if (result == 0) logger (LOG_ERR, "malicious PTR record detected"); if (result == 0 || ! *addr) { free (addr); return (NULL); } p = strchr (addr, '.'); if (p) { switch (options->dohostname) { case 1: /* -H */ case 4: /* -HHHH */ break; case 2: /* -HH */ case 5: /* -HHHHH */ /* Strip out the domain if it matches */ p++; if (*p && dhcp->dnssearch) { char *s = xstrdup (dhcp->dnssearch); char *sp = s; char *t; while ((t = strsep (&sp, " "))) if (strcmp (t, p) == 0) { *--p = '\0'; break; } free (s); } else if (dhcp->dnsdomain) { if (strcmp (dhcp->dnsdomain, p) == 0) *--p = '\0'; } break; case 3: /* -HHH */ case 6: /* -HHHHHH */ /* Just strip the domain */ *p = '\0'; break; default: /* Too many H! */ break; } } strlcpy (hostname, addr, MAXHOSTNAMELEN); free (addr); return (hostname); } int configure (const options_t *options, interface_t *iface, const dhcp_t *dhcp, bool up) { route_t *route = NULL; struct route_head *new_routes = NULL; route_t *new_route = NULL; char *newhostname = NULL; char *curhostname = NULL; int remember; #ifdef ENABLE_IPV4LL bool haslinklocal = false; #endif #ifdef THERE_IS_NO_FORK int skip = 0; size_t skiplen; char *skipp; #endif if (! options || ! iface || ! dhcp) return (-1); if (dhcp->address.s_addr == 0) up = 0; /* Remove old routes. * Always do this as the interface may have >1 address not added by us * so the routes we added may still exist. */ NSTAILQ_FOREACH (route, iface->previous_routes, entries) if ((route->destination.s_addr || options->dogateway) && (! up || ! in_routes (dhcp->routes, route))) del_route (iface->name, route->destination, route->netmask, route->gateway, options->metric); /* If we aren't up, then reset the interface as much as we can */ if (! up) { if (iface->previous_routes) { free_route (iface->previous_routes); iface->previous_routes = NULL; } /* Restore the original MTU value */ if (iface->mtu && iface->previous_mtu != iface->mtu) { set_mtu (iface->name, iface->mtu); iface->previous_mtu = iface->mtu; } #ifdef ENABLE_INFO /* If we haven't created an info file, do so now */ if (! dhcp->frominfo) write_info (iface, dhcp, options, false); #endif /* Only reset things if we had set them before */ if (iface->previous_address.s_addr != 0) { if (! options->keep_address) { del_address (iface->name, iface->previous_address, iface->previous_netmask); memset (&iface->previous_address, 0, sizeof (iface->previous_address)); memset (&iface->previous_netmask, 0, sizeof (iface->previous_netmask)); } } restore_resolv (iface->name); exec_script (options->script, iface->infofile, "down"); return (0); } /* Set the MTU requested. * If the DHCP server no longer sends one OR it's invalid then * we restore the original MTU */ if (options->domtu) { unsigned short mtu = iface->mtu; if (dhcp->mtu) mtu = dhcp->mtu; if (mtu != iface->previous_mtu) { if (set_mtu (iface->name, mtu) == 0) iface->previous_mtu = mtu; } } /* This also changes netmask */ if (! options->doinform || ! has_address (iface->name, dhcp->address)) if (add_address (iface->name, dhcp->address, dhcp->netmask, dhcp->broadcast) == -1 && errno != EEXIST) return (false); /* Now delete the old address if different */ if (iface->previous_address.s_addr != dhcp->address.s_addr && iface->previous_address.s_addr != 0 && ! options->keep_address) del_address (iface->name, iface->previous_address, iface->previous_netmask); #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); } #endif #ifdef THERE_IS_NO_FORK free (dhcpcd_skiproutes); /* We can never have more than 255 routes. So we need space * for 255 3 digit numbers and commas */ skiplen = 255 * 4 + 1; skipp = dhcpcd_skiproutes = xmalloc (sizeof (char) * skiplen); *skipp = '\0'; #endif /* Remember added routes */ NSTAILQ_FOREACH (route, dhcp->routes, entries) { #ifdef ENABLE_IPV4LL /* Check if we have already got a link locale route dished * out by the DHCP server */ if (route->destination.s_addr == htonl (LINKLOCAL_ADDR) && route->netmask.s_addr == htonl (LINKLOCAL_MASK)) haslinklocal = true; #endif /* Don't set default routes if not asked to */ if (route->destination.s_addr == 0 && route->netmask.s_addr == 0 && ! options->dogateway) continue; remember = add_route (iface->name, route->destination, route->netmask, route->gateway, options->metric); /* If we failed to add the route, we may have already added it ourselves. If so, remember it again. */ if (remember < 0 && in_routes (iface->previous_routes, route)) remember = 1; if (remember >= 0) { if (! new_routes) { new_routes = xmalloc (sizeof (*new_routes)); STAILQ_INIT (new_routes); } new_route = xmalloc (sizeof (route_t)); memcpy (new_route, route, sizeof (*new_route)); STAILQ_INSERT_TAIL (new_routes, new_route, entries); } #ifdef THERE_IS_NO_FORK /* If we have daemonised yet we need to record which routes * we failed to add so we can skip them */ else if (! options->daemonised) { /* We can never have more than 255 / 4 routes, * so 3 chars is plently */ if (*skipp) *skipp++ = ','; skipp += snprintf (skipp, dhcpcd_skiproutes + skiplen - skipp, "%d", skip); } skip++; #endif } #ifdef THERE_IS_NO_FORK if (*dhcpcd_skiproutes) *skipp = '\0'; else { free (dhcpcd_skiproutes); dhcpcd_skiproutes = NULL; } #endif #ifdef ENABLE_IPV4LL /* Ensure we always add the link local route if we got a private * address and isn't link local itself */ if (options->doipv4ll && ! haslinklocal && IN_PRIVATE (ntohl (dhcp->address.s_addr))) { struct in_addr dest; struct in_addr mask; struct in_addr gate; dest.s_addr = htonl (LINKLOCAL_ADDR); mask.s_addr = htonl (LINKLOCAL_MASK); gate.s_addr = 0; remember = add_route (iface->name, dest, mask, gate, options->metric); if (remember >= 0) { if (! new_routes) { new_routes = xmalloc (sizeof (*new_routes)); STAILQ_INIT (new_routes); } new_route = xmalloc (sizeof (*new_route)); new_route->destination.s_addr = dest.s_addr; new_route->netmask.s_addr = mask.s_addr; new_route->gateway.s_addr = gate.s_addr; STAILQ_INSERT_TAIL (new_routes, new_route, entries); } } #endif if (iface->previous_routes) free_route (iface->previous_routes); iface->previous_routes = new_routes; 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); #endif #ifdef ENABLE_NIS if (options->donis && (dhcp->nisservers || dhcp->nisdomain)) make_nis(iface->name, dhcp); #endif curhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); *curhostname = '\0'; gethostname (curhostname, MAXHOSTNAMELEN); if (options->dohostname || strlen (curhostname) == 0 || strcmp (curhostname, "(none)") == 0 || strcmp (curhostname, "localhost") == 0) { newhostname = xmalloc (sizeof (char) * MAXHOSTNAMELEN); if (dhcp->hostname) strlcpy (newhostname, dhcp->hostname, MAXHOSTNAMELEN); else *newhostname = '\0'; /* Now we have made a resolv.conf we can obtain a hostname * if we need it */ if (! *newhostname || options->dohostname > 3) lookuphostname (newhostname, dhcp, options); if (*newhostname) { logger (LOG_INFO, "setting hostname to `%s'", newhostname); sethostname (newhostname, (int) strlen (newhostname)); } free (newhostname); } free (curhostname); #ifdef ENABLE_INFO if (! dhcp->frominfo) write_info (iface, dhcp, options, true); #endif if (iface->previous_address.s_addr != dhcp->address.s_addr || iface->previous_netmask.s_addr != dhcp->netmask.s_addr) { memcpy (&iface->previous_address, &dhcp->address, sizeof (iface->previous_address)); memcpy (&iface->previous_netmask, &dhcp->netmask, sizeof (iface->previous_netmask)); exec_script (options->script, iface->infofile, "new"); } else exec_script (options->script, iface->infofile, "up"); return (0); } dhcpcd-3.2.3.orig/configure.h0000644000076400001440000000311410760476043014565 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef DHCPCONFIG_H #define DHCPCONFIG_H #include "dhcpcd.h" #include "interface.h" #include "dhcp.h" int configure (const options_t *options, interface_t *iface, const dhcp_t *dhcp, bool up); #endif dhcpcd-3.2.3.orig/dhcp.c0000644000076400001440000005247410760476043013532 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "dhcpcd.h" #include "dhcp.h" #include "interface.h" #include "logger.h" #include "socket.h" #ifndef STAILQ_CONCAT #define STAILQ_CONCAT(head1, head2) do { \ if (!STAILQ_EMPTY((head2))) { \ *(head1)->stqh_last = (head2)->stqh_first; \ (head1)->stqh_last = (head2)->stqh_last; \ STAILQ_INIT((head2)); \ } \ } while (0) #endif typedef struct message { int value; const char *name; } dhcp_message_t; static dhcp_message_t dhcp_messages[] = { { DHCP_DISCOVER, "DHCP_DISCOVER" }, { DHCP_OFFER, "DHCP_OFFER" }, { DHCP_REQUEST, "DHCP_REQUEST" }, { DHCP_DECLINE, "DHCP_DECLINE" }, { DHCP_ACK, "DHCP_ACK" }, { DHCP_NAK, "DHCP_NAK" }, { DHCP_RELEASE, "DHCP_RELEASE" }, { DHCP_INFORM, "DHCP_INFORM" }, { -1, NULL } }; static const char *dhcp_message (int type) { dhcp_message_t *d; for (d = dhcp_messages; d->name; d++) if (d->value == type) return (d->name); return (NULL); } ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, uint32_t xid, char type, const options_t *options) { struct udp_dhcp_packet *packet; dhcpmessage_t *message; unsigned char *m; unsigned char *p; unsigned char *n_params = NULL; size_t l; struct in_addr from; struct in_addr to; time_t up = uptime() - iface->start_uptime; uint32_t ul; uint16_t sz; size_t message_length; ssize_t retval; if (!iface || !options || !dhcp) return -1; memset (&from, 0, sizeof (from)); memset (&to, 0, sizeof (to)); if (type == DHCP_RELEASE) to.s_addr = dhcp->serveraddress.s_addr; message = xzalloc (sizeof (*message)); m = (unsigned char *) message; p = (unsigned char *) &message->options; if ((type == DHCP_INFORM || type == DHCP_RELEASE || type == DHCP_REQUEST) && ! IN_LINKLOCAL (ntohl (iface->previous_address.s_addr))) { message->ciaddr = iface->previous_address.s_addr; from.s_addr = iface->previous_address.s_addr; /* Just incase we haven't actually configured the address yet */ if (type == DHCP_INFORM && iface->previous_address.s_addr == 0) message->ciaddr = dhcp->address.s_addr; /* Zero the address if we're currently on a different subnet */ if (type == DHCP_REQUEST && iface->previous_netmask.s_addr != dhcp->netmask.s_addr) message->ciaddr = from.s_addr = 0; if (from.s_addr != 0) to.s_addr = dhcp->serveraddress.s_addr; } message->op = DHCP_BOOTREQUEST; message->hwtype = iface->family; switch (iface->family) { case ARPHRD_ETHER: case ARPHRD_IEEE802: message->hwlen = ETHER_ADDR_LEN; memcpy (&message->chaddr, &iface->hwaddr, ETHER_ADDR_LEN); break; case ARPHRD_IEEE1394: case ARPHRD_INFINIBAND: message->hwlen = 0; if (message->ciaddr == 0) message->flags = htons (BROADCAST_FLAG); break; default: logger (LOG_ERR, "dhcp: unknown hardware type %d", iface->family); } if (up < 0 || up > (time_t) UINT16_MAX) message->secs = htons ((uint16_t) UINT16_MAX); else message->secs = htons (up); message->xid = xid; message->cookie = htonl (MAGIC_COOKIE); *p++ = DHCP_MESSAGETYPE; *p++ = 1; *p++ = type; if (type == DHCP_REQUEST) { *p++ = DHCP_MAXMESSAGESIZE; *p++ = 2; sz = get_mtu (iface->name); if (sz < MTU_MIN) { if (set_mtu (iface->name, MTU_MIN) == 0) sz = MTU_MIN; } sz = htons (sz); memcpy (p, &sz, 2); p += 2; } *p++ = DHCP_CLIENTID; *p++ = iface->clientid_len; memcpy (p, iface->clientid, iface->clientid_len); p+= iface->clientid_len; if (type != DHCP_DECLINE && type != DHCP_RELEASE) { if (options->userclass_len > 0) { *p++ = DHCP_USERCLASS; *p++ = options->userclass_len; memcpy (p, &options->userclass, options->userclass_len); p += options->userclass_len; } if (*options->classid > 0) { *p++ = DHCP_CLASSID; *p++ = l = strlen (options->classid); memcpy (p, options->classid, l); p += l; } } if (type == DHCP_DISCOVER || type == DHCP_REQUEST) { #define PUTADDR(_type, _val) { \ *p++ = _type; \ *p++ = 4; \ memcpy (p, &_val.s_addr, 4); \ p += 4; \ } if (IN_LINKLOCAL (ntohl (dhcp->address.s_addr))) logger (LOG_ERR, "cannot request a link local address"); else { if (dhcp->address.s_addr && dhcp->address.s_addr != iface->previous_address.s_addr) { PUTADDR (DHCP_ADDRESS, dhcp->address); if (dhcp->serveraddress.s_addr) PUTADDR (DHCP_SERVERIDENTIFIER, dhcp->serveraddress); } } #undef PUTADDR if (options->leasetime != 0) { *p++ = DHCP_LEASETIME; *p++ = 4; ul = htonl (options->leasetime); memcpy (p, &ul, 4); p += 4; } } if (type == DHCP_DISCOVER || type == DHCP_INFORM || type == DHCP_REQUEST) { if (options->hostname[0]) { if (options->fqdn == FQDN_DISABLE) { *p++ = DHCP_HOSTNAME; *p++ = l = strlen (options->hostname); memcpy (p, options->hostname, l); p += l; } else { /* Draft IETF DHC-FQDN option (81) */ *p++ = DHCP_FQDN; *p++ = (l = strlen (options->hostname)) + 3; /* Flags: 0000NEOS * S: 1 => Client requests Server to update * a RR in DNS as well as PTR * O: 1 => Server indicates to client that * DNS has been updated * E: 1 => Name data is DNS format * N: 1 => Client requests Server to not * update DNS */ *p++ = options->fqdn & 0x9; *p++ = 0; /* from server for PTR RR */ *p++ = 0; /* from server for A RR if S=1 */ memcpy (p, options->hostname, l); p += l; } } *p++ = DHCP_PARAMETERREQUESTLIST; n_params = p; *p++ = 0; /* Only request DNSSERVER in discover to keep the packets small. * RFC2131 Section 3.5 states that the REQUEST must include the * list from the DISCOVER message, so I think this is ok. */ if (type == DHCP_DISCOVER && ! options->test) *p++ = DHCP_DNSSERVER; else { if (type != DHCP_INFORM) { *p++ = DHCP_RENEWALTIME; *p++ = DHCP_REBINDTIME; } *p++ = DHCP_NETMASK; *p++ = DHCP_BROADCAST; /* -S means request CSR and MSCSR * -SS means only request MSCSR incase DHCP message * is too big */ if (options->domscsr < 2) *p++ = DHCP_CSR; if (options->domscsr > 0) *p++ = DHCP_MSCSR; /* RFC 3442 states classless static routes should be * before routers and static routes as classless static * routes override them both */ *p++ = DHCP_STATICROUTE; *p++ = DHCP_ROUTERS; *p++ = DHCP_HOSTNAME; *p++ = DHCP_DNSSEARCH; *p++ = DHCP_DNSDOMAIN; *p++ = DHCP_DNSSERVER; #ifdef ENABLE_NIS *p++ = DHCP_NISDOMAIN; *p++ = DHCP_NISSERVER; #endif #ifdef ENABLE_NTP *p++ = DHCP_NTPSERVER; #endif *p++ = DHCP_MTU; #ifdef ENABLE_INFO *p++ = DHCP_ROOTPATH; *p++ = DHCP_SIPSERVER; #endif } *n_params = p - n_params - 1; } *p++ = DHCP_END; #ifdef BOOTP_MESSAGE_LENTH_MIN /* Some crappy DHCP servers think they have to obey the BOOTP minimum * message length. * They are wrong, but we should still cater for them. */ while (p - m < BOOTP_MESSAGE_LENTH_MIN) *p++ = DHCP_PAD; #endif message_length = p - m; packet = xzalloc (sizeof (*packet)); make_dhcp_packet (packet, (unsigned char *) message, message_length, from, to); free (message); logger (LOG_DEBUG, "sending %s with xid 0x%x", dhcp_message (type), xid); retval = send_packet (iface, ETHERTYPE_IP, (unsigned char *) packet, message_length + sizeof (packet->ip) + sizeof (packet->udp)); free (packet); return (retval); } /* Decode an RFC3397 DNS search order option into a space * seperated string. Returns length of string (including * terminating zero) or zero on error. out may be NULL * to just determine output length. */ static unsigned int decode_search (const unsigned char *p, int len, char *out) { const unsigned char *r, *q = p; unsigned int count = 0, l, hops; while (q - p < len) { r = NULL; hops = 0; while ((l = *q++)) { unsigned int label_type = l & 0xc0; if (label_type == 0x80 || label_type == 0x40) return 0; else if (label_type == 0xc0) { /* pointer */ l = (l & 0x3f) << 8; l |= *q++; /* save source of first jump. */ if (!r) r = q; hops++; if (hops > 255) return 0; q = p + l; if (q - p >= len) return 0; } else { /* straightforward name segment, add with '.' */ count += l + 1; if (out) { memcpy (out, q, l); out += l; *out++ = '.'; } q += l; } } /* change last dot to space */ if (out) *(out - 1) = ' '; if (r) q = r; } /* change last space to zero terminator */ if (out) *(out - 1) = 0; return count; } /* Add our classless static routes to the routes variable * and return the last route set */ static struct route_head *decode_CSR (const unsigned char *p, int len) { const unsigned char *q = p; unsigned int cidr; unsigned int ocets; struct route_head *routes = NULL; route_t *route; /* Minimum is 5 -first is CIDR and a router length of 4 */ if (len < 5) return NULL; while (q - p < len) { if (! routes) { routes = xmalloc (sizeof (*routes)); STAILQ_INIT (routes); } route = xzalloc (sizeof (*route)); cidr = *q++; if (cidr > 32) { logger (LOG_ERR, "invalid CIDR of %d in classless static route", cidr); free_route (routes); return (NULL); } ocets = (cidr + 7) / 8; if (ocets > 0) { memcpy (&route->destination.s_addr, q, (size_t) ocets); q += ocets; } /* Now enter the netmask */ if (ocets > 0) { memset (&route->netmask.s_addr, 255, (size_t) ocets - 1); memset ((unsigned char *) &route->netmask.s_addr + (ocets - 1), (256 - (1 << (32 - cidr) % 8)), 1); } /* Finally, snag the router */ memcpy (&route->gateway.s_addr, q, 4); q += 4; STAILQ_INSERT_TAIL (routes, route, entries); } return (routes); } void free_dhcp (dhcp_t *dhcp) { if (! dhcp) return; free_route (dhcp->routes); free (dhcp->hostname); free_address (dhcp->dnsservers); free (dhcp->dnsdomain); free (dhcp->dnssearch); free_address (dhcp->ntpservers); free (dhcp->nisdomain); free_address (dhcp->nisservers); free (dhcp->rootpath); free (dhcp->sipservers); if (dhcp->fqdn) { free (dhcp->fqdn->name); free (dhcp->fqdn); } } static bool dhcp_add_address (struct address_head **addresses, const unsigned char *data, int length) { int i; address_t *address; for (i = 0; i < length; i += 4) { /* Sanity check */ if (i + 4 > length) { logger (LOG_ERR, "invalid address length"); return (false); } if (*addresses == NULL) { *addresses = xmalloc (sizeof (**addresses)); STAILQ_INIT (*addresses); } address = xzalloc (sizeof (*address)); memcpy (&address->address.s_addr, data + i, 4); STAILQ_INSERT_TAIL (*addresses, address, entries); } return (true); } #ifdef ENABLE_INFO static char *decode_sipservers (const unsigned char *data, int length) { char *sip = NULL; char *p; const char encoding = *data++; struct in_addr addr; size_t len; length--; switch (encoding) { case 0: if ((len = decode_search (data, length, NULL)) > 0) { sip = xmalloc (len); decode_search (data, length, sip); } break; case 1: if (length == 0 || length % 4 != 0) { logger (LOG_ERR, "invalid length %d for option 120", length + 1); break; } len = ((length / 4) * (4 * 4)) + 1; sip = p = xmalloc (len); while (length != 0) { memcpy (&addr.s_addr, data, 4); data += 4; p += snprintf (p, len - (p - sip), "%s ", inet_ntoa (addr)); length -= 4; } *--p = '\0'; break; default: logger (LOG_ERR, "unknown sip encoding %d", encoding); break; } return (sip); } #endif /* This calculates the netmask that we should use for static routes. * This IS different from the calculation used to calculate the netmask * for an interface address. */ static uint32_t route_netmask (uint32_t ip_in) { /* used to be unsigned long - check if error */ uint32_t p = ntohl (ip_in); uint32_t t; if (IN_CLASSA (p)) t = ~IN_CLASSA_NET; else { if (IN_CLASSB (p)) t = ~IN_CLASSB_NET; else { if (IN_CLASSC (p)) t = ~IN_CLASSC_NET; else t = 0; } } while (t & p) t >>= 1; return (htonl (~t)); } static struct route_head *decode_routes (const unsigned char *data, int length) { int i; struct route_head *head = NULL; route_t *route; for (i = 0; i < length; i += 8) { if (! head) { head = xmalloc (sizeof (*head)); STAILQ_INIT (head); } route = xzalloc (sizeof (*route)); memcpy (&route->destination.s_addr, data + i, 4); memcpy (&route->gateway.s_addr, data + i + 4, 4); route->netmask.s_addr = route_netmask (route->destination.s_addr); STAILQ_INSERT_TAIL (head, route, entries); } return (head); } static struct route_head *decode_routers (const unsigned char *data, int length) { int i; struct route_head *head = NULL; route_t *route = NULL; for (i = 0; i < length; i += 4) { if (! head) { head = xmalloc (sizeof (*head)); STAILQ_INIT (head); } route = xzalloc (sizeof (*route)); memcpy (&route->gateway.s_addr, data + i, 4); STAILQ_INSERT_TAIL (head, route, entries); } return (head); } int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message) { const unsigned char *p = message->options; const unsigned char *end = p; /* Add size later for gcc-3 issue */ unsigned char option; unsigned char length; unsigned int len = 0; int retval = -1; struct timeval tv; struct route_head *routers = NULL; struct route_head *routes = NULL; struct route_head *csr = NULL; struct route_head *mscsr = NULL; bool in_overload = false; bool parse_sname = false; bool parse_file = false; end += sizeof (message->options); if (gettimeofday (&tv, NULL) == -1) { logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); return (-1); } dhcp->address.s_addr = message->yiaddr; dhcp->leasedfrom = tv.tv_sec; dhcp->frominfo = false; dhcp->address.s_addr = message->yiaddr; strlcpy (dhcp->servername, (char *) message->servername, sizeof (dhcp->servername)); #define LEN_ERR \ { \ logger (LOG_ERR, "invalid length %d for option %d", \ length, option); \ p += length; \ continue; \ } parse_start: while (p < end) { option = *p++; if (! option) continue; if (option == DHCP_END) goto eexit; length = *p++; if (option != DHCP_PAD && length == 0) { logger (LOG_ERR, "option %d has zero length", option); retval = -1; goto eexit; } if (p + length >= end) { logger (LOG_ERR, "dhcp option exceeds message length"); retval = -1; goto eexit; } switch (option) { case DHCP_MESSAGETYPE: retval = (int) *p; p += length; continue; default: if (length == 0) { logger (LOG_DEBUG, "option %d has zero length, skipping", option); continue; } } #define LENGTH(_length) \ if (length != _length) \ LEN_ERR; #define MIN_LENGTH(_length) \ if (length < _length) \ LEN_ERR; #define MULT_LENGTH(_mult) \ if (length % _mult != 0) \ LEN_ERR; #define GET_UINT8(_val) \ LENGTH (sizeof (uint8_t)); \ memcpy (&_val, p, sizeof (uint8_t)); #define GET_UINT16(_val) \ LENGTH (sizeof (uint16_t)); \ memcpy (&_val, p, sizeof (uint16_t)); #define GET_UINT32(_val) \ LENGTH (sizeof (uint32_t)); \ memcpy (&_val, p, sizeof (uint32_t)); #define GET_UINT16_H(_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 which is the * minimum maximum message size. */ if (dhcp->mtu < MTU_MIN) { logger (LOG_DEBUG, "MTU %d is too low, minimum is %d; ignoring", dhcp->mtu, MTU_MIN); dhcp->mtu = 0; } break; #undef GET_UINT32_H #undef GET_UINT32 #undef GET_UINT16_H #undef GET_UINT16 #undef GET_UINT8 #define GETSTR(_var) { \ MIN_LENGTH (sizeof (char)); \ if (_var) free (_var); \ _var = xmalloc ((size_t) length + 1); \ memcpy (_var, p, (size_t) length); \ memset (_var + length, 0, 1); \ } case DHCP_HOSTNAME: GETSTR (dhcp->hostname); break; case DHCP_DNSDOMAIN: GETSTR (dhcp->dnsdomain); break; case DHCP_MESSAGE: GETSTR (dhcp->message); break; #ifdef ENABLE_INFO case DHCP_ROOTPATH: GETSTR (dhcp->rootpath); break; #endif #ifdef ENABLE_NIS case DHCP_NISDOMAIN: GETSTR (dhcp->nisdomain); break; #endif #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; #ifdef ENABLE_NTP case DHCP_NTPSERVER: GETADDR (dhcp->ntpservers); break; #endif #ifdef ENABLE_NIS case DHCP_NISSERVER: GETADDR (dhcp->nisservers); break; #endif #undef GETADDR case DHCP_DNSSEARCH: MIN_LENGTH (1); free (dhcp->dnssearch); len = decode_search (p, length, NULL); if (len > 0) { dhcp->dnssearch = xmalloc (len); decode_search (p, length, dhcp->dnssearch); } break; case DHCP_CSR: MIN_LENGTH (5); free_route (csr); csr = decode_CSR (p, length); break; case DHCP_MSCSR: MIN_LENGTH (5); free_route (mscsr); mscsr = decode_CSR (p, length); break; #ifdef ENABLE_INFO case DHCP_SIPSERVER: free (dhcp->sipservers); dhcp->sipservers = decode_sipservers (p,length); break; #endif case DHCP_STATICROUTE: MULT_LENGTH (8); free_route (routes); routes = decode_routes (p, length); break; case DHCP_ROUTERS: MULT_LENGTH (4); free_route (routers); routers = decode_routers (p, length); break; case DHCP_OPTIONSOVERLOADED: LENGTH (1); /* The overloaded option in an overloaded option * should be ignored, overwise we may get an * infinite loop */ if (! in_overload) { if (*p & 1) parse_file = true; if (*p & 2) parse_sname = true; } break; case DHCP_FQDN: /* We ignore replies about FQDN */ break; #undef LENGTH #undef MIN_LENGTH #undef MULT_LENGTH default: logger (LOG_DEBUG, "no facility to parse DHCP code %u", option); break; } p += length; } eexit: /* We may have options overloaded, so go back and grab them */ if (parse_file) { parse_file = false; p = message->bootfile; end = p + sizeof (message->bootfile); in_overload = true; goto parse_start; } else if (parse_sname) { parse_sname = false; p = message->servername; end = p + sizeof (message->servername); memset (dhcp->servername, 0, sizeof (dhcp->servername)); in_overload = true; goto parse_start; } /* Fill in any missing fields */ if (! dhcp->netmask.s_addr) dhcp->netmask.s_addr = get_netmask (dhcp->address.s_addr); if (! dhcp->broadcast.s_addr) dhcp->broadcast.s_addr = dhcp->address.s_addr | ~dhcp->netmask.s_addr; /* If we have classess static routes then we discard * static routes and routers according to RFC 3442 */ if (csr) { dhcp->routes = csr; free_route (mscsr); free_route (routers); free_route (routes); } else if (mscsr) { dhcp->routes = mscsr; free_route (routers); free_route (routes); } else { /* Ensure that we apply static routes before routers */ if (! routes) routes = routers; else if (routers) STAILQ_CONCAT (routes, routers); dhcp->routes = routes; } return (retval); } dhcpcd-3.2.3.orig/dhcp.h0000644000076400001440000001472610760476043013535 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef DHCP_H #define DHCP_H #include #include #include #include #include #include "dhcpcd.h" #include "interface.h" /* Max MTU - defines dhcp option length */ #define MTU_MAX 1500 #define MTU_MIN 576 /* UDP port numbers for DHCP */ #define DHCP_SERVER_PORT 67 #define DHCP_CLIENT_PORT 68 #define MAGIC_COOKIE 0x63825363 #define BROADCAST_FLAG 0x8000 /* DHCP message OP code */ #define DHCP_BOOTREQUEST 1 #define DHCP_BOOTREPLY 2 /* DHCP message type */ #define DHCP_DISCOVER 1 #define DHCP_OFFER 2 #define DHCP_REQUEST 3 #define DHCP_DECLINE 4 #define DHCP_ACK 5 #define DHCP_NAK 6 #define DHCP_RELEASE 7 #define DHCP_INFORM 8 /* DHCP options */ enum DHCP_OPTIONS { DHCP_PAD = 0, DHCP_NETMASK = 1, DHCP_TIMEROFFSET = 2, DHCP_ROUTERS = 3, DHCP_TIMESERVER = 4, DHCP_NAMESERVER = 5, DHCP_DNSSERVER = 6, DHCP_LOGSERVER = 7, DHCP_COOKIESERVER = 8, DHCP_HOSTNAME = 12, DHCP_DNSDOMAIN = 15, DHCP_ROOTPATH = 17, DHCP_DEFAULTIPTTL = 23, DHCP_MTU = 26, DHCP_BROADCAST = 28, DHCP_MASKDISCOVERY = 29, DHCP_ROUTERDISCOVERY = 31, DHCP_STATICROUTE = 33, DHCP_NISDOMAIN = 40, DHCP_NISSERVER = 41, DHCP_NTPSERVER = 42, DHCP_ADDRESS = 50, DHCP_LEASETIME = 51, DHCP_OPTIONSOVERLOADED = 52, DHCP_MESSAGETYPE = 53, DHCP_SERVERIDENTIFIER = 54, DHCP_PARAMETERREQUESTLIST = 55, DHCP_MESSAGE = 56, DHCP_MAXMESSAGESIZE = 57, DHCP_RENEWALTIME = 58, DHCP_REBINDTIME = 59, DHCP_CLASSID = 60, DHCP_CLIENTID = 61, DHCP_USERCLASS = 77, /* RFC 3004 */ DHCP_FQDN = 81, DHCP_DNSSEARCH = 119, /* RFC 3397 */ DHCP_SIPSERVER = 120, /* RFC 3361 */ DHCP_CSR = 121, /* RFC 3442 */ DHCP_MSCSR = 249, /* MS code for RFC 3442 */ DHCP_END = 255 }; /* SetFQDNHostName values - lsnybble used in flags * byte (see buildmsg.c), hsnybble to create order * and to allow 0x00 to mean disable */ enum FQQN { FQDN_DISABLE = 0x00, FQDN_NONE = 0x18, FQDN_PTR = 0x20, FQDN_BOTH = 0x31 }; typedef struct fqdn_t { 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; uint32_t leasedfrom; uint32_t leasetime; uint32_t renewaltime; uint32_t rebindtime; struct route_head *routes; char *hostname; fqdn_t *fqdn; struct address_head *dnsservers; char *dnsdomain; char *dnssearch; struct address_head *ntpservers; struct address_head *nisservers; char *nisdomain; char *sipservers; char *message; char *rootpath; bool frominfo; } dhcp_t; /* Sizes for DHCP options */ #define DHCP_CHADDR_LEN 16 #define SERVERNAME_LEN 64 #define BOOTFILE_LEN 128 #define DHCP_UDP_LEN (20 + 8) #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) #define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN - DHCP_UDP_LEN \ - DHCP_RESERVE_LEN) /* Some crappy DHCP servers require the BOOTP minimum length */ #define BOOTP_MESSAGE_LENTH_MIN 300 typedef struct dhcpmessage_t { unsigned char op; /* message type */ unsigned char hwtype; /* hardware address type */ unsigned char hwlen; /* hardware address length */ unsigned char hwopcount; /* should be zero in client message */ uint32_t xid; /* transaction id */ uint16_t secs; /* elapsed time in sec. from boot */ uint16_t flags; uint32_t ciaddr; /* (previously allocated) client IP */ uint32_t yiaddr; /* 'your' client IP address */ uint32_t siaddr; /* should be zero in client's messages */ uint32_t giaddr; /* should be zero in client's messages */ unsigned char chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */ unsigned char servername[SERVERNAME_LEN]; /* server host name */ unsigned char bootfile[BOOTFILE_LEN]; /* boot file name */ uint32_t cookie; unsigned char options[DHCP_OPTION_LEN]; /* message options - cookie */ } dhcpmessage_t; struct udp_dhcp_packet { struct ip ip; struct udphdr udp; dhcpmessage_t dhcp; }; ssize_t send_message (const interface_t *iface, const dhcp_t *dhcp, uint32_t xid, char type, const options_t *options); void free_dhcp (dhcp_t *dhcp); int parse_dhcpmessage (dhcp_t *dhcp, const dhcpmessage_t *message); #endif dhcpcd-3.2.3.orig/dhcpcd.8.in0000644000076400001440000002536210760476043014367 0ustar srkusers.\" Copyright 2006-2008 Roy Marples .\" All rights reserved .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .Dd Feb 20, 2008 .Dt DHCPCD 8 SMM .Sh NAME .Nm dhcpcd .Nd an RFC 2131 compliant DHCP client .Sh SYNOPSIS .Nm .Op Fl dknpAEGHMLNRSTY .Op Fl c , -script Ar script .Op Fl h , -hostname Ar hostname .Op Fl i , -classid Ar classid .Op Fl l , -leasetime Ar seconds .Op Fl m , -metric Ar metric .Op Fl r , -request Ar address .Op Fl t , -timeout Ar seconds .Op Fl u , -userclass Ar class .Op Fl F , -fqdn Ar FQDN .Op Fl I , -clientid Ar clientid .Ar interface .Nm .Fl k , -release .Ar interface .Nm .Fl x , -exit .Ar interface .Sh DESCRIPTION .Nm is an implementation of the DHCP client specified in .Rs .%T "RFC 2131" .Re .Nm gets the host information .Po IP address, routes, etc .Pc from a DHCP server and configures the network .Ar interface of the machine on which it is running. .Nm will then write DNS information to .Xr resolvconf 8 , if available, otherwise directly to .Pa /etc/resolv.conf . .Nm will also configure .Pa /etc/yp.conf and .Pa /etc/ntpd.conf with NIS and NTP information if the DHCP server provided them. If those file contents changed, then .Nm will also attempt to restart the respective services to notify them of the change. If the hostname is currenly blank, (null) or localhost then .Nm will set the hostname to the one supplied by the DHCP server, or look it up in DNS if none supplied. .Nm then daemonises and waits for the lease renewal time to lapse. Then it attempts to renew its lease and reconfigure if the new lease changes. .Ss Local Link configuration If .Nm failed to obtain a lease, it will probe for a valid IPv4LL address .Po aka Zeroconf, aka APIPA .Pc . Once obtained it will probe every 10 seconds for a DHCP server to get a proper address. .Pp Even when .Nm obtains a proper lease, it will still add a Local Link route .Po 165.254.0.0/16 .Pc so that the host can communicate with clients using these addresses. .Pp When using IPv4LL, .Nm will always succeed and return a 0 exit code. To disable this behaviour, you can use the .Fl L , -noipv4ll option. .Ss Hooking into DHCP events .Nm will run @PREFIX@/etc/dhcpcd.sh, or the script specified by the .Fl c , -script option. It will set $1 to a shell compatible file that holds various configuration settings obtained from the DHCP server and $2 to either up, down or new depending on the state of .Nm . .Nm ignores the exist code of the script. .Ss Fine tuning You can fine tune the behaviour of .Nm with the following options :- .Bl -tag -width indent .It Fl d , -debug Echo debug and informational messages to the console. Subsequent debug options stop .Nm from daemonising. .It Fl h , -hostname Ar hostname By default, .Nm will send the current hostname to the DHCP server so it can register in DNS. You can use this option to specify the .Ar hostname sent, or an empty string to stop any .Ar hostname from being sent. .It Fl i , -classid Ar classid Override the DHCP vendor .Ar classid field we send. The default is dhcpcd-. .It Fl k , -release This causes an existing .Nm process running on the .Ar interface to release it's lease, deconfigure the .Ar interface and then exit. .It Fl l , -leasetime Ar seconds Request a specific lease time in .Ar seconds . By default .Nm does not request any lease time and leaves the it in the hands of the DHCP server. .It Fl m , -metric Ar metric Added routes will use the .Ar metric on systems where this is supported .Po presently only Linux .Pc . Route metrics allow the addition of routes to the same destination across different interfaces, the lower the metric the more it is preferred. .It Fl n , -renew Notifies an existing .Nm process running on the .Ar interface to renew it's lease. If .Nm is not running, then it starts up as normal. .It Fl p , -persistent .Nm normally deconfigures the .Ar interface and configuration when it exits. Sometimes, this isn't desirable if for example you have root mounted over NFS. You can use this option to stop this from happening. .It Fl r , -request Op Ar address .Nm normally sends a DHCP Broadcast to find servers to offer an address. .Nm will then request the address used. You can use this option to skip the broadcast step and just request an .Ar address . The downside is if you request an .Ar address the DHCP server does not know about or the DHCP server is not authorative, it will remain silent. In this situation, we go back to the init state and broadcast again. If no .Ar address is given then we use the first address currently assigned to the .Ar interface . .It Fl s , -inform Op Ar address Op / Ar cidr Behaves exactly like .Fl r , -request as above, but sends a DHCP inform instead of a request. This requires the interface to be configured first. This does not get a lease as such, just notifies the DHCP server of the .Ar address we are using. .It Fl t , -timeout Ar seconds Timeout after .Ar seconds , instead of the default 20. A setting of 0 .Ar seconds causes .Nm to wait forever to get a lease. .It Fl u , -userclass Ar class Tags the DHCP message with the userclass .Ar class . DHCP servers use this give memebers of the class DHCP options other than the default, without having to know things like hardware address or hostname. .If Fl F , -fqdn Ar fqdn Requests that the DHCP server updates DNS using FQDN instead of just a hostname. Valid values for .Ar fqdn are none, ptr and both. .Nm dhcpcd itself never does any DNS updates. .It Fl H , --sethostname Forces .Nm to set the hostname as supplied by the DHCP server. Because some OS's and users prefer to have just the hostname, or the full FQDN more .Fl H , --sethostname options change the behaviour. Below is the list of possible combinations:- .Bl -tag -width indent .It Fl H set the hostname to the full FQDN. .It Fl HH strip the domain if it matches the dns domain. .It Fl HHH strip the domain regardless. .It Fl HHHH same as .Fl H but force hostname lookup via DNS. .It Fl HHHHH same as above, but strip the domain if it matches the dns domain. .It Fl HHHHHH same as above, but strip the domain regardless. .El .It Fl I , -clientid Ar clientid Send .Ar clientid as a client identifier string. If .Ar clientid matches a hardware address format, such as 01:00:01:02:03:04:05 then we encode it as that, otherwise as a string. You need to specify the hardware type in the first byte. Ethernet is 01, and the hardware address in the example is 00:01:02:03:04:05. If the .Ar clientid is a blank string, then we disable DUID support and use a .Ar clientid as shown above. .It Fl S, -mscsr Microsoft have their own code for Classless Static Routes .Po RFC 3442 .Pc . You can use this option to request this as well as the normal CSR. Another instace of this option only requests the Microsoft CSR to prevent DHCP message over-running its maximum size. DHCP server administrators should update their CSR code from the Microsoft specific one to the RFC compliant one as the content is fully compatible. .El .Ss Restriciting behaviour .Nm will try to do as much as it can by default. However, there are sometimes situations where you don't want the things to be configured exactly how the the DHCP server wants. Here are some option that deal with turning these bits off. .Bl -tag -width indent .It Fl A , -noarp Don't request or claim the address by ARP. .It Fl G , -nogateway Don't set any default routes. .It Fl L , -noipv4ll Don't use IPv4LL at all. .It Fl M , -nomtu Don't set the MTU of the .Ar interface . .It Fl N , -nontp Don't touch .Pa /etc/ntpd.conf or restart the ntp service. .It Fl R , -nodns Don't send DNS information to resolvconf or touch .Pa /etc/resolv.conf . .It Fl T , -test On receipt of discover messages, simply print the contents of the DHCP message to the console. .Nm will not configure the .Ar interface , touch any files or restart any services. .It Fl Y , -nonis Don't touch .Pa /etc/yp.conf or restart the ypbind service. .El .Sh NOTES Because .Nm supports InfiniBand, we put a Node-specific Client Identifier in the ClientID field. This is required by RFC 4390. It's also required for DHCP IPv6 which .Nm should support one day. However, some DHCP servers have no idea what this is and reject the message as they do not understand type 255. This is not conformant with RFC 2132 and the server should be fixed. Also, some DHCP server configurations require an ethernet hardware address of 6 hexacdecimal numbers in the ClientID which is the default behaviour of most other DHCP clients. If your DHCP server is as desribed above, you should fix the server, or if that is not an option you can compile DUID support out of .Nm or use the .Fl I , -clientid Ar clientid option and set .Ar clientid to ''. .Pp ISC dhcpd, dnsmasq, udhcpd and Microsoft DHCP server 2003 default configurations work just fine with the default .Nm configuration. .Pp .Nm requires a Berkley Packet Filter, or BPF device on BSD based systems and a Linux Socket Filter, or LPF device on Linux based systems. .Sh FILES .Bl -ohang .It Pa @PREFIX@/etc/dhcpcd.sh Bourne shell script that is run when we configure or deconfigure an interface. .It Pa @INFODIR@/dhcpcd.duid Text file that holds the DUID used to identify the host. .It Pa @INFODIR@/dhcpcd- Ns Ar interface Ns .info Bourne shell file that holds the DHCP values used in configuring the interface. This path is passed as the first argument to .Pa @PREFIX@/etc/dhcpcd.sh . .El .Sh SEE ALSO .Xr ntp 1 , .Xr resolv.conf 5 , .Xr resolvconf 8 , .Xr yp.conf 5 , .Xr ypbind 8 .Sh STANDARDS RFC 2131, RFC 2132, RFC 2855, RFC 3004, RFC 3361, RFC 3397, RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702. .Sh AUTHORS .An "Roy Marples" Aq roy@marples.name .Sh BUGS Please report them to http://bugs.marples.name dhcpcd-3.2.3.orig/dhcpcd.c0000644000076400001440000003747310760476043014043 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples"; #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "client.h" #include "dhcpcd.h" #include "dhcp.h" #include "interface.h" #include "logger.h" #include "socket.h" #include "version.h" static int doversion = 0; static int dohelp = 0; #define EXTRA_OPTS static const struct option longopts[] = { {"arp", no_argument, NULL, 'a'}, {"script", required_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, {"hostname", optional_argument, NULL, 'h'}, {"classid", optional_argument, NULL, 'i'}, {"release", no_argument, NULL, 'k'}, {"leasetime", required_argument, NULL, 'l'}, {"metric", required_argument, NULL, 'm'}, {"renew", no_argument, NULL, 'n'}, {"persistent", no_argument, NULL, 'p'}, {"inform", optional_argument, NULL, 's'}, {"request", optional_argument, NULL, 'r'}, {"timeout", required_argument, NULL, 't'}, {"userclass", required_argument, NULL, 'u'}, {"exit", no_argument, NULL, 'x'}, {"lastlease", no_argument, NULL, 'E'}, {"fqdn", required_argument, NULL, 'F'}, {"nogateway", no_argument, NULL, 'G'}, {"sethostname", no_argument, NULL, 'H'}, {"clientid", optional_argument, NULL, 'I'}, {"noipv4ll", no_argument, NULL, 'L'}, {"nomtu", no_argument, NULL, 'M'}, {"nontp", no_argument, NULL, 'N'}, {"nodns", no_argument, NULL, 'R'}, {"msscr", no_argument, NULL, 'S'}, {"test", no_argument, NULL, 'T'}, {"nonis", no_argument, NULL, 'Y'}, {"help", no_argument, &dohelp, 1}, {"version", no_argument, &doversion, 1}, #ifdef THERE_IS_NO_FORK {"daemonised", no_argument, NULL, 'f'}, {"skiproutes", required_argument, NULL, 'g'}, #endif {NULL, 0, NULL, 0} }; #ifdef THERE_IS_NO_FORK char dhcpcd[PATH_MAX]; char **dhcpcd_argv = NULL; int dhcpcd_argc = 0; char *dhcpcd_skiproutes = NULL; #undef EXTRA_OPTS #define EXTRA_OPTS "fg:" #endif static int atoint (const char *s) { char *t; long n; errno = 0; n = strtol (s, &t, 0); if ((errno != 0 && n == 0) || s == t || (errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))) { logger (LOG_ERR, "`%s' out of range", s); return (-1); } return ((int) n); } static pid_t read_pid (const char *pidfile) { FILE *fp; pid_t pid = 0; if ((fp = fopen (pidfile, "r")) == NULL) { errno = ENOENT; return 0; } fscanf (fp, "%d", &pid); fclose (fp); return (pid); } static void usage (void) { printf ("usage: "PACKAGE" [-adknpEGHMNRSTY] [-c script] [-h hostname] [-i classID]\n" " [-l leasetime] [-m metric] [-r ipaddress] [-s ipaddress]\n" " [-t timeout] [-u userclass] [-F none | ptr | both]\n" " [-I clientID] \n"); } int main(int argc, char **argv) { options_t *options; int userclasses = 0; int opt; int option_index = 0; char *prefix; pid_t pid; int debug = 0; int i; int pidfd = -1; int sig = 0; int retval = EXIT_FAILURE; /* Close any un-needed fd's */ for (i = getdtablesize() - 1; i >= 3; --i) close (i); openlog (PACKAGE, LOG_PID, LOG_LOCAL0); options = xzalloc (sizeof (*options)); options->script = (char *) DEFAULT_SCRIPT; snprintf (options->classid, CLASS_ID_MAX_LEN, "%s %s", PACKAGE, VERSION); options->doarp = true; options->dodns = true; options->domtu = true; options->donis = true; options->dontp = true; options->dogateway = true; options->daemonise = true; options->doinform = false; options->doipv4ll = true; options->doduid = true; options->timeout = DEFAULT_TIMEOUT; gethostname (options->hostname, sizeof (options->hostname)); if (strcmp (options->hostname, "(none)") == 0 || strcmp (options->hostname, "localhost") == 0) memset (options->hostname, 0, sizeof (options->hostname)); /* Don't set any optional arguments here so we retain POSIX * compatibility with getopt */ while ((opt = getopt_long(argc, argv, EXTRA_OPTS "c:dh:i:kl:m:npr:s:t:u:xAEF:GHI:LMNRSTY", longopts, &option_index)) != -1) { switch (opt) { case 0: if (longopts[option_index].flag) break; logger (LOG_ERR, "option `%s' should set a flag", longopts[option_index].name); goto abort; case 'c': options->script = optarg; break; case 'd': debug++; switch (debug) { case 1: setloglevel (LOG_DEBUG); break; case 2: options->daemonise = false; break; } break; #ifdef THERE_IS_NO_FORK case 'f': options->daemonised = true; close_fds (); break; case 'g': dhcpcd_skiproutes = xstrdup (optarg); break; #endif case 'h': if (! optarg) *options->hostname = '\0'; else if (strlen (optarg) > MAXHOSTNAMELEN) { logger (LOG_ERR, "`%s' too long for HostName string, max is %d", optarg, MAXHOSTNAMELEN); goto abort; } else strlcpy (options->hostname, optarg, sizeof (options->hostname)); break; case 'i': if (! optarg) { *options->classid = '\0'; } else if (strlen (optarg) > CLASS_ID_MAX_LEN) { logger (LOG_ERR, "`%s' too long for ClassID string, max is %d", optarg, CLASS_ID_MAX_LEN); goto abort; } else strlcpy (options->classid, optarg, sizeof (options->classid)); break; case 'k': sig = SIGHUP; break; case 'l': if (*optarg == '-') { logger (LOG_ERR, "leasetime must be a positive value"); goto abort; } errno = 0; options->leasetime = (uint32_t) strtol (optarg, NULL, 0); if (errno == EINVAL || errno == ERANGE) { logger (LOG_ERR, "`%s' out of range", optarg); goto abort; } break; case 'm': options->metric = atoint (optarg); if (options->metric < 0) { logger (LOG_ERR, "metric must be a positive value"); goto abort; } break; case 'n': sig = SIGALRM; break; case 'p': options->persistent = true; break; case 's': options->doinform = true; options->doarp = false; if (! optarg || strlen (optarg) == 0) { options->request_address.s_addr = 0; break; } else { char *slash = strchr (optarg, '/'); if (slash) { int cidr; /* nullify the slash, so the -r option can read the * address */ *slash++ = '\0'; if (sscanf (slash, "%d", &cidr) != 1 || inet_cidrtoaddr (cidr, &options->request_netmask) != 0) { logger (LOG_ERR, "`%s' is not a valid CIDR", slash); goto abort; } } } /* FALLTHROUGH */ case 'r': if (! options->doinform) options->dorequest = true; if (strlen (optarg) > 0 && ! inet_aton (optarg, &options->request_address)) { logger (LOG_ERR, "`%s' is not a valid IP address", optarg); goto abort; } break; case 't': options->timeout = atoint (optarg); if (options->timeout < 0) { logger (LOG_ERR, "timeout must be a positive value"); goto abort; } break; case 'u': { int offset = 0; for (i = 0; i < userclasses; i++) offset += (int) options->userclass[offset] + 1; if (offset + 1 + strlen (optarg) > USERCLASS_MAX_LEN) { logger (LOG_ERR, "userclass overrun, max is %d", USERCLASS_MAX_LEN); goto abort; } userclasses++; memcpy (options->userclass + offset + 1 , optarg, strlen (optarg)); options->userclass[offset] = strlen (optarg); options->userclass_len += (strlen (optarg)) + 1; } break; case 'x': sig = SIGTERM; break; case 'A': #ifndef ENABLE_ARP logger (LOG_ERR, "arp not compiled into dhcpcd"); goto abort; #endif options->doarp = false; break; case 'E': #ifndef ENABLE_INFO logger (LOG_ERR, "info not compiled into dhcpcd"); goto abort; #endif options->dolastlease = true; break; case 'F': if (strncmp (optarg, "none", strlen (optarg)) == 0) options->fqdn = FQDN_NONE; else if (strncmp (optarg, "ptr", strlen (optarg)) == 0) options->fqdn = FQDN_PTR; else if (strncmp (optarg, "both", strlen (optarg)) == 0) options->fqdn = FQDN_BOTH; else { logger (LOG_ERR, "invalid value `%s' for FQDN", optarg); goto abort; } break; case 'G': options->dogateway = false; break; case 'H': options->dohostname++; break; case 'I': if (optarg) { if (strlen (optarg) > CLIENT_ID_MAX_LEN) { logger (LOG_ERR, "`%s' is too long for ClientID, max is %d", optarg, CLIENT_ID_MAX_LEN); goto abort; } if (strlcpy (options->clientid, optarg, sizeof (options->clientid)) == 0) /* empty string disabled duid */ options->doduid = false; } else { memset (options->clientid, 0, sizeof (options->clientid)); options->doduid = false; } break; case 'L': options->doipv4ll = false; break; case 'M': options->domtu = false; break; case 'N': options->dontp = false; break; case 'R': options->dodns = false; break; case 'S': options->domscsr++; break; case 'T': #ifndef ENABLE_INFO logger (LOG_ERR, "info support not compiled into dhcpcd"); goto abort; #endif options->test = true; options->persistent = true; break; case 'Y': options->donis = false; break; case '?': usage (); goto abort; default: usage (); goto abort; } } if (doversion) { printf (""PACKAGE" "VERSION"\n"); printf ("Compile time options:" #ifdef ENABLE_ARP " ARP" #endif #ifdef ENABLE_DUID " DUID" #endif #ifdef ENABLE_INFO " INFO" #endif #ifdef ENABLE_INFO_COMPAT " INFO_COMPAT" #endif #ifdef ENABLE_IPV4LL " IPV4LL" #endif #ifdef ENABLE_NIS " NIS" #endif #ifdef ENABLE_NTP " NTP" #endif #ifdef SERVICE " " SERVICE #endif #ifdef ENABLE_RESOLVCONF " RESOLVCONF" #endif #ifdef THERE_IS_NO_FORK " THERE_IS_NO_FORK" #endif "\n"); } if (dohelp) usage (); #ifdef THERE_IS_NO_FORK dhcpcd_argv = argv; dhcpcd_argc = argc; if (! realpath (argv[0], dhcpcd)) { logger (LOG_ERR, "unable to resolve the path `%s': %s", argv[0], strerror (errno)); goto abort; } #endif if (optind < argc) { if (strlen (argv[optind]) > IF_NAMESIZE) { logger (LOG_ERR, "`%s' too long for an interface name (max=%d)", argv[optind], IF_NAMESIZE); goto abort; } strlcpy (options->interface, argv[optind], sizeof (options->interface)); } else { /* If only version was requested then exit now */ if (doversion || dohelp) { retval = 0; goto abort; } logger (LOG_ERR, "no interface specified"); goto abort; } if (strchr (options->hostname, '.')) { if (options->fqdn == FQDN_DISABLE) options->fqdn = FQDN_BOTH; } else options->fqdn = FQDN_DISABLE; if (options->request_address.s_addr == 0 && options->doinform) { if ((options->request_address.s_addr = get_address (options->interface)) != 0) options->keep_address = true; } if (IN_LINKLOCAL (ntohl (options->request_address.s_addr))) { logger (LOG_ERR, "you are not allowed to request a link local address"); goto abort; } if (geteuid ()) logger (LOG_WARNING, PACKAGE " will not work correctly unless" " run as root"); prefix = xmalloc (sizeof (char) * (IF_NAMESIZE + 3)); snprintf (prefix, IF_NAMESIZE, "%s: ", options->interface); setlogprefix (prefix); snprintf (options->pidfile, sizeof (options->pidfile), PIDFILE, options->interface); free (prefix); chdir ("/"); umask (022); if (mkdir (INFODIR, S_IRUSR | S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", INFODIR, strerror (errno)); goto abort; } if (mkdir (ETCDIR, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST) { logger (LOG_ERR, "mkdir(\"%s\",0): %s\n", ETCDIR, strerror (errno)); goto abort; } if (options->test) { if (options->dorequest || options->doinform) { logger (LOG_ERR, "cannot test with --inform or --request"); goto abort; } if (options->dolastlease) { logger (LOG_ERR, "cannot test with --lastlease"); goto abort; } if (sig != 0) { logger (LOG_ERR, "cannot test with --release or --renew"); goto abort; } } if (sig != 0) { int killed = -1; pid = read_pid (options->pidfile); if (pid != 0) logger (LOG_INFO, "sending signal %d to pid %d", sig, pid); if (! pid || (killed = kill (pid, sig))) logger (sig == SIGALRM ? LOG_INFO : LOG_ERR, ""PACKAGE" not running"); if (pid != 0 && (sig != SIGALRM || killed != 0)) unlink (options->pidfile); if (killed == 0) { retval = EXIT_SUCCESS; goto abort; } if (sig != SIGALRM) goto abort; } if (! options->test && ! options->daemonised) { if ((pid = read_pid (options->pidfile)) > 0 && kill (pid, 0) == 0) { logger (LOG_ERR, ""PACKAGE " already running on pid %d (%s)", pid, options->pidfile); goto abort; } pidfd = open (options->pidfile, O_WRONLY | O_CREAT | O_NONBLOCK, 0664); if (pidfd == -1) { logger (LOG_ERR, "open `%s': %s", options->pidfile, strerror (errno)); goto abort; } /* Lock the file so that only one instance of dhcpcd runs * on an interface */ if (flock (pidfd, LOCK_EX | LOCK_NB) == -1) { logger (LOG_ERR, "flock `%s': %s", options->pidfile, strerror (errno)); goto abort; } /* dhcpcd.sh should not interhit this fd */ if ((i = fcntl (pidfd, F_GETFD, 0)) == -1 || fcntl (pidfd, F_SETFD, i | FD_CLOEXEC) == -1) logger (LOG_ERR, "fcntl: %s", strerror (errno)); writepid (pidfd, getpid ()); logger (LOG_INFO, PACKAGE " " VERSION " starting"); } /* Seed random */ srandomdev (); /* Massage our filters per platform */ setup_packet_filters (); if (dhcp_run (options, &pidfd) == 0) retval = EXIT_SUCCESS; abort: /* If we didn't daemonise then we need to punt the pidfile now */ if (pidfd > -1) { close (pidfd); unlink (options->pidfile); } free (options); #ifdef THERE_IS_NO_FORK /* There may have been an error before the dhcp_run function * clears this, so just do it here to be safe */ free (dhcpcd_skiproutes); #endif logger (LOG_INFO, "exiting"); exit (retval); /* NOTREACHED */ } dhcpcd-3.2.3.orig/dhcpcd.h0000644000076400001440000000510310760476043014031 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef DHCPCD_H #define DHCPCD_H #include #include #include #include #include #include #include "common.h" #define DEFAULT_TIMEOUT 20 #define DEFAULT_LEASETIME 3600 /* 1 hour */ #define CLASS_ID_MAX_LEN 48 #define CLIENT_ID_MAX_LEN 48 #define USERCLASS_MAX_LEN 255 #ifdef THERE_IS_NO_FORK extern char dhcpcd[PATH_MAX]; extern char **dhcpcd_argv; extern int dhcpcd_argc; extern char *dhcpcd_skiproutes; #endif typedef struct options_t { char interface[IF_NAMESIZE]; char hostname[MAXHOSTNAMELEN]; int fqdn; char classid[CLASS_ID_MAX_LEN]; char clientid[CLIENT_ID_MAX_LEN]; char userclass[USERCLASS_MAX_LEN]; size_t userclass_len; uint32_t leasetime; time_t timeout; int metric; bool doarp; bool dodns; bool dodomainname; bool dogateway; int dohostname; bool domtu; bool donis; bool dontp; bool dolastlease; bool doinform; bool dorequest; bool doipv4ll; bool doduid; int domscsr; struct in_addr request_address; struct in_addr request_netmask; bool persistent; bool keep_address; bool daemonise; bool daemonised; bool test; char *script; char pidfile[PATH_MAX]; } options_t; #endif dhcpcd-3.2.3.orig/dhcpcd.sh0000755000076400001440000000250510760476043014222 0ustar srkusers#!/bin/sh # # This is a sample /etc/dhcpcd.sh script. # /etc/dhcpcd.sh script is executed by dhcpcd daemon # any time it configures or shuts down interface. # The following parameters are passed to dhcpcd.exe script: # $1 = HostInfoFilePath, e.g "/var/lib/dhcpcd/dhcpcd-eth0.info" # $2 = "up" if interface has been configured with the same # IP address as before reboot; # $2 = "down" if interface has been shut down; # $2 = "new" if interface has been configured with new IP address; # # Sanity checks if [ $# -lt 2 ]; then logger -s -p local0.err -t dhcpcd.sh "wrong usage" exit 1 fi hostinfo="$1" state="$2" # Reading HostInfo file for configuration parameters [ -e "${hostinfo}" ] && . "${hostinfo}" case "${state}" in up) logger -s -p local0.info -t dhcpcd.sh \ "interface ${INTERFACE} has been configured with old IP=${IPADDR}" # Put your code here for when the interface has been brought up with an # old IP address here ;; new) logger -s -p local0.info -t dhcpcd.sh \ "interface ${INTERFACE} has been configured with new IP=${IPADDR}" # Put your code here for when the interface has been brought up with a # new IP address ;; down) logger -s -p local0.info -t dhcpcd.sh \ "interface ${INTERFACE} has been brought down" # Put your code here for the when the interface has been shut down ;; esac exit 0 dhcpcd-3.2.3.orig/duid.c0000644000076400001440000000627710760476043013541 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "duid.h" #include "logger.h" #ifdef ENABLE_DUID #define THIRTY_YEARS_IN_SECONDS 946707779 size_t get_duid (unsigned char *duid, const interface_t *iface) { FILE *f; uint16_t type = 0; uint16_t hw = 0; uint32_t ul; time_t t; int x = 0; unsigned char *p = duid; size_t len = 0; if (! iface) return (0); /* If we already have a DUID then use it as it's never supposed * to change once we have one even if the interfaces do */ if ((f = fopen (DUIDFILE, "r"))) { char *line = get_line (f); if (line) { len = hwaddr_aton (NULL, line); if (len && len <= DUID_LEN) hwaddr_aton (duid, line); free (line); } fclose (f); if (len) return (len); } else { if (errno != ENOENT) { logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); return (0); } } /* No file? OK, lets make one based on our interface */ type = htons (1); /* DUI-D-LLT */ memcpy (p, &type, 2); p += 2; hw = htons (iface->family); memcpy (p, &hw, 2); p += 2; /* time returns seconds from jan 1 1970, but DUID-LLT is * seconds from jan 1 2000 modulo 2^32 */ t = time (NULL) - THIRTY_YEARS_IN_SECONDS; ul = htonl (t & 0xffffffff); memcpy (p, &ul, 4); p += 4; /* Finally, add the MAC address of the interface */ memcpy (p, iface->hwaddr, iface->hwlen); p += iface->hwlen; len = p - duid; if (! (f = fopen (DUIDFILE, "w"))) logger (LOG_ERR, "fopen `%s': %s", DUIDFILE, strerror (errno)); else { x = fprintf (f, "%s\n", hwaddr_ntoa (duid, len)); fclose (f); } /* Failed to write the duid? scrub it, we cannot use it */ if (x < 1) { len = 0; unlink (DUIDFILE); } return (len); } #endif dhcpcd-3.2.3.orig/duid.h0000644000076400001440000000313410760476043013533 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef DUID_H #define DUID_H #include "config.h" #ifdef ENABLE_DUID #ifndef DUID_LEN # define DUID_LEN 128 + 2 #endif #include "interface.h" size_t get_duid (unsigned char *duid, const interface_t *iface); #endif #endif dhcpcd-3.2.3.orig/info.c0000644000076400001440000003046110760476043013537 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "dhcp.h" #include "interface.h" #include "logger.h" #include "info.h" #ifdef ENABLE_INFO /* Create a malloced string of cstr, changing ' to '\'' * so the contents work in a shell */ static char *cleanmetas (const char *cstr) { const char *p = cstr; char *new; char *n; size_t len; if (cstr == NULL || (len = strlen (cstr)) == 0) return (xstrdup ("")); n = new = xmalloc (sizeof (char) * len + 2); do if (*p == '\'') { size_t pos = n - new; len += 4; new = xrealloc (new, sizeof (char) * len + 1); n = new + pos; *n++ = '\''; *n++ = '\\'; *n++ = '\''; *n++ = '\''; } else *n++ = *p; while (*p++); /* Terminate the sucker */ *n = '\0'; return (new); } static void print_addresses (FILE *f, const struct address_head *addresses) { const address_t *addr; STAILQ_FOREACH (addr, addresses, entries) { fprintf (f, "%s", inet_ntoa (addr->address)); if (STAILQ_NEXT (addr, entries)) fprintf (f, " "); } } static void print_clean (FILE *f, const char *name, const char *value) { char *clean; if (! value) return; clean = cleanmetas (value); fprintf (f, "%s='%s'\n", name, clean); free (clean); } bool write_info(const interface_t *iface, const dhcp_t *dhcp, const options_t *options, bool overwrite) { FILE *f; route_t *route; struct stat sb; if (options->test) f = stdout; else { if (! overwrite && stat (iface->infofile, &sb) == 0) return (true); logger (LOG_DEBUG, "writing %s", iface->infofile); if ((f = fopen (iface->infofile, "w")) == NULL) { logger (LOG_ERR, "fopen `%s': %s", iface->infofile, strerror (errno)); return (false); } } if (dhcp->address.s_addr) { struct in_addr n; n.s_addr = dhcp->address.s_addr & dhcp->netmask.s_addr; fprintf (f, "IPADDR='%s'\n", inet_ntoa (dhcp->address)); fprintf (f, "NETMASK='%s'\n", inet_ntoa (dhcp->netmask)); fprintf (f, "NETWORK='%s'\n", inet_ntoa (n)); fprintf (f, "BROADCAST='%s'\n", inet_ntoa (dhcp->broadcast)); } if (dhcp->mtu > 0) fprintf (f, "MTU='%d'\n", dhcp->mtu); if (dhcp->routes) { bool doneone = false; fprintf (f, "ROUTES='"); STAILQ_FOREACH (route, dhcp->routes, entries) { if (route->destination.s_addr != 0) { if (doneone) fprintf (f, " "); fprintf (f, "%s", inet_ntoa (route->destination)); fprintf (f, ",%s", inet_ntoa (route->netmask)); fprintf (f, ",%s", inet_ntoa (route->gateway)); doneone = true; } } fprintf (f, "'\n"); doneone = false; fprintf (f, "GATEWAYS='"); STAILQ_FOREACH (route, dhcp->routes, entries) { if (route->destination.s_addr == 0) { if (doneone) fprintf (f, " "); fprintf (f, "%s", inet_ntoa (route->gateway)); doneone = true; } } fprintf (f, "'\n"); } print_clean (f, "HOSTNAME", dhcp->hostname); print_clean (f, "DNSDOMAIN", dhcp->dnsdomain); print_clean (f, "DNSSEARCH", dhcp->dnssearch); if (dhcp->dnsservers) { fprintf (f, "DNSSERVERS='"); print_addresses (f, dhcp->dnsservers); fprintf (f, "'\n"); } if (dhcp->fqdn) { fprintf (f, "FQDNFLAGS='%u'\n", dhcp->fqdn->flags); fprintf (f, "FQDNRCODE1='%u'\n", dhcp->fqdn->r1); fprintf (f, "FQDNRCODE2='%u'\n", dhcp->fqdn->r2); print_clean (f, "FQDNHOSTNAME", dhcp->fqdn->name); } if (dhcp->ntpservers) { fprintf (f, "NTPSERVERS='"); print_addresses (f, dhcp->ntpservers); fprintf (f, "'\n"); } print_clean (f, "NISDOMAIN", dhcp->nisdomain); if (dhcp->nisservers) { fprintf (f, "NISSERVERS='"); print_addresses (f, dhcp->nisservers); fprintf (f, "'\n"); } print_clean (f, "ROOTPATH", dhcp->rootpath); print_clean (f, "SIPSERVERS", dhcp->sipservers); if (dhcp->serveraddress.s_addr) fprintf (f, "DHCPSID='%s'\n", inet_ntoa (dhcp->serveraddress)); if (dhcp->servername[0]) print_clean (f, "DHCPSNAME", dhcp->servername); if (! options->doinform && dhcp->address.s_addr) { if (! options->test) fprintf (f, "LEASEDFROM='%u'\n", dhcp->leasedfrom); fprintf (f, "LEASETIME='%u'\n", dhcp->leasetime); fprintf (f, "RENEWALTIME='%u'\n", dhcp->renewaltime); fprintf (f, "REBINDTIME='%u'\n", dhcp->rebindtime); } print_clean (f, "INTERFACE", iface->name); print_clean (f, "CLASSID", options->classid); if (iface->clientid_len > 0) { fprintf (f, "CLIENTID='%s'\n", hwaddr_ntoa (iface->clientid, iface->clientid_len)); } fprintf (f, "DHCPCHADDR='%s'\n", hwaddr_ntoa (iface->hwaddr, iface->hwlen)); #ifdef ENABLE_INFO_COMPAT /* Support the old .info settings if we need to */ fprintf (f, "\n# dhcpcd-1.x and 2.x compatible variables\n"); if (dhcp->dnsservers) { address_t *addr; fprintf (f, "DNS='"); STAILQ_FOREACH (addr, dhcp->dnsservers, entries) { fprintf (f, "%s", inet_ntoa (addr->address)); if (STAILQ_NEXT (addr, entries)) fprintf (f, ","); } fprintf (f, "'\n"); } if (dhcp->routes) { bool doneone = false; fprintf (f, "GATEWAY='"); STAILQ_FOREACH (route, dhcp->routes, entries) { if (route->destination.s_addr == 0) { if (doneone) fprintf (f, ","); fprintf (f, "%s", inet_ntoa (route->gateway)); doneone = true; } } fprintf (f, "'\n"); } #endif if (! options->test) fclose (f); return (true); } static bool parse_address (struct in_addr *addr, const char *value, const char *var) { if (inet_aton (value, addr) == 0) { logger (LOG_ERR, "%s `%s': %s", var, value, strerror (errno)); return (false); } return (true); } static bool parse_uint (unsigned int *i, const char *value, const char *var) { if (sscanf (value, "%u", i) != 1) { logger (LOG_ERR, "%s `%s': not a valid number", var, value); return (false); } return (true); } static bool parse_ushort (unsigned short *s, const char *value, const char *var) { if (sscanf (value, "%hu", s) != 1) { logger (LOG_ERR, "%s `%s': not a valid number", var, value); return (false); } return (true); } static struct address_head *parse_addresses (char *value, const char *var) { char *token; char *p = value; struct address_head *head = NULL; while ((token = strsep (&p, " "))) { address_t *a = xzalloc (sizeof (*a)); if (inet_aton (token, &a->address) == 0) { logger (LOG_ERR, "%s: invalid address `%s'", var, token); free_address (head); free (a); return (NULL); } if (! head) { head = xmalloc (sizeof (*head)); STAILQ_INIT (head); } STAILQ_INSERT_TAIL (head, a, entries); } return (head); } bool read_info (const interface_t *iface, dhcp_t *dhcp) { FILE *fp; char *line; char *var; char *value; char *p; struct stat sb; if (stat (iface->infofile, &sb) != 0) { logger (LOG_ERR, "lease information file `%s' does not exist", iface->infofile); return (false); } if (! (fp = fopen (iface->infofile, "r"))) { logger (LOG_ERR, "fopen `%s': %s", iface->infofile, strerror (errno)); return (false); } dhcp->frominfo = true; while ((line = get_line (fp))) { var = line; /* Strip leading spaces/tabs */ while ((*var == ' ') || (*var == '\t')) var++; /* Trim trailing \n */ p = var + strlen (var) - 1; if (*p == '\n') *p = 0; /* Skip comments */ if (*var == '#') goto next; /* If we don't have an equals sign then skip it */ if (! (p = strchr (var, '='))) goto next; /* Terminate the = so we have two strings */ *p = 0; value = p + 1; /* Strip leading and trailing quotes if present */ if (*value == '\'' || *value == '"') value++; p = value + strlen (value) - 1; if (*p == '\'' || *p == '"') *p = 0; /* Don't process null vars or values */ if (! *var || ! *value) goto next; if (strcmp (var, "IPADDR") == 0) parse_address (&dhcp->address, value, "IPADDR"); else if (strcmp (var, "NETMASK") == 0) parse_address (&dhcp->netmask, value, "NETMASK"); else if (strcmp (var, "BROADCAST") == 0) parse_address (&dhcp->broadcast, value, "BROADCAST"); else if (strcmp (var, "MTU") == 0) parse_ushort (&dhcp->mtu, value, "MTU"); else if (strcmp (var, "ROUTES") == 0) { p = value; while ((value = strsep (&p, " "))) { char *pp = value; char *dest = strsep (&pp, ","); char *net = strsep (&pp, ","); char *gate = strsep (&pp, ","); route_t *route; if (! dest || ! net || ! gate) { logger (LOG_ERR, "read_info ROUTES `%s,%s,%s': invalid route", dest, net, gate); goto next; } /* See if we can create a route */ route = xzalloc (sizeof (*route)); if (inet_aton (dest, &route->destination) == 0) { logger (LOG_ERR, "read_info ROUTES `%s': not a valid destination address", dest); free (route); goto next; } if (inet_aton (dest, &route->netmask) == 0) { logger (LOG_ERR, "read_info ROUTES `%s': not a valid netmask address", net); free (route); goto next; } if (inet_aton (dest, &route->gateway) == 0) { logger (LOG_ERR, "read_info ROUTES `%s': not a valid gateway address", gate); free (route); goto next; } /* OK, now add our route */ if (! dhcp->routes) { dhcp->routes = xmalloc (sizeof (*dhcp->routes)); STAILQ_INIT (dhcp->routes); } STAILQ_INSERT_TAIL (dhcp->routes, route, entries); } } else if (strcmp (var, "GATEWAYS") == 0) { p = value; while ((value = strsep (&p, " "))) { route_t *route = xzalloc (sizeof (*route)); if (parse_address (&route->gateway, value, "GATEWAYS")) { if (! dhcp->routes) { dhcp->routes = xmalloc (sizeof (*dhcp->routes)); STAILQ_INIT (dhcp->routes); } STAILQ_INSERT_TAIL (dhcp->routes, route, entries); } else free (route); } } else if (strcmp (var, "HOSTNAME") == 0) dhcp->hostname = xstrdup (value); else if (strcmp (var, "DNSDOMAIN") == 0) dhcp->dnsdomain = xstrdup (value); else if (strcmp (var, "DNSSEARCH") == 0) dhcp->dnssearch = xstrdup (value); else if (strcmp (var, "DNSSERVERS") == 0) dhcp->dnsservers = parse_addresses (value, "DNSSERVERS"); else if (strcmp (var, "NTPSERVERS") == 0) dhcp->ntpservers = parse_addresses (value, "NTPSERVERS"); else if (strcmp (var, "NISDOMAIN") == 0) dhcp->nisdomain = xstrdup (value); else if (strcmp (var, "NISSERVERS") == 0) dhcp->nisservers = parse_addresses (value, "NISSERVERS"); else if (strcmp (var, "ROOTPATH") == 0) dhcp->rootpath = xstrdup (value); else if (strcmp (var, "DHCPSID") == 0) parse_address (&dhcp->serveraddress, value, "DHCPSID"); else if (strcmp (var, "DHCPSNAME") == 0) strlcpy (dhcp->servername, value, sizeof (dhcp->servername)); else if (strcmp (var, "LEASEDFROM") == 0) parse_uint (&dhcp->leasedfrom, value, "LEASEDFROM"); else if (strcmp (var, "LEASETIME") == 0) parse_uint (&dhcp->leasetime, value, "LEASETIME"); else if (strcmp (var, "RENEWALTIME") == 0) parse_uint (&dhcp->renewaltime, value, "RENEWALTIME"); else if (strcmp (var, "REBINDTIME") == 0) parse_uint (&dhcp->rebindtime, value, "REBINDTIME"); next: free (line); } fclose (fp); return (true); } #endif dhcpcd-3.2.3.orig/info.h0000644000076400001440000000324210760476043013541 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef INFO_H #define INFO_H #include "dhcpcd.h" #include "interface.h" #include "dhcp.h" #ifdef ENABLE_INFO bool write_info (const interface_t *iface, const dhcp_t *dhcp, const options_t *options, bool overwrite); bool read_info (const interface_t *iface, dhcp_t *dhcp); #endif #endif dhcpcd-3.2.3.orig/interface.c0000644000076400001440000006074210760476043014551 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include /* Netlink suff */ #ifdef __linux__ #include /* Needed for 2.4 kernels */ #include #include #include #include #else #include #include #include #include #endif #include #include #include #include #include #include #include #include "config.h" #include "common.h" #include "dhcp.h" #include "interface.h" #include "logger.h" void free_address (struct address_head *addresses) { address_t *p; address_t *n; if (! addresses) return; p = STAILQ_FIRST (addresses); while (p) { n = STAILQ_NEXT (p, entries); free (p); p = n; } free (addresses); } void free_route (struct route_head *routes) { route_t *p; route_t *n; if (! routes) return; p = STAILQ_FIRST (routes); while (p) { n = STAILQ_NEXT (p, entries); free (p); p = n; } free (routes); } int inet_ntocidr (struct in_addr address) { int cidr = 0; uint32_t mask = htonl (address.s_addr); while (mask) { cidr++; mask <<= 1; } return (cidr); } int inet_cidrtoaddr (int cidr, struct in_addr *addr) { int ocets; if (cidr < 0 || cidr > 32) { errno = EINVAL; return (-1); } ocets = (cidr + 7) / 8; memset (addr, 0, sizeof (*addr)); if (ocets > 0) { memset (&addr->s_addr, 255, (size_t) ocets - 1); memset ((unsigned char *) &addr->s_addr + (ocets - 1), (256 - (1 << (32 - cidr) % 8)), 1); } return (0); } uint32_t get_netmask (uint32_t addr) { uint32_t dst; if (addr == 0) return (0); dst = htonl (addr); if (IN_CLASSA (dst)) return (ntohl (IN_CLASSA_NET)); if (IN_CLASSB (dst)) return (ntohl (IN_CLASSB_NET)); if (IN_CLASSC (dst)) return (ntohl (IN_CLASSC_NET)); return (0); } char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen) { static char buffer[(HWADDR_LEN * 3) + 1]; char *p = buffer; size_t i; for (i = 0; i < hwlen && i < HWADDR_LEN; i++) { if (i > 0) *p ++= ':'; p += snprintf (p, 3, "%.2x", hwaddr[i]); } *p ++= '\0'; return (buffer); } size_t hwaddr_aton (unsigned char *buffer, const char *addr) { char c[3]; const char *p = addr; unsigned char *bp = buffer; size_t len = 0; c[2] = '\0'; while (*p) { c[0] = *p++; c[1] = *p++; /* Ensure that next data is EOL or a seperator with data */ if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) { errno = EINVAL; return (0); } /* Ensure that digits are hex */ if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) { errno = EINVAL; return (0); } p++; if (bp) *bp++ = (unsigned char) strtol (c, NULL, 16); else len++; } if (bp) return (bp - buffer); return (len); } static int _do_interface (const char *ifname, _unused unsigned char *hwaddr, _unused size_t *hwlen, struct in_addr *addr, bool flush, bool get) { int s; struct ifconf ifc; int retval = 0; int len = 10 * sizeof (struct ifreq); int lastlen = 0; char *p; if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return -1; } /* Not all implementations return the needed buffer size for * SIOGIFCONF so we loop like so for all until it works */ memset (&ifc, 0, sizeof (ifc)); for (;;) { ifc.ifc_len = len; ifc.ifc_buf = xmalloc ((size_t) len); if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { if (errno != EINVAL || lastlen != 0) { logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", strerror (errno)); close (s); free (ifc.ifc_buf); return -1; } } else { if (ifc.ifc_len == lastlen) break; lastlen = ifc.ifc_len; } free (ifc.ifc_buf); ifc.ifc_buf = NULL; len *= 2; } for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) { union { char *buffer; struct ifreq *ifr; } ifreqs; struct sockaddr_in address; struct ifreq *ifr; /* Cast the ifc buffer to an ifreq cleanly */ ifreqs.buffer = p; ifr = ifreqs.ifr; #ifdef __linux__ p += sizeof (*ifr); #else p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len; #endif if (strcmp (ifname, ifr->ifr_name) != 0) continue; #ifdef AF_LINK if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) { struct sockaddr_dl sdl; memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl)); *hwlen = sdl.sdl_alen; memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, (size_t) sdl.sdl_alen); retval = 1; break; } #endif if (ifr->ifr_addr.sa_family == AF_INET) { memcpy (&address, &ifr->ifr_addr, sizeof (address)); if (flush) { struct sockaddr_in netmask; if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) { logger (LOG_ERR, "ioctl SIOCGIFNETMASK: %s", strerror (errno)); continue; } memcpy (&netmask, &ifr->ifr_addr, sizeof (netmask)); if (del_address (ifname, address.sin_addr, netmask.sin_addr) == -1) retval = -1; } else if (get) { addr->s_addr = address.sin_addr.s_addr; retval = 1; break; } else if (address.sin_addr.s_addr == addr->s_addr) { retval = 1; break; } } } close (s); free (ifc.ifc_buf); return retval; } interface_t *read_interface (const char *ifname, _unused int metric) { int s; struct ifreq ifr; interface_t *iface = NULL; unsigned char *hwaddr = NULL; size_t hwlen = 0; sa_family_t family = 0; unsigned short mtu; #ifdef __linux__ char *p; #endif if (! ifname) return NULL; memset (&ifr, 0, sizeof (ifr)); strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return NULL; } #ifdef __linux__ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); goto exit; } switch (ifr.ifr_hwaddr.sa_family) { case ARPHRD_ETHER: case ARPHRD_IEEE802: hwlen = ETHER_ADDR_LEN; break; case ARPHRD_IEEE1394: hwlen = EUI64_ADDR_LEN; case ARPHRD_INFINIBAND: hwlen = INFINIBAND_ADDR_LEN; break; default: logger (LOG_ERR, "interface is not Ethernet, FireWire, " \ "InfiniBand or Token Ring"); goto exit; } hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); family = ifr.ifr_hwaddr.sa_family; #else ifr.ifr_metric = metric; strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); goto exit; } hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) { logger (LOG_ERR, "could not find interface %s", ifname); goto exit; } family = ARPHRD_ETHER; #endif strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCGIFMTU, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); goto exit; } if (ifr.ifr_mtu < MTU_MIN) { logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", ifr.ifr_mtu, MTU_MIN); ifr.ifr_mtu = MTU_MIN; strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); if (ioctl (s, SIOCSIFMTU, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", strerror (errno)); goto exit; } } mtu = ifr.ifr_mtu; strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); #ifdef __linux__ /* We can only bring the real interface up */ if ((p = strchr (ifr.ifr_name, ':'))) *p = '\0'; #endif if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) { logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); goto exit; } if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) { ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) { logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", strerror (errno)); goto exit; } } iface = xzalloc (sizeof (*iface)); strlcpy (iface->name, ifname, IF_NAMESIZE); #ifdef ENABLE_INFO snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); #endif 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; #ifdef __linux__ iface->listen_fd = -1; #endif exit: close (s); free (hwaddr); return iface; } int get_mtu (const char *ifname) { struct ifreq ifr; int r; int s; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return (-1); } memset (&ifr, 0, sizeof (ifr)); strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); r = ioctl (s, SIOCGIFMTU, &ifr); close (s); if (r == -1) { logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); return (-1); } return (ifr.ifr_mtu); } int set_mtu (const char *ifname, short int mtu) { struct ifreq ifr; int r; int s; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return (-1); } memset (&ifr, 0, sizeof (ifr)); logger (LOG_DEBUG, "setting MTU to %d", mtu); strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); ifr.ifr_mtu = mtu; r = ioctl (s, SIOCSIFMTU, &ifr); close (s); if (r == -1) logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); return (r == 0 ? 0 : -1); } static void log_route (struct in_addr destination, struct in_addr netmask, struct in_addr gateway, _unused int metric, int change, int del) { char *dstd = xstrdup (inet_ntoa (destination)); #ifdef __linux__ #define METRIC " metric %d" #else #define METRIC "" #endif if (gateway.s_addr == destination.s_addr || gateway.s_addr == INADDR_ANY) logger (LOG_INFO, "%s route to %s/%d" METRIC, change ? "changing" : del ? "removing" : "adding", dstd, inet_ntocidr (netmask) #ifdef __linux__ , metric #endif ); else if (destination.s_addr == INADDR_ANY) logger (LOG_INFO, "%s default route via %s" METRIC, change ? "changing" : del ? "removing" : "adding", inet_ntoa (gateway) #ifdef __linux__ , metric #endif ); else logger (LOG_INFO, "%s route to %s/%d via %s" METRIC, change ? "changing" : del ? "removing" : "adding", dstd, inet_ntocidr (netmask), inet_ntoa (gateway) #ifdef __linux__ , metric #endif ); free (dstd); } #if defined(BSD) || defined(__FreeBSD_kernel__) /* Darwin doesn't define this for some very odd reason */ #ifndef SA_SIZE # define SA_SIZE(sa) \ ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ sizeof(long) : \ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) #endif static int do_address (const char *ifname, struct in_addr address, struct in_addr netmask, struct in_addr broadcast, int del) { int s; struct ifaliasreq ifa; if (! ifname) return -1; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return -1; } memset (&ifa, 0, sizeof (ifa)); strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name)); #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 (*_s.sin); \ memcpy (&_s.sin->sin_addr, &_addr, sizeof (_s.sin->sin_addr)); \ } ADDADDR (ifa.ifra_addr, address); ADDADDR (ifa.ifra_mask, netmask); if (! del) ADDADDR (ifa.ifra_broadaddr, broadcast); #undef ADDADDR if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) { logger (LOG_ERR, "ioctl %s: %s", del ? "SIOCDIFADDR" : "SIOCAIFADDR", strerror (errno)); close (s); return -1; } close (s); return 0; } 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) { int s; static int seq; union sockunion { struct sockaddr sa; struct sockaddr_in sin; #ifdef INET6 struct sockaddr_in6 sin6; #endif struct sockaddr_dl sdl; struct sockaddr_storage ss; } su; struct rtm { struct rt_msghdr hdr; char buffer[sizeof (su) * 3]; } rtm; char *bp = rtm.buffer; size_t l; if (! ifname) return -1; log_route (destination, netmask, gateway, metric, change, del); if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return -1; } memset (&rtm, 0, sizeof (rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = ++seq; rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC; /* This order is important */ rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; #define ADDADDR(_addr) \ memset (&su, 0, sizeof (su)); \ su.sin.sin_family = AF_INET; \ su.sin.sin_len = sizeof (su.sin); \ memcpy (&su.sin.sin_addr, &_addr, sizeof (su.sin.sin_addr)); \ l = SA_SIZE (&(su.sa)); \ memcpy (bp, &(su), l); \ bp += l; ADDADDR (destination); if (netmask.s_addr == INADDR_BROADCAST || gateway.s_addr == INADDR_ANY) { /* Make us a link layer socket */ unsigned char *hwaddr; size_t hwlen = 0; if (netmask.s_addr == INADDR_BROADCAST) rtm.hdr.rtm_flags |= RTF_HOST; hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); memset (&su, 0, sizeof (su)); su.sdl.sdl_len = sizeof (su.sdl); su.sdl.sdl_family = AF_LINK; su.sdl.sdl_nlen = strlen (ifname); memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen); su.sdl.sdl_alen = hwlen; memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, hwaddr, (size_t) su.sdl.sdl_alen); l = SA_SIZE (&(su.sa)); memcpy (bp, &su, l); bp += l; free (hwaddr); } else { rtm.hdr.rtm_flags |= RTF_GATEWAY; ADDADDR (gateway); } ADDADDR (netmask); #undef ADDADDR rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; if (write (s, &rtm, l) == -1) { /* Don't report error about routes already existing */ if (errno != EEXIST) logger (LOG_ERR, "write: %s", strerror (errno)); close (s); return -1; } close (s); return 0; } #elif __linux__ /* This netlink stuff is overly compex IMO. * The BSD implementation is much cleaner and a lot less code. * send_netlink handles the actual transmission so we can work out * if there was an error or not. */ #define BUFFERLEN 256 int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg) { int s; pid_t mypid = getpid (); struct sockaddr_nl nl; struct iovec iov; struct msghdr msg; static unsigned int seq; char *buffer; ssize_t bytes; union { char *buffer; struct nlmsghdr *nlm; } h; if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return -1; } memset (&nl, 0, sizeof (nl)); nl.nl_family = AF_NETLINK; if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) { logger (LOG_ERR, "bind: %s", strerror (errno)); close (s); return -1; } memset (&iov, 0, sizeof (iov)); iov.iov_base = hdr; iov.iov_len = hdr->nlmsg_len; memset (&msg, 0, sizeof (msg)); msg.msg_name = &nl; msg.msg_namelen = sizeof (nl); msg.msg_iov = &iov; msg.msg_iovlen = 1; /* Request a reply */ hdr->nlmsg_flags |= NLM_F_ACK; hdr->nlmsg_seq = ++seq; if (sendmsg (s, &msg, 0) == -1) { logger (LOG_ERR, "write: %s", strerror (errno)); close (s); return -1; } buffer = xzalloc (sizeof (char) * BUFFERLEN); iov.iov_base = buffer; for (;;) { iov.iov_len = BUFFERLEN; bytes = recvmsg (s, &msg, 0); if (bytes == -1) { if (errno != EINTR) logger (LOG_ERR, "recvmsg: %s", strerror (errno)); continue; } if (bytes == 0) { logger (LOG_ERR, "netlink: EOF"); goto eexit; } if (msg.msg_namelen != sizeof (nl)) { logger (LOG_ERR, "netlink: sender address length mismatch"); goto eexit; } for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) { int len = h.nlm->nlmsg_len; int l = len - sizeof (*h.nlm); struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); if (l < 0 || len > bytes) { if (msg.msg_flags & MSG_TRUNC) logger (LOG_ERR, "netlink: truncated message"); else logger (LOG_ERR, "netlink: malformed message"); goto eexit; } /* Ensure it's our message */ if (nl.nl_pid != 0 || (pid_t) h.nlm->nlmsg_pid != mypid || h.nlm->nlmsg_seq != seq) { /* Next Message */ bytes -= NLMSG_ALIGN (len); h.buffer += NLMSG_ALIGN (len); continue; } /* We get an NLMSG_ERROR back with a code of zero for success */ if (h.nlm->nlmsg_type != NLMSG_ERROR) { logger (LOG_ERR, "netlink: unexpected reply %d", h.nlm->nlmsg_type); goto eexit; } if ((unsigned) l < sizeof (*err)) { logger (LOG_ERR, "netlink: error truncated"); goto eexit; } if (err->error == 0) { int retval = 0; close (s); if (callback) { if ((retval = callback (hdr, arg)) == -1) logger (LOG_ERR, "netlink: callback failed"); } free (buffer); return (retval); } errno = -err->error; /* Don't report on something already existing */ if (errno != EEXIST) logger (LOG_ERR, "netlink: %s", strerror (errno)); goto eexit; } } eexit: close (s); free (buffer); return -1; } #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) static int add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type, const void *data, int alen) { 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) { int len = RTA_LENGTH (sizeof (data)); struct rtattr *rta; if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) { logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", maxlen); return -1; } rta = NLMSG_TAIL (n); rta->rta_type = type; rta->rta_len = len; memcpy (RTA_DATA (rta), &data, sizeof (data)); n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; return 0; } struct nlma { struct nlmsghdr hdr; struct ifaddrmsg ifa; char buffer[64]; }; struct nlmr { struct nlmsghdr hdr; struct rtmsg rt; char buffer[256]; }; static int do_address(const char *ifname, struct in_addr address, struct in_addr netmask, struct in_addr broadcast, int del) { struct nlma *nlm; int retval; if (!ifname) return -1; nlm = xzalloc (sizeof (*nlm)); nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); nlm->hdr.nlmsg_flags = NLM_F_REQUEST; if (! del) nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) { logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", ifname); free (nlm); return -1; } nlm->ifa.ifa_family = AF_INET; nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); /* This creates the aliased interface */ add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL, ifname, strlen (ifname) + 1); add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL, &address.s_addr, sizeof (address.s_addr)); if (! del) add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, &broadcast.s_addr, sizeof (broadcast.s_addr)); retval = send_netlink (&nlm->hdr, NULL, NULL); free (nlm); return retval; } static int do_route (const char *ifname, struct in_addr destination, struct in_addr netmask, struct in_addr gateway, int metric, int change, int del) { struct nlmr *nlm; unsigned int ifindex; int retval; if (! ifname) return -1; log_route (destination, netmask, gateway, metric, change, del); if (! (ifindex = if_nametoindex (ifname))) { logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", ifname); return -1; } nlm = xzalloc (sizeof (*nlm)); nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); if (change) nlm->hdr.nlmsg_flags = NLM_F_REPLACE; else if (! del) nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; nlm->rt.rtm_family = AF_INET; nlm->rt.rtm_table = RT_TABLE_MAIN; if (del) nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; else { nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; nlm->rt.rtm_protocol = RTPROT_BOOT; if (netmask.s_addr == INADDR_BROADCAST || gateway.s_addr == INADDR_ANY) nlm->rt.rtm_scope = RT_SCOPE_LINK; else nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; nlm->rt.rtm_type = RTN_UNICAST; } nlm->rt.rtm_dst_len = inet_ntocidr (netmask); add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST, &destination.s_addr, sizeof (destination.s_addr)); if (netmask.s_addr != INADDR_BROADCAST && destination.s_addr != gateway.s_addr) add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY, &gateway.s_addr, sizeof (gateway.s_addr)); add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); retval = send_netlink (&nlm->hdr, NULL, NULL); free (nlm); return retval; } #else #error "Platform not supported!" #error "We currently support BPF and Linux sockets." #error "Other platforms may work using BPF. If yours does, please let me know" #error "so I can add it to our list." #endif int add_address (const char *ifname, struct in_addr address, struct in_addr netmask, struct in_addr broadcast) { logger (LOG_INFO, "adding IP address %s/%d", inet_ntoa (address), inet_ntocidr (netmask)); 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 t; logger (LOG_INFO, "removing IP address %s/%d", inet_ntoa (address), inet_ntocidr (netmask)); memset (&t, 0, sizeof (t)); return (do_address (ifname, address, netmask, t, 1)); } int add_route (const char *ifname, struct in_addr destination, struct in_addr netmask, struct in_addr gateway, int metric) { 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) { 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) { return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); } int flush_addresses (const char *ifname) { return (_do_interface (ifname, NULL, NULL, NULL, true, false)); } in_addr_t get_address (const char *ifname) { struct in_addr address; if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) return (address.s_addr); return (0); } int has_address (const char *ifname, struct in_addr address) { return (_do_interface (ifname, NULL, NULL, &address, false, false)); } dhcpcd-3.2.3.orig/interface.h0000644000076400001440000001163310760476043014551 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef INTERFACE_H #define INTERFACE_H #include #include #include #include #include #include #include #include #include #include "config.h" #ifdef __linux__ # include #endif #ifdef ENABLE_DUID #ifndef DUID_LEN # define DUID_LEN 128 + 2 #endif #endif #define EUI64_ADDR_LEN 8 #define INFINIBAND_ADDR_LEN 20 /* Linux 2.4 doesn't define this */ #ifndef ARPHRD_IEEE1394 # define ARPHRD_IEEE1394 24 #endif /* The BSD's don't define this yet */ #ifndef ARPHRD_INFINIBAND # define ARPHRD_INFINIBAND 32 #endif #define HWADDR_LEN 20 /* Work out if we have a private address or not * 10/8 * 172.16/12 * 192.168/16 */ #ifndef IN_PRIVATE # define IN_PRIVATE(addr) (((addr & IN_CLASSA_NET) == 0x0a000000) || \ ((addr & 0xfff00000) == 0xac100000) || \ ((addr & IN_CLASSB_NET) == 0xc0a80000)) #endif #define LINKLOCAL_ADDR 0xa9fe0000 #define LINKLOCAL_MASK 0xffff0000 #define LINKLOCAL_BRDC 0xa9feffff #ifndef IN_LINKLOCAL # define IN_LINKLOCAL(addr) ((addr & IN_CLASSB_NET) == LINKLOCAL_ADDR) #endif #ifndef STAILQ_ENTRY # error "your sys/queue.h is too old and lacks STAILQ" #endif #define NSTAILQ_FOREACH(var, head, field) \ if (head) STAILQ_FOREACH (var, head, field) typedef struct route_t { struct in_addr destination; struct in_addr netmask; struct in_addr gateway; STAILQ_ENTRY (route_t) entries; } route_t; STAILQ_HEAD (route_head, route_t); typedef struct address_t { struct in_addr address; STAILQ_ENTRY (address_t) entries; } address_t; STAILQ_HEAD (address_head, address_t); typedef struct interface_t { char name[IF_NAMESIZE]; sa_family_t family; unsigned char hwaddr[HWADDR_LEN]; size_t hwlen; bool arpable; unsigned short mtu; int fd; size_t buffer_length; #ifdef __linux__ int listen_fd; int socket_protocol; #endif char infofile[PATH_MAX]; unsigned short previous_mtu; struct in_addr previous_address; struct in_addr previous_netmask; struct route_head *previous_routes; time_t start_uptime; unsigned char *clientid; size_t clientid_len; } interface_t; void free_address (struct address_head *addresses); void free_route (struct route_head *routes); uint32_t get_netmask (uint32_t addr); char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen); size_t hwaddr_aton (unsigned char *hwaddr, const char *addr); interface_t *read_interface (const char *ifname, int metric); 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); int del_address (const char *ifname, struct in_addr address, struct in_addr netmask); int flush_addresses (const char *ifname); in_addr_t get_address (const char *ifname); int has_address (const char *ifname, struct in_addr address); int add_route (const char *ifname, struct in_addr destination, struct in_addr netmask, struct in_addr gateway, int metric); int change_route (const char *ifname, struct in_addr destination, 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); int inet_ntocidr (struct in_addr address); int inet_cidrtoaddr (int cidr, struct in_addr *addr); #ifdef __linux__ typedef int (*netlink_callback) (struct nlmsghdr *hdr, void *arg); int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg); #endif #endif dhcpcd-3.2.3.orig/ipv4ll.c0000644000076400001440000000436510760476043014022 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "config.h" #include "arp.h" #include "ipv4ll.h" #ifdef ENABLE_IPV4LL #ifndef ENABLE_ARP # error IPV4LL requires ARP #endif #define IPV4LL_LEASETIME 20 int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp) { struct in_addr addr; for (;;) { addr.s_addr = htonl (LINKLOCAL_ADDR | (((uint32_t) abs ((int) random ()) % 0xFD00) + 0x0100)); errno = 0; if (! arp_claim (iface, addr)) break; /* Our ARP may have been interrupted */ if (errno) return (-1); } dhcp->address.s_addr = addr.s_addr; dhcp->netmask.s_addr = htonl (LINKLOCAL_MASK); dhcp->broadcast.s_addr = htonl (LINKLOCAL_BRDC); /* Finally configure some DHCP like lease times */ dhcp->leasetime = IPV4LL_LEASETIME; dhcp->renewaltime = (dhcp->leasetime * 0.5); dhcp->rebindtime = (dhcp->leasetime * 0.875); return (0); } #endif dhcpcd-3.2.3.orig/ipv4ll.h0000644000076400001440000000304710760476043014023 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef IPV4LL_H #define IPV4LL_H #ifdef ENABLE_IPV4LL #include "dhcp.h" #include "interface.h" int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp); #endif #endif dhcpcd-3.2.3.orig/logger.c0000644000076400001440000000613510760476043014064 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define SYSLOG_NAMES #include #include #include #include #include #include #include "common.h" #include "logger.h" static int loglevel = LOG_WARNING; static char logprefix[12] = {0}; int logtolevel (const char *priority) { CODE *c; if (isdigit ((int) *priority)) return (atoi (priority)); for (c = prioritynames; c->c_name; c++) if (! strcasecmp (priority, c->c_name)) return (c->c_val); return (-1); } static const char *leveltolog (int level) { CODE *c; for (c = prioritynames; c->c_name; c++) if (c->c_val == level) return (c->c_name); return (NULL); } void setloglevel (int level) { loglevel = level; } void setlogprefix (const char *prefix) { snprintf (logprefix, sizeof (logprefix), "%s", prefix); } void logger (int level, const char *fmt, ...) { va_list p; va_list p2; FILE *f = stderr; 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", leveltolog (level), logprefix); vfprintf (f, fmt, p); fputc ('\n', f); /* stdout, stderr may be re-directed to some kind of buffer. * So we always flush to ensure it's written. */ fflush (f); } if (level < LOG_DEBUG || level <= loglevel) { size_t len = strlen (logprefix); size_t fmt2len = strlen (fmt) + len + 1; char *fmt2 = malloc (sizeof (char) * fmt2len); char *pf = fmt2; if (fmt2) { memcpy (pf, logprefix, len); pf += len; strlcpy (pf, fmt, fmt2len - len); vsyslog (level, fmt2, p2); free (fmt2); } else { vsyslog (level, fmt, p2); syslog (LOG_ERR, "logger: memory exhausted"); exit (EXIT_FAILURE); } } va_end (p2); va_end (p); } dhcpcd-3.2.3.orig/logger.h0000644000076400001440000000341310760476043014065 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef LOGGER_H #define LOGGER_H #if defined(__GNUC__) # define _PRINTF_LIKE(_one, _two) __attribute__ ((__format__ (__printf__, _one, _two))) #else # define _PRINTF_LIKE(_one, _two) #endif #include int logtolevel (const char *priority); void setloglevel (int level); void setlogprefix (const char *prefix); void logger (int level, const char *fmt, ...) _PRINTF_LIKE (2, 3); #endif dhcpcd-3.2.3.orig/mk/0000755000076400001440000000000010760476043013043 5ustar srkusersdhcpcd-3.2.3.orig/mk/cc.mk0000644000076400001440000000151110760476043013757 0ustar srkusers# Copyright 2008 Roy Marples # Setup some good default CFLAGS CFLAGS?= -O2 # Default to using the C99 standard CSTD?= c99 _CSTD_SH= if test -n "${CSTD}"; then echo "-std=${CSTD}"; else echo ""; fi _CSTD!= ${_CSTD_SH} CFLAGS+= ${_CSTD}$(shell ${_CSTD_SH}) # Try and use some good cc flags _CC_FLAGS= -pedantic -Wall -Wunused -Wimplicit -Wshadow -Wformat=2 \ -Wmissing-declarations -Wno-missing-prototypes -Wwrite-strings \ -Wbad-function-cast -Wnested-externs -Wcomment -Winline \ -Wchar-subscripts -Wcast-align -Wno-format-nonliteral \ -Wdeclaration-after-statement -Wsequence-point -Wextra _CC_FLAGS_SH= for f in ${_CC_FLAGS}; do \ if ${CC} $$f -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ then printf "%s" "$$f "; fi \ done _CC_FLAGS!= ${_CC_FLAGS_SH} CFLAGS+= ${_CC_FLAGS}$(shell ${CC_FLAGS_SH}) dhcpcd-3.2.3.orig/mk/depend.mk0000644000076400001440000000041210760476043014630 0ustar srkusers# This only works for make implementations that always include a .depend if # it exists. Only GNU make does not do this. # Copyright 2008 Roy Marples CLEANFILES+= .depend .depend: ${SRCS} ${CC} ${CFLAGS} -MM ${SRCS} > .depend depend: .depend dhcpcd-3.2.3.orig/mk/dist.mk0000644000076400001440000000043510760476043014341 0ustar srkusers# rules to make a distribution tarball from a git repo # Copyright 2008 Roy Marples GITREF?= HEAD DISTPREFIX?= ${PROG}-${VERSION} DISTFILE?= ${DISTPREFIX}.tar.bz2 CLEANFILES+= ${DISTFILE} dist: git archive --prefix=${DISTPREFIX}/ ${GITREF} | bzip2 > ${DISTFILE} dhcpcd-3.2.3.orig/mk/man.mk0000644000076400001440000000055110760476043014150 0ustar srkusers# rules to install manpages # Copyright 2008 Roy Marples MANPREFIX?= /usr/share MANDIR?= ${MANPREFIX}/man/man MANMODE?= 0444 MINSTALL?= ${INSTALL} -m ${MANMODE} man: ${MAN} # We cheat as all our pages go into section 8 maninstall: man ${INSTALL} -d ${DESTDIR}${MANDIR}8 for man in ${MAN}; do ${MINSTALL} $$man ${DESTDIR}${MANDIR}8; done dhcpcd-3.2.3.orig/mk/os.mk0000644000076400001440000000546110760476043014023 0ustar srkusers# Setup OS specific variables # Copyright 2008 Roy Marples # Work out if we need -lresolv or not _LIBRESOLV_SH= printf '\#include \n\#include \nint main (void) { return (res_init ()); }\n' > .res_init.c; \ if ${CC} .res_init.c -o .res_init >/dev/null 2>&1; then \ echo ""; \ elif ${CC} .res_init.c -lresolv -o .res_init >/dev/null 2>&1; then \ echo "-lresolv"; \ else \ echo "Cannot work out how to get res_init to link" >&2; \ rm -f .res_init.c .res_init; \ exit 1; \ fi; \ rm -f .res_init.c .res_init _LIBRESOLV!= ${_LIBRESOLV_SH} LIBRESOLV= ${_LIBRESOLV}$(shell ${_LIBRESOLV_SH}) # Work out if we need -lrt or not _LIBRT_SH= printf '\#include \n\#include \n\nint main (void) { struct timespec ts;\n\#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)\nreturn (clock_gettime (CLOCK_MONOTONIC, &ts));\n\#else\nreturn -1;\n\#endif\n}\n' > .clock_gettime.c; \ if ${CC} .clock_gettime.c -o .clock_gettime >/dev/null 2>&1; then \ echo ""; \ elif ${CC} .clock_gettime.c -lrt -o .clock_gettime >/dev/null 2>&1; then \ echo "-lrt"; \ else \ echo ""; \ fi; \ rm -f .clock_gettime.c .clock_gettime _LIBRT!= ${_LIBRT_SH} LIBRT= ${_LIBRT}$(shell ${_LIBRT_SH}) # Work out if our fork() works or not _HAVE_FORK_SH= if test "${HAVE_FORK}" = "yes"; then \ echo ""; \ elif test -n "${HAVE_FORK}"; then \ echo "-DTHERE_IS_NO_FORK"; \ else \ printf '\#include \n\#include \nint main (void) { pid_t pid = fork(); if (pid == -1) exit (-1); exit (0); }\n' > .fork.c; \ ${CC} .fork.c -o .fork >/dev/null 2>&1; \ if ./.fork; then \ echo ""; \ else \ echo "-DTHERE_IS_NO_FORK"; \ fi; \ rm -f .fork.c .fork; \ fi; _HAVE_FORK!= ${_HAVE_FORK_SH} FORK= ${_HAVE_FORK}$(shell ${_HAVE_FORK_SH}) # info dir defaults to /var/lib/dhcpcd on Linux and /var/db elsewhere _INFODIR_SH= if test -n "${INFODIR}"; then \ echo "${INFODIR}"; \ else \ case `uname -s` in \ Linux) echo "/var/lib/dhcpcd";; \ *) echo "/var/db";; \ esac \ fi _INFODIR!= ${_INFODIR_SH} INFOD?= ${_INFODIR}$(shell ${_INFODIR_SH}) # Work out how to restart services _RC_SH= if test -n "${HAVE_INIT}"; then \ test "${HAVE_INIT}" = "no" || echo "-DENABLE_${HAVE_INIT}"; \ elif test -x /sbin/runscript; then echo "-DENABLE_OPENRC"; \ elif test -x /sbin/service; then echo "-DENABLE_SERVICE"; \ elif test -x /etc/rc.d/rc.S -a -x /etc/rc.d/rc.M; then echo "-DENABLE_SLACKRC"; \ elif test -d /etc/rc.d; then echo "-DENABLE_BSDRC"; \ elif test -d /etc/init.d; then echo "-DENABLE_SYSV"; \ fi _RC!= ${_RC_SH} RC= ${_RC}$(shell ${_RC_SH}) # glibc requires _BSD_SOURCE and _XOPEN_SOURCE _DEF_SH= case `uname -s` in Linux) echo "-D_BSD_SOURCE -D_XOPEN_SOURCE=600";; *) echo;; esac _DEF!= ${_DEF_SH} CFLAGS+= ${_DEF}$(shell ${_DEF_SH}) dhcpcd-3.2.3.orig/mk/prog.mk0000644000076400001440000000123010760476043014337 0ustar srkusers# rules to build a program # based on FreeBSD's bsd.prog.mk # Copyright 2008 Roy Marples BINDIR?= ${PREFIX}/usr/bin BINMODE?= 0755 OBJS+= ${SRCS:.c=.o} INSTALL?= install all: ${PROG} ${MAN} ${PROG}: ${SCRIPTS} ${OBJS} ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LDADD} _proginstall: ${PROG} ${INSTALL} -d ${DESTDIR}${BINDIR} ${INSTALL} -m ${BINMODE} ${PROG} ${DESTDIR}${BINDIR} include ${MK}/depend.mk include ${MK}/man.mk include ${MK}/dist.mk install: _proginstall maninstall clean: rm -f ${OBJS} ${PROG} ${CLEANFILES} LINTFLAGS?= -hx LINTFLAGS+= -X 159,247,352 lint: ${SRCS:.c=.c} ${LINT} ${LINTFLAGS} ${CFLAGS:M-[DIU]*} $^ ${.ALLSRC} dhcpcd-3.2.3.orig/signal.c0000644000076400001440000001114710760476043014061 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include "common.h" #include "logger.h" #include "signal.h" static int signal_pipe[2]; static int signals[5]; static const int handle_sigs[] = { SIGHUP, SIGALRM, SIGTERM, SIGINT }; static void signal_handler (int sig) { unsigned int i = 0; int serrno = errno; /* Add a signal to our stack */ while (signals[i]) i++; if (i > sizeof (signals) / sizeof (signals[0])) logger (LOG_ERR, "signal buffer overrun"); else signals[i] = sig; if (write (signal_pipe[1], &sig, sizeof (sig)) == -1) logger (LOG_ERR, "Could not send signal: %s", strerror (errno)); /* Restore errno */ errno = serrno; } int signal_fd (void) { return (signal_pipe[0]); } /* Check if we have a signal or not */ int signal_exists (const struct pollfd *fd) { if (signals[0] || (fd && fd->revents & POLLIN)) return (0); return (-1); } /* Read a signal from the signal pipe. Returns 0 if there is * no signal, -1 on error (and sets errno appropriately), and * your signal on success */ int signal_read (struct pollfd *fd) { int sig = -1; /* Pop a signal off the our stack */ if (signals[0]) { unsigned int i = 0; sig = signals[0]; while (i < (sizeof (signals) / sizeof (signals[0])) - 1) { signals[i] = signals[i + 1]; if (! signals[++i]) break; } } if (fd && fd->revents & POLLIN) { char buf[16]; size_t bytes; memset (buf, 0, sizeof (buf)); bytes = read (signal_pipe[0], buf, sizeof (buf)); if (bytes >= sizeof (sig)) memcpy (&sig, buf, sizeof (sig)); /* We need to clear us from rset if nothing left in the buffer * in case we are called many times */ if (bytes == sizeof (sig)) fd->revents = 0; } return (sig); } /* Call this before doing anything else. Sets up the socket pair * and installs the signal handler */ int signal_init (void) { struct sigaction sa; if (pipe (signal_pipe) == -1) { logger (LOG_ERR, "pipe: %s", strerror (errno)); return (-1); } /* Stop any scripts from inheriting us */ close_on_exec (signal_pipe[0]); close_on_exec (signal_pipe[1]); /* Ignore child signals and don't make zombies. * Because we do this, we don't need to be in signal_setup */ memset (&sa, 0, sizeof (sa)); sa.sa_handler = SIG_DFL; sa.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT; if (sigaction (SIGCHLD, &sa, NULL) == -1) { logger (LOG_ERR, "sigaction: %s", strerror (errno)); return (-1); } memset (signals, 0, sizeof (signals)); return (0); } int signal_setup (void) { unsigned int i; struct sigaction sa; memset (&sa, 0, sizeof (sa)); sa.sa_handler = signal_handler; sigemptyset (&sa.sa_mask); for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) if (sigaction (handle_sigs[i], &sa, NULL) == -1) { logger (LOG_ERR, "sigaction: %s", strerror (errno)); return (-1); } return (0); } int signal_reset (void) { struct sigaction sa; unsigned int i; memset (&sa, 0, sizeof (sa)); sa.sa_handler = SIG_DFL; sigemptyset (&sa.sa_mask); for (i = 0; i < sizeof (handle_sigs) / sizeof (handle_sigs[0]); i++) if (sigaction (handle_sigs[i], &sa, NULL) == -1) { logger (LOG_ERR, "sigaction: %s", strerror (errno)); return (-1); } return (0); } dhcpcd-3.2.3.orig/signal.h0000644000076400001440000000315210760476043014063 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef SIGNAL_H #define SIGNAL_H #include int signal_init (void); int signal_setup (void); int signal_reset (void); int signal_fd (void); int signal_exists (const struct pollfd *fd); int signal_read (struct pollfd *fd); #endif dhcpcd-3.2.3.orig/socket.c0000644000076400001440000004146010760476043014075 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #define __FAVOR_BSD /* Nasty hack so we can use BSD semantics for UDP */ #include #undef __FAVOR_BSD #include #include #include #include #include #include #include #include #if defined(BSD) || defined(__FreeBSD_kernel__) # include #elif __linux__ # include # include # define bpf_insn sock_filter #endif #include "config.h" #include "dhcp.h" #include "interface.h" #include "logger.h" #include "socket.h" /* A suitably large buffer for all transactions. * BPF buffer size is set by the kernel, so no define. */ #ifdef __linux__ # define BUFFER_LENGTH 4096 #endif /* Broadcast address for IPoIB */ static const uint8_t ipv4_bcast_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }; /* Credit where credit is due :) * The below BPF filter is taken from ISC DHCP */ static struct bpf_insn dhcp_bpf_filter [] = { /* Make sure this is an IP packet... */ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8), /* 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), /* 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), /* If we passed all the tests, ask for the whole packet. */ BPF_STMT (BPF_RET + BPF_K, ~0U), /* Otherwise, drop it. */ BPF_STMT (BPF_RET + BPF_K, 0), }; static struct bpf_insn arp_bpf_filter [] = { /* Make sure this is an ARP packet... */ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 12), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_ARP, 0, 3), /* Make sure this is an ARP REPLY... */ BPF_STMT (BPF_LD + BPF_H + BPF_ABS, 20), BPF_JUMP (BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), /* If we passed all the tests, ask for the whole packet. */ BPF_STMT (BPF_RET + BPF_K, ~0U), /* Otherwise, drop it. */ BPF_STMT (BPF_RET + BPF_K, 0), }; void setup_packet_filters (void) { #ifdef __linux__ /* We need to massage the filters for Linux cooked packets */ dhcp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ dhcp_bpf_filter[2].k -= ETH_HLEN; dhcp_bpf_filter[4].k -= ETH_HLEN; dhcp_bpf_filter[6].k -= ETH_HLEN; dhcp_bpf_filter[7].k -= ETH_HLEN; arp_bpf_filter[1].jf = 0; /* skip the IP packet type check */ arp_bpf_filter[2].k -= ETH_HLEN; #endif } static uint16_t checksum (unsigned char *addr, uint16_t len) { uint32_t sum = 0; union { unsigned char *addr; uint16_t *i; } p; uint16_t nleft = len; p.addr = addr; while (nleft > 1) { sum += *p.i++; nleft -= 2; } if (nleft == 1) { uint8_t a = 0; memcpy (&a, p.i, 1); sum += ntohs (a) << 8; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); return ~sum; } void make_dhcp_packet(struct udp_dhcp_packet *packet, const unsigned char *data, size_t length, struct in_addr source, struct in_addr dest) { struct ip *ip = &packet->ip; struct udphdr *udp = &packet->udp; /* OK, this is important :) * We copy the data to our packet and then create a small part of the * ip structure and an invalid ip_len (basically udp length). * We then fill the udp structure and put the checksum * of the whole packet into the udp checksum. * Finally we complete the ip structure and ip checksum. * If we don't do the ordering like so then the udp checksum will be * broken, so find another way of doing it! */ memcpy (&packet->dhcp, data, length); ip->ip_p = IPPROTO_UDP; ip->ip_src.s_addr = source.s_addr; if (dest.s_addr == 0) ip->ip_dst.s_addr = INADDR_BROADCAST; else ip->ip_dst.s_addr = dest.s_addr; udp->uh_sport = htons (DHCP_CLIENT_PORT); udp->uh_dport = htons (DHCP_SERVER_PORT); udp->uh_ulen = htons (sizeof (*udp) + length); ip->ip_len = udp->uh_ulen; udp->uh_sum = checksum ((unsigned char *) packet, sizeof (*packet)); ip->ip_v = IPVERSION; ip->ip_hl = 5; ip->ip_id = 0; ip->ip_tos = IPTOS_LOWDELAY; ip->ip_len = htons (sizeof (*ip) + sizeof (*udp) + length); ip->ip_id = 0; ip->ip_off = htons (IP_DF); /* Don't fragment */ ip->ip_ttl = IPDEFTTL; ip->ip_sum = checksum ((unsigned char *) ip, sizeof (*ip)); } static int valid_dhcp_packet (unsigned char *data) { union { unsigned char *data; struct udp_dhcp_packet *packet; } d; uint16_t bytes; uint16_t ipsum; uint16_t iplen; uint16_t udpsum; struct in_addr source; struct in_addr dest; int retval = 0; d.data = data; bytes = ntohs (d.packet->ip.ip_len); ipsum = d.packet->ip.ip_sum; iplen = d.packet->ip.ip_len; udpsum = d.packet->udp.uh_sum; d.data = data; d.packet->ip.ip_sum = 0; if (ipsum != checksum ((unsigned char *) &d.packet->ip, sizeof (d.packet->ip))) { logger (LOG_DEBUG, "bad IP header checksum, ignoring"); retval = -1; goto eexit; } memcpy (&source, &d.packet->ip.ip_src, sizeof (d.packet->ip.ip_src)); memcpy (&dest, &d.packet->ip.ip_dst, sizeof (d.packet->ip.ip_dst)); memset (&d.packet->ip, 0, sizeof (d.packet->ip)); d.packet->udp.uh_sum = 0; d.packet->ip.ip_p = IPPROTO_UDP; memcpy (&d.packet->ip.ip_src, &source, sizeof (d.packet->ip.ip_src)); memcpy (&d.packet->ip.ip_dst, &dest, sizeof (d.packet->ip.ip_dst)); d.packet->ip.ip_len = d.packet->udp.uh_ulen; if (udpsum && udpsum != checksum (d.data, bytes)) { logger (LOG_ERR, "bad UDP checksum, ignoring"); retval = -1; } eexit: d.packet->ip.ip_sum = ipsum; d.packet->ip.ip_len = iplen; d.packet->udp.uh_sum = udpsum; return retval; } #if defined(BSD) || defined(__FreeBSD_kernel__) int open_socket (interface_t *iface, int protocol) { int n = 0; int fd = -1; char *device; int flags; struct ifreq ifr; int buf = 0; struct bpf_program pf; device = xmalloc (sizeof (char) * PATH_MAX); do { snprintf (device, PATH_MAX, "/dev/bpf%d", n++); fd = open (device, O_RDWR); } while (fd == -1 && errno == EBUSY); free (device); if (fd == -1) { logger (LOG_ERR, "unable to open a BPF device"); return -1; } close_on_exec (fd); memset (&ifr, 0, sizeof (ifr)); strlcpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); if (ioctl (fd, BIOCSETIF, &ifr) == -1) { logger (LOG_ERR, "cannot attach interface `%s' to bpf device `%s': %s", iface->name, device, strerror (errno)); close (fd); return -1; } /* Get the required BPF buffer length from the kernel. */ if (ioctl (fd, BIOCGBLEN, &buf) == -1) { logger (LOG_ERR, "ioctl BIOCGBLEN: %s", strerror (errno)); close (fd); return -1; } iface->buffer_length = buf; flags = 1; if (ioctl (fd, BIOCIMMEDIATE, &flags) == -1) { logger (LOG_ERR, "ioctl BIOCIMMEDIATE: %s", strerror (errno)); close (fd); return -1; } /* Install the DHCP filter */ if (protocol == ETHERTYPE_ARP) { pf.bf_insns = arp_bpf_filter; pf.bf_len = sizeof (arp_bpf_filter) / sizeof (arp_bpf_filter[0]); } else { pf.bf_insns = dhcp_bpf_filter; pf.bf_len = sizeof (dhcp_bpf_filter) / sizeof (dhcp_bpf_filter[0]); } if (ioctl (fd, BIOCSETF, &pf) == -1) { logger (LOG_ERR, "ioctl BIOCSETF: %s", strerror (errno)); close (fd); return -1; } if (iface->fd > -1) close (iface->fd); iface->fd = fd; return fd; } ssize_t send_packet (const interface_t *iface, int type, const unsigned char *data, size_t len) { ssize_t retval = -1; struct iovec iov[2]; if (iface->family == ARPHRD_ETHER) { struct ether_header hw; memset (&hw, 0, sizeof (hw)); memset (&hw.ether_dhost, 0xff, ETHER_ADDR_LEN); hw.ether_type = htons (type); iov[0].iov_base = &hw; iov[0].iov_len = sizeof (hw); } else { logger (LOG_ERR, "unsupported interace type %d", iface->family); return -1; } iov[1].iov_base = (unsigned char *) data; iov[1].iov_len = len; if ((retval = writev(iface->fd, iov, 2)) == -1) logger (LOG_ERR, "writev: %s", strerror (errno)); return retval; } /* BPF requires that we read the entire buffer. * So we pass the buffer in the API so we can loop on >1 dhcp packet. */ ssize_t get_packet (const interface_t *iface, unsigned char *data, unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos) { union { unsigned char *buffer; struct bpf_hdr *packet; } bpf; bpf.buffer = buffer; if (*buffer_pos < 1) { memset (bpf.buffer, 0, iface->buffer_length); *buffer_len = read (iface->fd, bpf.buffer, iface->buffer_length); *buffer_pos = 0; if (*buffer_len < 1) { struct timespec ts; logger (LOG_ERR, "read: %s", strerror (errno)); ts.tv_sec = 3; ts.tv_nsec = 0; nanosleep (&ts, NULL); return (-1); } } else bpf.buffer += *buffer_pos; while (bpf.packet) { size_t len = 0; union { unsigned char *buffer; struct ether_header *hw; } hdr; unsigned char *payload; bool have_data = false; /* Ensure that the entire packet is in our buffer */ if (*buffer_pos + bpf.packet->bh_hdrlen + bpf.packet->bh_caplen > (unsigned) *buffer_len) break; hdr.buffer = bpf.buffer + bpf.packet->bh_hdrlen; payload = hdr.buffer + sizeof (*hdr.hw); /* If it's an ARP reply, then just send it back */ if (hdr.hw->ether_type == htons (ETHERTYPE_ARP)) { len = bpf.packet->bh_caplen - sizeof (*hdr.hw); memcpy (data, payload, len); have_data = true; } else { if (valid_dhcp_packet (payload) >= 0) { union { unsigned char *buffer; struct udp_dhcp_packet *packet; } pay; pay.buffer = payload; len = ntohs (pay.packet->ip.ip_len) - sizeof (pay.packet->ip) - sizeof (pay.packet->udp); memcpy (data, &pay.packet->dhcp, len); have_data = true; } } /* Update the buffer_pos pointer */ bpf.buffer += BPF_WORDALIGN (bpf.packet->bh_hdrlen + bpf.packet->bh_caplen); if ((unsigned) (bpf.buffer - buffer) < *buffer_len) *buffer_pos = bpf.buffer - buffer; else *buffer_pos = 0; if (have_data) return len; if (*buffer_pos == 0) break; } /* No valid packets left, so return */ *buffer_pos = 0; return -1; } #elif __linux__ int open_socket (interface_t *iface, int protocol) { int fd; union sockunion { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_ll sll; struct sockaddr_storage ss; } su; struct sock_fprog pf; struct ifreq ifr; int n = 1; /* We need to bind to a port, otherwise Linux generate ICMP messages * that cannot contect the port when we have an address. * We don't actually use this fd at all, instead using our packet * filter socket. */ if (iface->listen_fd == -1 && protocol == ETHERTYPE_IP) { if ((fd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); } else { memset (&su, 0, sizeof (su)); su.sin.sin_family = AF_INET; su.sin.sin_port = htons (DHCP_CLIENT_PORT); if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof (n)) == -1) logger (LOG_ERR, "SO_REUSEADDR: %s", strerror (errno)); if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &n, sizeof (n)) == -1) logger (LOG_ERR, "SO_RCVBUF: %s", strerror (errno)); memset (&ifr, 0, sizeof (ifr)); strncpy (ifr.ifr_name, iface->name, sizeof (ifr.ifr_name)); if (setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) == -1) logger (LOG_ERR, "SO_SOBINDTODEVICE: %s", strerror (errno)); if (bind (fd, &su.sa, sizeof (su)) == -1) { logger (LOG_ERR, "bind: %s", strerror (errno)); close (fd); } else { iface->listen_fd = fd; close_on_exec (fd); } } } if ((fd = socket (PF_PACKET, SOCK_DGRAM, htons (protocol))) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return (-1); } close_on_exec (fd); memset (&su, 0, sizeof (su)); su.sll.sll_family = PF_PACKET; su.sll.sll_protocol = htons (protocol); if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", iface->name); close (fd); return (-1); } /* Install the DHCP filter */ memset (&pf, 0, sizeof (pf)); if (protocol == ETHERTYPE_ARP) { pf.filter = arp_bpf_filter; pf.len = sizeof (arp_bpf_filter) / sizeof (arp_bpf_filter[0]); } else { pf.filter = dhcp_bpf_filter; pf.len = sizeof (dhcp_bpf_filter) / sizeof (dhcp_bpf_filter[0]); } if (setsockopt (fd, SOL_SOCKET, SO_ATTACH_FILTER, &pf, sizeof (pf)) != 0) { logger (LOG_ERR, "SO_ATTACH_FILTER: %s", strerror (errno)); close (fd); return (-1); } if (bind (fd, &su.sa, sizeof (su)) == -1) { logger (LOG_ERR, "bind: %s", strerror (errno)); close (fd); return (-1); } if (iface->fd > -1) close (iface->fd); iface->fd = fd; iface->socket_protocol = protocol; iface->buffer_length = BUFFER_LENGTH; return (fd); } ssize_t send_packet (const interface_t *iface, int type, const unsigned char *data, size_t len) { union sockunion { struct sockaddr sa; struct sockaddr_ll sll; struct sockaddr_storage ss; } su; ssize_t retval; if (! iface) return (-1); memset (&su, 0, sizeof (su)); su.sll.sll_family = AF_PACKET; su.sll.sll_protocol = htons (type); if (! (su.sll.sll_ifindex = if_nametoindex (iface->name))) { logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", iface->name); return (-1); } su.sll.sll_hatype = htons (iface->family); su.sll.sll_halen = iface->hwlen; if (iface->family == ARPHRD_INFINIBAND) memcpy (&su.sll.sll_addr, &ipv4_bcast_addr, sizeof (ipv4_bcast_addr)); else memset (&su.sll.sll_addr, 0xff, iface->hwlen); if ((retval = sendto (iface->fd, data, len, 0, &su.sa, sizeof (su))) == -1) logger (LOG_ERR, "sendto: %s", strerror (errno)); return (retval); } /* Linux has no need for the buffer as we can read as much as we want. * We only have the buffer listed to keep the same API. */ ssize_t get_packet (const interface_t *iface, unsigned char *data, unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos) { ssize_t bytes; union { unsigned char *buffer; struct udp_dhcp_packet *packet; } pay; /* We don't use the given buffer, but we need to rewind the position */ *buffer_pos = 0; memset (buffer, 0, iface->buffer_length); bytes = read (iface->fd, buffer, iface->buffer_length); if (bytes == -1) { struct timespec ts; logger (LOG_ERR, "read: %s", strerror (errno)); ts.tv_sec = 3; ts.tv_nsec = 0; nanosleep (&ts, NULL); return (-1); } *buffer_len = bytes; /* If it's an ARP reply, then just send it back */ if (iface->socket_protocol == ETHERTYPE_ARP) { memcpy (data, buffer, bytes); return (bytes); } if ((unsigned) bytes < (sizeof (pay.packet->ip) + sizeof (pay.packet->udp))) { logger (LOG_DEBUG, "message too short, ignoring"); return (-1); } pay.buffer = buffer; if (bytes < ntohs (pay.packet->ip.ip_len)) { logger (LOG_DEBUG, "truncated packet, ignoring"); return (-1); } if (valid_dhcp_packet (buffer) == -1) return (-1); bytes = ntohs (pay.packet->ip.ip_len) - (sizeof (pay.packet->ip) + sizeof (pay.packet->udp)); memcpy (data, &pay.packet->dhcp, bytes); return (bytes); } #else #error "Platform not supported!" #error "We currently support BPF and Linux sockets." #error "Other platforms may work using BPF. If yours does, please let me know" #error "so I can add it to our list." #endif dhcpcd-3.2.3.orig/socket.h0000644000076400001440000000371110760476043014077 0ustar srkusers/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef SOCKET_H #define SOCKET_H #include #include "dhcp.h" #include "interface.h" void setup_packet_filters (void); void make_dhcp_packet(struct udp_dhcp_packet *packet, const unsigned char *data, size_t length, struct in_addr source, struct in_addr dest); int open_socket (interface_t *iface, int protocol); ssize_t send_packet (const interface_t *iface, int type, const unsigned char *data, size_t len); ssize_t get_packet (const interface_t *iface, unsigned char *data, unsigned char *buffer, size_t *buffer_len, size_t *buffer_pos); #endif