diff options
author | Dmitry Shmidt <dimitrysh@google.com> | 2011-01-24 16:27:51 -0800 |
---|---|---|
committer | Dmitry Shmidt <dimitrysh@google.com> | 2011-01-24 16:27:51 -0800 |
commit | e86eee143ed21592f88a46623a81f71002430459 (patch) | |
tree | e0be4ce113729bce176fd5054aeaf51a88b2e169 /net.c | |
parent | 6bcc301d166624837871fd601b4d3b5d43551e6b (diff) | |
download | android_external_dhcpcd-e86eee143ed21592f88a46623a81f71002430459.tar.gz android_external_dhcpcd-e86eee143ed21592f88a46623a81f71002430459.tar.bz2 android_external_dhcpcd-e86eee143ed21592f88a46623a81f71002430459.zip |
dhcpcd: Update to Version 5.2.10
Change-Id: I949331c7aad91b125decd51da4041983d3a352bc
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'net.c')
-rw-r--r-- | net.c | 654 |
1 files changed, 361 insertions, 293 deletions
@@ -1,6 +1,6 @@ /* * dhcpcd - DHCP client daemon - * Copyright 2006-2008 Roy Marples <roy@marples.name> + * Copyright (c) 2006-2010 Roy Marples <roy@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without @@ -27,45 +27,52 @@ #include <sys/types.h> #include <sys/ioctl.h> +#include <sys/param.h> #include <sys/socket.h> #include <sys/time.h> +#include <arpa/inet.h> #include <net/if.h> #include <net/if_arp.h> -#include <arpa/inet.h> -#include <netinet/in_systm.h> -#ifdef __linux__ -#include <netinet/ether.h> -#include <netpacket/packet.h> +#ifdef AF_LINK +# include <net/if_dl.h> +# include <net/if_types.h> #endif +#include <netinet/in_systm.h> #include <netinet/in.h> #include <netinet/ip.h> #define __FAVOR_BSD /* Nasty glibc hack so we can use BSD semantics for UDP */ #include <netinet/udp.h> #undef __FAVOR_BSD -#ifdef SIOCGIFMEDIA -#include <net/if_media.h> +#ifdef AF_PACKET +# include <netpacket/packet.h> #endif -#include <arpa/inet.h> -#ifdef AF_LINK -# include <net/if_dl.h> +#ifdef SIOCGIFMEDIA +# include <net/if_media.h> #endif #include <ctype.h> #include <errno.h> +#include <ifaddrs.h> +#include <fnmatch.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <syslog.h> #include <unistd.h> #include "config.h" #include "common.h" #include "dhcp.h" -#include "logger.h" +#include "if-options.h" #include "net.h" #include "signals.h" +static char hwaddr_buffer[(HWADDR_LEN * 3) + 1]; + +int socket_afnet = -1; + int inet_ntocidr(struct in_addr address) { @@ -76,7 +83,6 @@ inet_ntocidr(struct in_addr address) cidr++; mask <<= 1; } - return cidr; } @@ -85,7 +91,7 @@ inet_cidrtoaddr(int cidr, struct in_addr *addr) { int ocets; - if (cidr < 0 || cidr > 32) { + if (cidr < 1 || cidr > 32) { errno = EINVAL; return -1; } @@ -95,7 +101,7 @@ inet_cidrtoaddr(int cidr, struct in_addr *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); + (256 - (1 << (32 - cidr) % 8)), 1); } return 0; @@ -123,8 +129,7 @@ get_netmask(uint32_t addr) char * hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen) { - static char buffer[(HWADDR_LEN * 3) + 1]; - char *p = buffer; + char *p = hwaddr_buffer; size_t i; for (i = 0; i < hwlen && i < HWADDR_LEN; i++) { @@ -135,7 +140,7 @@ hwaddr_ntoa(const unsigned char *hwaddr, size_t hwlen) *p ++= '\0'; - return buffer; + return hwaddr_buffer; } size_t @@ -176,274 +181,368 @@ hwaddr_aton(unsigned char *buffer, const char *addr) return len; } -int -do_interface(const char *ifname, - _unused unsigned char *hwaddr, _unused size_t *hwlen, - struct in_addr *addr, struct in_addr *net, int get) +struct interface * +init_interface(const char *ifname) { - int s; - struct ifconf ifc; - int retval = 0, found = 0; - int len = 10 * sizeof(struct ifreq); - int lastlen = 0; - char *p; - union { - char *buffer; - struct ifreq *ifr; - } ifreqs; - struct sockaddr_in address; - struct ifreq *ifr; - struct sockaddr_in netmask; -#ifdef AF_LINK - struct sockaddr_dl *sdl; -#endif - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return -1; + struct ifreq ifr; + struct interface *iface = NULL; - /* 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) { - close(s); - free(ifc.ifc_buf); - return -1; - } - } else { - if (ifc.ifc_len == lastlen) - break; - lastlen = ifc.ifc_len; - } + memset(&ifr, 0, sizeof(ifr)); + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1) + goto eexit; - free(ifc.ifc_buf); - ifc.ifc_buf = NULL; - len *= 2; + iface = xzalloc(sizeof(*iface)); + strlcpy(iface->name, ifname, sizeof(iface->name)); + iface->flags = ifr.ifr_flags; + /* We reserve the 100 range for virtual interfaces, if and when + * we can work them out. */ + iface->metric = 200 + if_nametoindex(iface->name); + if (getifssid(ifname, iface->ssid) != -1) { + iface->wireless = 1; + iface->metric += 100; } - for (p = (char *)ifc.ifc_buf; p < (char *)ifc.ifc_buf + ifc.ifc_len;) { - /* Cast the ifc buffer to an ifreq cleanly */ - ifreqs.buffer = p; - ifr = ifreqs.ifr; - -#ifndef __linux__ - if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_ifru)) - p += offsetof(struct ifreq, ifr_ifru) + - ifr->ifr_addr.sa_len; - else -#endif - p += sizeof(*ifr); - - if (strcmp(ifname, ifr->ifr_name) != 0) - continue; - - found = 1; + if (ioctl(socket_afnet, SIOCGIFMTU, &ifr) == -1) + goto eexit; + /* Ensure that the MTU is big enough for DHCP */ + if (ifr.ifr_mtu < MTU_MIN) { + ifr.ifr_mtu = MTU_MIN; + strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + if (ioctl(socket_afnet, SIOCSIFMTU, &ifr) == -1) + goto eexit; + } -#ifdef AF_LINK - if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) { - sdl = xmalloc(ifr->ifr_addr.sa_len); - memcpy(sdl, &ifr->ifr_addr, ifr->ifr_addr.sa_len); - *hwlen = sdl->sdl_alen; - memcpy(hwaddr, LLADDR(sdl), *hwlen); - free(sdl); - retval = 1; - break; - } -#endif + snprintf(iface->leasefile, sizeof(iface->leasefile), + LEASEFILE, ifname); + /* 0 is a valid fd, so init to -1 */ + iface->raw_fd = -1; + iface->udp_fd = -1; + iface->arp_fd = -1; + goto exit; - if (ifr->ifr_addr.sa_family == AF_INET) { - memcpy(&address, &ifr->ifr_addr, sizeof(address)); - if (ioctl(s, SIOCGIFNETMASK, ifr) == -1) - continue; - memcpy(&netmask, &ifr->ifr_addr, sizeof(netmask)); - if (get) { - addr->s_addr = address.sin_addr.s_addr; - net->s_addr = netmask.sin_addr.s_addr; - retval = 1; - break; - } else { - if (address.sin_addr.s_addr == addr->s_addr && - (!net || - netmask.sin_addr.s_addr == net->s_addr)) - { - retval = 1; - break; - } - } - } +eexit: + free(iface); + iface = NULL; +exit: + return iface; +} +void +free_interface(struct interface *iface) +{ + if (!iface) + return; + if (iface->state) { + free_options(iface->state->options); + free(iface->state->old); + free(iface->state->new); + free(iface->state->offer); + free(iface->state); } - - if (!found) - errno = ENXIO; - close(s); - free(ifc.ifc_buf); - return retval; + free(iface->clientid); + free(iface); } int -up_interface(const char *ifname) +carrier_status(struct interface *iface) { - int s; + int ret; struct ifreq ifr; - int retval = -1; +#ifdef SIOCGIFMEDIA + struct ifmediareq ifmr; +#endif #ifdef __linux__ char *p; #endif - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return -1; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); #ifdef __linux__ - /* We can only bring the real interface up */ + /* We can only test the real interface up */ if ((p = strchr(ifr.ifr_name, ':'))) *p = '\0'; #endif - if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) { - if ((ifr.ifr_flags & IFF_UP)) - retval = 0; - else { - ifr.ifr_flags |= IFF_UP; - if (ioctl(s, SIOCSIFFLAGS, &ifr) == 0) - retval = 0; - } - } - close(s); - return retval; + + if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == -1) + return -1; + iface->flags = ifr.ifr_flags; + + ret = -1; +#ifdef SIOCGIFMEDIA + memset(&ifmr, 0, sizeof(ifmr)); + strlcpy(ifmr.ifm_name, iface->name, sizeof(ifmr.ifm_name)); + if (ioctl(socket_afnet, SIOCGIFMEDIA, &ifmr) != -1 && + ifmr.ifm_status & IFM_AVALID) + ret = (ifmr.ifm_status & IFM_ACTIVE) ? 1 : 0; +#endif + if (ret == -1) + ret = (ifr.ifr_flags & IFF_RUNNING) ? 1 : 0; + return ret; } int -carrier_status(const char *ifname) +up_interface(struct interface *iface) { - int s; struct ifreq ifr; int retval = -1; -#ifdef SIOCGIFMEDIA - struct ifmediareq ifmr; -#endif #ifdef __linux__ char *p; #endif - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return -1; memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); #ifdef __linux__ - /* We can only test the real interface up */ + /* We can only bring the real interface up */ if ((p = strchr(ifr.ifr_name, ':'))) *p = '\0'; #endif - if ((retval = ioctl(s, SIOCGIFFLAGS, &ifr)) == 0) { - if (ifr.ifr_flags & IFF_UP && ifr.ifr_flags & IFF_RUNNING) - retval = 1; - else + if (ioctl(socket_afnet, SIOCGIFFLAGS, &ifr) == 0) { + if ((ifr.ifr_flags & IFF_UP)) retval = 0; - } - -#ifdef SIOCGIFMEDIA - if (retval == 1) { - memset(&ifmr, 0, sizeof(ifmr)); - strncpy(ifmr.ifm_name, ifr.ifr_name, sizeof(ifmr.ifm_name)); - if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1 && - ifmr.ifm_status & IFM_AVALID) - { - if (!(ifmr.ifm_status & IFM_ACTIVE)) + else { + ifr.ifr_flags |= IFF_UP; + if (ioctl(socket_afnet, SIOCSIFFLAGS, &ifr) == 0) retval = 0; } + iface->flags = ifr.ifr_flags; } -#endif - close(s); return retval; } struct interface * -read_interface(const char *ifname, _unused int metric) +discover_interfaces(int argc, char * const *argv) { - int s; - struct ifreq ifr; - struct interface *iface = NULL; - unsigned char *hwaddr = NULL; - size_t hwlen = 0; - sa_family_t family = 0; - - memset(&ifr, 0, sizeof(ifr)); - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); + struct ifaddrs *ifaddrs, *ifa; + char *p; + int i; + struct interface *ifp, *ifs, *ifl; +#ifdef __linux__ + char ifn[IF_NAMESIZE]; +#endif +#ifdef AF_LINK + const struct sockaddr_dl *sdl; +#ifdef IFLR_ACTIVE + struct if_laddrreq iflr; + int socket_aflink; - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + socket_aflink = socket(AF_LINK, SOCK_DGRAM, 0); + if (socket_aflink == -1) return NULL; + memset(&iflr, 0, sizeof(iflr)); +#endif +#elif AF_PACKET + const struct sockaddr_ll *sll; +#endif -#ifdef __linux__ - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFHWADDR, &ifr) == -1) - goto eexit; + if (getifaddrs(&ifaddrs) == -1) + return NULL; - switch (ifr.ifr_hwaddr.sa_family) { - case ARPHRD_ETHER: - case ARPHRD_IEEE802: - hwlen = ETHER_ADDR_LEN; - break; - case ARPHRD_IEEE1394: - hwlen = EUI64_ADDR_LEN; - case ARPHRD_INFINIBAND: - hwlen = INFINIBAND_ADDR_LEN; - break; - } + ifs = ifl = NULL; + for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr != NULL) { +#ifdef AF_LINK + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; +#elif AF_PACKET + if (ifa->ifa_addr->sa_family != AF_PACKET) + continue; +#endif + } - hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN); - memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); - family = ifr.ifr_hwaddr.sa_family; + /* It's possible for an interface to have >1 AF_LINK. + * For our purposes, we use the first one. */ + for (ifp = ifs; ifp; ifp = ifp->next) + if (strcmp(ifp->name, ifa->ifa_name) == 0) + break; + if (ifp) + continue; + if (argc > 0) { + for (i = 0; i < argc; i++) { +#ifdef __linux__ + /* Check the real interface name */ + strlcpy(ifn, argv[i], sizeof(ifn)); + p = strchr(ifn, ':'); + if (p) + *p = '\0'; + if (strcmp(ifn, ifa->ifa_name) == 0) + break; #else - ifr.ifr_metric = metric; - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCSIFMETRIC, &ifr) == -1) - goto eexit; + if (strcmp(argv[i], ifa->ifa_name) == 0) + break; +#endif + } + if (i == argc) + continue; + p = argv[i]; + } else { + /* -1 means we're discovering against a specific + * interface, but we still need the below rules + * to apply. */ + if (argc == -1 && strcmp(argv[0], ifa->ifa_name) != 0) + continue; + for (i = 0; i < ifdc; i++) + if (!fnmatch(ifdv[i], ifa->ifa_name, 0)) + break; + if (i < ifdc) + continue; + for (i = 0; i < ifac; i++) + if (!fnmatch(ifav[i], ifa->ifa_name, 0)) + break; + if (ifac && i == ifac) + continue; + p = ifa->ifa_name; + } + if ((ifp = init_interface(p)) == NULL) + continue; - hwaddr = xmalloc(sizeof(unsigned char) * HWADDR_LEN); - if (do_interface(ifname, hwaddr, &hwlen, NULL, NULL, 0) != 1) - goto eexit; + /* Bring the interface up if not already */ + if (!(ifp->flags & IFF_UP) +#ifdef SIOCGIFMEDIA + && carrier_status(ifp) != -1 +#endif + ) + { + if (up_interface(ifp) == 0) + options |= DHCPCD_WAITUP; + else + syslog(LOG_ERR, "%s: up_interface: %m", ifp->name); + } - family = ARPHRD_ETHER; + /* Don't allow loopback unless explicit */ + if (ifp->flags & IFF_LOOPBACK) { + if (argc == 0 && ifac == 0) { + free_interface(ifp); + continue; + } + } else if (ifa->ifa_addr != NULL) { +#ifdef AF_LINK + sdl = (const struct sockaddr_dl *)(void *)ifa->ifa_addr; + +#ifdef IFLR_ACTIVE + /* We need to check for active address */ + strlcpy(iflr.iflr_name, ifp->name, + sizeof(iflr.iflr_name)); + memcpy(&iflr.addr, ifa->ifa_addr, + MIN(ifa->ifa_addr->sa_len, sizeof(iflr.addr))); + iflr.flags = IFLR_PREFIX; + iflr.prefixlen = sdl->sdl_alen * NBBY; + if (ioctl(socket_aflink, SIOCGLIFADDR, &iflr) == -1 || + !(iflr.flags & IFLR_ACTIVE)) + { + free_interface(ifp); + continue; + } #endif - strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); - if (ioctl(s, SIOCGIFMTU, &ifr) == -1) - goto eexit; + switch(sdl->sdl_type) { + case IFT_ETHER: + ifp->family = ARPHRD_ETHER; + break; + case IFT_IEEE1394: + ifp->family = ARPHRD_IEEE1394; + break; + } + ifp->hwlen = sdl->sdl_alen; +#ifndef CLLADDR +# define CLLADDR(s) ((const char *)((s)->sdl_data + (s)->sdl_nlen)) +#endif + memcpy(ifp->hwaddr, CLLADDR(sdl), ifp->hwlen); +#elif AF_PACKET + sll = (const struct sockaddr_ll *)(void *)ifa->ifa_addr; + ifp->family = sll->sll_hatype; + ifp->hwlen = sll->sll_halen; + if (ifp->hwlen != 0) + memcpy(ifp->hwaddr, sll->sll_addr, ifp->hwlen); +#endif + } - /* Ensure that the MTU is big enough for DHCP */ - if (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) - goto eexit; + /* We only work on ethernet by default */ + if (!(ifp->flags & IFF_POINTOPOINT) && + ifp->family != ARPHRD_ETHER) + { + if (argc == 0 && ifac == 0) { + free_interface(ifp); + continue; + } + switch (ifp->family) { + case ARPHRD_IEEE1394: /* FALLTHROUGH */ + case ARPHRD_INFINIBAND: + /* We don't warn for supported families */ + break; + default: + syslog(LOG_WARNING, + "%s: unknown hardware family", p); + } + } + + /* Handle any platform init for the interface */ + if (if_init(ifp) == -1) { + syslog(LOG_ERR, "%s: if_init: %m", p); + free_interface(ifp); + continue; + } + + if (ifl) + ifl->next = ifp; + else + ifs = ifp; + ifl = ifp; } + freeifaddrs(ifaddrs); - if (up_interface(ifname) != 0) - goto eexit; +#ifdef IFLR_ACTIVE + close(socket_aflink); +#endif - iface = xzalloc(sizeof(*iface)); - strlcpy(iface->name, ifname, IF_NAMESIZE); - snprintf(iface->leasefile, PATH_MAX, LEASEFILE, ifname); - memcpy(&iface->hwaddr, hwaddr, hwlen); - iface->hwlen = hwlen; + return ifs; +} - iface->family = family; - iface->arpable = !(ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)); +int +do_address(const char *ifname, + struct in_addr *addr, struct in_addr *net, struct in_addr *dst, int act) +{ + struct ifaddrs *ifaddrs, *ifa; + const struct sockaddr_in *a, *n, *d; + int retval; - /* 0 is a valid fd, so init to -1 */ - iface->raw_fd = -1; - iface->udp_fd = -1; - iface->arp_fd = -1; - iface->link_fd = -1; + if (getifaddrs(&ifaddrs) == -1) + return -1; -eexit: - close(s); - free(hwaddr); - return iface; + retval = 0; + for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr == NULL || + ifa->ifa_addr->sa_family != AF_INET || + strcmp(ifa->ifa_name, ifname) != 0) + continue; + a = (const struct sockaddr_in *)(void *)ifa->ifa_addr; + n = (const struct sockaddr_in *)(void *)ifa->ifa_netmask; + if (ifa->ifa_flags & IFF_POINTOPOINT) + d = (const struct sockaddr_in *)(void *) + ifa->ifa_dstaddr; + else + d = NULL; + if (act == 1) { + addr->s_addr = a->sin_addr.s_addr; + net->s_addr = n->sin_addr.s_addr; + if (dst) { + if (ifa->ifa_flags & IFF_POINTOPOINT) + dst->s_addr = d->sin_addr.s_addr; + else + dst->s_addr = INADDR_ANY; + } + retval = 1; + break; + } + if (addr->s_addr == a->sin_addr.s_addr && + (net == NULL || net->s_addr == n->sin_addr.s_addr)) + { + retval = 1; + break; + } + } + freeifaddrs(ifaddrs); + return retval; } int @@ -451,16 +550,11 @@ do_mtu(const char *ifname, short int mtu) { struct ifreq ifr; int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) - return -1; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifr.ifr_mtu = mtu; - r = ioctl(s, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr); - close(s); + r = ioctl(socket_afnet, mtu ? SIOCSIFMTU : SIOCGIFMTU, &ifr); if (r == -1) return -1; return ifr.ifr_mtu; @@ -482,13 +576,11 @@ int open_udp_socket(struct interface *iface) { int s; - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; - } su; + struct sockaddr_in sin; int n; #ifdef SO_BINDTODEVICE struct ifreq ifr; + char *p; #endif if ((s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) @@ -500,7 +592,12 @@ open_udp_socket(struct interface *iface) #ifdef SO_BINDTODEVICE memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, iface->name, sizeof(ifr.ifr_name)); - if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == -1) + /* We can only bind to the real device */ + p = strchr(ifr.ifr_name, ':'); + if (p) + *p = '\0'; + if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &ifr, + sizeof(ifr)) == -1) goto eexit; #endif /* As we don't use this socket for receiving, set the @@ -508,11 +605,11 @@ open_udp_socket(struct interface *iface) n = 1; if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n)) == -1) goto eexit; - memset(&su, 0, sizeof(su)); - su.sin.sin_family = AF_INET; - su.sin.sin_port = htons(DHCP_CLIENT_PORT); - su.sin.sin_addr.s_addr = iface->addr.s_addr; - if (bind(s, &su.sa, sizeof(su)) == -1) + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(DHCP_CLIENT_PORT); + sin.sin_addr.s_addr = iface->addr.s_addr; + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) goto eexit; iface->udp_fd = s; @@ -526,19 +623,16 @@ eexit: ssize_t send_packet(const struct interface *iface, struct in_addr to, - const uint8_t *data, ssize_t len) + const uint8_t *data, ssize_t len) { - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; - } su; - - memset(&su, 0, sizeof(su)); - su.sin.sin_family = AF_INET; - su.sin.sin_addr.s_addr = to.s_addr; - su.sin.sin_port = htons(DHCP_SERVER_PORT); - - return sendto(iface->udp_fd, data, len, 0, &su.sa, sizeof(su)); + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = to.s_addr; + sin.sin_port = htons(DHCP_SERVER_PORT); + return sendto(iface->udp_fd, data, len, 0, + (struct sockaddr *)&sin, sizeof(sin)); } struct udp_dhcp_packet @@ -574,7 +668,7 @@ checksum(const void *data, uint16_t len) ssize_t make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length, - struct in_addr source, struct in_addr dest) + struct in_addr source, struct in_addr dest) { struct udp_dhcp_packet *udpp; struct ip *ip; @@ -609,14 +703,10 @@ make_udp_packet(uint8_t **packet, const uint8_t *data, size_t length, udp->uh_sum = checksum(udpp, sizeof(*udpp)); 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_hl = sizeof(*ip) >> 2; + ip->ip_id = arc4random() & UINT16_MAX; ip->ip_ttl = IPDEFTTL; - + ip->ip_len = htons(sizeof(*ip) + sizeof(*udp) + length); ip->ip_sum = checksum(ip, sizeof(*ip)); *packet = (uint8_t *)udpp; @@ -630,20 +720,30 @@ get_udp_data(const uint8_t **data, const uint8_t *udp) memcpy(&packet, udp, sizeof(packet)); *data = udp + offsetof(struct udp_dhcp_packet, dhcp); - return ntohs(packet.ip.ip_len) - sizeof(packet.ip) - sizeof(packet.udp); + return ntohs(packet.ip.ip_len) - + sizeof(packet.ip) - + sizeof(packet.udp); } int -valid_udp_packet(const uint8_t *data, size_t data_len) +valid_udp_packet(const uint8_t *data, size_t data_len, struct in_addr *from) { struct udp_dhcp_packet packet; uint16_t bytes, udpsum; + if (data_len < sizeof(packet.ip)) { + if (from) + from->s_addr = INADDR_ANY; + errno = EINVAL; + return -1; + } + memcpy(&packet, data, MIN(data_len, sizeof(packet))); + if (from) + from->s_addr = packet.ip.ip_src.s_addr; if (data_len > sizeof(packet)) { errno = EINVAL; return -1; } - memcpy(&packet, data, data_len); if (checksum(&packet.ip, sizeof(packet.ip)) != 0) { errno = EINVAL; return -1; @@ -671,35 +771,3 @@ valid_udp_packet(const uint8_t *data, size_t data_len) return 0; } - -int -send_arp(const struct interface *iface, int op, in_addr_t sip, in_addr_t tip) -{ - struct arphdr *arp; - size_t arpsize; - uint8_t *p; - int retval; - - arpsize = sizeof(*arp) + 2 * iface->hwlen + 2 * sizeof(sip); - arp = xmalloc(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); - p = (uint8_t *)arp; - p += sizeof(*arp); - memcpy(p, iface->hwaddr, iface->hwlen); - p += iface->hwlen; - memcpy(p, &sip, sizeof(sip)); - p += sizeof(sip); - /* ARP requests should ignore this */ - retval = iface->hwlen; - while (retval--) - *p++ = '\0'; - memcpy(p, &tip, sizeof(tip)); - p += sizeof(tip); - retval = send_raw_packet(iface, ETHERTYPE_ARP, arp, arpsize); - free(arp); - return retval; -} |