Check hub addresses for sources hubs.
[doldaconnect.git] / daemon / net.c
index f16441f..576ea6f 100644 (file)
@@ -51,9 +51,16 @@ static struct configvar myvars[] =
 {
     /* 0 = Direct mode, 1 = Passive mode, 2 = SOCKS proxy */
     {CONF_VAR_INT, "mode", {.num = 0}},
+    {CONF_VAR_BOOL, "reuseaddr", {.num = 0}},
     /* Only for direct mode */
     {CONF_VAR_IPV4, "visibleipv4", {.ipv4 = {0}}},
     {CONF_VAR_STRING, "publicif", {.str = L""}},
+    /* Diffserv should be supported on IPv4, too, but I don't know the
+     * API to do that. */
+    {CONF_VAR_INT, "diffserv-mincost", {.num = 0}},
+    {CONF_VAR_INT, "diffserv-maxrel", {.num = 0}},
+    {CONF_VAR_INT, "diffserv-maxtp", {.num = 0}},
+    {CONF_VAR_INT, "diffserv-mindelay", {.num = 0}},
     {CONF_VAR_END}
 };
 
@@ -83,7 +90,7 @@ int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf)
            *lenbuf = sizeof(*ipv4);
            return(0);
        }
-       if((pif = icwcstombs(confgetstr("net", "publicif"), NULL)) == NULL)
+       if((pif = icswcstombs(confgetstr("net", "publicif"), NULL, NULL)) == NULL)
        {
            flog(LOG_ERR, "could not convert net.publicif into local charset: %s", strerror(errno));
            return(-1);
@@ -121,12 +128,14 @@ int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf)
                    memcpy(ipv4, &ifr->ifr_addr, sizeof(ifr->ifr_addr));
                } else {
                    free(ipv4);
+                   free(conf.ifc_buf);
                    flog(LOG_WARNING, "could not locate an unambiguous interface for determining your public IP address - set net.publicif");
                    errno = ENFILE; /* XXX: There's no appropriate one for this... */
                    return(-1);
                }
            }
        }
+       free(conf.ifc_buf);
        close(sock);
        if(ipv4 != NULL)
        {
@@ -269,6 +278,23 @@ void putsock(struct socket *sk)
     }
 }
 
