Ensure that UNIX sockets are automatically unlinked upon close.
[doldaconnect.git] / daemon / net.c
index 5960a55..f2ade0f 100644 (file)
 
 static struct configvar myvars[] =
 {
-    /* 0 = Direct mode, 1 = Passive mode, 2 = SOCKS proxy */
+    /** The network mode to use. Currently supported values are 0 for
+     * active mode and 1 for passive mode. In the future, SOCKS5 proxy
+     * support may be added. */
     {CONF_VAR_INT, "mode", {.num = 0}},
+    /** Set the SO_REUSEADDR socket option on listening sockets, so
+     * that dead TCP connections waiting for timeout are ignored. */
     {CONF_VAR_BOOL, "reuseaddr", {.num = 0}},
-    /* Only for direct mode */
+    /** Overrides the IPv4 address reported to other clients in active
+     * mode. Useful for servers behind NAT routers. If both this and
+     * net.publicif are unspecified the address of the hub connection
+     * is used. */
     {CONF_VAR_IPV4, "visibleipv4", {.ipv4 = {0}}},
+    /** Specifies an interface name from which to fetch the IPv4
+     * address reported to other clients in active mode. If both this
+     * and net.visibleipv4 are unspecified the address of the hub
+     * connection is used. */
     {CONF_VAR_STRING, "publicif", {.str = L""}},
     /* Diffserv should be supported on IPv4, too, but I don't know the
      * API to do that. */
+    /** The Diffserv value to use on IPv6 connections when the
+     * minimize cost TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-mincost", {.num = 0}},
+    /** The Diffserv value to use on IPv6 connections when the
+     * maximize reliability TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-maxrel", {.num = 0}},
+    /** The Diffserv value to use on IPv6 connections when the
+     * maximize throughput TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-maxtp", {.num = 0}},
+    /** The Diffserv value to use on IPv6 connections when the
+     * minimize delay TOS value is used (see the TOS VALUES
+     * section). */
     {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}},
     {CONF_VAR_END}
 };
@@ -253,18 +276,19 @@ void putsock(struct socket *sk)
            {
                sk->outbuf.d.f = buf->next;
                free(buf->data);
+               free(buf->addr);
                free(buf);
            }
            while((buf = sk->inbuf.d.f) != NULL)
            {
                sk->inbuf.d.f = buf->next;
                free(buf->data);
+               free(buf->addr);
                free(buf);
            }
            break;
        }
-       if(sk->fd >= 0)
-           close(sk->fd);
+       closesock(sk);
        if(sk->remote != NULL)
            free(sk->remote);
        free(sk);
@@ -462,6 +486,16 @@ static void sockflush(struct socket *sk)
 
 void closesock(struct socket *sk)
 {
+    struct sockaddr_un *un;
+    
+    if((sk->family == AF_UNIX) && !sockgetlocalname(sk, (struct sockaddr **)&un, NULL) && (un->sun_family == PF_UNIX))
+    {
+       if(strchr(un->sun_path, '/'))
+       {
+           if(unlink(un->sun_path))
+               flog(LOG_WARNING, "could not unlink UNIX socket %s: %s", un->sun_path, strerror(errno));
+       }
+    }
     sk->state = SOCK_STL;
     close(sk->fd);
     sk->fd = -1;
@@ -702,7 +736,8 @@ struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)(
 
 int pollsocks(int timeout)
 {
-    int i, num, ret, retlen;
+    int i, num, ret;
+    socklen_t retlen;
     int newfd;
     struct pollfd *pfds;
     struct socket *sk, *next, *newsk;
@@ -1035,13 +1070,52 @@ int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *le
        return(-1);
     }
     *namebuf = memcpy(smalloc(len), &name, len);
-    *lenbuf = len;
+    if(lenbuf != NULL)
+       *lenbuf = len;
     return(0);
 }
 
