]> git.saurik.com Git - apple/ipsec.git/blobdiff - ipsec-tools/racoon/sockmisc.c
ipsec-332.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / sockmisc.c
index 14399cc6b97d809cef9a0fd643bf309cc3d28c00..ac0645feef1084aca45be5771bd5abcccc6321e0 100644 (file)
@@ -43,7 +43,8 @@
 #include <netinet6/ipsec.h>
 #endif
 
-#if defined(IP_RECVDSTADDR) && !defined(IPV6_RECVDSTADDR)
+#if defined(INET6) && !defined(INET6_ADVAPI) && \
+       defined(IP_RECVDSTADDR) && !defined(IPV6_RECVDSTADDR)
 #define IPV6_RECVDSTADDR IP_RECVDSTADDR
 #endif
 
@@ -54,6 +55,7 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#include <fcntl.h>
 
 #include "var.h"
 #include "misc.h"
@@ -81,8 +83,8 @@ const int niflags = 0;
  */
 int
 cmpsaddrwop(addr1, addr2)
-       const struct sockaddr *addr1;
-       const struct sockaddr *addr2;
+       const struct sockaddr_storage *addr1;
+       const struct sockaddr_storage *addr2;
 {
        caddr_t sa1, sa2;
 
@@ -91,17 +93,10 @@ cmpsaddrwop(addr1, addr2)
        if (addr1 == 0 || addr2 == 0)
                return 1;
 
-#ifdef __linux__
-       if (addr1->sa_family != addr2->sa_family)
+       if (addr1->ss_len != addr2->ss_len
+        || addr1->ss_family != addr2->ss_family)
                return 1;
-#else
-       if (addr1->sa_len != addr2->sa_len
-        || addr1->sa_family != addr2->sa_family)
-               return 1;
-
-#endif /* __linux__ */
-
-       switch (addr1->sa_family) {
+       switch (addr1->ss_family) {
        case AF_INET:
                sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
                sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
@@ -126,6 +121,63 @@ cmpsaddrwop(addr1, addr2)
        return 0;
 }
 
+/*
+ * compare two sockaddr without port number using prefix.
+ * OUT:        0: equal.
+ *     1: not equal.
+ */
+int
+cmpsaddrwop_withprefix(const struct sockaddr_storage *addr1, const struct sockaddr_storage *addr2, int prefix)
+{
+    u_int32_t mask;
+    int i;
+    
+       if (addr1 == 0 && addr2 == 0)
+               return 0;
+       if (addr1 == 0 || addr2 == 0)
+               return 1;
+    
+       if (addr1->ss_len != addr2->ss_len
+        || addr1->ss_family != addr2->ss_family)
+               return 1;
+       switch (addr1->ss_family) {
+        case AF_INET:
+            mask = ~0;
+            mask <<= 32-prefix;
+            if ((((struct sockaddr_in *)addr1)->sin_addr.s_addr & htonl(mask)) != 
+                (((struct sockaddr_in *)addr2)->sin_addr.s_addr & htonl(mask)))
+                return 1;
+            break;
+#ifdef INET6
+        case AF_INET6:
+            for (i = 0; i < 4; i++) {
+                if (prefix >= 32) {
+                    mask = ~0;
+                    prefix -= 32;
+                } else if (prefix == 0)
+                    mask = 0;
+                else {
+                    mask = ~0;
+                    mask <<= 32-prefix;
+                    prefix = 0;
+                }
+                if ((((struct sockaddr_in6 *)addr1)->sin6_addr.__u6_addr.__u6_addr32[i] & htonl(mask)) != 
+                    (((struct sockaddr_in6 *)addr2)->sin6_addr.__u6_addr.__u6_addr32[i] & htonl(mask)))
+                    return 1;
+            }
+            if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
+                ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
+                return 1;
+            break;
+#endif
+        default:
+            return 1;
+       }
+    
+       return 0;
+}
+
+
 /*
  * compare two sockaddr with port, taking care wildcard.
  * addr1 is a subject address, addr2 is in a database entry.
@@ -134,8 +186,8 @@ cmpsaddrwop(addr1, addr2)
  */
 int
 cmpsaddrwild(addr1, addr2)
-       const struct sockaddr *addr1;
-       const struct sockaddr *addr2;
+       const struct sockaddr_storage *addr1;
+       const struct sockaddr_storage *addr2;
 {
        caddr_t sa1, sa2;
        u_short port1, port2;
@@ -145,17 +197,11 @@ cmpsaddrwild(addr1, addr2)
        if (addr1 == 0 || addr2 == 0)
                return 1;
 
-#ifdef __linux__
-       if (addr1->sa_family != addr2->sa_family)
-               return 1;
-#else
-       if (addr1->sa_len != addr2->sa_len
-        || addr1->sa_family != addr2->sa_family)
+       if (addr1->ss_len != addr2->ss_len
+        || addr1->ss_family != addr2->ss_family)
                return 1;
 
-#endif /* __linux__ */
-
-       switch (addr1->sa_family) {
+       switch (addr1->ss_family) {
        case AF_INET:
                sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
                sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
@@ -198,9 +244,7 @@ cmpsaddrwild(addr1, addr2)
  *     1: not equal.
  */
 int
-cmpsaddrstrict(addr1, addr2)
-       const struct sockaddr *addr1;
-       const struct sockaddr *addr2;
+cmpsaddrstrict(const struct sockaddr_storage *addr1, const struct sockaddr_storage *addr2)
 {
        caddr_t sa1, sa2;
        u_short port1, port2;
@@ -210,17 +254,11 @@ cmpsaddrstrict(addr1, addr2)
        if (addr1 == 0 || addr2 == 0)
                return 1;
 
-#ifdef __linux__
-       if (addr1->sa_family != addr2->sa_family)
-               return 1;
-#else
-       if (addr1->sa_len != addr2->sa_len
-        || addr1->sa_family != addr2->sa_family)
+       if (addr1->ss_len != addr2->ss_len
+        || addr1->ss_family != addr2->ss_family)
                return 1;
 
-#endif /* __linux__ */
-
-       switch (addr1->sa_family) {
+       switch (addr1->ss_family) {
        case AF_INET:
                sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
                sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
@@ -253,40 +291,110 @@ cmpsaddrstrict(addr1, addr2)
        return 0;
 }
 
+/*
+ * compare two sockaddr with strict match on port using prefix.
+ * OUT:        0: equal.
+ *     1: not equal.
+ */
+int
+cmpsaddrstrict_withprefix(const struct sockaddr_storage *addr1, const struct sockaddr_storage *addr2, int prefix)
+{
+       u_short port1, port2;
+    u_int32_t mask;
+    int i;
+    
+       if (addr1 == 0 && addr2 == 0)
+               return 0;
+       if (addr1 == 0 || addr2 == 0)
+               return 1;
+    
+       if (addr1->ss_len != addr2->ss_len
+        || addr1->ss_family != addr2->ss_family)
+               return 1;
+    
+       switch (addr1->ss_family) {
+        case AF_INET:  
+            port1 = ((struct sockaddr_in *)addr1)->sin_port;
+            port2 = ((struct sockaddr_in *)addr2)->sin_port;
+            if (port1 != port2)
+                return 1;
+            mask = ~0;
+            mask <<= 32-prefix;
+            if ((((struct sockaddr_in *)addr1)->sin_addr.s_addr & htonl(mask)) != 
+                (((struct sockaddr_in *)addr2)->sin_addr.s_addr & htonl(mask)))
+                return 1;
+            break;
+#ifdef INET6
+        case AF_INET6:    
+            port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
+            port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
+            if (port1 != port2)
+                return 1;
+            for (i = 0; i < 4; i++) {
+                if (prefix >= 32) {
+                    mask = ~0;
+                    prefix -= 32;
+                } else if (prefix == 0)
+                    mask = 0;
+                else {
+                    mask = ~0;
+                    mask <<= 32-prefix;
+                    prefix = 0;
+                }
+                if ((((struct sockaddr_in6 *)addr1)->sin6_addr.__u6_addr.__u6_addr32[i] & htonl(mask)) != 
+                    (((struct sockaddr_in6 *)addr2)->sin6_addr.__u6_addr.__u6_addr32[i] & htonl(mask)))
+                    return 1;
+            }            
+            if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
+                ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
+                return 1;
+            break;
+#endif
+        default:
+            return 1;
+       }
+    
+       return 0;
+}
+
+
 /* get local address against the destination. */
-struct sockaddr *
-getlocaladdr(remote)
-       struct sockaddr *remote;
+struct sockaddr_storage *
+getlocaladdr(struct sockaddr *remote)
 {
-       struct sockaddr *local;
+       struct sockaddr_storage *local;
        u_int local_len = sizeof(struct sockaddr_storage);
        int s;  /* for dummy connection */
 
        /* allocate buffer */
        if ((local = racoon_calloc(1, local_len)) == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to get address buffer.\n");
                goto err;
        }
        
        /* get real interface received packet */
        if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "socket (%s)\n", strerror(errno));
                goto err;
        }
 
+       if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
+               plog(ASL_LEVEL_ERR, "failed to put localaddr socket in non-blocking mode\n");
+       }
+    
        setsockopt_bypass(s, remote->sa_family);
        
        if (connect(s, remote, sysdep_sa_len(remote)) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "connect (%s)\n", strerror(errno));
                close(s);
                goto err;
        }
 
-       if (getsockname(s, local, &local_len) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+       if (getsockname(s, (struct sockaddr *)local, &local_len) < 0) {
+               plog(ASL_LEVEL_ERR, 
                        "getsockname (%s)\n", strerror(errno));
                close(s);
                return NULL;
@@ -306,23 +414,22 @@ getlocaladdr(remote)
  * setsockopt() have already performed on socket.
  */
 int
-recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
-       int s;
-       void *buf;
-       size_t buflen;
-       int flags;
-       struct sockaddr *from;
-       socklen_t *fromlen;
-       struct sockaddr *to;
-       u_int *tolen;
+recvfromto(int s,
+           void *buf,
+           size_t buflen,
+           int flags,
+           struct sockaddr_storage *from,
+           socklen_t *fromlen,
+           struct sockaddr_storage *to,
+           u_int *tolen)
 {
        int otolen;
-       u_int len;
+       ssize_t len;
        struct sockaddr_storage ss;
        struct msghdr m;
-       struct cmsghdr *cm;
+       struct cmsghdr *cm, *cm_prev;
        struct iovec iov[2];
-       u_char cmsgbuf[256];
+    u_int32_t cmsgbuf[256/sizeof(u_int32_t)];       // Wcast-align fix - force 32 bit alignment
 #if defined(INET6) && defined(INET6_ADVAPI)
        struct in6_pktinfo *pi;
 #endif /*INET6_ADVAPI*/
@@ -332,8 +439,8 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
 #endif
 
        len = sizeof(ss);
-       if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+       if (getsockname(s, (struct sockaddr *)&ss, (socklen_t*)&len) < 0) {
+               plog(ASL_LEVEL_ERR, 
                        "getsockname (%s)\n", strerror(errno));
                return -1;
        }
@@ -348,20 +455,25 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
        cm = (struct cmsghdr *)cmsgbuf;
        m.msg_control = (caddr_t)cm;
        m.msg_controllen = sizeof(cmsgbuf);
-       if ((len = recvmsg(s, &m, flags)) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "recvmsg (%s)\n", strerror(errno));
+       m.msg_flags = 0;
+       while ((len = recvmsg(s, &m, flags)) < 0) {
+               if (errno == EINTR)
+                       continue;
+               plog(ASL_LEVEL_ERR, "recvmsg (%s)\n", strerror(errno));
                return -1;
        }
+       if (len == 0) {
+               return 0;
+       }
        *fromlen = m.msg_namelen;
 
        otolen = *tolen;
        *tolen = 0;
-       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
-            m.msg_controllen != 0 && cm;
-            cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
+       for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m), cm_prev = NULL;
+            m.msg_controllen != 0 && cm && cm != cm_prev;
+            cm_prev = cm, cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
 #if 0
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);)
 #endif
 #if defined(INET6) && defined(INET6_ADVAPI)
@@ -369,14 +481,12 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
                 && cm->cmsg_level == IPPROTO_IPV6
                 && cm->cmsg_type == IPV6_PKTINFO
                 && otolen >= sizeof(*sin6)) {
-                       pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
+                       pi = ALIGNED_CAST(struct in6_pktinfo *)(CMSG_DATA(cm));
                        *tolen = sizeof(*sin6);
                        sin6 = (struct sockaddr_in6 *)to;
                        memset(sin6, 0, sizeof(*sin6));
                        sin6->sin6_family = AF_INET6;
-#ifndef __linux__
                        sin6->sin6_len = sizeof(*sin6);
-#endif
                        memcpy(&sin6->sin6_addr, &pi->ipi6_addr,
                                sizeof(sin6->sin6_addr));
                        /* XXX other cases, such as site-local? */
@@ -390,24 +500,6 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
                        continue;
                }
 #endif
-#ifdef __linux__
-               if (ss.ss_family == AF_INET
-                && cm->cmsg_level == IPPROTO_IP
-                && cm->cmsg_type == IP_PKTINFO
-                && otolen >= sizeof(sin)) {
-                       struct in_pktinfo *pi = (struct in_pktinfo *)(CMSG_DATA(cm));
-                       *tolen = sizeof(*sin);
-                       sin = (struct sockaddr_in *)to;
-                       memset(sin, 0, sizeof(*sin));
-                       sin->sin_family = AF_INET;
-                       memcpy(&sin->sin_addr, &pi->ipi_addr,
-                               sizeof(sin->sin_addr));
-                       sin->sin_port =
-                               ((struct sockaddr_in *)&ss)->sin_port;
-                       otolen = -1;    /* "to" already set */
-                       continue;
-               }
-#endif
 #if defined(INET6) && defined(IPV6_RECVDSTADDR)
                if (ss.ss_family == AF_INET6
                      && cm->cmsg_level == IPPROTO_IPV6
@@ -426,7 +518,6 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
                        continue;
                }
 #endif
-#ifndef __linux__
                if (ss.ss_family == AF_INET
                 && cm->cmsg_level == IPPROTO_IP
                 && cm->cmsg_type == IP_RECVDSTADDR
@@ -442,9 +533,8 @@ recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
                        otolen = -1;    /* "to" already set */
                        continue;
                }
-#endif
        }
-
+    plogdump(ASL_LEVEL_DEBUG, buf, buflen, "@@@@@@ data from readmsg:\n");
        return len;
 }
 
@@ -454,48 +544,47 @@ sendfromto(s, buf, buflen, src, dst, cnt)
        int s, cnt;
        const void *buf;
        size_t buflen;
-       struct sockaddr *src;
-       struct sockaddr *dst;
+       struct sockaddr_storage *src;
+       struct sockaddr_storage *dst;
 {
        struct sockaddr_storage ss;
-       u_int len;
+       int len;
        int i;
 
-       if (src->sa_family != dst->sa_family) {
-               plog(LLV_ERROR, LOCATION, NULL,
+       if (src->ss_family != dst->ss_family) {
+               plog(ASL_LEVEL_ERR, 
                        "address family mismatch\n");
                return -1;
        }
 
        len = sizeof(ss);
-       if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+       if (getsockname(s, (struct sockaddr *)&ss, (socklen_t*)&len) < 0) {
+               plog(ASL_LEVEL_ERR, 
                        "getsockname (%s)\n", strerror(errno));
                return -1;
        }
 
-       plog(LLV_DEBUG, LOCATION, NULL,
+       plog(ASL_LEVEL_DEBUG, 
                "sockname %s\n", saddr2str((struct sockaddr *)&ss));
-       plog(LLV_DEBUG, LOCATION, NULL,
-               "send packet from %s\n", saddr2str(src));
-       plog(LLV_DEBUG, LOCATION, NULL,
-               "send packet to %s\n", saddr2str(dst));
+       plog(ASL_LEVEL_DEBUG, 
+               "send packet from %s\n", saddr2str((struct sockaddr *)src));
+       plog(ASL_LEVEL_DEBUG, 
+               "send packet to %s\n", saddr2str((struct sockaddr *)dst));
 
-       if (src->sa_family != ss.ss_family) {
-               plog(LLV_ERROR, LOCATION, NULL,
+       if (src->ss_family != ss.ss_family) {
+               plog(ASL_LEVEL_ERR, 
                        "address family mismatch\n");
                return -1;
        }
 
-       switch (src->sa_family) {
+       switch (src->ss_family) {
 #if defined(INET6) && defined(INET6_ADVAPI)
-// XXX: This block wasn't compiled on Linux - does it work?
        case AF_INET6:
            {
                struct msghdr m;
                struct cmsghdr *cm;
                struct iovec iov[2];
-               u_char cmsgbuf[256];
+        u_int32_t cmsgbuf[256/sizeof(u_int32_t)];   // Wcast-align fix - force 32 bit alignment
                struct in6_pktinfo *pi;
                int ifindex;
                struct sockaddr_in6 src6, dst6;
@@ -531,100 +620,46 @@ sendfromto(s, buf, buflen, src, dst, cnt)
                cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
                cm->cmsg_level = IPPROTO_IPV6;
                cm->cmsg_type = IPV6_PKTINFO;
-               pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+               pi = ALIGNED_CAST(struct in6_pktinfo *)CMSG_DATA(cm);
                memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr));
                pi->ipi6_ifindex = ifindex;
 
-               plog(LLV_DEBUG, LOCATION, NULL,
+               plog(ASL_LEVEL_DEBUG, 
                        "src6 %s %d\n",
                        saddr2str((struct sockaddr *)&src6),
                        src6.sin6_scope_id);
-               plog(LLV_DEBUG, LOCATION, NULL,
+               plog(ASL_LEVEL_DEBUG, 
                        "dst6 %s %d\n",
                        saddr2str((struct sockaddr *)&dst6),
                        dst6.sin6_scope_id);
-
+            
                for (i = 0; i < cnt; i++) {
                        len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
                        if (len < 0) {
-                               plog(LLV_ERROR, LOCATION, NULL,
+                               plog(ASL_LEVEL_ERR, 
                                        "sendmsg (%s)\n", strerror(errno));
-                               return -1;
+                               if (errno != EHOSTUNREACH && errno != ENETDOWN && errno != ENETUNREACH) {
+                                       return -1;
+                               }
+                               // <rdar://problem/6609744> treat these failures like
+                               // packet loss, in case the network interface is flaky
+                               len = 0;
                        }
-                       plog(LLV_DEBUG, LOCATION, NULL,
+                       plog(ASL_LEVEL_DEBUG, 
                                "%d times of %d bytes message will be sent "
                                "to %s\n",
-                               i + 1, len, saddr2str(dst));
+                               i + 1, len, saddr2str((struct sockaddr *)dst));
                }
-               plogdump(LLV_DEBUG, (char *)buf, buflen);
 
                return len;
            }
 #endif
-#ifdef __linux__
-       case AF_INET:
-           {
-               struct msghdr m;
-               struct cmsghdr *cm;
-               struct iovec iov[2];
-               u_char cmsgbuf[256];
-               struct in_pktinfo *pi;
-               int ifindex = 0;
-               struct sockaddr_in src6, dst6;
-
-               memcpy(&src6, src, sizeof(src6));
-               memcpy(&dst6, dst, sizeof(dst6));
-
-               memset(&m, 0, sizeof(m));
-               m.msg_name = (caddr_t)&dst6;
-               m.msg_namelen = sizeof(dst6);
-               iov[0].iov_base = (char *)buf;
-               iov[0].iov_len = buflen;
-               m.msg_iov = iov;
-               m.msg_iovlen = 1;
-
-               memset(cmsgbuf, 0, sizeof(cmsgbuf));
-               cm = (struct cmsghdr *)cmsgbuf;
-               m.msg_control = (caddr_t)cm;
-               m.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
-
-               cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
-               cm->cmsg_level = IPPROTO_IP;
-               cm->cmsg_type = IP_PKTINFO;
-               pi = (struct in_pktinfo *)CMSG_DATA(cm);
-               memcpy(&pi->ipi_spec_dst, &src6.sin_addr, sizeof(src6.sin_addr));
-               pi->ipi_ifindex = ifindex;
-
-               plog(LLV_DEBUG, LOCATION, NULL,
-                       "src4 %s\n",
-                       saddr2str((struct sockaddr *)&src6));
-               plog(LLV_DEBUG, LOCATION, NULL,
-                       "dst4 %s\n",
-                       saddr2str((struct sockaddr *)&dst6));
-
-               for (i = 0; i < cnt; i++) {
-                       len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
-                       if (len < 0) {
-                               plog(LLV_ERROR, LOCATION, NULL,
-                                       "sendmsg (%s)\n", strerror(errno));
-                               return -1;
-                       }
-                       plog(LLV_DEBUG, LOCATION, NULL,
-                               "%d times of %d bytes message will be sent "
-                               "to %s\n",
-                               i + 1, len, saddr2str(dst));
-               }
-               plogdump(LLV_DEBUG, (char *)buf, buflen);
-
-               return len;
-           }
-#endif /* __linux__ */
        default:
            {
                int needclose = 0;
                int sendsock;
 
-               if (ss.ss_family == src->sa_family && memcmp(&ss, src, sysdep_sa_len(src)) == 0) {
+               if (ss.ss_family == src->ss_family && memcmp(&ss, src, sysdep_sa_len((struct sockaddr *)src)) == 0) {
                        sendsock = s;
                        needclose = 0;
                } else {
@@ -636,63 +671,72 @@ sendfromto(s, buf, buflen, src, dst, cnt)
                         * Better approach is to prepare bind'ed udp sockets for
                         * each of the interface addresses.
                         */
-                       sendsock = socket(src->sa_family, SOCK_DGRAM, 0);
+                       sendsock = socket(src->ss_family, SOCK_DGRAM, 0);
                        if (sendsock < 0) {
-                               plog(LLV_ERROR, LOCATION, NULL,
+                               plog(ASL_LEVEL_ERR, 
                                        "socket (%s)\n", strerror(errno));
                                return -1;
                        }
+                       if (fcntl(sendsock, F_SETFL, O_NONBLOCK) == -1) {
+                               plog(ASL_LEVEL_ERR, "failed to put sendsock socket in non-blocking mode\n");
+                       }
                        if (setsockopt(sendsock, SOL_SOCKET,
-#ifdef __linux__
-                                      SO_REUSEADDR,
-#else
                                       SO_REUSEPORT,
-#endif
                                       (void *)&yes, sizeof(yes)) < 0) {
-                               plog(LLV_ERROR, LOCATION, NULL,
-                                       "setsockopt (%s)\n", strerror(errno));
+                               plog(ASL_LEVEL_ERR, 
+                                       "setsockopt SO_REUSEPORT (%s)\n", 
+                                       strerror(errno));
                                close(sendsock);
                                return -1;
                        }
 #ifdef IPV6_USE_MIN_MTU
-                       if (src->sa_family == AF_INET6 &&
+                       if (src->ss_family == AF_INET6 &&
                            setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
                            (void *)&yes, sizeof(yes)) < 0) {
-                               plog(LLV_ERROR, LOCATION, NULL,
-                                       "setsockopt (%s)\n", strerror(errno));
+                               plog(ASL_LEVEL_ERR, 
+                                       "setsockopt IPV6_USE_MIN_MTU (%s)\n", 
+                                       strerror(errno));
                                close(sendsock);
                                return -1;
                        }
 #endif
-                       if (setsockopt_bypass(sendsock, src->sa_family) < 0) {
+                       if (setsockopt_bypass(sendsock, src->ss_family) < 0) {
                                close(sendsock);
                                return -1;
                        }
 
-                       if (bind(sendsock, (struct sockaddr *)src, sysdep_sa_len(src)) < 0) {
-                               plog(LLV_ERROR, LOCATION, NULL,
+                       if (bind(sendsock, (struct sockaddr *)src, sysdep_sa_len((struct sockaddr *)src)) < 0) {
+                               plog(ASL_LEVEL_ERR, 
                                        "bind 1 (%s)\n", strerror(errno));
                                close(sendsock);
                                return -1;
                        }
                        needclose = 1;
                }
-
-               for (i = 0; i < cnt; i++) {
-                       len = sendto(sendsock, buf, buflen, 0, dst, sysdep_sa_len(dst));
+        plogdump(ASL_LEVEL_DEBUG, (void*)buf, buflen, "@@@@@@ data being sent:\n");
+               
+            for (i = 0; i < cnt; i++) {
+                       len = sendto(sendsock, buf, buflen, 0, (struct sockaddr *)dst, sysdep_sa_len((struct sockaddr *)dst));
                        if (len < 0) {
-                               plog(LLV_ERROR, LOCATION, NULL,
+                               plog(ASL_LEVEL_ERR, 
                                        "sendto (%s)\n", strerror(errno));
-                               if (needclose)
-                                       close(sendsock);
-                               return len;
+                               if (errno != EHOSTUNREACH && errno != ENETDOWN && errno != ENETUNREACH) {
+                                       if (needclose)
+                                               close(sendsock);
+                                       return -1;
+                               }
+                               plog(ASL_LEVEL_ERR, 
+                                       "treating socket error (%s) like packet loss\n", strerror(errno));
+                               // else treat these failures like a packet loss
+                               len = 0;
                        }
-                       plog(LLV_DEBUG, LOCATION, NULL,
+                       plog(ASL_LEVEL_DEBUG, 
                                "%d times of %d bytes message will be sent "
                                "to %s\n",
-                               i + 1, len, saddr2str(dst));
+                               i + 1, len, saddr2str((struct sockaddr *)dst));
                }
-               plogdump(LLV_DEBUG, (char *)buf, buflen);
+               //plog(ASL_LEVEL_DEBUG, "sent %d bytes", buflen);
 
                if (needclose)
                        close(sendsock);
@@ -703,8 +747,7 @@ sendfromto(s, buf, buflen, src, dst, cnt)
 }
 
 int
-setsockopt_bypass(so, family)
-       int so, family;
+setsockopt_bypass(int so, int family)
 {
        int level;
        char *buf;
@@ -720,7 +763,7 @@ setsockopt_bypass(so, family)
                break;
 #endif
        default:
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "unsupported address family %d\n", family);
                return -1;
        }
@@ -728,7 +771,7 @@ setsockopt_bypass(so, family)
        policy = "in bypass";
        buf = ipsec_set_policy(policy, strlen(policy));
        if (buf == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "ipsec_set_policy (%s)\n",
                        ipsec_strerror());
                return -1;
@@ -737,8 +780,8 @@ setsockopt_bypass(so, family)
                       (level == IPPROTO_IP ?
                                 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
                       buf, ipsec_get_policylen(buf)) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "setsockopt (%s)\n",
+               plog(ASL_LEVEL_ERR, 
+                       "setsockopt IP_IPSEC_POLICY (%s)\n",
                        strerror(errno));
                return -1;
        }
@@ -747,7 +790,7 @@ setsockopt_bypass(so, family)
        policy = "out bypass";
        buf = ipsec_set_policy(policy, strlen(policy));
        if (buf == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "ipsec_set_policy (%s)\n",
                        ipsec_strerror());
                return -1;
@@ -756,8 +799,8 @@ setsockopt_bypass(so, family)
                       (level == IPPROTO_IP ?
                                 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
                       buf, ipsec_get_policylen(buf)) < 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "setsockopt (%s)\n",
+               plog(ASL_LEVEL_ERR, 
+                       "setsockopt IP_IPSEC_POLICY (%s)\n",
                        strerror(errno));
                return -1;
        }
@@ -766,57 +809,48 @@ setsockopt_bypass(so, family)
        return 0;
 }
 
-struct sockaddr *
-newsaddr(len)
-       int len;
+struct sockaddr_storage *
+newsaddr(int len)
 {
-       struct sockaddr *new;
+       struct sockaddr_storage *new;
 
-       new = racoon_calloc(1, len);
-       if (new == NULL)
-               plog(LLV_ERROR, LOCATION, NULL,
+       if ((new = racoon_calloc(1, sizeof(*new))) == NULL) {
+               plog(ASL_LEVEL_ERR, 
                        "%s\n", strerror(errno)); 
-
-#ifdef __linux__
-       if (len == sizeof (struct sockaddr_in6))
-               new->sa_family = AF_INET6;
-       else
-               new->sa_family = AF_INET;
-#else
+               goto out;
+       }
        /* initial */
-       new->sa_len = len;
-#endif
-
+       new->ss_len = len;
+out:
        return new;
 }
 
-struct sockaddr *
-dupsaddr(src)
-       struct sockaddr *src;
+struct sockaddr_storage *
+dupsaddr(struct sockaddr_storage *addr)
 {
-       struct sockaddr *dst;
+       struct sockaddr_storage *new;
 
-       dst = racoon_calloc(1, sysdep_sa_len(src));
-       if (dst == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
-                       "%s\n", strerror(errno)); 
+       new = racoon_calloc(1, sizeof(*new));
+       if (new == NULL) {
+               plog(ASL_LEVEL_ERR, "%s\n", strerror(errno)); 
                return NULL;
        }
 
-       memcpy(dst, src, sysdep_sa_len(src));
-
-       return dst;
+       memcpy(new, addr, addr->ss_len);
+    
+       return new;
 }
 
 char *
-saddr2str(saddr)
-       const struct sockaddr *saddr;
+saddr2str(const struct sockaddr *saddr)
 {
        static char buf[NI_MAXHOST + NI_MAXSERV + 10];
        char addr[NI_MAXHOST], port[NI_MAXSERV];
 
-       if (saddr == NULL)
-               return NULL;
+       if (saddr == NULL) {
+               buf[0] = '\0';
+               return buf;
+       }
 
        if (saddr->sa_family == AF_UNSPEC)
                snprintf (buf, sizeof(buf), "%s", "anonymous");
@@ -829,15 +863,38 @@ saddr2str(saddr)
 }
 
 char *
-saddrwop2str(saddr)
-       const struct sockaddr *saddr;
+saddr2str_with_prefix(const struct sockaddr *saddr, int prefix)
 {
        static char buf[NI_MAXHOST + NI_MAXSERV + 10];
-       char addr[NI_MAXHOST];
+       char addr[NI_MAXHOST], port[NI_MAXSERV];
+    
+       if (saddr == NULL) {
+               buf[0] = '\0';
+               return buf;
+       }
+    
+       if (saddr->sa_family == AF_UNSPEC)
+               snprintf (buf, sizeof(buf), "%s", "anonymous");
+       else {
+               GETNAMEINFO(saddr, addr, port);
+               snprintf(buf, sizeof(buf), "%s/%d[%s]", addr, prefix, port);
+       }
+    
+       return buf;
+}
 
-       if (saddr == NULL)
-               return NULL;
 
+char *
+saddrwop2str(const struct sockaddr *saddr)
+{
+       static char buf[NI_MAXHOST + NI_MAXSERV + 10];
+       char addr[NI_MAXHOST];
+
+       if (saddr == NULL) {
+               buf[0] = '\0';
+               return buf;
+       }
+       
        GETNAMEINFO_NULL(saddr, addr);
        snprintf(buf, sizeof(buf), "%s", addr);
 
@@ -850,13 +907,15 @@ naddrwop2str(const struct netaddr *naddr)
        static char buf[NI_MAXHOST + 10];
        static const struct sockaddr sa_any;    /* this is initialized to all zeros */
        
-       if (naddr == NULL)
-               return NULL;
-
+       if (naddr == NULL) {
+               buf[0] = '\0';
+               return buf;
+       }
+       
        if (memcmp(&naddr->sa, &sa_any, sizeof(sa_any)) == 0)
                snprintf(buf, sizeof(buf), "%s", "any");
        else {
-               snprintf(buf, sizeof(buf), "%s", saddrwop2str(&naddr->sa.sa));
+               snprintf(buf, sizeof(buf), "%s", saddrwop2str((struct sockaddr *)&naddr->sa.sa));
                snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "/%ld", naddr->prefix);
        }
        return buf;
@@ -869,8 +928,10 @@ naddrwop2str_fromto(const char *format, const struct netaddr *saddr,
        static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
        char *src, *dst;
 
-       src = strdup(naddrwop2str(saddr));
-       dst = strdup(naddrwop2str(daddr));
+       src = racoon_strdup(naddrwop2str(saddr));
+       dst = racoon_strdup(naddrwop2str(daddr));
+       STRDUP_FATAL(src);
+       STRDUP_FATAL(dst);
        /* WARNING: Be careful about the format string! Don't 
           ever pass in something that a user can modify!!! */
        snprintf (buf, sizeof(buf), format, src, dst);
@@ -889,24 +950,36 @@ saddr2str_fromto(format, saddr, daddr)
        static char buf[2*(NI_MAXHOST + NI_MAXSERV + 10) + 100];
        char *src, *dst;
 
-       src = strdup(saddr2str(saddr));
-       dst = strdup(saddr2str(daddr));
+       if (saddr) {
+               src = racoon_strdup(saddr2str(saddr));
+               STRDUP_FATAL(src);
+       } else {
+               src = NULL;
+       }
+       if (daddr) {
+               dst = racoon_strdup(saddr2str(daddr));
+               STRDUP_FATAL(dst);
+       } else {
+               dst = NULL;
+       }
        /* WARNING: Be careful about the format string! Don't 
           ever pass in something that a user can modify!!! */
-       snprintf (buf, sizeof(buf), format, src, dst);
-       racoon_free (src);
-       racoon_free (dst);
+       snprintf (buf, sizeof(buf), format, src? src:"[null]", dst? dst:"[null]");
+       if (src) {
+               racoon_free (src);
+       }
+       if (dst) {
+               racoon_free (dst);
+       }
 
        return buf;
 }
 
-struct sockaddr *
-str2saddr(host, port)
-       char *host;
-       char *port;
+struct sockaddr_storage *
+str2saddr(char *host, char *port)
 {
        struct addrinfo hints, *res;
-       struct sockaddr *saddr;
+       struct sockaddr_storage *saddr;
        int error;
 
        memset(&hints, 0, sizeof(hints));
@@ -915,22 +988,22 @@ str2saddr(host, port)
        hints.ai_flags = AI_NUMERICHOST;
        error = getaddrinfo(host, port, &hints, &res);
        if (error != 0) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "getaddrinfo(%s%s%s): %s\n",
                        host, port ? "," : "", port ? port : "",
                        gai_strerror(error));
                return NULL;
        }
        if (res->ai_next != NULL) {
-               plog(LLV_WARNING, LOCATION, NULL,
+               plog(ASL_LEVEL_WARNING, 
                        "getaddrinfo(%s%s%s): "
                        "resolved to multiple address, "
                        "taking the first one\n",
                        host, port ? "," : "", port ? port : "");
        }
-       saddr = racoon_malloc(res->ai_addrlen);
+       saddr = newsaddr(sizeof(*saddr));
        if (saddr == NULL) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                        "failed to allocate buffer.\n");
                freeaddrinfo(res);
                return NULL;
@@ -943,14 +1016,14 @@ str2saddr(host, port)
 
 void
 mask_sockaddr(a, b, l)
-       struct sockaddr *a;
-       const struct sockaddr *b;
+       struct sockaddr_storage *a;
+       const struct sockaddr_storage *b;
        size_t l;
 {
        size_t i;
        u_int8_t *p, alen;
 
-       switch (b->sa_family) {
+       switch (b->ss_family) {
        case AF_INET:
                alen = sizeof(struct in_addr);
                p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr;
@@ -962,18 +1035,18 @@ mask_sockaddr(a, b, l)
                break;
 #endif
        default:
-               plog(LLV_ERROR2, LOCATION, NULL,
-                       "invalid address family: %d\n", b->sa_family);
+               plog(ASL_LEVEL_ERR, 
+                       "invalid address family: %d\n", b->ss_family);
                exit(1);
        }
 
        if ((alen << 3) < l) {
-               plog(LLV_ERROR2, LOCATION, NULL,
-                       "unexpected inconsistency: %d %zu\n", b->sa_family, l);
+               plog(ASL_LEVEL_ERR, 
+                       "unexpected inconsistency: %d %zu\n", b->ss_family, l);
                exit(1);
        }
 
-       memcpy(a, b, sysdep_sa_len(b));
+       memcpy(a, b, sysdep_sa_len((struct sockaddr *)b));
        p[l / 8] &= (0xff00 >> (l % 8)) & 0xff;
        for (i = l / 8 + 1; i < alen; i++)
                p[i] = 0x00;
@@ -991,15 +1064,15 @@ mask_sockaddr(a, b, l)
  *             10.20.30.40:501 => -1   ... port doesn't match and isn't 0 (=any)
  */
 int
-naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr)
+naddr_score(const struct netaddr *naddr, const struct sockaddr_storage *saddr)
 {
        static const struct netaddr naddr_any;  /* initialized to all-zeros */
-       struct sockaddr sa;
-       uint16_t naddr_port, saddr_port;
+       struct sockaddr_storage sa;
+       u_int16_t naddr_port, saddr_port;
        int port_score;
 
        if (!naddr || !saddr) {
-               plog(LLV_ERROR, LOCATION, NULL,
+               plog(ASL_LEVEL_ERR, 
                     "Call with null args: naddr=%p, saddr=%p\n",
                     naddr, saddr);
                return -1;
@@ -1010,7 +1083,7 @@ naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr)
                return 0;
 
        /* If families don't match we really can't do much... */
-       if (naddr->sa.sa.sa_family != saddr->sa_family)
+       if (naddr->sa.sa.ss_family != saddr->ss_family)
                return -1;
        
        /* If port check fail don't bother to check addresses. */
@@ -1025,12 +1098,15 @@ naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr)
 
        /* Here it comes - compare network addresses. */
        mask_sockaddr(&sa, saddr, naddr->prefix);
-       if (loglevel >= LLV_DEBUG) {    /* debug only */
+       if (loglevel >= ASL_LEVEL_DEBUG) {      /* debug only */
                char *a1, *a2, *a3;
-               a1 = strdup(naddrwop2str(naddr));
-               a2 = strdup(saddrwop2str(saddr));
-               a3 = strdup(saddrwop2str(&sa));
-               plog(LLV_DEBUG, LOCATION, NULL,
+               a1 = racoon_strdup(naddrwop2str(naddr));
+               a2 = racoon_strdup(saddrwop2str((struct sockaddr *)saddr));
+               a3 = racoon_strdup(saddrwop2str((struct sockaddr *)&sa));
+               STRDUP_FATAL(a1);
+               STRDUP_FATAL(a2);
+               STRDUP_FATAL(a3);
+               plog(ASL_LEVEL_DEBUG, 
                     "naddr=%s, saddr=%s (masked=%s)\n",
                     a1, a2, a3);
                free(a1);
@@ -1043,16 +1119,16 @@ naddr_score(const struct netaddr *naddr, const struct sockaddr *saddr)
        return -1;
 }
 
-/* Some usefull functions for sockaddr port manipulations. */
+/* Some useful functions for sockaddr_storage port manipulations. */
 u_int16_t
-extract_port (const struct sockaddr *addr)
+extract_port (const struct sockaddr_storage *addr)
 {
   u_int16_t port = -1;
   
   if (!addr)
     return port;
 
-  switch (addr->sa_family) {
+  switch (addr->ss_family) {
     case AF_INET:
       port = ((struct sockaddr_in *)addr)->sin_port;
       break;
@@ -1060,7 +1136,7 @@ extract_port (const struct sockaddr *addr)
       port = ((struct sockaddr_in6 *)addr)->sin6_port;
       break;
     default:
-      plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
+      plog(ASL_LEVEL_ERR, "unknown AF: %u\n", addr->ss_family);
       break;
   }
 
@@ -1068,14 +1144,14 @@ extract_port (const struct sockaddr *addr)
 }
 
 u_int16_t *
-get_port_ptr (struct sockaddr *addr)
+get_port_ptr (struct sockaddr_storage *addr)
 {
   u_int16_t *port_ptr;
 
   if (!addr)
     return NULL;
 
-  switch (addr->sa_family) {
+  switch (addr->ss_family) {
     case AF_INET:
       port_ptr = &(((struct sockaddr_in *)addr)->sin_port);
       break;
@@ -1083,7 +1159,7 @@ get_port_ptr (struct sockaddr *addr)
       port_ptr = &(((struct sockaddr_in6 *)addr)->sin6_port);
       break;
     default:
-      plog(LLV_ERROR, LOCATION, NULL, "unknown AF: %u\n", addr->sa_family);
+      plog(ASL_LEVEL_ERR, "unknown AF: %u\n", addr->ss_family);
       return NULL;
       break;
   }
@@ -1092,7 +1168,7 @@ get_port_ptr (struct sockaddr *addr)
 }
 
 u_int16_t *
-set_port (struct sockaddr *addr, u_int16_t new_port)
+set_port (struct sockaddr_storage *addr, u_int16_t new_port)
 {
   u_int16_t *port_ptr;