+void sockpushdata(struct socket *sk, void *buf, size_t size)
+{
+    switch(sk->type)
+    {
+    case SOCK_STREAM:
+       sizebuf(&sk->inbuf.s.buf, &sk->inbuf.s.bufsize, sk->inbuf.s.datasize + size, 1, 1);
+       memmove(sk->inbuf.s.buf + size, sk->inbuf.s.buf, sk->inbuf.s.datasize);
+       memcpy(sk->inbuf.s.buf, buf, size);
+       sk->inbuf.s.datasize += size;
+       break;
+    case SOCK_DGRAM:
+       /* XXX */
+       break;
+    }
+    return;
+}
+
 void *sockgetinbuf(struct socket *sk, size_t *size)
 {
     void *buf;
@@ -521,6 +547,7 @@ size_t sockqueuesize(struct socket *sk)
 struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
 {
     struct socket *sk;
+    int intbuf;
     
     if(confgetint("net", "mode") == 1)
     {
@@ -538,6 +565,11 @@ struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, v
        if((sk = mksock(name->sa_family, type)) == NULL)
            return(NULL);
        sk->state = SOCK_LST;
+       if(confgetint("net", "reuseaddr"))
+       {
+           intbuf = 1;
+           setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf));
+       }
        if(bind(sk->fd, name, namelen) < 0)
        {
            putsock(sk);
@@ -567,6 +599,7 @@ struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, v
 struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
 {
     struct socket *sk;
+    int intbuf;
     
     /* I don't know if this is actually correct (it probably isn't),
      * but since, at on least Linux systems, PF_* are specifically
@@ -577,6 +610,11 @@ struct socket *netcslistenlocal(int type, struct sockaddr *name, socklen_t namel
     if((sk = mksock(name->sa_family, type)) == NULL)
        return(NULL);
     sk->state = SOCK_LST;
+    if(confgetint("net", "reuseaddr"))
+    {
+       intbuf = 1;
+       setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf));
+    }
     if(bind(sk->fd, name, namelen) < 0)
     {
        putsock(sk);
@@ -824,16 +862,72 @@ int pollsocks(int timeout)
 
 int socksettos(struct socket *sk, int tos)
 {
+    int buf;
+    
     if(sk->family == AF_INET)
     {
-       if(setsockopt(sk->fd, SOL_IP, IP_TOS, &tos, sizeof(tos)) < 0)
+       switch(tos)
+       {
+       case 0:
+           buf = 0;
+           break;
+       case SOCK_TOS_MINCOST:
+           buf = 0x02;
+           break;
+       case SOCK_TOS_MAXREL:
+           buf = 0x04;
+           break;
+       case SOCK_TOS_MAXTP:
+           buf = 0x08;
+           break;
+       case SOCK_TOS_MINDELAY:
+           buf = 0x10;
+           break;
+       default:
+           flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);
+           return(-1);
+       }
+       if(setsockopt(sk->fd, SOL_IP, IP_TOS, &buf, sizeof(buf)) < 0)
        {
            flog(LOG_WARNING, "could not set sock TOS to %i: %s", tos, strerror(errno));
            return(-1);
        }
        return(0);
     }
-    /* XXX: How does the IPv6 traffic class work? */
+    if(sk->family == AF_INET6)
+    {
+       switch(tos)
+       {
+       case 0:
+           buf = 0;
+       case SOCK_TOS_MINCOST:
+           buf = confgetint("net", "diffserv-mincost");
+           break;
+       case SOCK_TOS_MAXREL:
+           buf = confgetint("net", "diffserv-maxrel");
+           break;
+       case SOCK_TOS_MAXTP:
+           buf = confgetint("net", "diffserv-maxtp");
+           break;
+       case SOCK_TOS_MINDELAY:
+           buf = confgetint("net", "diffserv-mindelay");
+           break;
+       default:
+           flog(LOG_WARNING, "attempted to set unknown TOS value %i to IPv4 sock", tos);
+           return(-1);
+       }
+       /*
+         On Linux, the API IPv6 flow label management doesn't seem to
+         be entirely complete, so I guess this will have to wait.
+         
+       if(setsockopt(...) < 0)
+       {
+           flog(LOG_WARNING, "could not set sock traffic class to %i: %s", tos, strerror(errno));
+           return(-1);
+       }
+       */
+       return(0);
+    }
     flog(LOG_WARNING, "could not set TOS on sock of family %i", sk->family);
     return(1);
 }
@@ -998,6 +1092,40 @@ int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *l
     }
 }
 
+int addreq(struct sockaddr *x, struct sockaddr *y)
+{
+    struct sockaddr_un *u1, *u2;
+    struct sockaddr_in *n1, *n2;
+#ifdef HAVE_IPV6
+    struct sockaddr_in6 *s1, *s2;
+#endif
+    
+    if(x->sa_family != y->sa_family)
+       return(0);
+    switch(x->sa_family) {
+    case AF_UNIX:
+       u1 = (struct sockaddr_un *)x; u2 = (struct sockaddr_un *)y;
+       if(strncmp(u1->sun_path, u2->sun_path, sizeof(u1->sun_path)))
+           return(0);
+       break;
+    case AF_INET:
+       n1 = (struct sockaddr_in *)x; n2 = (struct sockaddr_in *)y;
+       if(n1->sin_port != n2->sin_port)
+           return(0);
+       if(n1->sin_addr.s_addr != n2->sin_addr.s_addr)
+           return(0);
+       break;
+    case AF_INET6:
+       s1 = (struct sockaddr_in6 *)x; s2 = (struct sockaddr_in6 *)y;
+       if(s1->sin6_port != s2->sin6_port)
+           return(0);
+       if(memcmp(s1->sin6_addr.s6_addr, s2->sin6_addr.s6_addr, sizeof(s1->sin6_addr.s6_addr)))
+           return(0);
+       break;
+    }
+    return(1);
+}
+
 char *formataddress(struct sockaddr *arg, socklen_t arglen)
 {
     struct sockaddr_un *UNIX; /* Some wise guy has #defined unix with
@@ -1030,7 +1158,7 @@ char *formataddress(struct sockaddr *arg, socklen_t arglen)
        ipv6 = (struct sockaddr_in6 *)arg;
        if(inet_ntop(AF_INET6, &ipv6->sin6_addr, buf, sizeof(buf)) == NULL)
            return(NULL);
-       ret = sprintf2("%s:%i", buf, (int)ntohs(ipv6->sin6_port));
+       ret = sprintf2("[%s]:%i", buf, (int)ntohs(ipv6->sin6_port));
        break;
 #endif
     default: