Fossil SCM

Fix "fossil server" so that it listens on both IPv4 and IPv6 on Unix.

drh 2025-04-11 13:01 trunk
Commit 7ce8400d02223bad7b38c672ed493a292c938b9cc219fecb8c29d111565fc3ef
1 file changed +29 -22
+29 -22
--- src/cgi.c
+++ src/cgi.c
@@ -72,10 +72,11 @@
7272
# include <ws2tcpip.h>
7373
#else
7474
# include <sys/socket.h>
7575
# include <sys/un.h>
7676
# include <netinet/in.h>
77
+# include <netdb.h>
7778
# include <arpa/inet.h>
7879
# include <sys/times.h>
7980
# include <sys/time.h>
8081
# include <sys/wait.h>
8182
# include <sys/select.h>
@@ -2075,34 +2076,40 @@
20752076
}
20762077
if( zLeftOver ){ *zLeftOver = zInput; }
20772078
return zResult;
20782079
}
20792080
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
+
20802092
/*
20812093
** Determine the IP address on the other side of a connection.
20822094
** Return a pointer to a string. Or return 0 if unable.
20832095
**
20842096
** The string is held in a static buffer that is overwritten on
20852097
** each call.
20862098
*/
20872099
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) ){
20952108
return 0;
20962109
}
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;
21042111
}
21052112
21062113
/*
21072114
** This routine handles a single HTTP request which is coming in on
21082115
** g.httpIn and which replies on g.httpOut
@@ -2542,11 +2549,11 @@
25422549
fd_set readfds; /* Set of file descriptors for select() */
25432550
socklen_t lenaddr; /* Length of the inaddr structure */
25442551
int child; /* PID of the child process */
25452552
int nchildren = 0; /* Number of child processes */
25462553
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 */
25482555
struct sockaddr_un uxaddr; /* The address for unix-domain sockets */
25492556
int opt = 1; /* setsockopt flag */
25502557
int rc; /* Result code from system calls */
25512558
int iPort = mnPort; /* Port to try to use */
25522559
@@ -2583,23 +2590,22 @@
25832590
file_set_mode(g.zSockName, listener, "0660", 1);
25842591
}
25852592
}else{
25862593
/* Initialize a TCP/IP socket on port iPort */
25872594
memset(&inaddr, 0, sizeof(inaddr));
2588
- inaddr.sin_family = AF_INET;
2595
+ inaddr.sin6_family = AF_INET6;
25892596
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 ){
25922598
fossil_fatal("not a valid IP address: %s", zIpAddr);
25932599
}
25942600
}else if( flags & HTTP_SERVER_LOCALHOST ){
2595
- inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2601
+ inaddr.sin6_addr = in6addr_loopback;
25962602
}else{
2597
- inaddr.sin_addr.s_addr = htonl(INADDR_ANY);
2603
+ inaddr.sin6_addr = in6addr_any;
25982604
}
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);
26012607
if( listener<0 ){
26022608
iPort++;
26032609
continue;
26042610
}
26052611
}
@@ -2705,10 +2711,11 @@
27052711
close(2);
27062712
fd = dup(connection);
27072713
if( fd!=2 ) nErr++;
27082714
}
27092715
close(connection);
2716
+ close(listener);
27102717
g.nPendingRequest = nchildren+1;
27112718
g.nRequest = nRequest+1;
27122719
return nErr;
27132720
}
27142721
}
27152722
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button