Fossil SCM

Rework server sockets to work around limitations in OpenBSD's socket implementation. See [forum:/forumpost/7f8d2afe4d8c0ad5|forum thread 7f8d2afe4d8c0ad5].

drh 2025-04-17 15:08 UTC trunk
Commit 8dd05c52f5fac7a84b2f162e6de0b66e9e33378550ebf258abb4c0dd21173158
1 file changed +36 -27
+36 -27
--- src/cgi.c
+++ src/cgi.c
@@ -2568,14 +2568,16 @@
25682568
socklen_t lenaddr; /* Length of the inaddr structure */
25692569
int child; /* PID of the child process */
25702570
int nchildren = 0; /* Number of child processes */
25712571
struct timeval delay; /* How long to wait inside select() */
25722572
struct sockaddr_in6 inaddr; /* The socket address */
2573
+ struct sockaddr_in inaddr4; /* IPv4 address; needed by OpenBSD */
25732574
struct sockaddr_un uxaddr; /* The address for unix-domain sockets */
25742575
int opt = 1; /* setsockopt flag */
25752576
int rc; /* Result code from system calls */
25762577
int iPort = mnPort; /* Port to try to use */
2578
+ int bIPv4 = 0; /* Use IPv4 only; use inaddr4, not inaddr */
25772579
25782580
while( iPort<=mxPort ){
25792581
if( flags & HTTP_SERVER_UNIXSOCKET ){
25802582
/* Initialize a Unix socket named g.zSockName */
25812583
assert( g.zSockName!=0 );
@@ -2607,47 +2609,52 @@
26072609
}else{
26082610
file_set_mode(g.zSockName, listener, "0660", 1);
26092611
}
26102612
}else{
26112613
/* Initialize a TCP/IP socket on port iPort */
2612
- memset(&inaddr, 0, sizeof(inaddr));
2613
- inaddr.sin6_family = AF_INET6;
2614
+ if( (flags & HTTP_SERVER_LOCALHOST)!=0 && zIpAddr==0 ){
2615
+ /* Map all loopback to 127.0.0.1, since this is the easiest way
2616
+ ** to support OpenBSD and its limitations without burdening
2617
+ ** Linux and MacOS with lots of extra code and complication. */
2618
+ zIpAddr = "127.0.0.1";
2619
+ }
26142620
if( zIpAddr ){
2615
- /* Bind to the specific IP address given by zIpAddr[] */
2616
- size_t nAddr = strlen(zIpAddr);
2617
- char z4to6[30];
2618
-
2619
- if( nAddr<16 ){
2620
- /* The specified IP address might be in IPv4 notation (ex: 1.2.3.4)
2621
- ** which inet_pton() does not understand. Convert in into a IPv6
2622
- ** mapping of an IPv4 address: (::FFFF:1.2.3.4) */
2623
- memcpy(z4to6,"::ffff:", 7);
2624
- memcpy(z4to6+7, zIpAddr, nAddr+2);
2621
+ if( strchr(zIpAddr,':') ){
2622
+ memset(&inaddr, 0, sizeof(inaddr));
2623
+ inaddr.sin6_family = AF_INET6;
2624
+ bIPv4 = 0;
2625
+ if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0 ){
2626
+ fossil_fatal("not a valid IPv6 address: %s", zIpAddr);
2627
+ }
26252628
}else{
2626
- z4to6[0] = 0;
2627
- }
2628
-
2629
- /* Convert the zIpAddr text string into an actual IPv6 address */
2630
- if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0
2631
- && (z4to6[0]==0 || inet_pton(AF_INET6, z4to6, &inaddr.sin6_addr)==0)
2632
- ){
2633
- fossil_fatal("not a valid IP address: %s", zIpAddr);
2634
- }
2635
- }else if( flags & HTTP_SERVER_LOCALHOST ){
2636
- /* Bind to the loop-back IP address */
2637
- inet_pton(AF_INET6, "::ffff.127.0.0.1", &inaddr.sin6_addr);
2629
+ memset(&inaddr4, 0, sizeof(inaddr4));
2630
+ inaddr4.sin_family = AF_INET;
2631
+ bIPv4 = 1;
2632
+ inaddr4.sin_addr.s_addr = inet_addr(zIpAddr);
2633
+ if( inaddr4.sin_addr.s_addr == INADDR_NONE ){
2634
+ fossil_fatal("not a valid IPv4 address: %s", zIpAddr);
2635
+ }
2636
+ }
26382637
}else{
26392638
/* Bind to any and all available IP addresses */
2639
+ memset(&inaddr, 0, sizeof(inaddr));
2640
+ inaddr.sin6_family = AF_INET6;
26402641
inaddr.sin6_addr = in6addr_any;
2642
+ bIPv4 = 0;
26412643
}
2642
- inaddr.sin6_port = htons(iPort);
2643
- listener = socket(AF_INET6, SOCK_STREAM, 0);
2644
+ if( bIPv4 ){
2645
+ inaddr4.sin_port = htons(iPort);
2646
+ listener = socket(AF_INET, SOCK_STREAM, 0);
2647
+ }else{
2648
+ inaddr.sin6_port = htons(iPort);
2649
+ listener = socket(AF_INET6, SOCK_STREAM, 0);
2650
+ allowBothIpV4andV6(listener);
2651
+ }
26442652
if( listener<0 ){
26452653
iPort++;
26462654
continue;
26472655
}
2648
- allowBothIpV4andV6(listener);
26492656
}
26502657
26512658
/* if we can't terminate nicely, at least allow the socket to be reused */
26522659
setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
26532660
@@ -2658,10 +2665,12 @@
26582665
** created. See https://lkml.org/lkml/2004/11/1/84 and
26592666
** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */
26602667
if( g.zSockOwner ){
26612668
file_set_owner(g.zSockName, listener, g.zSockOwner);
26622669
}
2670
+ }else if( bIPv4 ){
2671
+ rc = bind(listener, (struct sockaddr*)&inaddr4, sizeof(inaddr4));
26632672
}else{
26642673
rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
26652674
}
26662675
if( rc<0 ){
26672676
close(listener);
26682677
--- src/cgi.c
+++ src/cgi.c
@@ -2568,14 +2568,16 @@
2568 socklen_t lenaddr; /* Length of the inaddr structure */
2569 int child; /* PID of the child process */
2570 int nchildren = 0; /* Number of child processes */
2571 struct timeval delay; /* How long to wait inside select() */
2572 struct sockaddr_in6 inaddr; /* The socket address */
 
2573 struct sockaddr_un uxaddr; /* The address for unix-domain sockets */
2574 int opt = 1; /* setsockopt flag */
2575 int rc; /* Result code from system calls */
2576 int iPort = mnPort; /* Port to try to use */
 
2577
2578 while( iPort<=mxPort ){
2579 if( flags & HTTP_SERVER_UNIXSOCKET ){
2580 /* Initialize a Unix socket named g.zSockName */
2581 assert( g.zSockName!=0 );
@@ -2607,47 +2609,52 @@
2607 }else{
2608 file_set_mode(g.zSockName, listener, "0660", 1);
2609 }
2610 }else{
2611 /* Initialize a TCP/IP socket on port iPort */
2612 memset(&inaddr, 0, sizeof(inaddr));
2613 inaddr.sin6_family = AF_INET6;
 
 
 
 
2614 if( zIpAddr ){
2615 /* Bind to the specific IP address given by zIpAddr[] */
2616 size_t nAddr = strlen(zIpAddr);
2617 char z4to6[30];
2618
2619 if( nAddr<16 ){
2620 /* The specified IP address might be in IPv4 notation (ex: 1.2.3.4)
2621 ** which inet_pton() does not understand. Convert in into a IPv6
2622 ** mapping of an IPv4 address: (::FFFF:1.2.3.4) */
2623 memcpy(z4to6,"::ffff:", 7);
2624 memcpy(z4to6+7, zIpAddr, nAddr+2);
2625 }else{
2626 z4to6[0] = 0;
2627 }
2628
2629 /* Convert the zIpAddr text string into an actual IPv6 address */
2630 if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0
2631 && (z4to6[0]==0 || inet_pton(AF_INET6, z4to6, &inaddr.sin6_addr)==0)
2632 ){
2633 fossil_fatal("not a valid IP address: %s", zIpAddr);
2634 }
2635 }else if( flags & HTTP_SERVER_LOCALHOST ){
2636 /* Bind to the loop-back IP address */
2637 inet_pton(AF_INET6, "::ffff.127.0.0.1", &inaddr.sin6_addr);
2638 }else{
2639 /* Bind to any and all available IP addresses */
 
 
2640 inaddr.sin6_addr = in6addr_any;
 
2641 }
2642 inaddr.sin6_port = htons(iPort);
2643 listener = socket(AF_INET6, SOCK_STREAM, 0);
 
 
 
 
 
 
2644 if( listener<0 ){
2645 iPort++;
2646 continue;
2647 }
2648 allowBothIpV4andV6(listener);
2649 }
2650
2651 /* if we can't terminate nicely, at least allow the socket to be reused */
2652 setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
2653
@@ -2658,10 +2665,12 @@
2658 ** created. See https://lkml.org/lkml/2004/11/1/84 and
2659 ** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */
2660 if( g.zSockOwner ){
2661 file_set_owner(g.zSockName, listener, g.zSockOwner);
2662 }
 
 
2663 }else{
2664 rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
2665 }
2666 if( rc<0 ){
2667 close(listener);
2668
--- src/cgi.c
+++ src/cgi.c
@@ -2568,14 +2568,16 @@
2568 socklen_t lenaddr; /* Length of the inaddr structure */
2569 int child; /* PID of the child process */
2570 int nchildren = 0; /* Number of child processes */
2571 struct timeval delay; /* How long to wait inside select() */
2572 struct sockaddr_in6 inaddr; /* The socket address */
2573 struct sockaddr_in inaddr4; /* IPv4 address; needed by OpenBSD */
2574 struct sockaddr_un uxaddr; /* The address for unix-domain sockets */
2575 int opt = 1; /* setsockopt flag */
2576 int rc; /* Result code from system calls */
2577 int iPort = mnPort; /* Port to try to use */
2578 int bIPv4 = 0; /* Use IPv4 only; use inaddr4, not inaddr */
2579
2580 while( iPort<=mxPort ){
2581 if( flags & HTTP_SERVER_UNIXSOCKET ){
2582 /* Initialize a Unix socket named g.zSockName */
2583 assert( g.zSockName!=0 );
@@ -2607,47 +2609,52 @@
2609 }else{
2610 file_set_mode(g.zSockName, listener, "0660", 1);
2611 }
2612 }else{
2613 /* Initialize a TCP/IP socket on port iPort */
2614 if( (flags & HTTP_SERVER_LOCALHOST)!=0 && zIpAddr==0 ){
2615 /* Map all loopback to 127.0.0.1, since this is the easiest way
2616 ** to support OpenBSD and its limitations without burdening
2617 ** Linux and MacOS with lots of extra code and complication. */
2618 zIpAddr = "127.0.0.1";
2619 }
2620 if( zIpAddr ){
2621 if( strchr(zIpAddr,':') ){
2622 memset(&inaddr, 0, sizeof(inaddr));
2623 inaddr.sin6_family = AF_INET6;
2624 bIPv4 = 0;
2625 if( inet_pton(AF_INET6, zIpAddr, &inaddr.sin6_addr)==0 ){
2626 fossil_fatal("not a valid IPv6 address: %s", zIpAddr);
2627 }
 
 
 
2628 }else{
2629 memset(&inaddr4, 0, sizeof(inaddr4));
2630 inaddr4.sin_family = AF_INET;
2631 bIPv4 = 1;
2632 inaddr4.sin_addr.s_addr = inet_addr(zIpAddr);
2633 if( inaddr4.sin_addr.s_addr == INADDR_NONE ){
2634 fossil_fatal("not a valid IPv4 address: %s", zIpAddr);
2635 }
2636 }
 
 
 
 
2637 }else{
2638 /* Bind to any and all available IP addresses */
2639 memset(&inaddr, 0, sizeof(inaddr));
2640 inaddr.sin6_family = AF_INET6;
2641 inaddr.sin6_addr = in6addr_any;
2642 bIPv4 = 0;
2643 }
2644 if( bIPv4 ){
2645 inaddr4.sin_port = htons(iPort);
2646 listener = socket(AF_INET, SOCK_STREAM, 0);
2647 }else{
2648 inaddr.sin6_port = htons(iPort);
2649 listener = socket(AF_INET6, SOCK_STREAM, 0);
2650 allowBothIpV4andV6(listener);
2651 }
2652 if( listener<0 ){
2653 iPort++;
2654 continue;
2655 }
 
2656 }
2657
2658 /* if we can't terminate nicely, at least allow the socket to be reused */
2659 setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
2660
@@ -2658,10 +2665,12 @@
2665 ** created. See https://lkml.org/lkml/2004/11/1/84 and
2666 ** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */
2667 if( g.zSockOwner ){
2668 file_set_owner(g.zSockName, listener, g.zSockOwner);
2669 }
2670 }else if( bIPv4 ){
2671 rc = bind(listener, (struct sockaddr*)&inaddr4, sizeof(inaddr4));
2672 }else{
2673 rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr));
2674 }
2675 if( rc<0 ){
2676 close(listener);
2677

Keyboard Shortcuts

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