Subversion Repositories

?revision_form?Rev ?revision_input??revision_submit??revision_endform?

Rev 3 | Blame | Compare with Previous | Last modification | View Log | RSS feed

--- prayer-1.0.18.orig/prayer/config.c
+++ prayer-1.0.18/prayer/config.c
@@ -1650,7 +1650,7 @@
 
     if (!config_parse_rest(&option))
         error = T;
-    else if ((s = (strchr(option, ':')))) {
+    else if ((s = (strrchr(option, ':')))) {
         *s++ = '\0';
         if (!config_parse_number(&port, s))
             error = T;
--- prayer-1.0.18.orig/prayer/ipaddr.c
+++ prayer-1.0.18/prayer/ipaddr.c
@@ -32,11 +32,7 @@
 
 BOOL ipaddr_copy(struct ipaddr * dst, struct ipaddr * src)
 {
-    dst->version = src->version;
-    dst->addr[0] = src->addr[0];
-    dst->addr[1] = src->addr[1];
-    dst->addr[2] = src->addr[2];
-    dst->addr[3] = src->addr[3];
+    memcpy(dst, src, sizeof(struct ipaddr));
 
     return (T);
 }
@@ -55,19 +51,7 @@
     if (addr1->version != addr2->version)
         return (NIL);
 
-    if (addr1->addr[0] != addr2->addr[0])
-        return (NIL);
-
-    if (addr1->addr[1] != addr2->addr[1])
-        return (NIL);
-
-    if (addr1->addr[2] != addr2->addr[2])
-        return (NIL);
-
-    if (addr1->addr[3] != addr2->addr[3])
-        return (NIL);
-
-    return (T);
+    return (memcmp(&addr1->addr, &addr2->addr, addr1->version == 6 ? 16 : 4) == 0);
 }
 
 /* ====================================================================== */
@@ -81,8 +65,7 @@
 {
     static char buf[64];
 
-    sprintf(buf, "%d.%d.%d.%d",
-            addr->addr[0], addr->addr[1], addr->addr[2], addr->addr[3]);
+    os_inet_ntop(addr->addr, addr->version, buf, 64);
 
     return (buf);
 }
@@ -96,7 +79,7 @@
 {
     char *result;
 
-    if ((result = os_gethostbyaddr(addr->addr)))
+    if ((result = os_gethostbyaddr(addr->addr, addr->version)))
         return (result);
 
     return (ipaddr_text(addr));
@@ -116,39 +99,10 @@
 
 BOOL ipaddr_parse(struct ipaddr * addr, char *text)
 {
-    char *next;
-
     if (text == NIL)
         return (NIL);
 
-    /* IPv4 only for the moment */
-    addr->version = 4;
-
-    /* Parse first number */
-    if (!(next = strchr(text, '.')))
-        return (NIL);
-    addr->addr[0] = atoi(text);
-    text = next + 1;
-
-    /* Parse second number */
-    if (!(next = strchr(text, '.')))
-        return (NIL);
-    addr->addr[1] = atoi(text);
-    text = next + 1;
-
-    /* Parse third number */
-    if (!(next = strchr(text, '.')))
-        return (NIL);
-    addr->addr[2] = atoi(text);
-    text = next + 1;
-
-    /* Parse forth number */
-    if ((next = strchr(text, '.')))
-        return (NIL);
-    addr->addr[3] = atoi(text);
-
-    /* Looks good */
-    return (T);
+    return (os_inet_pton(text, addr));
 }
 
 /* ====================================================================== */
@@ -157,56 +111,63 @@
  *
  * Compare IP address to text list of form:
  * ipaddr:
- *   text: Text string of form "131.111.0.0/16 : 192.168.0.0/24".
+ *   text: Text string of form "131.111.0.0/16 : 192.168.0.0/24 : 2001:12cd:1::/48".
+ *         (There has to be a space on either side of the colon for it to
+ *          separate two networks)
  *
  * Returns: T if addr matches list.
  ************************************************************************/
 
 BOOL ipaddr_compare_list(struct ipaddr * ipaddr, char *text)
 {
-    char *next, *s, *alloc;
+    char *next = NULL, *s, *alloc;
+    int i;
     unsigned long bits, mask;
     struct ipaddr parsed;
 
     alloc = text = pool_strdup(NIL, text);
 
     while (text && *text) {
-        if ((next = strchr(text, ':')))
-            *next++ = '\0';
+        s = text;
+        while ((s = strchr(s, ':'))) {
+           if (*(s - 1) == ' ' || *(s + 1) == ' ') {
+              *(next = s) = '\0';
+              next++;
+            }
+            s++;
+        }
 
         text = string_trim_whitespace(text);
 
         if ((s = strchr(text, '/'))) {
             *s++ = '\0';
             bits = atoi(s);
-        } else
-            bits = 32;
-
-        if (bits > 32)
-            bits = 32;
-
-        /* Create mask with appropriate number of bits set */
-        mask = 0;
-        while (bits > 0) {
-            mask >>= 1;
-            mask |= 0x80000000;
-            bits--;
         }
+        else
+            bits = 128;  /* Doesn't matter if it's too big */
 
         if (ipaddr_parse(&parsed, text)) {
-            unsigned long a1;
-            unsigned long a2;
-
-            a1 = ((ipaddr->addr[0] << 24) + (ipaddr->addr[1] << 16) +
-                  (ipaddr->addr[2] << 8) + (ipaddr->addr[3]));
-
-            a2 = ((parsed.addr[0] << 24) + (parsed.addr[1] << 16) +
-                  (parsed.addr[2] << 8) + (parsed.addr[3]));
-
-            if ((a1 & mask) == (a2 & mask)) {
-                free(alloc);
-                return (T);
-            }
+            if (parsed.version != ipaddr->version) {
+                text = next; continue;
+            }
+
+            for (i = 0; i < (parsed.version == 6 ? 4 : 1); i++) {
+                if (bits == 0) mask = 0;
+                else if (bits < 32) {
+                    mask = (-1) << (32 - bits);
+                    bits = 0;
+                }
+                else {
+                    mask = -1;
+                    bits -= 32;
+                }
+
+                if ((parsed.addr[i] & mask) != (ipaddr->addr[i] & mask)) {
+                    text = next; continue;
+                }
+            }
+            free(alloc);
+            return (T);
         }
         text = next;
     }
@@ -225,11 +187,11 @@
 
 void ipaddr_send_iostream(struct ipaddr *addr, struct iostream *stream)
 {
+    int i;
     ioputc(addr->version, stream);
-    ioputc(addr->addr[0], stream);
-    ioputc(addr->addr[1], stream);
-    ioputc(addr->addr[2], stream);
-    ioputc(addr->addr[3], stream);
+    for (i = 0; i < (addr->version == 6 ? 16 : 4); i++) {
+        ioputc(((char *)addr->addr)[i], stream);
+    }
 }
 
 /* ====================================================================== */
@@ -246,13 +208,13 @@
 
     if ((c = iogetc(stream)) != EOF) {
         addr->version = (unsigned char) c;
-        for (i = 0; i < 4; i++) {
+        for (i = 0; i < (addr->version == 6 ? 16 : 4); i++) {
             if ((c = iogetc(stream)) == EOF) {
                 rc = NIL;
                 break;
             }
 
-            addr->addr[i] = (unsigned char) c;
+            ((char *)addr->addr)[i] = (unsigned char) c;
         }
     }
 
@@ -279,9 +241,14 @@
 ipaddr_set(struct ipaddr *ipaddr, unsigned long version,
            unsigned char *addr)
 {
-    if (version != 4)
-        log_fatal("ipaddr_set(): IPv4 only supported at the moment!");
+    if (version != 4 && version != 6)
+        log_fatal("ipaddr_set(): IPv4 and IPv6 only supported!");
+
+    ipaddr->version = version;
+    memcpy(ipaddr->addr, addr, version == 6 ? 16 : 4);
+    if (ipaddr->addr[0] == 0 && ipaddr->addr[1] == 0 && ipaddr->addr[2] == 0xffff) {
+        ipaddr->addr[0] = ipaddr->addr[3];
+        ipaddr->version = 4;
+    }
 
-    ipaddr->version = 4;
-    memcpy(ipaddr->addr, addr, 4);
 }
--- prayer-1.0.18.orig/prayer/ipaddr.h
+++ prayer-1.0.18/prayer/ipaddr.h
@@ -8,7 +8,7 @@
 
 struct ipaddr {
     unsigned long version;
-    unsigned char addr[4];
+    unsigned long addr[4];
 };
 
 struct ipaddr *ipaddr_create(struct pool *pool);
--- prayer-1.0.18.orig/prayer/os.h
+++ prayer-1.0.18/prayer/os.h
@@ -24,7 +24,11 @@
 
 int os_socket_nonblocking(int sockfd);
 
-char *os_gethostbyaddr(void *addr);
+char *os_gethostbyaddr(void *addr, unsigned int version);
+
+int os_inet_ntop(void *addr, unsigned long version, char *buf, unsigned long buflen);
+
+int os_inet_pton(char *str, struct ipaddr *addr);
 
 void os_child_reaper();
 
--- prayer-1.0.18.orig/prayer/os_linux.c
+++ prayer-1.0.18/prayer/os_linux.c
@@ -13,14 +13,11 @@
 #include <sys/un.h>
 #include <sys/resource.h>
 #include <netinet/in.h>
-#include <netinet/tcp.h>
 #include <arpa/inet.h>
 #include <signal.h>
 #include <netdb.h>
 #include <sys/file.h>
 
-#include <openssl/rand.h>
-
 /* ====================================================================== */
 
 BOOL os_socketpair(int *sockfd)
@@ -63,33 +60,28 @@
 
 int os_connect_inet_socket(char *host, unsigned long port)
 {
-    struct hostent *hostent;
-    struct sockaddr_in serv_addr;
+    struct addrinfo *first_ai, *ai;
+    char port_str[12];
     int sockfd;
 
-    /* Open the socket */
-    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-        return (-1);
-
-    /* Set up the socket */
-    bzero((char *) &serv_addr, sizeof(serv_addr));
-    serv_addr.sin_family = AF_INET;
-    serv_addr.sin_port = htons(port);
-
-    if ((hostent = gethostbyname(host)) == NIL) {
-        close(sockfd);
-        return (-1);
-    }
-    bcopy(hostent->h_addr, (char *) &serv_addr.sin_addr,
-          hostent->h_length);
-
-    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr))
-        < 0) {
-        close(sockfd);
-        return (-1);
-    }
-
-    return (sockfd);
+    sprintf(port_str, "%lu", port);
+    if (getaddrinfo(host, port_str, NULL, &first_ai)) {
+        return (-1);
+    }
+    for (ai = first_ai; ai->ai_next; ai = ai->ai_next) {
+        /* Open the socket */
+        if ((sockfd = socket(ai->ai_family, SOCK_STREAM, 0)) < 0) {
+            break;
+        }
+        if (connect(sockfd, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0) {
+            close(sockfd);
+            break;
+        }
+        freeaddrinfo(first_ai);
+        return (sockfd);
+    }
+    freeaddrinfo(first_ai);
+    return (-1);
 }
 
 /* ====================================================================== */
@@ -150,9 +141,39 @@
 int os_bind_inet_socket(unsigned long port, char *interface)
 {
     int i, sockfd;
-    struct sockaddr_in serv_addr;
+    struct sockaddr_storage serv_addr;
+    struct addrinfo *ai;
+
+    bzero((char *) &serv_addr, sizeof(serv_addr));
 
-    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+    if (interface) {
+        if (getaddrinfo(interface, NULL, NULL, &ai)) {
+            log_panic
+                ("[os_bind_inet_socket()] Failed to lookup hostname: %s",
+                 interface);
+            return -1;
+        }
+#if 0   /* Use the first interface address; don't panic if both IPv6
+          and IPv4 addresses are returned. */
+        if (hostent->h_addr_list[1]) {
+            log_panic
+                ("[os_bind_inet_socket()] Ambiguous interface name: %s",
+                 interface);
+            return (-1);
+        }
+#endif
+        memcpy(&serv_addr, ai->ai_addr, ai->ai_addrlen);
+        freeaddrinfo(ai);
+    }
+    else {
+        serv_addr.ss_family = AF_INET6;
+        ((struct sockaddr_in6*)&serv_addr)->sin6_addr = in6addr_any;
+    }
+    /* This isn't formally correct, but *in fact*, sin6_port is at the
+       same place as sin_port, so it works. */
+    ((struct sockaddr_in6*)&serv_addr)->sin6_port = htons(port);
+    
+    if ((sockfd = socket(serv_addr.ss_family, SOCK_STREAM, 0)) < 0) {
         log_panic("[os_bind_inet_socket()] socket() failed, %s",
                   strerror(errno));
         return (-1);
@@ -168,41 +189,6 @@
         return (-1);
     }
 
-    bzero((char *) &serv_addr, sizeof(serv_addr));
-    serv_addr.sin_family = AF_INET;
-    serv_addr.sin_port = htons(port);
-    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
-
-    /* Calculate serv_addr for specific interface to bind to */
-    if (interface) {
-        struct hostent *hostent;
-        struct in_addr *s;
-
-        if (!(hostent = gethostbyname(interface))) {
-            log_panic
-                ("[os_bind_inet_socket()] Failed to lookup hostname: %s",
-                 interface);
-
-            return (-1);
-        }
-
-        if (hostent->h_addr_list[1]) {
-            log_panic
-                ("[os_bind_inet_socket()] Ambiguous interface name: %s",
-                 interface);
-            return (-1);
-        }
-
-        if (!(s = ((struct in_addr *)hostent->h_addr_list[0]))) {
-            log_panic("[os_bind_inet_socket()] Invalid interface name: %s",
-                      interface);
-            return (-1);
-        }
-
-        /* s has four bytes in network byte order */
-        memcpy(&serv_addr.sin_addr.s_addr, s, sizeof(struct in_addr));
-    }
-
     /* bind() as Internet domain socket */
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) <
         0) {
@@ -255,8 +242,8 @@
 
 int os_accept_inet(int sockfd, struct ipaddr *ipaddr)
 {
-    struct sockaddr_in addr;
-    socklen_t len = (socklen_t) sizeof(struct sockaddr_in);
+    struct sockaddr_storage addr;
+    socklen_t len = (socklen_t) sizeof(addr);
     int newsockfd;
 
     do {
@@ -271,8 +258,12 @@
         return (-1);
     }
 
-    if (ipaddr)
-        ipaddr_set(ipaddr, 4, (unsigned char *) &addr.sin_addr);
+    if (ipaddr) {
+        if (addr.ss_family == AF_INET6)
+            ipaddr_set(ipaddr, 6, (unsigned char *)&((struct sockaddr_in6*)&addr)->sin6_addr);
+        else
+            ipaddr_set(ipaddr, 4, (unsigned char *)&((struct sockaddr_in*)&addr)->sin_addr);
+    }
 
     /* Set close on exec so subprocesses can't interfere */
     if (fcntl(newsockfd, F_SETFD, FD_CLOEXEC) < 0) {
@@ -322,9 +313,14 @@
 
 /* Convert IPv4 address into text form */
 
-char *os_gethostbyaddr(void *opaque)
+char *os_gethostbyaddr(void *opaque, unsigned int version)
 {
-    struct hostent *hostent = gethostbyaddr(opaque, 4, AF_INET);
+    struct hostent *hostent;
+
+    if (version == 6)
+        hostent = gethostbyaddr(opaque, 16, AF_INET6);
+    else
+        hostent = gethostbyaddr(opaque, 4, AF_INET);
 
     if (hostent && hostent->h_name && hostent->h_name[0])
         return (hostent->h_name);
@@ -332,6 +328,32 @@
     return (NIL);
 }
 
+int os_inet_ntop(void *addr, unsigned long version, char *buf, unsigned long buflen) {
+    if (version == 6) {
+        if (inet_ntop(AF_INET6, addr, buf, buflen))
+            return (T);
+    }
+    else {
+        if (inet_ntop(AF_INET, addr, buf, buflen))
+            return (T);
+    }
+    return (NIL);
+}
+
+int os_inet_pton(char *str, struct ipaddr *addr) {
+    unsigned char buf[16];
+
+    if (inet_pton(AF_INET6, str, buf)) {
+        ipaddr_set(addr, 6, buf);
+        return (T);
+    }
+    else if (inet_pton(AF_INET, str, buf)) {
+        ipaddr_set(addr, 4, buf);
+        return (T);
+    }
+    return (NIL);
+}
+
 /* ====================================================================== */
 
 /* Trivial SIG_CLD handler to prevent zombies from hanging around */