X-Git-Url: http://git.meshlink.io/?a=blobdiff_plain;f=avahi-autoipd%2Fiface-bsd.c;fp=avahi-autoipd%2Fiface-bsd.c;h=0000000000000000000000000000000000000000;hb=f1de9dcaab953757252d51b4725cbfa36daa10a5;hp=6a1085c800b0848cd3d6c97b60ca024959ea8a20;hpb=7a5b2f69af7d36d6cd4153142f125fa011784e03;p=catta diff --git a/avahi-autoipd/iface-bsd.c b/avahi-autoipd/iface-bsd.c deleted file mode 100644 index 6a1085c..0000000 --- a/avahi-autoipd/iface-bsd.c +++ /dev/null @@ -1,440 +0,0 @@ -/* rcs tags go here */ -/* Original author: Bruce M. Simpson */ - -/*** - This file is part of avahi. - - avahi is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - avahi is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General - Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with avahi; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -#include "iface.h" - -#ifndef IN_LINKLOCAL -#define IN_LINKLOCAL(i) (((u_int32_t)(i) & (0xffff0000)) == (0xa9fe0000)) -#endif - -#ifndef elementsof -#define elementsof(array) (sizeof(array)/sizeof(array[0])) -#endif - -#ifndef so_set_nonblock -#define so_set_nonblock(s, val) \ - do { \ - int __flags; \ - __flags = fcntl((s), F_GETFL); \ - if (__flags == -1) \ - break; \ - if (val != 0) \ - __flags |= O_NONBLOCK; \ - else \ - __flags &= ~O_NONBLOCK; \ - (void)fcntl((s), F_SETFL, __flags); \ - } while (0) -#endif - -#define MAX_RTMSG_SIZE 2048 - -struct rtm_dispinfo { - u_char *di_buf; - ssize_t di_buflen; - ssize_t di_len; -}; - -union rtmunion { - struct rt_msghdr rtm; - struct if_msghdr ifm; - struct ifa_msghdr ifam; - struct ifma_msghdr ifmam; - struct if_announcemsghdr ifan; -}; -typedef union rtmunion rtmunion_t; - -struct Address; -typedef struct Address Address; - -struct Address { - in_addr_t address; - AVAHI_LLIST_FIELDS(Address, addresses); -}; - -static int rtm_dispatch(void); -static int rtm_dispatch_newdeladdr(struct rtm_dispinfo *di); -static int rtm_dispatch_ifannounce(struct rtm_dispinfo *di); -static struct sockaddr *next_sa(struct sockaddr *sa); - -static int fd = -1; -static int ifindex = -1; -static AVAHI_LLIST_HEAD(Address, addresses) = NULL; - -int -iface_init(int idx) -{ - - fd = socket(PF_ROUTE, SOCK_RAW, AF_INET); - if (fd == -1) { - daemon_log(LOG_ERR, "socket(PF_ROUTE): %s", strerror(errno)); - return (-1); - } - - so_set_nonblock(fd, 1); - - ifindex = idx; - - return (fd); -} - -int -iface_get_initial_state(State *state) -{ - int mib[6]; - char *buf; - struct if_msghdr *ifm; - struct ifa_msghdr *ifam; - char *lim; - char *next; - struct sockaddr *sa; - size_t len; - int naddrs; - - assert(state != NULL); - assert(fd != -1); - - naddrs = 0; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; - mib[3] = 0; - mib[4] = NET_RT_IFLIST; - mib[5] = ifindex; - - if (sysctl(mib, elementsof(mib), NULL, &len, NULL, 0) != 0) { - daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s", - strerror(errno)); - return (-1); - } - - buf = malloc(len); - if (buf == NULL) { - daemon_log(LOG_ERR, "malloc(%d): %s", len, strerror(errno)); - return (-1); - } - - if (sysctl(mib, elementsof(mib), buf, &len, NULL, 0) != 0) { - daemon_log(LOG_ERR, "sysctl(NET_RT_IFLIST): %s", - strerror(errno)); - free(buf); - return (-1); - } - - lim = buf + len; - for (next = buf; next < lim; next += ifm->ifm_msglen) { - ifm = (struct if_msghdr *)next; - if (ifm->ifm_type == RTM_NEWADDR) { - ifam = (struct ifa_msghdr *)next; - sa = (struct sockaddr *)(ifam + 1); - if (sa->sa_family != AF_INET) - continue; - ++naddrs; - } - } - free(buf); - - *state = (naddrs > 0) ? STATE_SLEEPING : STATE_START; - - return (0); -} - -int -iface_process(Event *event) -{ - int routable; - - assert(fd != -1); - - routable = !!addresses; - - if (rtm_dispatch() == -1) - return (-1); - - if (routable && !addresses) - *event = EVENT_ROUTABLE_ADDR_UNCONFIGURED; - else if (!routable && addresses) - *event = EVENT_ROUTABLE_ADDR_CONFIGURED; - - return (0); -} - -void -iface_done(void) -{ - Address *a; - - if (fd != -1) { - close(fd); - fd = -1; - } - - while ((a = addresses) != NULL) { - AVAHI_LLIST_REMOVE(Address, addresses, addresses, a); - avahi_free(a); - } -} - -/* - * Dispatch kernel routing socket messages. - */ -static int -rtm_dispatch(void) -{ - struct msghdr mh; - struct iovec iov[1]; - struct rt_msghdr *rtm; - struct rtm_dispinfo *di; - ssize_t len; - int retval; - - di = malloc(sizeof(*di)); - if (di == NULL) { - daemon_log(LOG_ERR, "malloc(%d): %s", sizeof(*di), - strerror(errno)); - return (-1); - } - di->di_buflen = MAX_RTMSG_SIZE; - di->di_buf = calloc(MAX_RTMSG_SIZE, 1); - if (di->di_buf == NULL) { - free(di); - daemon_log(LOG_ERR, "calloc(%d): %s", MAX_RTMSG_SIZE, - strerror(errno)); - return (-1); - } - - memset(&mh, 0, sizeof(mh)); - iov[0].iov_base = di->di_buf; - iov[0].iov_len = di->di_buflen; - mh.msg_iov = iov; - mh.msg_iovlen = 1; - - retval = 0; - for (;;) { - len = recvmsg(fd, &mh, MSG_DONTWAIT); - if (len == -1) { - if (errno == EWOULDBLOCK) - break; - else { - daemon_log(LOG_ERR, "recvmsg(): %s", - strerror(errno)); - retval = -1; - break; - } - } - - rtm = (void *)di->di_buf; - if (rtm->rtm_version != RTM_VERSION) { - daemon_log(LOG_ERR, - "unknown routing socket message (version %d)\n", - rtm->rtm_version); - /* this is non-fatal; just ignore it for now. */ - continue; - } - - switch (rtm->rtm_type) { - case RTM_NEWADDR: - case RTM_DELADDR: - retval = rtm_dispatch_newdeladdr(di); - break; - case RTM_IFANNOUNCE: - retval = rtm_dispatch_ifannounce(di); - break; - default: - daemon_log(LOG_DEBUG, "%s: rtm_type %d ignored", __func__, rtm->rtm_type); - break; - } - - /* - * If we got an error; assume our position on the call - * stack is enclosed by a level-triggered event loop, - * and signal the error condition. - */ - if (retval != 0) - break; - } - free(di->di_buf); - free(di); - - return (retval); -} - -/* handle link coming or going away */ -static int -rtm_dispatch_ifannounce(struct rtm_dispinfo *di) -{ - rtmunion_t *rtm = (void *)di->di_buf; - - assert(rtm->rtm.rtm_type == RTM_IFANNOUNCE); - - daemon_log(LOG_DEBUG, "%s: IFANNOUNCE for ifindex %d", - __func__, rtm->ifan.ifan_index); - - switch (rtm->ifan.ifan_what) { - case IFAN_ARRIVAL: - if (rtm->ifan.ifan_index == ifindex) { - daemon_log(LOG_ERR, -"RTM_IFANNOUNCE IFAN_ARRIVAL, for ifindex %d, which we already manage.", - ifindex); - return (-1); - } - break; - case IFAN_DEPARTURE: - if (rtm->ifan.ifan_index == ifindex) { - daemon_log(LOG_ERR, "Interface vanished."); - return (-1); - } - break; - default: - /* ignore */ - break; - } - - return (0); -} - -static struct sockaddr * -next_sa(struct sockaddr *sa) -{ - void *p; - size_t sa_size; - -#ifdef SA_SIZE - sa_size = SA_SIZE(sa); -#else - /* This is not foolproof, kernel may round. */ - sa_size = sa->sa_len; - if (sa_size < sizeof(u_long)) - sa_size = sizeof(u_long); -#endif - - p = ((char *)sa) + sa_size; - - return (struct sockaddr *)p; -} - -/* handle address coming or going away */ -static int -rtm_dispatch_newdeladdr(struct rtm_dispinfo *di) -{ - Address *ap; - struct ifa_msghdr *ifam; - struct sockaddr *sa; - struct sockaddr_in *sin; - int link_local; - -/* macro to skip to next RTA; has side-effects */ -#define SKIPRTA(ifamsgp, rta, sa) \ - do { \ - if ((ifamsgp)->ifam_addrs & (rta)) \ - (sa) = next_sa((sa)); \ - } while (0) - - ifam = &((rtmunion_t *)di->di_buf)->ifam; - - assert(ifam->ifam_type == RTM_NEWADDR || - ifam->ifam_type == RTM_DELADDR); - - daemon_log(LOG_DEBUG, "%s: %s for iface %d (%s)", __func__, - ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", - ifam->ifam_index, (ifam->ifam_index == ifindex) ? "ours" : "not ours"); - - if (ifam->ifam_index != ifindex) - return (0); - - if (!(ifam->ifam_addrs & RTA_IFA)) { - daemon_log(LOG_ERR, "ifa msg has no RTA_IFA."); - return (0); - } - - /* skip over rtmsg padding correctly */ - sa = (struct sockaddr *)(ifam + 1); - SKIPRTA(ifam, RTA_DST, sa); - SKIPRTA(ifam, RTA_GATEWAY, sa); - SKIPRTA(ifam, RTA_NETMASK, sa); - SKIPRTA(ifam, RTA_GENMASK, sa); - SKIPRTA(ifam, RTA_IFP, sa); - - /* - * sa now points to RTA_IFA sockaddr; we are only interested - * in updates for routable addresses. - */ - if (sa->sa_family != AF_INET) { - daemon_log(LOG_DEBUG, "%s: RTA_IFA family not AF_INET (=%d)", __func__, sa->sa_family); - return (0); - } - - sin = (struct sockaddr_in *)sa; - link_local = IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr)); - - daemon_log(LOG_DEBUG, "%s: %s for %s (%s)", __func__, - ifam->ifam_type == RTM_NEWADDR ? "NEWADDR" : "DELADDR", - inet_ntoa(sin->sin_addr), link_local ? "link local" : "routable"); - - if (link_local) - return (0); - - for (ap = addresses; ap; ap = ap->addresses_next) { - if (ap->address == sin->sin_addr.s_addr) - break; - } - if (ifam->ifam_type == RTM_DELADDR && ap != NULL) { - AVAHI_LLIST_REMOVE(Address, addresses, addresses, ap); - avahi_free(ap); - } - if (ifam->ifam_type == RTM_NEWADDR && ap == NULL) { - ap = avahi_new(Address, 1); - ap->address = sin->sin_addr.s_addr; - AVAHI_LLIST_PREPEND(Address, addresses, addresses, ap); - } - - return (0); -#undef SKIPRTA -}