new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_net / os_net.c
old mode 100755 (executable)
new mode 100644 (file)
index 08e1352..23f80fe
@@ -1,6 +1,3 @@
-/* @(#) $Id: ./src/os_net/os_net.c, 2011/09/08 dcid Exp $
- */
-
 /* Copyright (C) 2009 Trend Micro Inc.
  * All rights reserved.
  *
  * and/or modify it under the terms of the GNU General Public
  * License (version 2) as published by the FSF - Free Software
  * Foundation
- *
- * License details at the LICENSE file included with OSSEC or
- * online at: http://www.ossec.net/en/licensing.html
  */
 
-/* OS_net Library.
- * APIs for many network operations.
+/* OS_net Library
+ * APIs for many network operations
  */
 
-
-
 #include <errno.h>
 #include "shared.h"
 #include "os_net.h"
+agent *agt;
 
-
-
+/* Prototypes */
+static OSNetInfo *OS_Bindport(char *_port, unsigned int _proto, const char *_ip);
+static int OS_Connect(char *_port, unsigned int protocol, const char *_ip);
+static int OS_DecodeAddrinfo (struct addrinfo *res);
+static char *OS_DecodeSockaddr (struct sockaddr *sa);
+static char *DecodeFamily (int val);
+static char *DecodeSocktype (int val);
+static char *DecodeProtocol (int val);
 
 /* Unix socket -- not for windows */
 #ifndef WIN32
-struct sockaddr_un n_us;
-socklen_t us_l = sizeof(n_us);
+static struct sockaddr_un n_us;
+static socklen_t us_l = sizeof(n_us);
 
 /* UNIX SOCKET */
 #ifndef SUN_LEN
 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)        \
-                                     + strlen ((ptr)->sun_path))
+                     + strlen ((ptr)->sun_path))
 #endif /* Sun_LEN */
 
 #else /* WIN32 */
 /*int ENOBUFS = 0;*/
-# ifndef ENOBUFS
-# define ENOBUFS 0
-# endif
+#ifndef ENOBUFS
+#define ENOBUFS 0
+#endif
 
 #endif /* WIN32*/
 
 
