]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/grabmyaddr.c
ipsec-332.100.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / grabmyaddr.c
index 6afc4ef724d36f288c42bcab1fb50e5576f3f466..db04bf287ffa44a24f64da277e10abe7fa583724 100644 (file)
 #include <sys/ioctl.h>
 
 #include <net/if.h>
-#if defined(__FreeBSD__) && __FreeBSD__ >= 3
 #include <net/if_var.h>
-#endif
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__APPLE__)
 #include <netinet/in.h>
 #include <netinet6/in6_var.h>
-#endif
 #include <net/route.h>
 
 #include <stdlib.h>
@@ -58,6 +54,7 @@
 #include <ifaddrs.h>
 #include <net/if.h>
 #endif 
+#include <fcntl.h>
 
 #include "var.h"
 #include "misc.h"
 #include "gcmalloc.h"
 #include "nattraversal.h"
 
-#ifdef __linux__
-#include <linux/types.h>
-#include <linux/rtnetlink.h>
-#ifndef HAVE_GETIFADDRS
-#define HAVE_GETIFADDRS
-#define NEED_LINUX_GETIFADDRS
-#endif
-#endif
-
 #ifndef HAVE_GETIFADDRS
-static unsigned int if_maxindex __P((void));
+static unsigned int if_maxindex (void);
 #endif
 
-static int suitable_ifaddr __P((const char *, const struct sockaddr *));
+static int suitable_ifaddr (const char *, const struct sockaddr *);
 #ifdef INET6
