From: Amos Jeffries Date: Sun, 12 Apr 2009 13:44:59 +0000 (+1200) Subject: Bug 2571: Squid with IPv6 fails to start on kernel without IPv6 X-Git-Tag: SQUID_3_2_0_1~1063 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=31be869;p=thirdparty%2Fsquid.git Bug 2571: Squid with IPv6 fails to start on kernel without IPv6 Adds comm_open_listener() wrapper to perform IPv6/IPv4 failover on sockets intended for listening only. Uses the wrapper in all places I can be sure of. Open a port specially bound for listening or sending through a specific port. This is a wrapper providing IPv4/IPv6 failover around comm_openex(). Please use for all listening sockets and bind() outbound sockets. It will open a socket bound for: - IPv4 if IPv6 is disabled or address is IPv4-native. - IPv6 if address is IPv6-native - IPv6 dual-stack mode if able to open [::] When an open performs failover it update the given address to feedback the new IPv4-only status of the socket. Further displays of the IP (in debugs or cachemgr) will occur in Native IPv4 format. A reconfigure is needed to reset the stored IP in most cases and attempt a port re-open. --- diff --git a/src/client_side.cc b/src/client_side.cc index e9bb5fd1a1..0d212f52db 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -3171,9 +3171,9 @@ clientHttpConnectionsOpen(void) enter_suid(); if (s->spoof_client_ip) { - fd = comm_openex(SOCK_STREAM, IPPROTO_TCP, s->s, (COMM_NONBLOCKING|COMM_TRANSPARENT), 0, "HTTP Socket"); + fd = comm_open_listener(SOCK_STREAM, IPPROTO_TCP, s->s, (COMM_NONBLOCKING|COMM_TRANSPARENT), "HTTP Socket"); } else { - fd = comm_open(SOCK_STREAM, IPPROTO_TCP, s->s, COMM_NONBLOCKING, "HTTP Socket"); + fd = comm_open_listener(SOCK_STREAM, IPPROTO_TCP, s->s, COMM_NONBLOCKING, "HTTP Socket"); } leave_suid(); @@ -3225,7 +3225,7 @@ clientHttpsConnectionsOpen(void) } enter_suid(); - fd = comm_open(SOCK_STREAM, + fd = comm_open_listener(SOCK_STREAM, IPPROTO_TCP, s->http.s, COMM_NONBLOCKING, "HTTPS Socket"); diff --git a/src/comm.cc b/src/comm.cc index d0529ba5d0..949a6d46ae 100644 --- a/src/comm.cc +++ b/src/comm.cc @@ -611,6 +611,31 @@ comm_open(int sock_type, return comm_openex(sock_type, proto, addr, flags, 0, note); } +int +comm_open_listener(int sock_type, + int proto, + IpAddress &addr, + int flags, + const char *note) +{ + int sock = -1; + + /* attempt native enabled port. */ + sock = comm_openex(sock_type, proto, addr, flags, 0, note); + +#if USE_IPV6 + /* under IPv6 there is the possibility IPv6 is present but disabled. */ + /* try again as IPv4-native */ + if ( sock < 0 && addr.IsIPv6() && addr.SetIPv4() ) { + /* attempt to open this IPv4-only. */ + sock = comm_openex(sock_type, proto, addr, flags, 0, note); + debugs(50, 2, HERE << "attempt open " << note << " socket on: " << addr); + } +#endif + + return sock; +} + static bool limitError(int const anErrno) { diff --git a/src/comm.h b/src/comm.h index a44938e2df..730fba81e4 100644 --- a/src/comm.h +++ b/src/comm.h @@ -55,6 +55,23 @@ SQUIDCEXTERN void comm_exit(void); SQUIDCEXTERN int comm_open(int, int, IpAddress &, int, const char *note); +/** + * Open a port specially bound for listening or sending through a specific port. + * This is a wrapper providing IPv4/IPv6 failover around comm_openex(). + * Please use for all listening sockets and bind() outbound sockets. + * + * It will open a socket bound for: + * - IPv4 if IPv6 is disabled or address is IPv4-native. + * - IPv6 if address is IPv6-native + * - IPv6 dual-stack mode if able to open [::] + * + * When an open performs failover it update the given address to feedback + * the new IPv4-only status of the socket. Further displays of the IP + * (in debugs or cachemgr) will occur in Native IPv4 format. + * A reconfigure is needed to reset the stored IP in most cases and attempt a port re-open. + */ +SQUIDCEXTERN int comm_open_listener(int sock_type, int proto, IpAddress &addr, int flags, const char *note); + SQUIDCEXTERN int comm_openex(int, int, IpAddress &, int, unsigned char TOS, const char *); SQUIDCEXTERN u_short comm_local_port(int fd); SQUIDCEXTERN int comm_set_tos(int fd, int tos); diff --git a/src/dns_internal.cc b/src/dns_internal.cc index 91afc58357..a6ea91e480 100644 --- a/src/dns_internal.cc +++ b/src/dns_internal.cc @@ -1345,34 +1345,20 @@ idnsInit(void) if (DnsSocket < 0) { int port; - IpAddress addr; + IpAddress addr; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own. if (!Config.Addrs.udp_outgoing.IsNoAddr()) addr = Config.Addrs.udp_outgoing; else addr = Config.Addrs.udp_incoming; - DnsSocket = comm_open(SOCK_DGRAM, + debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addr); + DnsSocket = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, addr, COMM_NONBLOCKING, "DNS Socket"); - debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addr); - -#if USE_IPV6 - if ( DnsSocket < 0 && addr.IsIPv6() && addr.SetIPv4() ) { - /* attempt to open this IPv4-only. */ - DnsSocket = comm_open(SOCK_DGRAM, - IPPROTO_UDP, - addr, - COMM_NONBLOCKING, - "DNS Socket"); - - debugs(78, 2, "idnsInit: attempt open DNS socket to: " << addr); - } -#endif - if (DnsSocket < 0) fatal("Could not create a DNS socket"); diff --git a/src/htcp.cc b/src/htcp.cc index ab1efb581c..8e16c6716f 100644 --- a/src/htcp.cc +++ b/src/htcp.cc @@ -1474,7 +1474,7 @@ htcpInit(void) incomingAddr.SetPort(Config.Port.htcp); enter_suid(); - htcpInSocket = comm_open(SOCK_DGRAM, + htcpInSocket = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, incomingAddr, COMM_NONBLOCKING, @@ -1493,7 +1493,7 @@ htcpInit(void) outgoingAddr.SetPort(Config.Port.htcp); enter_suid(); - htcpOutSocket = comm_open(SOCK_DGRAM, + htcpOutSocket = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, outgoingAddr, COMM_NONBLOCKING, diff --git a/src/icp_v2.cc b/src/icp_v2.cc index 350c8f68f8..e41c78594c 100644 --- a/src/icp_v2.cc +++ b/src/icp_v2.cc @@ -664,7 +664,7 @@ icpConnectionsOpen(void) addr = Config.Addrs.udp_incoming; addr.SetPort(port); - theInIcpConnection = comm_open(SOCK_DGRAM, + theInIcpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, addr, COMM_NONBLOCKING, @@ -690,7 +690,7 @@ icpConnectionsOpen(void) if ( !addr.IsNoAddr() ) { enter_suid(); addr.SetPort(port); - theOutIcpConnection = comm_open(SOCK_DGRAM, + theOutIcpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, addr, COMM_NONBLOCKING, diff --git a/src/ident.cc b/src/ident.cc index dad1a5daf1..f8d942344d 100644 --- a/src/ident.cc +++ b/src/ident.cc @@ -220,7 +220,7 @@ identStart(IpAddress &me, IpAddress &my_peer, IDCB * callback, void *data) return; } - fd = comm_open(SOCK_STREAM, + fd = comm_open_listener(SOCK_STREAM, IPPROTO_TCP, me, COMM_NONBLOCKING, diff --git a/src/snmp_core.cc b/src/snmp_core.cc index e46cd49504..ebff872735 100644 --- a/src/snmp_core.cc +++ b/src/snmp_core.cc @@ -365,7 +365,7 @@ snmpConnectionOpen(void) if (Config.Port.snmp > 0) { Config.Addrs.snmp_incoming.SetPort(Config.Port.snmp); enter_suid(); - theInSnmpConnection = comm_open(SOCK_DGRAM, + theInSnmpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, Config.Addrs.snmp_incoming, COMM_NONBLOCKING, @@ -373,7 +373,7 @@ snmpConnectionOpen(void) leave_suid(); if (theInSnmpConnection < 0) - fatal("Cannot open snmp Port"); + fatal("Cannot open SNMP Port"); commSetSelect(theInSnmpConnection, COMM_SELECT_READ, snmpHandleUdp, NULL, 0); @@ -382,7 +382,7 @@ snmpConnectionOpen(void) if (!Config.Addrs.snmp_outgoing.IsNoAddr()) { Config.Addrs.snmp_outgoing.SetPort(Config.Port.snmp); enter_suid(); - theOutSnmpConnection = comm_open(SOCK_DGRAM, + theOutSnmpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, Config.Addrs.snmp_outgoing, COMM_NONBLOCKING, diff --git a/src/wccp.cc b/src/wccp.cc index b24b371aa9..6b99312640 100644 --- a/src/wccp.cc +++ b/src/wccp.cc @@ -147,7 +147,7 @@ wccpConnectionOpen(void) Config.Wccp.address.SetPort(WCCP_PORT); - theWccpConnection = comm_open(SOCK_DGRAM, + theWccpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, Config.Wccp.address, COMM_NONBLOCKING, diff --git a/src/wccp2.cc b/src/wccp2.cc index 8acc052ede..7d5f66cc4f 100644 --- a/src/wccp2.cc +++ b/src/wccp2.cc @@ -995,7 +995,7 @@ wccp2ConnectionOpen(void) } Config.Wccp2.address.SetPort(WCCP_PORT); - theWccp2Connection = comm_open(SOCK_DGRAM, + theWccp2Connection = comm_open_listener(SOCK_DGRAM, 0, Config.Wccp2.address, COMM_NONBLOCKING,