summaryrefslogtreecommitdiffstats
path: root/workspace/networkDiscovery/dhcpcd/interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'workspace/networkDiscovery/dhcpcd/interface.c')
-rw-r--r--workspace/networkDiscovery/dhcpcd/interface.c1060
1 files changed, 0 insertions, 1060 deletions
diff --git a/workspace/networkDiscovery/dhcpcd/interface.c b/workspace/networkDiscovery/dhcpcd/interface.c
deleted file mode 100644
index d2ff8d6..0000000
--- a/workspace/networkDiscovery/dhcpcd/interface.c
+++ /dev/null
@@ -1,1060 +0,0 @@
-/*
- * dhcpcd - DHCP client daemon
- * Copyright 2006-2008 Roy Marples <roy@marples.name>
- * 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 <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/param.h>
-
-#include <arpa/inet.h>
-
-/* Netlink suff */
-#ifdef __linux__
-#include <asm/types.h> /* Needed for 2.4 kernels */
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <netinet/ether.h>
-#include <netpacket/packet.h>
-#else
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/route.h>
-#include <netinet/in.h>
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#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));
-}