-static int suitable_ifaddr6 __P((const char *, const struct sockaddr *));
-#endif
-
-#ifdef NEED_LINUX_GETIFADDRS
-
-/* We could do this _much_ better. kame racoon in its current form
- * will esentially die at frequent changes of address configuration.
- */
-
-struct ifaddrs
-{
-       struct ifaddrs *ifa_next;
-       char            ifa_name[16];
-       int             ifa_ifindex;
-       struct sockaddr *ifa_addr;
-       struct sockaddr_storage ifa_addrbuf;
-};
-
-static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
-{
-       while (RTA_OK(rta, len)) {
-               if (rta->rta_type <= max)
-                       tb[rta->rta_type] = rta;
-               rta = RTA_NEXT(rta,len);
-       }
-       return 0;
-}
-
-static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq)
-{
-       char    buf[8192];
-       struct sockaddr_nl nladdr;
-       struct iovec iov = { buf, sizeof(buf) };
-       struct ifaddrmsg *m;
-       struct rtattr * rta_tb[IFA_MAX+1];
-       struct ifaddrs *I;
-
-       while (1) {
-               int status;
-               struct nlmsghdr *h;
-
-               struct msghdr msg = {
-                       (void*)&nladdr, sizeof(nladdr),
-                       &iov,   1,
-                       NULL,   0,
-                       0
-               };
-
-               status = recvmsg(fd, &msg, 0);
-
-               if (status < 0)
-                       continue;
-
-               if (status == 0)
-                       return;
-
-               if (nladdr.nl_pid) /* Message not from kernel */
-                       continue;
-
-               h = (struct nlmsghdr*)buf;
-               while (NLMSG_OK(h, status)) {
-                       if (h->nlmsg_seq != seq)
-                               goto skip_it;
-
-                       if (h->nlmsg_type == NLMSG_DONE)
-                               return;
-
-                       if (h->nlmsg_type == NLMSG_ERROR)
-                               return;
-
-                       if (h->nlmsg_type != RTM_NEWADDR)
-                               goto skip_it;
-
-                       m = NLMSG_DATA(h);
-
-                       if (m->ifa_family != AF_INET &&
-                           m->ifa_family != AF_INET6)
-                               goto skip_it;
-
-                       if (m->ifa_flags&IFA_F_TENTATIVE)
-                               goto skip_it;
-
-                       memset(rta_tb, 0, sizeof(rta_tb));
-                       parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
-
-                       if (rta_tb[IFA_LOCAL] == NULL)
-                               rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
-                       if (rta_tb[IFA_LOCAL] == NULL)
-                               goto skip_it;
-                       
-                       I = malloc(sizeof(struct ifaddrs));
-                       if (!I)
-                               return;
-                       memset(I, 0, sizeof(*I));
-
-                       I->ifa_ifindex = m->ifa_index;
-                       I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf;
-                       I->ifa_addr->sa_family = m->ifa_family;
-                       if (m->ifa_family == AF_INET) {
-                               struct sockaddr_in *sin = (void*)I->ifa_addr;
-                               memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4);
-                       } else {
-                               struct sockaddr_in6 *sin = (void*)I->ifa_addr;
-                               memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16);
-                               if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
-                                       sin->sin6_scope_id = I->ifa_ifindex;
-                       }
-                       I->ifa_next = *ifa;
-                       *ifa = I;
-
-skip_it:
-                       h = NLMSG_NEXT(h, status);
-               }
-               if (msg.msg_flags & MSG_TRUNC)
-                       continue;
-       }
-       return;
-}
-
-static int getifaddrs(struct ifaddrs **ifa0)
-{
-       struct {
-               struct nlmsghdr nlh;
-               struct rtgenmsg g;
-       } req;
-       struct sockaddr_nl nladdr;
-       static __u32 seq;
-       struct ifaddrs *i;
-       int fd;
-
-       fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-       if (fd < 0)
-               return -1;
-
-       memset(&nladdr, 0, sizeof(nladdr));
-       nladdr.nl_family = AF_NETLINK;
-
-       req.nlh.nlmsg_len = sizeof(req);
-       req.nlh.nlmsg_type = RTM_GETADDR;
-       req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
-       req.nlh.nlmsg_pid = 0;
-       req.nlh.nlmsg_seq = ++seq;
-       req.g.rtgen_family = AF_UNSPEC;
-
-       if (sendto(fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
-               close(fd);
-               return -1;
-       }
-
-       *ifa0 = NULL;
-
-       recvaddrs(fd, ifa0, seq);
-
-       close(fd);
-
-       fd = socket(AF_INET, SOCK_DGRAM, 0);
-
-       for (i=*ifa0; i; i = i->ifa_next) {
-               struct ifreq ifr;
-               ifr.ifr_ifindex = i->ifa_ifindex;
-               ioctl(fd, SIOCGIFNAME, (void*)&ifr);
-               memcpy(i->ifa_name, ifr.ifr_name, 16);
-       }
-       close(fd);
-
-       return 0;
-}
-
-static void freeifaddrs(struct ifaddrs *ifa0)
-{
-        struct ifaddrs *i;
-
-        while (ifa0) {
-                i = ifa0;
-                ifa0 = i->ifa_next;
-                free(i);
-        }
-}
-
+static int suitable_ifaddr6 (const char *, const struct sockaddr *);
 #endif
+static bool exclude_interfaces(const char *);
 
 #ifndef HAVE_GETIFADDRS
 static unsigned int
@@ -319,12 +130,12 @@ find_myaddr(addr, udp_encap)
        for (q = lcconf->myaddrs; q; q = q->next) {
                if (!q->addr)
                        continue;
-               if (q->udp_encap && !udp_encap
-                       || !q->udp_encap && udp_encap)
+               if ((q->udp_encap && !udp_encap)
+                       || (!q->udp_encap && udp_encap))
                        continue;
-               if (addr->sa_family != q->addr->sa_family)
+               if (addr->sa_family != q->addr->ss_family)
                        continue;
-               if (getnameinfo(q->addr, sysdep_sa_len(q->addr), h2, sizeof(h2),
+               if (getnameinfo((struct sockaddr *)q->addr, sysdep_sa_len((struct sockaddr *)q->addr), h2, sizeof(h2),
                    NULL, 0, NI_NUMERICHOST | niflags) != 0)
                        return NULL;
                if (strcmp(h1, h2) == 0)
@@ -342,17 +153,13 @@ find_myaddr(addr, udp_encap)
 void
 grab_myaddrs()
 {
-#ifdef HAVE_GETIFADDRS
        struct myaddrs *p, *q;
        struct ifaddrs *ifa0, *ifap;
-#ifdef INET6
-       struct sockaddr_in6 *sin6;
-#endif
 
        char addr1[NI_MAXHOST];
 
        if (getifaddrs(&ifa0)) {
-               plog(LLV_ERROR2, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "getifaddrs failed: %s\n", strerror(errno));
                exit(1);
                /*NOTREACHED*/
@@ -371,8 +178,12 @@ grab_myaddrs()
                )
                        continue;
 
+               if (exclude_interfaces(ifap->ifa_name)) {
+                       continue;
+               }
+
                if (!suitable_ifaddr(ifap->ifa_name, ifap->ifa_addr)) {
-                       plog(LLV_DEBUG2, LOCATION, NULL,
+                       plog(ASL_LEVEL_DEBUG, 
                                "unsuitable address: %s %s\n",
                                ifap->ifa_name,
                                saddrwop2str(ifap->ifa_addr));
@@ -386,39 +197,46 @@ grab_myaddrs()
                        q = find_myaddr(ifap->ifa_addr, 1);
                        if (q)
                                q->in_use = 1;
+            else if (natt_enabled_in_rmconf ()) {
+                               q = dupmyaddr(p);
+                               if (q == NULL) {
+                                       plog(ASL_LEVEL_ERR,
+                         "unable to allocate space for natt addr.\n");
+                                       exit(1);
+                               }
+                               q->udp_encap = 1;
+                       }
 #endif                         
                } else {        
                        p = newmyaddr();
                        if (p == NULL) {
-                               plog(LLV_ERROR2, LOCATION, NULL,
+                               plog(ASL_LEVEL_ERR, 
                                        "unable to allocate space for addr.\n");
                                exit(1);
                                /*NOTREACHED*/
                        }
-                       p->addr = dupsaddr(ifap->ifa_addr);
+                       p->addr = dupsaddr(ALIGNED_CAST(struct sockaddr_storage*)ifap->ifa_addr);
                        if (p->addr == NULL) {
-                               plog(LLV_ERROR2, LOCATION, NULL,
+                               plog(ASL_LEVEL_ERR, 
                                        "unable to duplicate addr.\n");
                                exit(1);
                                /*NOTREACHED*/
                        }
                        p->ifname = racoon_strdup(ifap->ifa_name);
                        if (p->ifname == NULL) {
-                               plog(LLV_ERROR2, LOCATION, NULL,
+                               plog(ASL_LEVEL_ERR, 
                                        "unable to duplicate ifname.\n");
                                exit(1);
                                /*NOTREACHED*/
-                       }
-                               
-                       p->sock = -1;
+                       }                               
                        p->in_use = 1;
 
-                       if (getnameinfo(p->addr, p->addr->sa_len,
+                       if (getnameinfo((struct sockaddr *)p->addr, p->addr->ss_len,
                                        addr1, sizeof(addr1),
                                        NULL, 0,
                                        NI_NUMERICHOST | niflags))
                                strlcpy(addr1, "(invalid)", sizeof(addr1));
-                       plog(LLV_DEBUG, LOCATION, NULL,
+                       plog(ASL_LEVEL_DEBUG, 
                                "my interface: %s (%s)\n",
                                addr1, ifap->ifa_name);
                
@@ -429,7 +247,7 @@ grab_myaddrs()
                        if (natt_enabled_in_rmconf ()) {
                                q = dupmyaddr(p);
                                if (q == NULL) {
-                                       plog(LLV_ERROR2, LOCATION, NULL,
+                                       plog(ASL_LEVEL_ERR, 
                                                "unable to allocate space for natt addr.\n");
                                        exit(1);
                                }
@@ -441,11 +259,23 @@ grab_myaddrs()
        }
 
        freeifaddrs(ifa0);
+}
+
+static bool
+exclude_interfaces(ifname)
+       const char *ifname;
+{
+       if (ifname == NULL) {
+               return false;
+       }
 
+       if (strnstr(ifname, "awdl", IFNAMSIZ) != NULL) {
+               return true;
+       } else if (strnstr(ifname, "llw", IFNAMSIZ) != NULL) {
+               return true;
+       }
 
-#else /*!HAVE_GETIFADDRS*/
-#error "NOT SUPPORTED"
-#endif /*HAVE_GETIFADDRS*/
+       return false;
 }
 
 
@@ -457,7 +287,7 @@ suitable_ifaddr(ifname, ifaddr)
        const char *ifname;
        const struct sockaddr *ifaddr;
 {
-#ifdef ENABLE_HYBRID
+#if 0 //we need to be able to do nested ipsec for BTMM... stub out ifdef ENABLE_HYBRID
        /* Exclude any address we got through ISAKMP mode config */
        if (exclude_cfg_addr(ifaddr) == 0)
                return 0;
@@ -481,29 +311,30 @@ suitable_ifaddr6(ifname, ifaddr)
        const char *ifname;
        const struct sockaddr *ifaddr;
 {
-#ifndef __linux__
        struct in6_ifreq ifr6;
        int s;
-#endif
 
        if (ifaddr->sa_family != AF_INET6)
                return 0;
 
-#ifndef __linux__
        s = socket(PF_INET6, SOCK_DGRAM, 0);
        if (s == -1) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "socket(SOCK_DGRAM) failed:%s\n", strerror(errno));
                return 0;
        }
 
+    if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
+               plog(ASL_LEVEL_ERR, "failed to put IPv6 socket in non-blocking mode\n");
+       }
+
        memset(&ifr6, 0, sizeof(ifr6));
        strlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
 
-       ifr6.ifr_addr = *(const struct sockaddr_in6 *)ifaddr;
+       memcpy(&ifr6.ifr_addr, ifaddr, sizeof(struct sockaddr_in6));    // Wcast-align fix - copy instread of assign with cast
 
        if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "ioctl(SIOCGIFAFLAG_IN6) failed:%s\n", strerror(errno));
                close(s);
                return 0;
@@ -513,82 +344,16 @@ suitable_ifaddr6(ifname, ifaddr)
 
        if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED
         || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED
-        || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
+        || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST
+        /* Deprecated addresses will now be dropped by isakmp_close_unused */
+        || ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED) 
                return 0;
-#endif
 
        /* suitable */
        return 1;
 }
 #endif
 
-int
-update_myaddrs()
-{
-#ifdef __linux__
-       char msg[BUFSIZ];
-       int len;
-       struct nlmsghdr *h = (void*)msg;
-       len = read(lcconf->rtsock, msg, sizeof(msg));
-       if (len < 0)
-               return errno == ENOBUFS;
-       if (len < sizeof(*h))
-               return 0;
-       if (h->nlmsg_pid) /* not from kernel! */
-               return 0;
-       if (h->nlmsg_type == RTM_NEWLINK)
-               return 0;
-       plog(LLV_DEBUG, LOCATION, NULL,
-               "netlink signals update interface address list\n");
-       return 1;
-#else
-       char msg[BUFSIZ];
-       int len;
-       struct rt_msghdr *rtm;
-
-       len = read(lcconf->rtsock, msg, sizeof(msg));
-       if (len < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "read(PF_ROUTE) failed: %s\n",
-                       strerror(errno));
-               return 0;
-       }
-       rtm = (struct rt_msghdr *)msg;
-       if (len < rtm->rtm_msglen) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "read(PF_ROUTE) short read\n");
-               return 0;
-       }
-       if (rtm->rtm_version != RTM_VERSION) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "routing socket version mismatch\n");
-               close(lcconf->rtsock);
-               lcconf->rtsock = -1;
-               return 0;
-       }
-       switch (rtm->rtm_type) {
-       case RTM_NEWADDR:
-       case RTM_DELADDR:
-       case RTM_DELETE:
-       case RTM_IFINFO:
-               break;
-       case RTM_MISS:
-               /* ignore this message silently */
-               return 0;
-       default:
-               plog(LLV_DEBUG, LOCATION, NULL,
-                       "msg %d not interesting\n", rtm->rtm_type);
-               return 0;
-       }
-       /* XXX more filters here? */
-
-       plog(LLV_DEBUG, LOCATION, NULL,
-               "caught rtm:%d, need update interface address list\n",
-               rtm->rtm_type);
-
-       return 1;
-#endif /* __linux__ */
-}
 
 /*
  * initialize default port for ISAKMP to send, if no "listen"
@@ -604,13 +369,13 @@ autoconf_myaddrsport()
        struct myaddrs *p;
        int n;
 
-       plog(LLV_DEBUG, LOCATION, NULL,
+       plog(ASL_LEVEL_DEBUG, 
                "configuring default isakmp port.\n");
 
        for (p = lcconf->myaddrs, n = 0; p; p = p->next, n++) {
                set_port (p->addr, p->udp_encap ? lcconf->port_isakmp_natt : lcconf->port_isakmp);
        }
-       plog(LLV_DEBUG, LOCATION, NULL,
+       plog(ASL_LEVEL_DEBUG, 
                "%d addrs are configured successfully\n", n);
 
        return 0;
@@ -622,7 +387,7 @@ autoconf_myaddrsport()
  */
 u_short
 getmyaddrsport(local)
-       struct sockaddr *local;
+       struct sockaddr_storage *local;
 {
        struct myaddrs *p, *bestmatch = NULL;
        u_short bestmatch_port = PORT_ISAKMP;
@@ -637,7 +402,7 @@ getmyaddrsport(local)
                                continue;
                        }
                        
-                       switch (p->addr->sa_family) {
+                       switch (p->addr->ss_family) {
                        case AF_INET:
                                if (((struct sockaddr_in *)p->addr)->sin_port == PORT_ISAKMP) {
                                        bestmatch = p;
@@ -655,8 +420,8 @@ getmyaddrsport(local)
                                break;
 #endif
                        default:
-                               plog(LLV_ERROR, LOCATION, NULL,
-                                    "unsupported AF %d\n", p->addr->sa_family);
+                               plog(ASL_LEVEL_ERR, 
+                                    "unsupported AF %d\n", p->addr->ss_family);
                                continue;
                        }
                }
@@ -672,13 +437,15 @@ newmyaddr()
 
        new = racoon_calloc(1, sizeof(*new));
        if (new == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to allocate buffer for myaddrs.\n");
                return NULL;
        }
 
        new->next = NULL;
        new->addr = NULL;
+    new->source = NULL;
+    new->sock = -1;
 #ifdef __APPLE_
        new->ifname = NULL;
 #endif
@@ -693,7 +460,7 @@ dupmyaddr(struct myaddrs *old)
 
        new = racoon_calloc(1, sizeof(*new));
        if (new == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to allocate buffer for myaddrs.\n");
                return NULL;
        }
@@ -702,7 +469,7 @@ dupmyaddr(struct myaddrs *old)
        memcpy (new, old, sizeof (*new));
        new->addr = dupsaddr (old->addr);
        if (new->addr == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to allocate buffer for duplicate addr.\n");
                racoon_free(new);
                return NULL;
@@ -710,14 +477,16 @@ dupmyaddr(struct myaddrs *old)
        if (old->ifname) {
                new->ifname = racoon_strdup(old->ifname);
                if (new->ifname == NULL) {
-                       plog(LLV_ERROR, LOCATION, NULL,
+                       plog(ASL_LEVEL_ERR, 
                                "failed to allocate buffer for duplicate ifname.\n");
                        racoon_free(new->addr);
                        racoon_free(new);
                        return NULL;
                }
        }
-                       
+    new->source = NULL;
+    new->sock = -1;
+    
        new->next = old->next;
        old->next = new;
 
@@ -739,49 +508,24 @@ delmyaddr(myaddr)
 {
        if (myaddr->addr)
                racoon_free(myaddr->addr);
-#ifdef __APPLE__
        if (myaddr->ifname)
                racoon_free(myaddr->ifname);
-#endif
        racoon_free(myaddr);
 }
 
-int
-initmyaddr()
+void
+update_myaddrs(void *unused)
 {
-       /* initialize routing socket */
-       lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
-       if (lcconf->rtsock < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "socket(PF_ROUTE) failed: %s",
-                       strerror(errno));
-               return -1;
-       }
-
-#ifdef __linux__
-   {
-       struct sockaddr_nl nl;
-       u_int addr_len;
+    grab_myaddrs();
+    isakmp_close_unused();
+    autoconf_myaddrsport();
+    isakmp_open();
+}
 
-       memset(&nl, 0, sizeof(nl));
-       nl.nl_family = AF_NETLINK;
-       nl.nl_groups = RTMGRP_IPV4_IFADDR|RTMGRP_LINK;
 
-       if (bind(lcconf->rtsock, (struct sockaddr*)&nl, sizeof(nl)) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                    "bind(PF_NETLINK) failed: %s\n",
-                    strerror(errno));
-               return -1;
-       }
-       addr_len = sizeof(nl);
-       if (getsockname(lcconf->rtsock, (struct sockaddr*)&nl, &addr_len) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                    "getsockname(PF_NETLINK) failed: %s\n",
-                    strerror(errno));
-               return -1;
-       }
-   }
-#endif
+int
+initmyaddr(void)
+{
 
        if (lcconf->myaddrs == NULL && lcconf->autograbaddr == 1) {
                grab_myaddrs();
@@ -793,47 +537,29 @@ initmyaddr()
        return 0;
 }
 
+
 /* select the socket to be sent */
 /* should implement other method. */
 int
-getsockmyaddr(my)
-       struct sockaddr *my;
+getsockmyaddr(struct sockaddr *my)
 {
        struct myaddrs *p, *lastresort = NULL;
-#if defined(INET6) && defined(__linux__)
-       struct myaddrs *match_wo_scope_id = NULL;
-       int check_wo_scope_id = (my->sa_family == AF_INET6) && 
-               IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)my)->sin6_addr);
-#endif
 
        for (p = lcconf->myaddrs; p; p = p->next) {
                if (p->addr == NULL)
                        continue;
-               if (my->sa_family == p->addr->sa_family) {
+               if (my->sa_family == p->addr->ss_family) {
                        lastresort = p;
                } else continue;
-               if (sysdep_sa_len(my) == sysdep_sa_len(p->addr)
+               if (sysdep_sa_len(my) == sysdep_sa_len((struct sockaddr *)p->addr)
                 && memcmp(my, p->addr, sysdep_sa_len(my)) == 0) {
                        break;
                }
-#if defined(INET6) && defined(__linux__)
-               if (check_wo_scope_id && IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)p->addr)->sin6_addr) &&
-                       /* XXX: this depends on sin6_scope_id to be last
-                        * item in struct sockaddr_in6 */
-                       memcmp(my, p->addr, 
-                               sysdep_sa_len(my) - sizeof(uint32_t)) == 0) {
-                       match_wo_scope_id = p;
-               }
-#endif
        }
-#if defined(INET6) && defined(__linux__)
-       if (!p)
-               p = match_wo_scope_id;
-#endif
        if (!p)
                p = lastresort;
        if (!p) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "no socket matches address family %d\n",
                        my->sa_family);
                return -1;
