aboutsummaryrefslogtreecommitdiffstats
path: root/net.c
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2011-01-24 16:27:51 -0800
committerDmitry Shmidt <dimitrysh@google.com>2011-01-24 16:27:51 -0800
commite86eee143ed21592f88a46623a81f71002430459 (patch)
treee0be4ce113729bce176fd5054aeaf51a88b2e169 /net.c
parent6bcc301d166624837871fd601b4d3b5d43551e6b (diff)
downloadandroid_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.c654
1 files changed, 361 insertions, 293 deletions
diff --git a/net.c b/net.c
index 29344f8..e26b8d4 100644
--- a/net.c
+++ b/net.c
@@ -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;
-}