Fossil SCM
Rework server sockets to work around limitations in OpenBSD's socket implementation. See [forum:/forumpost/7f8d2afe4d8c0ad5|forum thread 7f8d2afe4d8c0ad5].
Commit
8dd05c52f5fac7a84b2f162e6de0b66e9e33378550ebf258abb4c0dd21173158
Parent
b9f569b2c906ce2…
1 file changed
+36
-27
+36
-27
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -2568,14 +2568,16 @@ | ||
| 2568 | 2568 | socklen_t lenaddr; /* Length of the inaddr structure */ |
| 2569 | 2569 | int child; /* PID of the child process */ |
| 2570 | 2570 | int nchildren = 0; /* Number of child processes */ |
| 2571 | 2571 | struct timeval delay; /* How long to wait inside select() */ |
| 2572 | 2572 | struct sockaddr_in6 inaddr; /* The socket address */ |
| 2573 | + struct sockaddr_in inaddr4; /* IPv4 address; needed by OpenBSD */ | |
| 2573 | 2574 | struct sockaddr_un uxaddr; /* The address for unix-domain sockets */ |
| 2574 | 2575 | int opt = 1; /* setsockopt flag */ |
| 2575 | 2576 | int rc; /* Result code from system calls */ |
| 2576 | 2577 | int iPort = mnPort; /* Port to try to use */ |
| 2578 | + int bIPv4 = 0; /* Use IPv4 only; use inaddr4, not inaddr */ | |
| 2577 | 2579 | |
| 2578 | 2580 | while( iPort<=mxPort ){ |
| 2579 | 2581 | if( flags & HTTP_SERVER_UNIXSOCKET ){ |
| 2580 | 2582 | /* Initialize a Unix socket named g.zSockName */ |
| 2581 | 2583 | assert( g.zSockName!=0 ); |
| @@ -2607,47 +2609,52 @@ | ||
| 2607 | 2609 | }else{ |
| 2608 | 2610 | file_set_mode(g.zSockName, listener, "0660", 1); |
| 2609 | 2611 | } |
| 2610 | 2612 | }else{ |
| 2611 | 2613 | /* 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 | + } | |
| 2614 | 2620 | 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 | + } | |
| 2625 | 2628 | }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 | + } | |
| 2638 | 2637 | }else{ |
| 2639 | 2638 | /* Bind to any and all available IP addresses */ |
| 2639 | + memset(&inaddr, 0, sizeof(inaddr)); | |
| 2640 | + inaddr.sin6_family = AF_INET6; | |
| 2640 | 2641 | inaddr.sin6_addr = in6addr_any; |
| 2642 | + bIPv4 = 0; | |
| 2641 | 2643 | } |
| 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 | + } | |
| 2644 | 2652 | if( listener<0 ){ |
| 2645 | 2653 | iPort++; |
| 2646 | 2654 | continue; |
| 2647 | 2655 | } |
| 2648 | - allowBothIpV4andV6(listener); | |
| 2649 | 2656 | } |
| 2650 | 2657 | |
| 2651 | 2658 | /* if we can't terminate nicely, at least allow the socket to be reused */ |
| 2652 | 2659 | setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt)); |
| 2653 | 2660 | |
| @@ -2658,10 +2665,12 @@ | ||
| 2658 | 2665 | ** created. See https://lkml.org/lkml/2004/11/1/84 and |
| 2659 | 2666 | ** https://fossil-scm.org/forum/forumpost/7517680ef9684c57 */ |
| 2660 | 2667 | if( g.zSockOwner ){ |
| 2661 | 2668 | file_set_owner(g.zSockName, listener, g.zSockOwner); |
| 2662 | 2669 | } |
| 2670 | + }else if( bIPv4 ){ | |
| 2671 | + rc = bind(listener, (struct sockaddr*)&inaddr4, sizeof(inaddr4)); | |
| 2663 | 2672 | }else{ |
| 2664 | 2673 | rc = bind(listener, (struct sockaddr*)&inaddr, sizeof(inaddr)); |
| 2665 | 2674 | } |
| 2666 | 2675 | if( rc<0 ){ |
| 2667 | 2676 | close(listener); |
| 2668 | 2677 |
| --- 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 |