@@ -841,3 +567,94 @@ getsockmyaddr(my)
 
        return p->sock;
 }
+
+void
+pfroute_handler(void *unused)
+{   
+    
+    struct rtmessage {          // Wcast-align fix - force alignment
+        struct rt_msghdr rtm;  
+        char discard[BUFSIZ];
+    } msg;
+       
+       int len;
+    
+       while((len = read(lcconf->rtsock, &msg, sizeof(msg))) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(ASL_LEVEL_DEBUG, 
+             "read(PF_ROUTE) failed: %s\n",
+             strerror(errno));
+               return;
+       }
+       if (len < msg.rtm.rtm_msglen) {
+               plog(ASL_LEVEL_DEBUG, 
+             "read(PF_ROUTE) short read\n");
+               return;
+       }
+       switch (msg.rtm.rtm_type) {
+        case RTM_NEWADDR:
+        case RTM_DELADDR:
+        case RTM_DELETE:
+        case RTM_IFINFO:
+            break;
+        case RTM_MISS:
+            /* ignore this message silently */
+            return;
+        default:
+            //plog(ASL_LEVEL_DEBUG,
+            //     "msg %d not interesting\n", msg.rtm.rtm_type);
+            return;
+       }
+       /* XXX more filters here? */
+    
+       plog(ASL_LEVEL_DEBUG, 
+         "caught rtm:%d, need update interface address list\n",
+         msg.rtm.rtm_type);
+    
+    // Interface changes occurred - update addrs
+    update_myaddrs(NULL);
+}
+
+void
+pfroute_close(void)
+{
+    
+    dispatch_source_cancel(lcconf->rt_source);
+    lcconf->rt_source = NULL;
+}
+
+int
+pfroute_init(void)
+{
+    int sock;
+    
+    /* initialize routing socket */
+    lcconf->rtsock = socket(PF_ROUTE, SOCK_RAW, PF_UNSPEC);
+    if (lcconf->rtsock < 0) {
+        plog(ASL_LEVEL_DEBUG, 
+             "socket(PF_ROUTE) failed: %s",
+             strerror(errno));
+        return -1;
+    }
+    if (fcntl(lcconf->rtsock, F_SETFL, O_NONBLOCK) == -1) {
+               plog(ASL_LEVEL_DEBUG, "failed to put PF_ROUTE socket in non-blocking mode\n");
+       }
+
+    lcconf->rt_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, lcconf->rtsock, 0, dispatch_get_main_queue());
+    if (lcconf->rt_source == NULL) {
+        plog(ASL_LEVEL_DEBUG, "could not create pfroute socket source.");
+        return -1;
+    }
+    dispatch_source_set_event_handler_f(lcconf->rt_source, pfroute_handler);
+    sock = lcconf->rtsock;
+    dispatch_source_set_cancel_handler(lcconf->rt_source, 
+                                         ^{
+                                             close(sock);
+                                         });
+    dispatch_resume(lcconf->rt_source);
+    return 0;
+}
+
+
+