diff options
Diffstat (limited to 'src/customdhcpcd/interface.c')
-rw-r--r-- | src/customdhcpcd/interface.c | 1615 |
1 files changed, 840 insertions, 775 deletions
diff --git a/src/customdhcpcd/interface.c b/src/customdhcpcd/interface.c index d2ff8d6..818a2f0 100644 --- a/src/customdhcpcd/interface.c +++ b/src/customdhcpcd/interface.c @@ -1,4 +1,4 @@ -/* +/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples <roy@marples.name> * All rights reserved @@ -63,438 +63,478 @@ void free_address (struct address_head *addresses) { - address_t *p; - address_t *n; - - if (! addresses) - return; - - p = STAILQ_FIRST (addresses); - while (p) { - n = STAILQ_NEXT (p, entries); - free (p); - p = n; - } - free (addresses); + address_t *p; + address_t *n; + + if (! addresses) + return; + + p = STAILQ_FIRST (addresses); + while (p) + { + n = STAILQ_NEXT (p, entries); + free (p); + p = n; + } + free (addresses); } void free_route (struct route_head *routes) { - route_t *p; - route_t *n; - - if (! routes) - return; - - p = STAILQ_FIRST (routes); - while (p) { - n = STAILQ_NEXT (p, entries); - free (p); - p = n; - } - free (routes); + route_t *p; + route_t *n; + + if (! routes) + return; + + p = STAILQ_FIRST (routes); + while (p) + { + n = STAILQ_NEXT (p, entries); + free (p); + p = n; + } + free (routes); } int inet_ntocidr (struct in_addr address) { - int cidr = 0; - uint32_t mask = htonl (address.s_addr); + int cidr = 0; + uint32_t mask = htonl (address.s_addr); - while (mask) { - cidr++; - mask <<= 1; - } + while (mask) + { + cidr++; + mask <<= 1; + } - return (cidr); + return (cidr); } -int inet_cidrtoaddr (int cidr, struct in_addr *addr) { - int ocets; - - if (cidr < 0 || cidr > 32) { - errno = EINVAL; - return (-1); - } - ocets = (cidr + 7) / 8; - - memset (addr, 0, sizeof (*addr)); - if (ocets > 0) { - memset (&addr->s_addr, 255, (size_t) ocets - 1); - memset ((unsigned char *) &addr->s_addr + (ocets - 1), - (256 - (1 << (32 - cidr) % 8)), 1); - } - - return (0); +int inet_cidrtoaddr (int cidr, struct in_addr *addr) +{ + int ocets; + + if (cidr < 0 || cidr > 32) + { + errno = EINVAL; + return (-1); + } + ocets = (cidr + 7) / 8; + + memset (addr, 0, sizeof (*addr)); + if (ocets > 0) + { + memset (&addr->s_addr, 255, (size_t) ocets - 1); + memset ((unsigned char *) &addr->s_addr + (ocets - 1), + (256 - (1 << (32 - cidr) % 8)), 1); + } + + return (0); } uint32_t get_netmask (uint32_t addr) { - uint32_t dst; + uint32_t dst; - if (addr == 0) - return (0); + if (addr == 0) + return (0); - dst = htonl (addr); - if (IN_CLASSA (dst)) - return (ntohl (IN_CLASSA_NET)); - if (IN_CLASSB (dst)) - return (ntohl (IN_CLASSB_NET)); - if (IN_CLASSC (dst)) - return (ntohl (IN_CLASSC_NET)); + dst = htonl (addr); + if (IN_CLASSA (dst)) + return (ntohl (IN_CLASSA_NET)); + if (IN_CLASSB (dst)) + return (ntohl (IN_CLASSB_NET)); + if (IN_CLASSC (dst)) + return (ntohl (IN_CLASSC_NET)); - return (0); + return (0); } char *hwaddr_ntoa (const unsigned char *hwaddr, size_t hwlen) { - static char buffer[(HWADDR_LEN * 3) + 1]; - char *p = buffer; - size_t i; + static char buffer[(HWADDR_LEN * 3) + 1]; + char *p = buffer; + size_t i; - for (i = 0; i < hwlen && i < HWADDR_LEN; i++) { - if (i > 0) - *p ++= ':'; - p += snprintf (p, 3, "%.2x", hwaddr[i]); - } + for (i = 0; i < hwlen && i < HWADDR_LEN; i++) + { + if (i > 0) + *p ++ = ':'; + p += snprintf (p, 3, "%.2x", hwaddr[i]); + } - *p ++= '\0'; + *p ++ = '\0'; - return (buffer); + return (buffer); } size_t hwaddr_aton (unsigned char *buffer, const char *addr) { - char c[3]; - const char *p = addr; - unsigned char *bp = buffer; - size_t len = 0; - - c[2] = '\0'; - while (*p) { - c[0] = *p++; - c[1] = *p++; - /* Ensure that next data is EOL or a seperator with data */ - if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) { - errno = EINVAL; - return (0); - } - /* Ensure that digits are hex */ - if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) { - errno = EINVAL; - return (0); - } - p++; - if (bp) - *bp++ = (unsigned char) strtol (c, NULL, 16); - else - len++; - } - - if (bp) - return (bp - buffer); - return (len); + char c[3]; + const char *p = addr; + unsigned char *bp = buffer; + size_t len = 0; + + c[2] = '\0'; + while (*p) + { + c[0] = *p++; + c[1] = *p++; + /* Ensure that next data is EOL or a seperator with data */ + if (! (*p == '\0' || (*p == ':' && *(p + 1) != '\0'))) + { + errno = EINVAL; + return (0); + } + /* Ensure that digits are hex */ + if (isxdigit ((int) c[0]) == 0 || isxdigit ((int) c[1]) == 0) + { + errno = EINVAL; + return (0); + } + p++; + if (bp) + *bp++ = (unsigned char) strtol (c, NULL, 16); + else + len++; + } + + if (bp) + return (bp - buffer); + return (len); } static int _do_interface (const char *ifname, - _unused unsigned char *hwaddr, _unused size_t *hwlen, - struct in_addr *addr, - bool flush, bool get) + _unused unsigned char *hwaddr, _unused size_t *hwlen, + struct in_addr *addr, + bool flush, bool get) { - int s; - struct ifconf ifc; - int retval = 0; - int len = 10 * sizeof (struct ifreq); - int lastlen = 0; - char *p; - - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - /* Not all implementations return the needed buffer size for - * SIOGIFCONF so we loop like so for all until it works */ - memset (&ifc, 0, sizeof (ifc)); - for (;;) { - ifc.ifc_len = len; - ifc.ifc_buf = xmalloc ((size_t) len); - if (ioctl (s, SIOCGIFCONF, &ifc) == -1) { - if (errno != EINVAL || lastlen != 0) { - logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", - strerror (errno)); - close (s); - free (ifc.ifc_buf); - return -1; - } - } else { - if (ifc.ifc_len == lastlen) - break; - lastlen = ifc.ifc_len; - } - - free (ifc.ifc_buf); - ifc.ifc_buf = NULL; - len *= 2; - } - - for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) { - union { - char *buffer; - struct ifreq *ifr; - } ifreqs; - struct sockaddr_in address; - struct ifreq *ifr; - - /* Cast the ifc buffer to an ifreq cleanly */ - ifreqs.buffer = p; - ifr = ifreqs.ifr; + int s; + struct ifconf ifc; + int retval = 0; + int len = 10 * sizeof (struct ifreq); + int lastlen = 0; + char *p; + + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + /* Not all implementations return the needed buffer size for + * SIOGIFCONF so we loop like so for all until it works */ + memset (&ifc, 0, sizeof (ifc)); + for (;;) + { + ifc.ifc_len = len; + ifc.ifc_buf = xmalloc ((size_t) len); + if (ioctl (s, SIOCGIFCONF, &ifc) == -1) + { + if (errno != EINVAL || lastlen != 0) + { + logger (LOG_ERR, "ioctl SIOCGIFCONF: %s", + strerror (errno)); + close (s); + free (ifc.ifc_buf); + return -1; + } + } + else + { + if (ifc.ifc_len == lastlen) + break; + lastlen = ifc.ifc_len; + } + + free (ifc.ifc_buf); + ifc.ifc_buf = NULL; + len *= 2; + } + + for (p = ifc.ifc_buf; p < ifc.ifc_buf + ifc.ifc_len;) + { + union + { + char *buffer; + struct ifreq *ifr; + } ifreqs; + struct sockaddr_in address; + struct ifreq *ifr; + + /* Cast the ifc buffer to an ifreq cleanly */ + ifreqs.buffer = p; + ifr = ifreqs.ifr; #ifdef __linux__ - p += sizeof (*ifr); + p += sizeof (*ifr); #else - p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len; + p += offsetof (struct ifreq, ifr_ifru) + ifr->ifr_addr.sa_len; #endif - if (strcmp (ifname, ifr->ifr_name) != 0) - continue; + if (strcmp (ifname, ifr->ifr_name) != 0) + continue; #ifdef AF_LINK - if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) { - struct sockaddr_dl sdl; - - memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl)); - *hwlen = sdl.sdl_alen; - memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, - (size_t) sdl.sdl_alen); - retval = 1; - break; - } + if (hwaddr && hwlen && ifr->ifr_addr.sa_family == AF_LINK) + { + struct sockaddr_dl sdl; + + memcpy (&sdl, &ifr->ifr_addr, sizeof (sdl)); + *hwlen = sdl.sdl_alen; + memcpy (hwaddr, sdl.sdl_data + sdl.sdl_nlen, + (size_t) sdl.sdl_alen); + retval = 1; + break; + } #endif - if (ifr->ifr_addr.sa_family == AF_INET) { - memcpy (&address, &ifr->ifr_addr, sizeof (address)); - if (flush) { - struct sockaddr_in netmask; - - if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) { - logger (LOG_ERR, - "ioctl SIOCGIFNETMASK: %s", - strerror (errno)); - continue; - } - memcpy (&netmask, &ifr->ifr_addr, - sizeof (netmask)); - - if (del_address (ifname, - address.sin_addr, - netmask.sin_addr) == -1) - retval = -1; - } else if (get) { - addr->s_addr = address.sin_addr.s_addr; - retval = 1; - break; - } else if (address.sin_addr.s_addr == addr->s_addr) { - retval = 1; - break; - } - } - - } - - close (s); - free (ifc.ifc_buf); - return retval; + if (ifr->ifr_addr.sa_family == AF_INET) + { + memcpy (&address, &ifr->ifr_addr, sizeof (address)); + if (flush) + { + struct sockaddr_in netmask; + + if (ioctl (s, SIOCGIFNETMASK, ifr) == -1) + { + logger (LOG_ERR, + "ioctl SIOCGIFNETMASK: %s", + strerror (errno)); + continue; + } + memcpy (&netmask, &ifr->ifr_addr, + sizeof (netmask)); + + if (del_address (ifname, + address.sin_addr, + netmask.sin_addr) == -1) + retval = -1; + } + else if (get) + { + addr->s_addr = address.sin_addr.s_addr; + retval = 1; + break; + } + else if (address.sin_addr.s_addr == addr->s_addr) + { + retval = 1; + break; + } + } + + } + + close (s); + free (ifc.ifc_buf); + return retval; } interface_t *read_interface (const char *ifname, _unused int metric) { - int s; - struct ifreq ifr; - interface_t *iface = NULL; - unsigned char *hwaddr = NULL; - size_t hwlen = 0; - sa_family_t family = 0; - unsigned short mtu; + int s; + struct ifreq ifr; + interface_t *iface = NULL; + unsigned char *hwaddr = NULL; + size_t hwlen = 0; + sa_family_t family = 0; + unsigned short mtu; #ifdef __linux__ - char *p; + char *p; #endif - if (! ifname) - return NULL; + if (! ifname) + return NULL; - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return NULL; - } + if ((s = socket (AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return NULL; + } #ifdef __linux__ - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); - goto exit; - } - - switch (ifr.ifr_hwaddr.sa_family) { - case ARPHRD_ETHER: - case ARPHRD_IEEE802: - hwlen = ETHER_ADDR_LEN; - break; - case ARPHRD_IEEE1394: - hwlen = EUI64_ADDR_LEN; - case ARPHRD_INFINIBAND: - hwlen = INFINIBAND_ADDR_LEN; - break; - default: - logger (LOG_ERR, - "interface is not Ethernet, FireWire, " \ - "InfiniBand or Token Ring"); - goto exit; - } - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); - family = ifr.ifr_hwaddr.sa_family; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCGIFHWADDR, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFHWADDR: %s", strerror (errno)); + goto exit; + } + + switch (ifr.ifr_hwaddr.sa_family) + { + case ARPHRD_ETHER: + case ARPHRD_IEEE802: + hwlen = ETHER_ADDR_LEN; + break; + case ARPHRD_IEEE1394: + hwlen = EUI64_ADDR_LEN; + case ARPHRD_INFINIBAND: + hwlen = INFINIBAND_ADDR_LEN; + break; + default: + logger (LOG_ERR, + "interface is not Ethernet, FireWire, " \ + "InfiniBand or Token Ring"); + goto exit; + } + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + memcpy (hwaddr, ifr.ifr_hwaddr.sa_data, hwlen); + family = ifr.ifr_hwaddr.sa_family; #else - ifr.ifr_metric = metric; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); - goto exit; - } - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) { - logger (LOG_ERR, "could not find interface %s", ifname); - goto exit; - } - - family = ARPHRD_ETHER; + ifr.ifr_metric = metric; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCSIFMETRIC, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCSIFMETRIC: %s", strerror (errno)); + goto exit; + } + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + if (_do_interface (ifname, hwaddr, &hwlen, NULL, false, false) != 1) + { + logger (LOG_ERR, "could not find interface %s", ifname); + goto exit; + } + + family = ARPHRD_ETHER; #endif - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCGIFMTU, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - goto exit; - } - - if (ifr.ifr_mtu < MTU_MIN) { - logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", - ifr.ifr_mtu, MTU_MIN); - ifr.ifr_mtu = MTU_MIN; - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - if (ioctl (s, SIOCSIFMTU, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", - strerror (errno)); - goto exit; - } - } - mtu = ifr.ifr_mtu; - - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCGIFMTU, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); + goto exit; + } + + if (ifr.ifr_mtu < MTU_MIN) + { + logger (LOG_DEBUG, "MTU of %d is too low, setting to %d", + ifr.ifr_mtu, MTU_MIN); + ifr.ifr_mtu = MTU_MIN; + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + if (ioctl (s, SIOCSIFMTU, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCSIFMTU,: %s", + strerror (errno)); + goto exit; + } + } + mtu = ifr.ifr_mtu; + + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); #ifdef __linux__ - /* We can only bring the real interface up */ - if ((p = strchr (ifr.ifr_name, ':'))) - *p = '\0'; + /* We can only bring the real interface up */ + if ((p = strchr (ifr.ifr_name, ':'))) + * p = '\0'; #endif - if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) { - logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); - goto exit; - } - - if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) { - ifr.ifr_flags |= IFF_UP | IFF_RUNNING; - if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) { - logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", - strerror (errno)); - goto exit; - } - } - - iface = xzalloc (sizeof (*iface)); - strlcpy (iface->name, ifname, IF_NAMESIZE); + if (ioctl (s, SIOCGIFFLAGS, &ifr) == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFFLAGS: %s", strerror (errno)); + goto exit; + } + + if (! (ifr.ifr_flags & IFF_UP) || ! (ifr.ifr_flags & IFF_RUNNING)) + { + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (ioctl (s, SIOCSIFFLAGS, &ifr) != 0) + { + logger (LOG_ERR, "ioctl SIOCSIFFLAGS: %s", + strerror (errno)); + goto exit; + } + } + + iface = xzalloc (sizeof (*iface)); + strlcpy (iface->name, ifname, IF_NAMESIZE); #ifdef ENABLE_INFO - snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); + snprintf (iface->infofile, PATH_MAX, INFOFILE, ifname); #endif - memcpy (&iface->hwaddr, hwaddr, hwlen); - iface->hwlen = hwlen; + memcpy (&iface->hwaddr, hwaddr, hwlen); + iface->hwlen = hwlen; - iface->family = family; - iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)); - iface->mtu = iface->previous_mtu = mtu; + iface->family = family; + iface->arpable = ! (ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK)); + iface->mtu = iface->previous_mtu = mtu; - logger (LOG_INFO, "hardware address = %s", - hwaddr_ntoa (iface->hwaddr, iface->hwlen)); + logger (LOG_INFO, "hardware address = %s", + hwaddr_ntoa (iface->hwaddr, iface->hwlen)); - /* 0 is a valid fd, so init to -1 */ - iface->fd = -1; + /* 0 is a valid fd, so init to -1 */ + iface->fd = -1; #ifdef __linux__ - iface->listen_fd = -1; + iface->listen_fd = -1; #endif exit: - close (s); - free (hwaddr); - return iface; + close (s); + free (hwaddr); + return iface; } int get_mtu (const char *ifname) { - struct ifreq ifr; - int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (ifr)); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - r = ioctl (s, SIOCGIFMTU, &ifr); - close (s); - - if (r == -1) { - logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); - return (-1); - } - - return (ifr.ifr_mtu); + struct ifreq ifr; + int r; + int s; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (ifr)); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + r = ioctl (s, SIOCGIFMTU, &ifr); + close (s); + + if (r == -1) + { + logger (LOG_ERR, "ioctl SIOCGIFMTU: %s", strerror (errno)); + return (-1); + } + + return (ifr.ifr_mtu); } int set_mtu (const char *ifname, short int mtu) { - struct ifreq ifr; - int r; - int s; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return (-1); - } - - memset (&ifr, 0, sizeof (ifr)); - logger (LOG_DEBUG, "setting MTU to %d", mtu); - strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); - ifr.ifr_mtu = mtu; - r = ioctl (s, SIOCSIFMTU, &ifr); - close (s); - - if (r == -1) - logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); - - return (r == 0 ? 0 : -1); + struct ifreq ifr; + int r; + int s; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return (-1); + } + + memset (&ifr, 0, sizeof (ifr)); + logger (LOG_DEBUG, "setting MTU to %d", mtu); + strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name)); + ifr.ifr_mtu = mtu; + r = ioctl (s, SIOCSIFMTU, &ifr); + close (s); + + if (r == -1) + logger (LOG_ERR, "ioctl SIOCSIFMTU: %s", strerror (errno)); + + return (r == 0 ? 0 : -1); } static void log_route (struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - _unused int metric, - int change, int del) + struct in_addr netmask, + struct in_addr gateway, + _unused int metric, + int change, int del) { - char *dstd = xstrdup (inet_ntoa (destination)); + char *dstd = xstrdup (inet_ntoa (destination)); #ifdef __linux__ #define METRIC " metric %d" @@ -502,34 +542,34 @@ static void log_route (struct in_addr destination, #define METRIC "" #endif - if (gateway.s_addr == destination.s_addr || - gateway.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s route to %s/%d" METRIC, - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask) + if (gateway.s_addr == destination.s_addr || + gateway.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s route to %s/%d" METRIC, + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask) #ifdef __linux__ - , metric + , metric #endif - ); - else if (destination.s_addr == INADDR_ANY) - logger (LOG_INFO, "%s default route via %s" METRIC, - change ? "changing" : del ? "removing" : "adding", - inet_ntoa (gateway) + ); + else if (destination.s_addr == INADDR_ANY) + logger (LOG_INFO, "%s default route via %s" METRIC, + change ? "changing" : del ? "removing" : "adding", + inet_ntoa (gateway) #ifdef __linux__ - , metric + , metric #endif - ); - else - logger (LOG_INFO, "%s route to %s/%d via %s" METRIC, - change ? "changing" : del ? "removing" : "adding", - dstd, inet_ntocidr (netmask), inet_ntoa (gateway) + ); + else + logger (LOG_INFO, "%s route to %s/%d via %s" METRIC, + change ? "changing" : del ? "removing" : "adding", + dstd, inet_ntocidr (netmask), inet_ntoa (gateway) #ifdef __linux__ - , metric + , metric #endif - ); + ); - free (dstd); + free (dstd); } #if defined(BSD) || defined(__FreeBSD_kernel__) @@ -543,22 +583,23 @@ static void log_route (struct in_addr destination, #endif static int do_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast, - int del) + struct in_addr netmask, struct in_addr broadcast, + int del) { - int s; - struct ifaliasreq ifa; + int s; + struct ifaliasreq ifa; - if (! ifname) - return -1; + if (! ifname) + return -1; - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } - memset (&ifa, 0, sizeof (ifa)); - strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name)); + memset (&ifa, 0, sizeof (ifa)); + strlcpy (ifa.ifra_name, ifname, sizeof (ifa.ifra_name)); #define ADDADDR(_var, _addr) { \ union { struct sockaddr *sa; struct sockaddr_in *sin; } _s; \ @@ -568,70 +609,73 @@ static int do_address (const char *ifname, struct in_addr address, memcpy (&_s.sin->sin_addr, &_addr, sizeof (_s.sin->sin_addr)); \ } - ADDADDR (ifa.ifra_addr, address); - ADDADDR (ifa.ifra_mask, netmask); -if (! del) - ADDADDR (ifa.ifra_broadaddr, broadcast); + ADDADDR (ifa.ifra_addr, address); + ADDADDR (ifa.ifra_mask, netmask); + if (! del) + ADDADDR (ifa.ifra_broadaddr, broadcast); #undef ADDADDR - if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) { - logger (LOG_ERR, "ioctl %s: %s", - del ? "SIOCDIFADDR" : "SIOCAIFADDR", - strerror (errno)); - close (s); - return -1; - } - -close (s); -return 0; + if (ioctl (s, del ? SIOCDIFADDR : SIOCAIFADDR, &ifa) == -1) + { + logger (LOG_ERR, "ioctl %s: %s", + del ? "SIOCDIFADDR" : "SIOCAIFADDR", + strerror (errno)); + close (s); + return -1; + } + + close (s); + return 0; } static int do_route (const char *ifname, - struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - int metric, - int change, int del) + struct in_addr destination, + struct in_addr netmask, + struct in_addr gateway, + int metric, + int change, int del) { - int s; - static int seq; - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; + int s; + static int seq; + union sockunion + { + struct sockaddr sa; + struct sockaddr_in sin; #ifdef INET6 - struct sockaddr_in6 sin6; + struct sockaddr_in6 sin6; #endif - struct sockaddr_dl sdl; - struct sockaddr_storage ss; - } su; - struct rtm - { - struct rt_msghdr hdr; - char buffer[sizeof (su) * 3]; - } rtm; - char *bp = rtm.buffer; - size_t l; - - if (! ifname) - return -1; - - log_route (destination, netmask, gateway, metric, change, del); - - if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&rtm, 0, sizeof (rtm)); - - rtm.hdr.rtm_version = RTM_VERSION; - rtm.hdr.rtm_seq = ++seq; - rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; - rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC; - - /* This order is important */ - rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; + struct sockaddr_dl sdl; + struct sockaddr_storage ss; + } su; + struct rtm + { + struct rt_msghdr hdr; + char buffer[sizeof (su) * 3]; + } rtm; + char *bp = rtm.buffer; + size_t l; + + if (! ifname) + return -1; + + log_route (destination, netmask, gateway, metric, change, del); + + if ((s = socket (PF_ROUTE, SOCK_RAW, 0)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&rtm, 0, sizeof (rtm)); + + rtm.hdr.rtm_version = RTM_VERSION; + rtm.hdr.rtm_seq = ++seq; + rtm.hdr.rtm_type = change ? RTM_CHANGE : del ? RTM_DELETE : RTM_ADD; + rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC; + + /* This order is important */ + rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK; #define ADDADDR(_addr) \ memset (&su, 0, sizeof (su)); \ @@ -642,52 +686,55 @@ static int do_route (const char *ifname, memcpy (bp, &(su), l); \ bp += l; - ADDADDR (destination); - - if (netmask.s_addr == INADDR_BROADCAST || - gateway.s_addr == INADDR_ANY) - { - /* Make us a link layer socket */ - unsigned char *hwaddr; - size_t hwlen = 0; - - if (netmask.s_addr == INADDR_BROADCAST) - rtm.hdr.rtm_flags |= RTF_HOST; - - hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); - _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); - memset (&su, 0, sizeof (su)); - su.sdl.sdl_len = sizeof (su.sdl); - su.sdl.sdl_family = AF_LINK; - su.sdl.sdl_nlen = strlen (ifname); - memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen); - su.sdl.sdl_alen = hwlen; - memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, - hwaddr, (size_t) su.sdl.sdl_alen); - - l = SA_SIZE (&(su.sa)); - memcpy (bp, &su, l); - bp += l; - free (hwaddr); - } else { - rtm.hdr.rtm_flags |= RTF_GATEWAY; - ADDADDR (gateway); - } - - ADDADDR (netmask); + ADDADDR (destination); + + if (netmask.s_addr == INADDR_BROADCAST || + gateway.s_addr == INADDR_ANY) + { + /* Make us a link layer socket */ + unsigned char *hwaddr; + size_t hwlen = 0; + + if (netmask.s_addr == INADDR_BROADCAST) + rtm.hdr.rtm_flags |= RTF_HOST; + + hwaddr = xmalloc (sizeof (unsigned char) * HWADDR_LEN); + _do_interface (ifname, hwaddr, &hwlen, NULL, false, false); + memset (&su, 0, sizeof (su)); + su.sdl.sdl_len = sizeof (su.sdl); + su.sdl.sdl_family = AF_LINK; + su.sdl.sdl_nlen = strlen (ifname); + memcpy (&su.sdl.sdl_data, ifname, (size_t) su.sdl.sdl_nlen); + su.sdl.sdl_alen = hwlen; + memcpy (((unsigned char *) &su.sdl.sdl_data) + su.sdl.sdl_nlen, + hwaddr, (size_t) su.sdl.sdl_alen); + + l = SA_SIZE (&(su.sa)); + memcpy (bp, &su, l); + bp += l; + free (hwaddr); + } + else + { + rtm.hdr.rtm_flags |= RTF_GATEWAY; + ADDADDR (gateway); + } + + ADDADDR (netmask); #undef ADDADDR - rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; - if (write (s, &rtm, l) == -1) { - /* Don't report error about routes already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } - - close (s); - return 0; + rtm.hdr.rtm_msglen = l = bp - (char *)&rtm; + if (write (s, &rtm, l) == -1) + { + /* Don't report error about routes already existing */ + if (errno != EEXIST) + logger (LOG_ERR, "write: %s", strerror (errno)); + close (s); + return -1; + } + + close (s); + return 0; } #elif __linux__ @@ -698,363 +745,381 @@ static int do_route (const char *ifname, #define BUFFERLEN 256 int send_netlink (struct nlmsghdr *hdr, netlink_callback callback, void *arg) { - int s; - pid_t mypid = getpid (); - struct sockaddr_nl nl; - struct iovec iov; - struct msghdr msg; - static unsigned int seq; - char *buffer; - ssize_t bytes; - union - { - char *buffer; - struct nlmsghdr *nlm; - } h; - - if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { - logger (LOG_ERR, "socket: %s", strerror (errno)); - return -1; - } - - memset (&nl, 0, sizeof (nl)); - nl.nl_family = AF_NETLINK; - if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) { - logger (LOG_ERR, "bind: %s", strerror (errno)); - close (s); - return -1; - } - - memset (&iov, 0, sizeof (iov)); - iov.iov_base = hdr; - iov.iov_len = hdr->nlmsg_len; - - memset (&msg, 0, sizeof (msg)); - msg.msg_name = &nl; - msg.msg_namelen = sizeof (nl); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - /* Request a reply */ - hdr->nlmsg_flags |= NLM_F_ACK; - hdr->nlmsg_seq = ++seq; - - if (sendmsg (s, &msg, 0) == -1) { - logger (LOG_ERR, "write: %s", strerror (errno)); - close (s); - return -1; - } - - buffer = xzalloc (sizeof (char) * BUFFERLEN); - iov.iov_base = buffer; - - for (;;) { - iov.iov_len = BUFFERLEN; - bytes = recvmsg (s, &msg, 0); - - if (bytes == -1) { - if (errno != EINTR) - logger (LOG_ERR, "recvmsg: %s", - strerror (errno)); - continue; - } - - if (bytes == 0) { - logger (LOG_ERR, "netlink: EOF"); - goto eexit; - } - - if (msg.msg_namelen != sizeof (nl)) { - logger (LOG_ERR, - "netlink: sender address length mismatch"); - goto eexit; - } - - for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) { - int len = h.nlm->nlmsg_len; - int l = len - sizeof (*h.nlm); - struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); - - if (l < 0 || len > bytes) { - if (msg.msg_flags & MSG_TRUNC) - logger (LOG_ERR, "netlink: truncated message"); - else - logger (LOG_ERR, "netlink: malformed message"); - goto eexit; - } - - /* Ensure it's our message */ - if (nl.nl_pid != 0 || - (pid_t) h.nlm->nlmsg_pid != mypid || - h.nlm->nlmsg_seq != seq) - { - /* Next Message */ - bytes -= NLMSG_ALIGN (len); - h.buffer += NLMSG_ALIGN (len); - continue; - } - - /* We get an NLMSG_ERROR back with a code of zero for success */ - if (h.nlm->nlmsg_type != NLMSG_ERROR) { - logger (LOG_ERR, "netlink: unexpected reply %d", - h.nlm->nlmsg_type); - goto eexit; - } - - if ((unsigned) l < sizeof (*err)) { - logger (LOG_ERR, "netlink: error truncated"); - goto eexit; - } - - if (err->error == 0) { - int retval = 0; - - close (s); - if (callback) { - if ((retval = callback (hdr, arg)) == -1) - logger (LOG_ERR, "netlink: callback failed"); - } - free (buffer); - return (retval); - } - - errno = -err->error; - /* Don't report on something already existing */ - if (errno != EEXIST) - logger (LOG_ERR, "netlink: %s", - strerror (errno)); - goto eexit; - } - } + int s; + pid_t mypid = getpid (); + struct sockaddr_nl nl; + struct iovec iov; + struct msghdr msg; + static unsigned int seq; + char *buffer; + ssize_t bytes; + union + { + char *buffer; + struct nlmsghdr *nlm; + } h; + + if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) + { + logger (LOG_ERR, "socket: %s", strerror (errno)); + return -1; + } + + memset (&nl, 0, sizeof (nl)); + nl.nl_family = AF_NETLINK; + if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) + { + logger (LOG_ERR, "bind: %s", strerror (errno)); + close (s); + return -1; + } + + memset (&iov, 0, sizeof (iov)); + iov.iov_base = hdr; + iov.iov_len = hdr->nlmsg_len; + + memset (&msg, 0, sizeof (msg)); + msg.msg_name = &nl; + msg.msg_namelen = sizeof (nl); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + /* Request a reply */ + hdr->nlmsg_flags |= NLM_F_ACK; + hdr->nlmsg_seq = ++seq; + + if (sendmsg (s, &msg, 0) == -1) + { + logger (LOG_ERR, "write: %s", strerror (errno)); + close (s); + return -1; + } + + buffer = xzalloc (sizeof (char) * BUFFERLEN); + iov.iov_base = buffer; + + for (;;) + { + iov.iov_len = BUFFERLEN; + bytes = recvmsg (s, &msg, 0); + + if (bytes == -1) + { + if (errno != EINTR) + logger (LOG_ERR, "recvmsg: %s", + strerror (errno)); + continue; + } + + if (bytes == 0) + { + logger (LOG_ERR, "netlink: EOF"); + goto eexit; + } + + if (msg.msg_namelen != sizeof (nl)) + { + logger (LOG_ERR, + "netlink: sender address length mismatch"); + goto eexit; + } + + for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) + { + int len = h.nlm->nlmsg_len; + int l = len - sizeof (*h.nlm); + struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); + + if (l < 0 || len > bytes) + { + if (msg.msg_flags & MSG_TRUNC) + logger (LOG_ERR, "netlink: truncated message"); + else + logger (LOG_ERR, "netlink: malformed message"); + goto eexit; + } + + /* Ensure it's our message */ + if (nl.nl_pid != 0 || + (pid_t) h.nlm->nlmsg_pid != mypid || + h.nlm->nlmsg_seq != seq) + { + /* Next Message */ + bytes -= NLMSG_ALIGN (len); + h.buffer += NLMSG_ALIGN (len); + continue; + } + + /* We get an NLMSG_ERROR back with a code of zero for success */ + if (h.nlm->nlmsg_type != NLMSG_ERROR) + { + logger (LOG_ERR, "netlink: unexpected reply %d", + h.nlm->nlmsg_type); + goto eexit; + } + + if ((unsigned) l < sizeof (*err)) + { + logger (LOG_ERR, "netlink: error truncated"); + goto eexit; + } + + if (err->error == 0) + { + int retval = 0; + + close (s); + if (callback) + { + if ((retval = callback (hdr, arg)) == -1) + logger (LOG_ERR, "netlink: callback failed"); + } + free (buffer); + return (retval); + } + + errno = -err->error; + /* Don't report on something already existing */ + if (errno != EEXIST) + logger (LOG_ERR, "netlink: %s", + strerror (errno)); + goto eexit; + } + } eexit: - close (s); - free (buffer); - return -1; + close (s); + free (buffer); + return -1; } #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((ptrdiff_t) (nmsg)) + NLMSG_ALIGN ((nmsg)->nlmsg_len))) static int add_attr_l(struct nlmsghdr *n, unsigned int maxlen, int type, - const void *data, int alen) + const void *data, int alen) { - int len = RTA_LENGTH(alen); - struct rtattr *rta; - - if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) { - logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", - maxlen); - return -1; - } - - rta = NLMSG_TAIL (n); - rta->rta_type = type; - rta->rta_len = len; - memcpy (RTA_DATA (rta), data, alen); - n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len); - - return 0; + int len = RTA_LENGTH(alen); + struct rtattr *rta; + + if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen) + { + logger (LOG_ERR, "add_attr_l: message exceeded bound of %d\n", + maxlen); + return -1; + } + + rta = NLMSG_TAIL (n); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA (rta), data, alen); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len); + + return 0; } static int add_attr_32(struct nlmsghdr *n, unsigned int maxlen, int type, - uint32_t data) + uint32_t data) { - int len = RTA_LENGTH (sizeof (data)); - struct rtattr *rta; - - if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) { - logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", - maxlen); - return -1; - } - - rta = NLMSG_TAIL (n); - rta->rta_type = type; - rta->rta_len = len; - memcpy (RTA_DATA (rta), &data, sizeof (data)); - n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; - - return 0; + int len = RTA_LENGTH (sizeof (data)); + struct rtattr *rta; + + if (NLMSG_ALIGN (n->nlmsg_len) + len > maxlen) + { + logger (LOG_ERR, "add_attr32: message exceeded bound of %d\n", + maxlen); + return -1; + } + + rta = NLMSG_TAIL (n); + rta->rta_type = type; + rta->rta_len = len; + memcpy (RTA_DATA (rta), &data, sizeof (data)); + n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + len; + + return 0; } struct nlma { - struct nlmsghdr hdr; - struct ifaddrmsg ifa; - char buffer[64]; + struct nlmsghdr hdr; + struct ifaddrmsg ifa; + char buffer[64]; }; struct nlmr { - struct nlmsghdr hdr; - struct rtmsg rt; - char buffer[256]; + struct nlmsghdr hdr; + struct rtmsg rt; + char buffer[256]; }; static int do_address(const char *ifname, - struct in_addr address, struct in_addr netmask, - struct in_addr broadcast, int del) + struct in_addr address, struct in_addr netmask, + struct in_addr broadcast, int del) { - struct nlma *nlm; - int retval; - - if (!ifname) - return -1; - - nlm = xzalloc (sizeof (*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); - nlm->hdr.nlmsg_flags = NLM_F_REQUEST; - if (! del) - nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; - nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; - if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - ifname); - free (nlm); - return -1; - } - nlm->ifa.ifa_family = AF_INET; - - nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); - - /* This creates the aliased interface */ - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL, - ifname, strlen (ifname) + 1); - - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL, - &address.s_addr, sizeof (address.s_addr)); - if (! del) - add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, - &broadcast.s_addr, sizeof (broadcast.s_addr)); - - retval = send_netlink (&nlm->hdr, NULL, NULL); - free (nlm); - return retval; + struct nlma *nlm; + int retval; + + if (!ifname) + return -1; + + nlm = xzalloc (sizeof (*nlm)); + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct ifaddrmsg)); + nlm->hdr.nlmsg_flags = NLM_F_REQUEST; + if (! del) + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE; + nlm->hdr.nlmsg_type = del ? RTM_DELADDR : RTM_NEWADDR; + if (! (nlm->ifa.ifa_index = if_nametoindex (ifname))) + { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + ifname); + free (nlm); + return -1; + } + nlm->ifa.ifa_family = AF_INET; + + nlm->ifa.ifa_prefixlen = inet_ntocidr (netmask); + + /* This creates the aliased interface */ + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LABEL, + ifname, strlen (ifname) + 1); + + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_LOCAL, + &address.s_addr, sizeof (address.s_addr)); + if (! del) + add_attr_l (&nlm->hdr, sizeof (*nlm), IFA_BROADCAST, + &broadcast.s_addr, sizeof (broadcast.s_addr)); + + retval = send_netlink (&nlm->hdr, NULL, NULL); + free (nlm); + return retval; } static int do_route (const char *ifname, - struct in_addr destination, - struct in_addr netmask, - struct in_addr gateway, - int metric, int change, int del) + struct in_addr destination, + struct in_addr netmask, + struct in_addr gateway, + int metric, int change, int del) { - struct nlmr *nlm; - unsigned int ifindex; - int retval; - - if (! ifname) - return -1; - - log_route (destination, netmask, gateway, metric, change, del); - - if (! (ifindex = if_nametoindex (ifname))) { - logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", - ifname); - return -1; - } - - nlm = xzalloc (sizeof (*nlm)); - nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - if (change) - nlm->hdr.nlmsg_flags = NLM_F_REPLACE; - else if (! del) - nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; - nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; - nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; - nlm->rt.rtm_family = AF_INET; - nlm->rt.rtm_table = RT_TABLE_MAIN; - - if (del) - nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; - else { - nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; - nlm->rt.rtm_protocol = RTPROT_BOOT; - if (netmask.s_addr == INADDR_BROADCAST || - gateway.s_addr == INADDR_ANY) - nlm->rt.rtm_scope = RT_SCOPE_LINK; - else - nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; - nlm->rt.rtm_type = RTN_UNICAST; - } - - nlm->rt.rtm_dst_len = inet_ntocidr (netmask); - add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST, - &destination.s_addr, sizeof (destination.s_addr)); - if (netmask.s_addr != INADDR_BROADCAST && - destination.s_addr != gateway.s_addr) - add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY, - &gateway.s_addr, sizeof (gateway.s_addr)); - - add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); - add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); - - retval = send_netlink (&nlm->hdr, NULL, NULL); - free (nlm); - return retval; + struct nlmr *nlm; + unsigned int ifindex; + int retval; + + if (! ifname) + return -1; + + log_route (destination, netmask, gateway, metric, change, del); + + if (! (ifindex = if_nametoindex (ifname))) + { + logger (LOG_ERR, "if_nametoindex: no index for interface `%s'", + ifname); + return -1; + } + + nlm = xzalloc (sizeof (*nlm)); + nlm->hdr.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + if (change) + nlm->hdr.nlmsg_flags = NLM_F_REPLACE; + else if (! del) + nlm->hdr.nlmsg_flags = NLM_F_CREATE | NLM_F_EXCL; + nlm->hdr.nlmsg_flags |= NLM_F_REQUEST; + nlm->hdr.nlmsg_type = del ? RTM_DELROUTE : RTM_NEWROUTE; + nlm->rt.rtm_family = AF_INET; + nlm->rt.rtm_table = RT_TABLE_MAIN; + + if (del) + nlm->rt.rtm_scope = RT_SCOPE_NOWHERE; + else + { + nlm->hdr.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; + nlm->rt.rtm_protocol = RTPROT_BOOT; + if (netmask.s_addr == INADDR_BROADCAST || + gateway.s_addr == INADDR_ANY) + nlm->rt.rtm_scope = RT_SCOPE_LINK; + else + nlm->rt.rtm_scope = RT_SCOPE_UNIVERSE; + nlm->rt.rtm_type = RTN_UNICAST; + } + + nlm->rt.rtm_dst_len = inet_ntocidr (netmask); + add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_DST, + &destination.s_addr, sizeof (destination.s_addr)); + if (netmask.s_addr != INADDR_BROADCAST && + destination.s_addr != gateway.s_addr) + add_attr_l (&nlm->hdr, sizeof (*nlm), RTA_GATEWAY, + &gateway.s_addr, sizeof (gateway.s_addr)); + + add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_OIF, ifindex); + add_attr_32 (&nlm->hdr, sizeof (*nlm), RTA_PRIORITY, metric); + + retval = send_netlink (&nlm->hdr, NULL, NULL); + free (nlm); + return retval; } #else - #error "Platform not supported!" - #error "We currently support BPF and Linux sockets." - #error "Other platforms may work using BPF. If yours does, please let me know" - #error "so I can add it to our list." +#error "Platform not supported!" +#error "We currently support BPF and Linux sockets." +#error "Other platforms may work using BPF. If yours does, please let me know" +#error "so I can add it to our list." #endif int add_address (const char *ifname, struct in_addr address, - struct in_addr netmask, struct in_addr broadcast) + struct in_addr netmask, struct in_addr broadcast) { - logger (LOG_INFO, "adding IP address %s/%d", - inet_ntoa (address), inet_ntocidr (netmask)); + logger (LOG_INFO, "adding IP address %s/%d", + inet_ntoa (address), inet_ntocidr (netmask)); - return (do_address (ifname, address, netmask, broadcast, 0)); + return (do_address (ifname, address, netmask, broadcast, 0)); } int del_address (const char *ifname, - struct in_addr address, struct in_addr netmask) + struct in_addr address, struct in_addr netmask) { - struct in_addr t; + struct in_addr t; - logger (LOG_INFO, "removing IP address %s/%d", - inet_ntoa (address), inet_ntocidr (netmask)); + logger (LOG_INFO, "removing IP address %s/%d", + inet_ntoa (address), inet_ntocidr (netmask)); - memset (&t, 0, sizeof (t)); - return (do_address (ifname, address, netmask, t, 1)); + memset (&t, 0, sizeof (t)); + return (do_address (ifname, address, netmask, t, 1)); } int add_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) + struct in_addr netmask, struct in_addr gateway, int metric) { - return (do_route (ifname, destination, netmask, gateway, metric, 0, 0)); + return (do_route (ifname, destination, netmask, gateway, metric, 0, 0)); } int change_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) + struct in_addr netmask, struct in_addr gateway, int metric) { - return (do_route (ifname, destination, netmask, gateway, metric, 1, 0)); + return (do_route (ifname, destination, netmask, gateway, metric, 1, 0)); } int del_route (const char *ifname, struct in_addr destination, - struct in_addr netmask, struct in_addr gateway, int metric) + struct in_addr netmask, struct in_addr gateway, int metric) { - return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); + return (do_route (ifname, destination, netmask, gateway, metric, 0, 1)); } int flush_addresses (const char *ifname) { - return (_do_interface (ifname, NULL, NULL, NULL, true, false)); + return (_do_interface (ifname, NULL, NULL, NULL, true, false)); } in_addr_t get_address (const char *ifname) { - struct in_addr address; - if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) - return (address.s_addr); - return (0); + struct in_addr address; + if (_do_interface (ifname, NULL, NULL, &address, false, true) > 0) + return (address.s_addr); + return (0); } int has_address (const char *ifname, struct in_addr address) { - return (_do_interface (ifname, NULL, NULL, &address, false, false)); + return (_do_interface (ifname, NULL, NULL, &address, false, false)); } |