-/* OS_Bindport v 0.2, 2005/02/11
- * Bind a specific port
- * v0.2: Added REUSEADDR.
- */
-int OS_Bindport(unsigned int _port, unsigned int _proto, char *_ip, int ipv6)
+/* Bind all relevant ports */
+OSNetInfo *OS_Bindport(char *_port, unsigned int _proto, const char *_ip)
 {
-    int ossock;
-    struct sockaddr_in server;
+    int ossock = 0, s;
+    struct addrinfo hints, *result, *rp;
+    OSNetInfo *ni;                     /* return data */
+
+    /* Allocate the return data structure and initialize it. */
+    ni = malloc (sizeof (OSNetInfo));
+    memset(ni, 0, sizeof (OSNetInfo));
+    FD_ZERO (&(ni->fdset));
+    ni->fdmax  = 0;
+    ni->fdcnt  = 0;
+    ni->status = 0;
+    ni->retval = 0;
+
+    /* init hints for getaddrinfo() */
+    memset(&hints, 0, sizeof(struct addrinfo));
+
+   /*
+    * If you cannot bind both IPv4 and IPv6, the problem is likely due to the
+    * AF_INET6 family with the AI_V4MAPPED flag. Alter your Makefile to use the
+    * NOV4MAP define and it should work like a breeze. All of the *BSDs fall
+    * into this category even though AI_V4MAPPED exists in netdb.h (true for
+    * all modern OS's). This should work with all Linux versions too, but the
+    * original code for AF_INET6 was left for Linux because it works.
+    *
+    * d. stoddard - 4/19/2018
+    */
+
+#if defined(__linux__) && !defined(NOV4MAP)
+#if defined (AI_V4MAPPED)
+    hints.ai_family = AF_INET6;                /* Allow IPv4 and IPv6 */
+    hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG | AI_V4MAPPED;
+#else
+    /* handle as normal IPv4 and IPv6 multi request */
+    hints.ai_family = AF_UNSPEC;       /* Allow IPv4 or IPv6 */
+    hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG;
+#endif /* AI_V4MAPPED */
+#else
+    /* FreeBSD, OpenBSD, NetBSD, and others */
+    hints.ai_family = AF_UNSPEC;       /* Allow IPv4 or IPv6 */
+    hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG;
+#endif
 
-    #ifndef WIN32
-    struct sockaddr_in6 server6;
-    #else
-    ipv6 = 0;
-    #endif
+    hints.ai_protocol = _proto;
+    if (_proto == IPPROTO_UDP) {
+        hints.ai_socktype = SOCK_DGRAM;
+    } else if (_proto == IPPROTO_TCP) {
+        hints.ai_socktype = SOCK_STREAM;
+    } else {
+        ni->status = -1;
+        ni->retval = OS_INVALID;
+        return(ni);
+    }
 
+    /* get linked list of adresses */
+    s = getaddrinfo(_ip, _port, &hints, &result);
 
-    if(_proto == IPPROTO_UDP)
-    {
-        if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
-        {
-            return OS_SOCKTERR;
-        }
+    /* Try to support legacy ipv4 only hosts */
+    if((s == EAI_FAMILY) || (s == EAI_NONAME)) {
+        hints.ai_family = AF_INET;
+        hints.ai_flags  = AI_PASSIVE | AI_ADDRCONFIG;
+        s = getaddrinfo(_ip, _port, &hints, &result);
     }
-    else if(_proto == IPPROTO_TCP)
-    {
-        int flag = 1;
-        if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
-        {
-            return(int)(OS_SOCKTERR);
-        }
 
-        if(setsockopt(ossock, SOL_SOCKET, SO_REUSEADDR,
-                              (char *)&flag,  sizeof(flag)) < 0)
-        {
-            OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
-        }
-    }
-    else
-    {
-        return(OS_INVALID);
+    if (s != 0) {
+        verbose("getaddrinfo: %s", gai_strerror(s));
+        ni->status = -1;
+        ni->retval = OS_INVALID;
+        return(ni);
     }
 
-    if(ipv6)
-    {
-        #ifndef WIN32
-        memset(&server6, 0, sizeof(server6));
-        server6.sin6_family = AF_INET6;
-        server6.sin6_port = htons( _port );
-        server6.sin6_addr = in6addr_any;
-
+    /* log the list of connections available */
+    OS_DecodeAddrinfo (result);
+
+   /*
+    * getaddrinfo() returns a list of address structures.  We try each
+    * address and attempt to connect to it.  If a socket(2) or bind(2) fails,
+    * we close the socket and try the next address. We repeat this for every
+    * address getaddrinfo() returns in the addrinfo linked list.
+    */
+
+    for (rp = result; rp != NULL; rp = rp->ai_next) {
+        ossock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+        if (ossock == -1) {
+            verbose ("socket error: family %s type %s protocol %s: %s",
+                     DecodeFamily (rp->ai_family),
+                     DecodeSocktype (rp->ai_socktype),
+                     DecodeProtocol (rp->ai_protocol),
+                     strerror(errno));
+            continue;
+        }
 
-        if(bind(ossock, (struct sockaddr *) &server6, sizeof(server6)) < 0)
-        {
-            OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
+        if (_proto == IPPROTO_TCP) {
+            int flag = 1;
+            if (setsockopt(ossock, SOL_SOCKET, SO_REUSEADDR,
+                          (char *)&flag, sizeof(flag)) < 0) {
+                verbose ("setsockopt error: SO_REUSEADDR %d: %s",
+                         errno, strerror(errno));
+                if(ossock > 0) {
+                    OS_CloseSocket(ossock);
+                }
+                continue;
+            }
         }
-        #endif
-    }
-    else
-    {
-        memset(&server, 0, sizeof(server));
-        server.sin_family = AF_INET;
-        server.sin_port = htons( _port );
 
+        if (bind(ossock, rp->ai_addr, rp->ai_addrlen) == -1) {
+           /*
+            * Don't issue an error message if the address and port is already
+            * bound.  This can happen when 0.0.0.0 or :: are bound in a
+            * previous iteration of this loop.
+            */
+            if (errno == EADDRINUSE) {
+                close (ossock);
+                continue;
+            }
+
+            /* tell them why this address failed */
+            verbose ("Bind failed on socket for %s: %s",
+                     OS_DecodeSockaddr (rp->ai_addr), strerror (errno));
+            close (ossock);
+            continue;
+        }
 
-        if((_ip == NULL)||(_ip[0] == '\0'))
-            server.sin_addr.s_addr = htonl(INADDR_ANY);
-        else
-            server.sin_addr.s_addr = inet_addr(_ip);
+        if (_proto == IPPROTO_TCP) {
+            if (listen(ossock, 32) < 0) {
+                verbose ("Request to listen() failed on socket for %s: %s",
+                          OS_DecodeSockaddr (rp->ai_addr), strerror (errno));
+                close (ossock);
+                continue;
+            }
+            verbose ("Request for TCP listen() succeeded.");
+        }
 
+        /* success - accumulate data for select call */
+        verbose ("Socket bound for %s", OS_DecodeSockaddr (rp->ai_addr));
 
-        if(bind(ossock, (struct sockaddr *) &server, sizeof(server)) < 0)
-        {
-            OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
+        /* save bound socket info for select() */
+        ni->fds[ni->fdcnt++] = ossock;  /* increment after use! */
+        FD_SET (ossock, &(ni->fdset));
+        if (ossock > ni->fdmax) {
+          ni->fdmax = ossock;
         }
     }
 
-
-
-    if(_proto == IPPROTO_TCP)
-    {
-        if(listen(ossock, 32) < 0)
-        {
-            OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
+    /* check to see if at least one address succeeded */
+    if (ni->fdcnt == 0) {
+        verbose ("Request to allocate and bind sockets failed.");
+        ni->status = -1;
+        ni->retval = OS_SOCKTERR;
+        if(result) {
+            freeaddrinfo(result);
         }
+        return(ni);
     }
 
-
-    return(ossock);
+    freeaddrinfo(result);              /* No longer needed */
+    ni->fdmax += 1;                    /* prep for use with select() */
+    return (ni);
 }
 
 
-/* OS_Bindporttcp v 0.1
- * Bind a TCP port, using the OS_Bindport
- */
-int OS_Bindporttcp(unsigned int _port, char *_ip, int ipv6)
+/* Bind a TCP port, using the OS_Bindport */
+OSNetInfo *OS_Bindporttcp(char *_port, const char *_ip)
 {
-    return(OS_Bindport(_port, IPPROTO_TCP, _ip, ipv6));
+    return (OS_Bindport(_port, IPPROTO_TCP, _ip));
 }
 
-
-/* OS_Bindportudp v 0.1
- * Bind a UDP port, using the OS_Bindport
- */
-int OS_Bindportudp(unsigned int _port, char *_ip, int ipv6)
+/* Bind a UDP port, using the OS_Bindport */
+OSNetInfo *OS_Bindportudp(char *_port, const char *_ip)
 {
-    return(OS_Bindport(_port, IPPROTO_UDP, _ip, ipv6));
+    return (OS_Bindport(_port, IPPROTO_UDP, _ip));
 }
 
 #ifndef WIN32
-/* OS_BindUnixDomain v0.1, 2004/07/29
- * Bind to a Unix domain, using DGRAM sockets
- */
-int OS_BindUnixDomain(char * path, int mode, int max_msg_size)
+/* Bind to a Unix domain, using DGRAM sockets */
+int OS_BindUnixDomain(const char *path, mode_t mode, int max_msg_size)
 {
     int len;
     int ossock = 0;
     socklen_t optlen = sizeof(len);
 
-    /* Making sure the path isn't there */
+    /* Make sure the path isn't there */
     unlink(path);
 
     memset(&n_us, 0, sizeof(n_us));
     n_us.sun_family = AF_UNIX;
-    strncpy(n_us.sun_path, path, sizeof(n_us.sun_path)-1);
+    strncpy(n_us.sun_path, path, sizeof(n_us.sun_path) - 1);
 
-    if((ossock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0)
-        return(OS_SOCKTERR);
+    if ((ossock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
+        return (OS_SOCKTERR);
+    }
 
-    if(bind(ossock, (struct sockaddr *)&n_us, SUN_LEN(&n_us)) < 0)
-    {
+    if (bind(ossock, (struct sockaddr *)&n_us, SUN_LEN(&n_us)) < 0) {
         OS_CloseSocket(ossock);
-        return(OS_SOCKTERR);
+        return (OS_SOCKTERR);
     }
 
-    /* Changing permissions */
-    if(chmod(path,mode) < 0)
-    {
+    /* Change permissions */
+    if (chmod(path, mode) < 0) {
         OS_CloseSocket(ossock);
-        return(OS_SOCKTERR);
+        return (OS_SOCKTERR);
     }
 
-
-    /* Getting current maximum size */
-    if(getsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1)
-    {
+    /* Get current maximum size */
+    if (getsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1) {
         OS_CloseSocket(ossock);
-        return(OS_SOCKTERR);
+        return (OS_SOCKTERR);
     }
 
-
-    /* Setting socket opt */
-    if(len < max_msg_size)
-    {
+    /* Set socket opt */
+    if (len < max_msg_size) {
         len = max_msg_size;
-        if(setsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, optlen) < 0)
-        {
+        if (setsockopt(ossock, SOL_SOCKET, SO_RCVBUF, &len, optlen) < 0) {
             OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
+            return (OS_SOCKTERR);
         }
     }
 
-    return(ossock);
+    return (ossock);
 }
 
-/* OS_ConnectUnixDomain v0.1, 2004/07/29
- * Open a client Unix domain socket
+/* Open a client Unix domain socket
  * ("/tmp/lala-socket",0666));
- *
  */
-int OS_ConnectUnixDomain(char * path, int max_msg_size)
+int OS_ConnectUnixDomain(const char *path, int max_msg_size)
 {
     int len;
     int ossock = 0;
@@ -229,196 +281,199 @@ int OS_ConnectUnixDomain(char * path, int max_msg_size)
 
     n_us.sun_family = AF_UNIX;
 
-    /* Setting up path */
-    strncpy(n_us.sun_path,path,sizeof(n_us.sun_path)-1);
-
-    if((ossock = socket(PF_UNIX, SOCK_DGRAM,0)) < 0)
-        return(OS_SOCKTERR);
+    /* Set up path */
+    strncpy(n_us.sun_path, path, sizeof(n_us.sun_path) - 1);
 
+    if ((ossock = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
+        return (OS_SOCKTERR);
+    }
 
-    /* Connecting to the UNIX domain.
-     * We can use "send" after that
-     */
-    if(connect(ossock,(struct sockaddr *)&n_us,SUN_LEN(&n_us)) < 0)
-    {
+    /* Connect to the UNIX domain */
+    if (connect(ossock, (struct sockaddr *)&n_us, SUN_LEN(&n_us)) < 0) {
         OS_CloseSocket(ossock);
-        return(OS_SOCKTERR);
+        return (OS_SOCKTERR);
     }
 
-
-    /* Getting current maximum size */
-    if(getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1)
-    {
+    /* Get current maximum size */
+    if (getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1) {
         OS_CloseSocket(ossock);
-        return(OS_SOCKTERR);
+        return (OS_SOCKTERR);
     }
 
-
-    /* Setting maximum message size */
-    if(len < max_msg_size)
-    {
+    /* Set maximum message size */
+    if (len < max_msg_size) {
         len = max_msg_size;
-        if(setsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, optlen) < 0)
-        {
+        if (setsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, optlen) < 0) {
             OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
+            return (OS_SOCKTERR);
         }
     }
 
-
-    /* Returning the socket */
-    return(ossock);
+    return (ossock);
 }
 
-
 int OS_getsocketsize(int ossock)
 {
     int len = 0;
     socklen_t optlen = sizeof(len);
 
-    /* Getting current maximum size */
-    if(getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1)
+    /* Get current maximum size */
+    if (getsockopt(ossock, SOL_SOCKET, SO_SNDBUF, &len, &optlen) == -1) {
+        OS_CloseSocket(ossock);
         return(OS_SOCKTERR);
+    }
 
-    return(len);
+    return (len);
 }
 
 #endif
 
-/* OS_Connect v 0.1, 2004/07/21
- * Open a TCP/UDP client socket
- */
-int OS_Connect(unsigned int _port, unsigned int protocol, char *_ip, int ipv6)
+/* Open a TCP/UDP client socket */
+int OS_Connect(char *_port, unsigned int protocol, const char *_ip)
 {
-    int ossock;
-    struct sockaddr_in server;
+    int ossock = 0, s;
+    struct addrinfo hints, *result, *rp, *local_ai = NULL;
+    char tempaddr[INET6_ADDRSTRLEN];
 
-    #ifndef WIN32
-    struct sockaddr_in6 server6;
-    #else
-    ipv6 = 0;
-    #endif
+    if ((_ip == NULL)||(_ip[0] == '\0')) {
+        OS_CloseSocket(ossock);
+        return(OS_INVALID);
+    }
 
-    if(protocol == IPPROTO_TCP)
-    {
-        if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
-            return(OS_SOCKTERR);
+    if (agt) {
+        if (agt->lip) {
+            memset(&hints, 0, sizeof(struct addrinfo));
+            hints.ai_flags = AI_NUMERICHOST;
+            s = getaddrinfo(agt->lip, NULL, &hints, &result);
+            if (s != 0) {
+                verbose("getaddrinfo: %s", gai_strerror(s));
+            }
+            else {
+                local_ai = result;
+            }
+        }
     }
-    else if(protocol == IPPROTO_UDP)
-    {
-        if((ossock = socket(ipv6 == 1?PF_INET6:PF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)
-            return(OS_SOCKTERR);
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    /* Allow IPv4 or IPv6 if local_ip isn't specified */
+    hints.ai_family = AF_UNSPEC;
+    if (agt) {
+        if (agt->lip) {
+            hints.ai_family = local_ai->ai_family;
+        }
     }
-    else
+    hints.ai_protocol = protocol;
+    if (protocol == IPPROTO_TCP) {
+        hints.ai_socktype = SOCK_STREAM;
+    } else if (protocol == IPPROTO_UDP) {
+        hints.ai_socktype = SOCK_DGRAM;
+    } else {
         return(OS_INVALID);
-
-
-
-    #ifdef HPUX
-    {
-    int flags;
-    flags = fcntl(ossock,F_GETFL,0);
-    fcntl(ossock, F_SETFL, flags | O_NONBLOCK);
     }
-    #endif
-
+    hints.ai_flags = 0;
 
-
-    if((_ip == NULL)||(_ip[0] == '\0'))
-    {
-        OS_CloseSocket(ossock);
+    s = getaddrinfo(_ip, _port, &hints, &result);
+    if (s != 0) {
+        verbose("getaddrinfo: %s", gai_strerror(s));
+        if(result) {
+            freeaddrinfo(result);
+        }
         return(OS_INVALID);
     }
 
+           /* getaddrinfo() returns a list of address structures.
+              Try each address until we successfully connect(2).
+              If socket(2) (or connect(2)) fails, we (close the socket
+              and) try the next address. */
 
-    if(ipv6 == 1)
-    {
-        #ifndef WIN32
-        memset(&server6, 0, sizeof(server6));
-        server6.sin6_family = AF_INET6;
-        server6.sin6_port = htons( _port );
-        inet_pton(AF_INET6, _ip, &server6.sin6_addr.s6_addr);
-
-        if(connect(ossock,(struct sockaddr *)&server6, sizeof(server6)) < 0)
-        {
-            OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
+    for (rp = result; rp != NULL; rp = rp->ai_next) {
+        ossock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+        if (ossock == -1) {
+            continue;
         }
-        #endif
-    }
-    else
-    {
-        memset(&server, 0, sizeof(server));
-        server.sin_family = AF_INET;
-        server.sin_port = htons( _port );
-        server.sin_addr.s_addr = inet_addr(_ip);
 
+        if (agt) {
+            if (agt->lip) {
+                if (bind(ossock, local_ai->ai_addr, local_ai->ai_addrlen)) {
+                    verbose("Unable to bind to local address %s.  Ignoring. (%s)",
+                            agt->lip, strerror(errno));
+                }
+                else verbose("Connecting from local address %s", agt->lip);
+            }
+        }
 
-        if(connect(ossock,(struct sockaddr *)&server, sizeof(server)) < 0)
-        {
+        if (connect(ossock, rp->ai_addr, rp->ai_addrlen) != -1) {
+            break;                  /* Success */
+        }
+    }
+    if (rp == NULL) {               /* No address succeeded */
+        if (ossock > 0) {
             OS_CloseSocket(ossock);
-            return(OS_SOCKTERR);
         }
+        if(result) {
+            freeaddrinfo(result);
+        }
+        return(OS_SOCKTERR);
     }
+    satop(rp->ai_addr, tempaddr, sizeof tempaddr);
+    verbose("INFO: Connected to %s at address %s, port %s", _ip,
+            tempaddr, _port);
+
+    freeaddrinfo(result);           /* No longer needed */
 
+    #ifdef HPUX
+    {
+    int flags;
+    flags = fcntl(ossock,F_GETFL,0);
+    fcntl(ossock, F_SETFL, flags | O_NONBLOCK);
+    }
+    #endif
 
     return(ossock);
 }
 
 
-/* OS_ConnectTCP, v0.1
- * Open a TCP socket
- */
-int OS_ConnectTCP(unsigned int _port, char *_ip, int ipv6)
+/* Open a TCP socket */
+int OS_ConnectTCP(char *_port, const char *_ip)
 {
-    return(OS_Connect(_port, IPPROTO_TCP, _ip, ipv6));
+    return (OS_Connect(_port, IPPROTO_TCP, _ip));
 }
 
-
-/* OS_ConnectUDP, v0.1
- * Open a UDP socket
- */
-int OS_ConnectUDP(unsigned int _port, char *_ip, int ipv6)
+/* Open a UDP socket */
+int OS_ConnectUDP(char *_port, const char *_ip)
 {
-    return(OS_Connect(_port, IPPROTO_UDP, _ip, ipv6));
+    return (OS_Connect(_port, IPPROTO_UDP, _ip));
 }
 
-/* OS_SendTCP v0.1, 2004/07/21
- * Send a TCP packet (in a open socket)
- */
-int OS_SendTCP(int socket, char *msg)
+/* Send a TCP packet (through an open socket) */
+int OS_SendTCP(int socket, const char *msg)
 {
-    if((send(socket, msg, strlen(msg),0)) <= 0)
+    if ((send(socket, msg, strlen(msg), 0)) <= 0) {
         return (OS_SOCKTERR);
+    }
 
-    return(0);
+    return (0);
 }
 
-/* OS_SendTCPbySize v0.1, 2004/07/21
- * Send a TCP packet (in a open socket) of a specific size
- */
-int OS_SendTCPbySize(int socket, int size, char *msg)
+/* Send a TCP packet of a specific size (through a open socket) */
+int OS_SendTCPbySize(int socket, int size, const char *msg)
 {
-    if((send(socket, msg, size, 0)) < size)
+    if ((send(socket, msg, size, 0)) < size) {
         return (OS_SOCKTERR);
+    }
 
-    return(0);
+    return (0);
 }
 
-
-/* OS_SendUDPbySize v0.1, 2004/07/21
- * Send a UDP packet (in a open socket) of a specific size
- */
-int OS_SendUDPbySize(int socket, int size, char *msg)
+/* Send a UDP packet of a specific size (through an open socket) */
+int OS_SendUDPbySize(int socket, int size, const char *msg)
 {
-    int i = 0;
+    unsigned int i = 0;
 
     /* Maximum attempts is 5 */
-    while((send(socket,msg,size,0)) < 0)
-    {
-        if((errno != ENOBUFS) || (i >= 5))
-        {
-            return(OS_SOCKTERR);
+    while ((send(socket, msg, size, 0)) < 0) {
+        if ((errno != ENOBUFS) || (i >= 5)) {
+            return (OS_SOCKTERR);
         }
 
         i++;
@@ -426,188 +481,358 @@ int OS_SendUDPbySize(int socket, int size, char *msg)
         sleep(i);
     }
 
-    return(0);
+    return (0);
 }
 
-
-
-/* OS_AcceptTCP v0.1, 2005/01/28
- * Accept a TCP connection
- */
-int OS_AcceptTCP(int socket, char *srcip, int addrsize)
+/* Accept a TCP connection */
+int OS_AcceptTCP(int socket, char *srcip, size_t addrsize)
 {
     int clientsocket;
-    struct sockaddr_in _nc;
+    struct sockaddr_storage _nc;
     socklen_t _ncl;
 
     memset(&_nc, 0, sizeof(_nc));
     _ncl = sizeof(_nc);
 
-    if((clientsocket = accept(socket, (struct sockaddr *) &_nc,
-                    &_ncl)) < 0)
-        return(-1);
+    if ((clientsocket = accept(socket, (struct sockaddr *) &_nc,
+                               &_ncl)) < 0) {
+        return (-1);
+    }
 
-    strncpy(srcip, inet_ntoa(_nc.sin_addr),addrsize -1);
-    srcip[addrsize -1]='\0';
+    satop((struct sockaddr *) &_nc, srcip, addrsize -1);
+    srcip[addrsize -1] = '\0';
 
-    return(clientsocket);
+    return (clientsocket);
 }
 
-
-/* OS_RecvTCP v0.1, 2004/07/21
- * Receive a TCP packet (in a open socket)
- */
+/* Receive a TCP packet (from an open socket) */
 char *OS_RecvTCP(int socket, int sizet)
 {
     char *ret;
 
     ret = (char *) calloc((sizet), sizeof(char));
-    if(ret == NULL)
-        return(NULL);
+    if (ret == NULL) {
+        return (NULL);
+    }
 
-    if(recv(socket, ret, sizet-1,0) <= 0)
-    {
+    if (recv(socket, ret, sizet - 1, 0) <= 0) {
         free(ret);
-        return(NULL);
+        return (NULL);
     }
 
-    return(ret);
+    return (ret);
 }
 
-
-/* OS_RecvTCPBuffer v0.1, 2004/07/21
- * Receive a TCP packet (in a open socket)
- */
+/* Receive a TCP packet (from an open socket) */
 int OS_RecvTCPBuffer(int socket, char *buffer, int sizet)
 {
     int retsize;
 
-    if((retsize = recv(socket, buffer, sizet -1, 0)) > 0)
-    {
+    if ((retsize = recv(socket, buffer, sizet - 1, 0)) > 0) {
         buffer[retsize] = '\0';
-        return(0);
+        return (retsize);
     }
-    return(-1);
+    return (-1);
 }
 
-
-
-
-/* OS_RecvUDP v 0.1, 2004/07/20
- * Receive a UDP packet
- */
+/* Receive a UDP packet */
 char *OS_RecvUDP(int socket, int sizet)
 {
     char *ret;
 
     ret = (char *) calloc((sizet), sizeof(char));
-    if(ret == NULL)
-        return(NULL);
+    if (ret == NULL) {
+        return (NULL);
+    }
 
-    if((recv(socket,ret,sizet-1,0))<0)
-    {
+    if ((recv(socket, ret, sizet - 1, 0)) < 0) {
         free(ret);
-        return(NULL);
+        return (NULL);
     }
 
-    return(ret);
+    return (ret);
 }
 
-
-/* OS_RecvConnUDP v0.1
- * Receives a message from a connected UDP socket
- */
+/* Receives a message from a connected UDP socket */
 int OS_RecvConnUDP(int socket, char *buffer, int buffer_size)
 {
     int recv_b;
 
     recv_b = recv(socket, buffer, buffer_size, 0);
-    if(recv_b < 0)
-        return(0);
+    if (recv_b < 0) {
+        return (0);
+    }
 
-    return(recv_b);
-}
+    buffer[recv_b] = '\0';
 
+    return (recv_b);
+}
 
 #ifndef WIN32
-/* OS_RecvUnix, v0.1, 2004/07/29
- * Receive a message using a Unix socket
- */
+/* Receive a message from a Unix socket */
 int OS_RecvUnix(int socket, int sizet, char *ret)
 {
     ssize_t recvd;
-    if((recvd = recvfrom(socket, ret, sizet -1, 0,
-                         (struct sockaddr*)&n_us,&us_l)) < 0)
-        return(0);
+    if ((recvd = recvfrom(socket, ret, sizet - 1, 0,
+                          (struct sockaddr *)&n_us, &us_l)) < 0) {
+        return (0);
+    }
 
     ret[recvd] = '\0';
-    return((int)recvd);
+    return ((int)recvd);
 }
 
-
-/* OS_SendUnix, v0.1, 2004/07/29
- * Send a message using a Unix socket.
- * Returns the OS_SOCKETERR if it
+/* Send a message using a Unix socket
+ * Returns the OS_SOCKETERR if it fails
  */
-int OS_SendUnix(int socket, char * msg, int size)
+int OS_SendUnix(int socket, const char *msg, int size)
 {
-    if(size == 0)
-        size = strlen(msg)+1;
+    if (size == 0) {
+        size = strlen(msg) + 1;
+    }
 
-    if(send(socket, msg, size,0) < size)
-    {
-        if(errno == ENOBUFS)
-            return(OS_SOCKBUSY);
+    if (send(socket, msg, size, 0) < size) {
+        if (errno == ENOBUFS) {
+            return (OS_SOCKBUSY);
+        }
 
-        return(OS_SOCKTERR);
+        return (OS_SOCKTERR);
     }
 
-    return(OS_SUCCESS);
+    return (OS_SUCCESS);
 }
 #endif
 
-
-/* OS_GetHost, v0.1, 2005/01/181
- * Calls gethostbyname (tries x attempts)
- */
-char *OS_GetHost(char *host, int attempts)
+/* Calls getaddrinfo (tries x attempts) */
+char *OS_GetHost(const char *host, unsigned int attempts)
 {
-    int i = 0;
-    int sz;
+    unsigned int i = 0;
+    int error;
 
     char *ip;
-    struct hostent *h;
+    struct addrinfo *hai, *result;
 
-    if(host == NULL)
-        return(NULL);
+    if (host == NULL) {
+        return (NULL);
+    }
 
-    while(i <= attempts)
-    {
-        if((h = gethostbyname(host)) == NULL)
-        {
+    while (i <= attempts) {
+        if ((error = getaddrinfo(host, NULL, NULL, &result)) != 0) {
             sleep(i++);
             continue;
         }
 
-        sz = strlen(inet_ntoa(*((struct in_addr *)h->h_addr)))+1;
-        if((ip = (char *) calloc(sz, sizeof(char))) == NULL)
-            return(NULL);
+        if ((ip = (char *) calloc(IPSIZE, sizeof(char))) == NULL) {
+            if (result) {
+                freeaddrinfo(result);
+            }
+            return (NULL);
+        }
 
-        strncpy(ip,inet_ntoa(*((struct in_addr *)h->h_addr)), sz-1);
+        hai = result;
+        satop(hai->ai_addr, ip, IPSIZE);
 
-        return(ip);
+        freeaddrinfo(result);
+        return (ip);
     }
 
-    return(NULL);
+    return (NULL);
+}
+
+/* satop(struct sockaddr *sa, char *dst, socklen_t size)
+ * Convert a sockaddr to a printable address.
+ */
+int satop(struct sockaddr *sa, char *dst, socklen_t size)
+{
+    sa_family_t af;
+    struct sockaddr_in *sa4;
+    struct sockaddr_in6 *sa6;
+#ifdef WIN32
+    int newlength;
+#endif
+
+    af = sa->sa_family;
+
+    switch (af)
+    {
+    case AF_INET:
+        sa4 = (struct sockaddr_in *) sa;
+#ifdef WIN32
+        newlength = size;
+        WSAAddressToString((LPSOCKADDR) sa4, sizeof(struct sockaddr_in),
+                           NULL, dst, (LPDWORD) &newlength);
+#else
+        inet_ntop(af, (const void *) &(sa4->sin_addr), dst, size);
+#endif
+        return(0);
+    case AF_INET6:
+        sa6 = (struct sockaddr_in6 *) sa;
+#ifdef WIN32
+        newlength = size;
+        WSAAddressToString((LPSOCKADDR) sa6, sizeof(struct sockaddr_in6),
+                           NULL, dst, (LPDWORD) &newlength);
+#else
+        inet_ntop(af, (const void *) &(sa6->sin6_addr), dst, size);
+#endif
+        if (IN6_IS_ADDR_V4MAPPED(&(sa6->sin6_addr)))
+        {  /* extract the embedded IPv4 address */
+            memmove(dst, dst+7, size-7);
+        }
+        return(0);
+    default:
+        *dst = '\0';
+        return(-1);
+    }
 }
 
 int OS_CloseSocket(int socket)
 {
-    #ifdef WIN32
+#ifdef WIN32
     return (closesocket(socket));
-    #else
+#else
     return (close(socket));
-    #endif /* WIN32 */
+#endif /* WIN32 */
+}
+
+
+/*
+ * OS_DecodeAddrinfo() will decode the contents of an addrinfo structure and
+ * log the IP version, address, and port number for each item in the
+ * linked list of addrinfo structs.
+ */
+
+int OS_DecodeAddrinfo (struct addrinfo *res) {
+    struct addrinfo *p;                        /* pointer to addrinfo structs */
+
+    for (p = res; p != NULL; p = p->ai_next)
+        verbose ("%s",OS_DecodeSockaddr (p->ai_addr));
+    return 0;
+}
+
+
+/*
+ * OS_DecodeSockaddr() will decode a socket address and return a string with
+ * the IP version, address, and port number.
+ */
+
+char *OS_DecodeSockaddr (struct sockaddr *sa) {
+    int rc;                            /* return code */
+    char ipaddr[INET6_ADDRSTRLEN];     /* printed address */
+    char ipport[NI_MAXSERV];           /* printed port */
+    static char buf[256];              /* message buffer */
+
+#if defined(__linux__) || defined (WIN32)
+    /* most Linux systems do not have sa_len in the sockaddr struct */
+    socklen_t slen = 0;
+    switch(sa->sa_family) {
+        case AF_INET:
+            slen = sizeof(struct sockaddr_in);
+            break;
+        case AF_INET6:
+            slen = sizeof(struct sockaddr_in6);
+            break;
+        default:
+            // XXX WTF
+            break;
+    }
+    rc = getnameinfo ((struct sockaddr *) sa, slen, ipaddr,
+                      sizeof (ipaddr), ipport, sizeof (ipport),
+                      NI_NUMERICHOST | NI_NUMERICSERV);
+#else
+    /* BSD systems require the value in sa->sa_len or error 4 occurs */
+    rc = getnameinfo ((struct sockaddr *) sa, sa->sa_len, ipaddr,
+                      sizeof (ipaddr), ipport, sizeof (ipport),
+                      NI_NUMERICHOST | NI_NUMERICSERV);
+#endif
+
+    if (rc) {
+        sprintf (buf, "Error %d on getnameinfo: %s", rc, gai_strerror (rc));
+        return (buf);
+    }
+
+    sprintf (buf, "%s: %s on port %s",
+             DecodeFamily (sa->sa_family), ipaddr, ipport);
+    return buf;
+}
+
+
+/*
+ * DecodeFamily() is used to convert the IP family into a string for info
+ * and debugging purposes.
+ */
+
+char *DecodeFamily (int val) {
+    static char buf[32];               /* response */
+
+    switch (val) {
+        case AF_INET:
+            strcpy (buf,"IPv4");
+            break;
+        case AF_INET6:
+            strcpy (buf,"IPv6");
+            break;
+        default:
+            sprintf (buf, "Unknown Family %d", val);
+            break;
+    }
+
+    return (buf);
+}
+
+
+/*
+ * DecodeSocktype() is used to convert the IP socket type into a string for
+ * info and debugging purposes.
+ */
+
+char *DecodeSocktype (int val) {
+    static char buf[32];               /* response */
+
+    switch (val) {
+        case SOCK_STREAM:
+            strcpy (buf,"STREAM");
+            break;
+        case SOCK_DGRAM:
+            strcpy (buf,"DGRAM");
+            break;
+        case SOCK_RAW:
+            strcpy (buf,"RAW");
+            break;
+        default:
+            sprintf (buf, "Unknown Sock Type %d", val);
+            break;
+    }
+
+    return (buf);
+}
+
+
+/*
+ * DecodeProtocol() is used to convert the IP protocol into a string for info
+ * and debugging purposes.
+ */
+
+char *DecodeProtocol (int val) {
+    static char buf[32];               /* response */
+
+    switch (val) {
+        case IPPROTO_IP:
+            strcpy (buf,"IP");
+            break;
+        case IPPROTO_ICMP:
+            strcpy (buf,"ICMP");
+            break;
+        case IPPROTO_TCP:
+            strcpy (buf,"TCP");
+            break;
+        case IPPROTO_UDP:
+            strcpy (buf,"UDP");
+            break;
+        default:
+            sprintf (buf, "Unknown Protocol %d", val);
+            break;
+    }
+
+    return (buf);
 }
 
-/* EOF */