-int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf)
+static void sethostaddr(struct sockaddr *dst, struct sockaddr *src)
+{
+    if(dst->sa_family != src->sa_family)
+    {
+       flog(LOG_ERR, "BUG: non-matching socket families in sethostaddr (%i -> %i)", src->sa_family, dst->sa_family);
+       return;
+    }
+    switch(src->sa_family)
+    {
+    case AF_INET:
+       ((struct sockaddr_in *)dst)->sin_addr = ((struct sockaddr_in *)src)->sin_addr;
+       break;
+    case AF_INET6:
+       ((struct sockaddr_in6 *)dst)->sin6_addr = ((struct sockaddr_in6 *)src)->sin6_addr;
+       break;
+    default:
+       flog(LOG_WARNING, "sethostaddr unimplemented for family %i", src->sa_family);
+       break;
+    }
+}
+
+static int makepublic(struct sockaddr *addr)
 {
     int ret;
+    socklen_t plen;
+    struct sockaddr *pname;
+    
+    if((ret = getpublicaddr(addr->sa_family, &pname, &plen)) < 0)
+    {
+       flog(LOG_ERR, "could not get public address: %s", strerror(errno));
+       return(-1);
+    }
+    if(ret)
+       return(0);
+    sethostaddr(addr, pname);
+    free(pname);
+    return(0);
+}
+
+int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf)
+{
     socklen_t len;
     struct sockaddr *name;
     
@@ -1050,22 +1124,15 @@ int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *l
     case 0:
        *namebuf = NULL;
        if((sk->state == SOCK_STL) || (sk->fd < 0))
-           return(-1);
-       if((ret = getpublicaddr(sk->family, &name, &len)) < 0)
        {
-           flog(LOG_ERR, "could not get public address: %s", strerror(errno));
+           errno = EBADF;
            return(-1);
        }
-       if(ret == 0)
-       {
-           *namebuf = name;
-           *lenbuf = len;
-           return(0);
-       }
        if(!sockgetlocalname(sk, &name, &len))
        {
            *namebuf = name;
            *lenbuf = len;
+           makepublic(name);
            return(0);
        }
        flog(LOG_ERR, "could not get remotely accessible name by any means");
@@ -1080,6 +1147,29 @@ int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *l
     }
 }
 
+int sockgetremotename2(struct socket *sk, struct socket *sk2, struct sockaddr **namebuf, socklen_t *lenbuf)
+{
+    struct sockaddr *name1, *name2;
+    socklen_t len1, len2;
+    
+    if(sk->family != sk2->family)
+    {
+       flog(LOG_ERR, "using sockgetremotename2 with sockets of differing family: %i %i", sk->family, sk2->family);
+       return(-1);
+    }
+    if(sockgetremotename(sk, &name1, &len1))
+       return(-1);
+    if(sockgetremotename(sk2, &name2, &len2)) {
+       free(name1);
+       return(-1);
+    }
+    sethostaddr(name1, name2);
+    free(name2);
+    *namebuf = name1;
+    *lenbuf = len1;
+    return(0);
+}
+
 int addreq(struct sockaddr *x, struct sockaddr *y)
 {
     struct sockaddr_un *u1, *u2;
@@ -1103,6 +1193,7 @@ int addreq(struct sockaddr *x, struct sockaddr *y)
        if(n1->sin_addr.s_addr != n2->sin_addr.s_addr)
            return(0);
        break;
+#ifdef HAVE_IPV6
     case AF_INET6:
        s1 = (struct sockaddr_in6 *)x; s2 = (struct sockaddr_in6 *)y;
        if(s1->sin6_port != s2->sin6_port)
@@ -1110,6 +1201,7 @@ int addreq(struct sockaddr *x, struct sockaddr *y)
        if(memcmp(s1->sin6_addr.s6_addr, s2->sin6_addr.s6_addr, sizeof(s1->sin6_addr.s6_addr)))
            return(0);
        break;
+#endif
     }
     return(1);
 }