Fossil SCM
Fix "fossil server" so that it listens on both IPv4 and IPv6 on Unix.
Commit
7ce8400d02223bad7b38c672ed493a292c938b9cc219fecb8c29d111565fc3ef
Parent
e546a2b4573159e…
1 file changed
+29
-22
+29
-22
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -72,10 +72,11 @@ | ||
| 72 | 72 | # include <ws2tcpip.h> |
| 73 | 73 | #else |
| 74 | 74 | # include <sys/socket.h> |
| 75 | 75 | # include <sys/un.h> |
| 76 | 76 | # include <netinet/in.h> |
| 77 | +# include <netdb.h> | |
| 77 | 78 | # include <arpa/inet.h> |
| 78 | 79 | # include <sys/times.h> |
| 79 | 80 | # include <sys/time.h> |
| 80 | 81 | # include <sys/wait.h> |
| 81 | 82 | # include <sys/select.h> |
| @@ -2075,34 +2076,40 @@ | ||
| 2075 | 2076 | } |
| 2076 | 2077 | if( zLeftOver ){ *zLeftOver = zInput; } |
| 2077 | 2078 | return zResult; |
| 2078 | 2079 | } |
| 2079 | 2080 | |
| 2081 | +/* | |
| 2082 | +** All possible forms of an IP address. Needed to work around GCC strict | |
| 2083 | +** aliasing rules. | |
| 2084 | +*/ | |
| 2085 | +typedef union { | |
| 2086 | + struct sockaddr sa; /* Abstract superclass */ | |
| 2087 | + struct sockaddr_in sa4; /* IPv4 */ | |
| 2088 | + struct sockaddr_in6 sa6; /* IPv6 */ | |
| 2089 | + struct sockaddr_storage sas; /* Should be the maximum of the above 3 */ | |
| 2090 | +} address; | |
| 2091 | + | |
| 2080 | 2092 | /* |
| 2081 | 2093 | ** Determine the IP address on the other side of a connection. |
| 2082 | 2094 | ** Return a pointer to a string. Or return 0 if unable. |
| 2083 | 2095 | ** |
| 2084 | 2096 | ** The string is held in a static buffer that is overwritten on |
| 2085 | 2097 | ** each call. |
| 2086 | 2098 | */ |
| 2087 | 2099 | char *cgi_remote_ip(int fd){ |
| 2088 | -#if 0 | |
| 2089 | - static char zIp[100]; | |
| 2090 | - struct sockaddr_in6 addr; | |
| 2091 | - socklen_t sz = sizeof(addr); | |
| 2092 | - if( getpeername(fd, &addr, &sz) ) return 0; | |
| 2093 | - zIp[0] = 0; | |
| 2094 | - if( inet_ntop(AF_INET6, &addr, zIp, sizeof(zIp))==0 ){ | |
| 2100 | + address remoteAddr; | |
| 2101 | + socklen_t size = sizeof(remoteAddr); | |
| 2102 | + static char zHost[NI_MAXHOST]; | |
| 2103 | + if( getpeername(0, &remoteAddr.sa, &size) ){ | |
| 2104 | + return 0; | |
| 2105 | + } | |
| 2106 | + if( getnameinfo(&remoteAddr.sa, size, zHost, sizeof(zHost), 0, 0, | |
| 2107 | + NI_NUMERICHOST) ){ | |
| 2095 | 2108 | return 0; |
| 2096 | 2109 | } |
| 2097 | - return zIp; | |
| 2098 | -#else | |
| 2099 | - struct sockaddr_in remoteName; | |
| 2100 | - socklen_t size = sizeof(struct sockaddr_in); | |
| 2101 | - if( getpeername(fd, (struct sockaddr*)&remoteName, &size) ) return 0; | |
| 2102 | - return inet_ntoa(remoteName.sin_addr); | |
| 2103 | -#endif | |
| 2110 | + return zHost; | |
| 2104 | 2111 | } |
| 2105 | 2112 | |
| 2106 | 2113 | /* |
| 2107 | 2114 | ** This routine handles a single HTTP request which is coming in on |
| 2108 | 2115 | ** g.httpIn and which replies on g.httpOut |
| @@ -2542,11 +2549,11 @@ | ||
| 2542 | 2549 | fd_set readfds; /* Set of file descriptors for select() */ |
| 2543 | 2550 | socklen_t lenaddr; /* Length of the inaddr structure */ |
| 2544 | 2551 | int child; /* PID of the child process */ |
| 2545 | 2552 | int nchildren = 0; /* Number of child processes */ |
| 2546 | 2553 | struct timeval delay; /* How long to wait inside select() */ |
| 2547 | - struct sockaddr_in inaddr; /* The socket address */ | |
| 2554 | + struct sockaddr_in6 inaddr; /* The socket address */ | |
| 2548 | 2555 | struct sockaddr_un uxaddr; /* The address for unix-domain sockets */ |
| 2549 | 2556 | int opt = 1; /* setsockopt flag */ |
| 2550 | 2557 | int rc; /* Result code from system calls */ |
| 2551 | 2558 | int iPort = mnPort; /* Port to try to use */ |
| 2552 | 2559 | |
| @@ -2583,23 +2590,22 @@ | ||
| 2583 | 2590 | file_set_mode(g.zSockName, listener, "0660", 1); |
| 2584 | 2591 | } |
| 2585 | 2592 | }else{ |
| 2586 | 2593 | /* Initialize a TCP/IP socket on port iPort */ |
| 2587 | 2594 | memset(&inaddr, 0, sizeof(inaddr)); |
| 2588 | - inaddr.sin_family = AF_INET; | |
| 2595 | + inaddr.sin6_family = AF_INET6; | |
| 2589 | 2596 | if( zIpAddr ){ |
| 2590 | - inaddr.sin_addr.s_addr = inet_addr(zIpAddr); | |
| 2591 | - if( inaddr.sin_addr.s_addr == INADDR_NONE ){ | |
| 2597 | + if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0 ){ | |
| 2592 | 2598 | fossil_fatal("not a valid IP address: %s", zIpAddr); |
| 2593 | 2599 | } |
| 2594 | 2600 | }else if( flags & HTTP_SERVER_LOCALHOST ){ |
| 2595 | - inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
| 2601 | + inaddr.sin6_addr = in6addr_loopback; | |
| 2596 | 2602 | }else{ |
| 2597 | - inaddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
| 2603 | + inaddr.sin6_addr = in6addr_any; | |
| 2598 | 2604 | } |
| 2599 | - inaddr.sin_port = htons(iPort); | |
| 2600 | - listener = socket(AF_INET, SOCK_STREAM, 0); | |
| 2605 | + inaddr.sin6_port = htons(iPort); | |
| 2606 | + listener = socket(AF_INET6, SOCK_STREAM, 0); | |
| 2601 | 2607 | if( listener<0 ){ |
| 2602 | 2608 | iPort++; |
| 2603 | 2609 | continue; |
| 2604 | 2610 | } |
| 2605 | 2611 | } |
| @@ -2705,10 +2711,11 @@ | ||
| 2705 | 2711 | close(2); |
| 2706 | 2712 | fd = dup(connection); |
| 2707 | 2713 | if( fd!=2 ) nErr++; |
| 2708 | 2714 | } |
| 2709 | 2715 | close(connection); |
| 2716 | + close(listener); | |
| 2710 | 2717 | g.nPendingRequest = nchildren+1; |
| 2711 | 2718 | g.nRequest = nRequest+1; |
| 2712 | 2719 | return nErr; |
| 2713 | 2720 | } |
| 2714 | 2721 | } |
| 2715 | 2722 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -72,10 +72,11 @@ | |
| 72 | # include <ws2tcpip.h> |
| 73 | #else |
| 74 | # include <sys/socket.h> |
| 75 | # include <sys/un.h> |
| 76 | # include <netinet/in.h> |
| 77 | # include <arpa/inet.h> |
| 78 | # include <sys/times.h> |
| 79 | # include <sys/time.h> |
| 80 | # include <sys/wait.h> |
| 81 | # include <sys/select.h> |
| @@ -2075,34 +2076,40 @@ | |
| 2075 | } |
| 2076 | if( zLeftOver ){ *zLeftOver = zInput; } |
| 2077 | return zResult; |
| 2078 | } |
| 2079 | |
| 2080 | /* |
| 2081 | ** Determine the IP address on the other side of a connection. |
| 2082 | ** Return a pointer to a string. Or return 0 if unable. |
| 2083 | ** |
| 2084 | ** The string is held in a static buffer that is overwritten on |
| 2085 | ** each call. |
| 2086 | */ |
| 2087 | char *cgi_remote_ip(int fd){ |
| 2088 | #if 0 |
| 2089 | static char zIp[100]; |
| 2090 | struct sockaddr_in6 addr; |
| 2091 | socklen_t sz = sizeof(addr); |
| 2092 | if( getpeername(fd, &addr, &sz) ) return 0; |
| 2093 | zIp[0] = 0; |
| 2094 | if( inet_ntop(AF_INET6, &addr, zIp, sizeof(zIp))==0 ){ |
| 2095 | return 0; |
| 2096 | } |
| 2097 | return zIp; |
| 2098 | #else |
| 2099 | struct sockaddr_in remoteName; |
| 2100 | socklen_t size = sizeof(struct sockaddr_in); |
| 2101 | if( getpeername(fd, (struct sockaddr*)&remoteName, &size) ) return 0; |
| 2102 | return inet_ntoa(remoteName.sin_addr); |
| 2103 | #endif |
| 2104 | } |
| 2105 | |
| 2106 | /* |
| 2107 | ** This routine handles a single HTTP request which is coming in on |
| 2108 | ** g.httpIn and which replies on g.httpOut |
| @@ -2542,11 +2549,11 @@ | |
| 2542 | fd_set readfds; /* Set of file descriptors for select() */ |
| 2543 | socklen_t lenaddr; /* Length of the inaddr structure */ |
| 2544 | int child; /* PID of the child process */ |
| 2545 | int nchildren = 0; /* Number of child processes */ |
| 2546 | struct timeval delay; /* How long to wait inside select() */ |
| 2547 | struct sockaddr_in inaddr; /* The socket address */ |
| 2548 | struct sockaddr_un uxaddr; /* The address for unix-domain sockets */ |
| 2549 | int opt = 1; /* setsockopt flag */ |
| 2550 | int rc; /* Result code from system calls */ |
| 2551 | int iPort = mnPort; /* Port to try to use */ |
| 2552 | |
| @@ -2583,23 +2590,22 @@ | |
| 2583 | file_set_mode(g.zSockName, listener, "0660", 1); |
| 2584 | } |
| 2585 | }else{ |
| 2586 | /* Initialize a TCP/IP socket on port iPort */ |
| 2587 | memset(&inaddr, 0, sizeof(inaddr)); |
| 2588 | inaddr.sin_family = AF_INET; |
| 2589 | if( zIpAddr ){ |
| 2590 | inaddr.sin_addr.s_addr = inet_addr(zIpAddr); |
| 2591 | if( inaddr.sin_addr.s_addr == INADDR_NONE ){ |
| 2592 | fossil_fatal("not a valid IP address: %s", zIpAddr); |
| 2593 | } |
| 2594 | }else if( flags & HTTP_SERVER_LOCALHOST ){ |
| 2595 | inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 2596 | }else{ |
| 2597 | inaddr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 2598 | } |
| 2599 | inaddr.sin_port = htons(iPort); |
| 2600 | listener = socket(AF_INET, SOCK_STREAM, 0); |
| 2601 | if( listener<0 ){ |
| 2602 | iPort++; |
| 2603 | continue; |
| 2604 | } |
| 2605 | } |
| @@ -2705,10 +2711,11 @@ | |
| 2705 | close(2); |
| 2706 | fd = dup(connection); |
| 2707 | if( fd!=2 ) nErr++; |
| 2708 | } |
| 2709 | close(connection); |
| 2710 | g.nPendingRequest = nchildren+1; |
| 2711 | g.nRequest = nRequest+1; |
| 2712 | return nErr; |
| 2713 | } |
| 2714 | } |
| 2715 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -72,10 +72,11 @@ | |
| 72 | # include <ws2tcpip.h> |
| 73 | #else |
| 74 | # include <sys/socket.h> |
| 75 | # include <sys/un.h> |
| 76 | # include <netinet/in.h> |
| 77 | # include <netdb.h> |
| 78 | # include <arpa/inet.h> |
| 79 | # include <sys/times.h> |
| 80 | # include <sys/time.h> |
| 81 | # include <sys/wait.h> |
| 82 | # include <sys/select.h> |
| @@ -2075,34 +2076,40 @@ | |
| 2076 | } |
| 2077 | if( zLeftOver ){ *zLeftOver = zInput; } |
| 2078 | return zResult; |
| 2079 | } |
| 2080 | |
| 2081 | /* |
| 2082 | ** All possible forms of an IP address. Needed to work around GCC strict |
| 2083 | ** aliasing rules. |
| 2084 | */ |
| 2085 | typedef union { |
| 2086 | struct sockaddr sa; /* Abstract superclass */ |
| 2087 | struct sockaddr_in sa4; /* IPv4 */ |
| 2088 | struct sockaddr_in6 sa6; /* IPv6 */ |
| 2089 | struct sockaddr_storage sas; /* Should be the maximum of the above 3 */ |
| 2090 | } address; |
| 2091 | |
| 2092 | /* |
| 2093 | ** Determine the IP address on the other side of a connection. |
| 2094 | ** Return a pointer to a string. Or return 0 if unable. |
| 2095 | ** |
| 2096 | ** The string is held in a static buffer that is overwritten on |
| 2097 | ** each call. |
| 2098 | */ |
| 2099 | char *cgi_remote_ip(int fd){ |
| 2100 | address remoteAddr; |
| 2101 | socklen_t size = sizeof(remoteAddr); |
| 2102 | static char zHost[NI_MAXHOST]; |
| 2103 | if( getpeername(0, &remoteAddr.sa, &size) ){ |
| 2104 | return 0; |
| 2105 | } |
| 2106 | if( getnameinfo(&remoteAddr.sa, size, zHost, sizeof(zHost), 0, 0, |
| 2107 | NI_NUMERICHOST) ){ |
| 2108 | return 0; |
| 2109 | } |
| 2110 | return zHost; |
| 2111 | } |
| 2112 | |
| 2113 | /* |
| 2114 | ** This routine handles a single HTTP request which is coming in on |
| 2115 | ** g.httpIn and which replies on g.httpOut |
| @@ -2542,11 +2549,11 @@ | |
| 2549 | fd_set readfds; /* Set of file descriptors for select() */ |
| 2550 | socklen_t lenaddr; /* Length of the inaddr structure */ |
| 2551 | int child; /* PID of the child process */ |
| 2552 | int nchildren = 0; /* Number of child processes */ |
| 2553 | struct timeval delay; /* How long to wait inside select() */ |
| 2554 | struct sockaddr_in6 inaddr; /* The socket address */ |
| 2555 | struct sockaddr_un uxaddr; /* The address for unix-domain sockets */ |
| 2556 | int opt = 1; /* setsockopt flag */ |
| 2557 | int rc; /* Result code from system calls */ |
| 2558 | int iPort = mnPort; /* Port to try to use */ |
| 2559 | |
| @@ -2583,23 +2590,22 @@ | |
| 2590 | file_set_mode(g.zSockName, listener, "0660", 1); |
| 2591 | } |
| 2592 | }else{ |
| 2593 | /* Initialize a TCP/IP socket on port iPort */ |
| 2594 | memset(&inaddr, 0, sizeof(inaddr)); |
| 2595 | inaddr.sin6_family = AF_INET6; |
| 2596 | if( zIpAddr ){ |
| 2597 | if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0 ){ |
| 2598 | fossil_fatal("not a valid IP address: %s", zIpAddr); |
| 2599 | } |
| 2600 | }else if( flags & HTTP_SERVER_LOCALHOST ){ |
| 2601 | inaddr.sin6_addr = in6addr_loopback; |
| 2602 | }else{ |
| 2603 | inaddr.sin6_addr = in6addr_any; |
| 2604 | } |
| 2605 | inaddr.sin6_port = htons(iPort); |
| 2606 | listener = socket(AF_INET6, SOCK_STREAM, 0); |
| 2607 | if( listener<0 ){ |
| 2608 | iPort++; |
| 2609 | continue; |
| 2610 | } |
| 2611 | } |
| @@ -2705,10 +2711,11 @@ | |
| 2711 | close(2); |
| 2712 | fd = dup(connection); |
| 2713 | if( fd!=2 ) nErr++; |
| 2714 | } |
| 2715 | close(connection); |
| 2716 | close(listener); |
| 2717 | g.nPendingRequest = nchildren+1; |
| 2718 | g.nRequest = nRequest+1; |
| 2719 | return nErr; |
| 2720 | } |
| 2721 | } |
| 2722 |