From d1aa0ef962746642ab352cabdbfeaf12fd01228d Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Sun, 1 Aug 2010 07:29:09 -0600 Subject: [PATCH] Bug 2994: Basic split-stack functionality Enable split-stack detection by default. There is now enough split-stack support to enable accepting IPv6 client connections on systems with separate IPv4/IPv6 stacks. Also some limited server connection capabilities (see tcp_outgoing_addr config hacks). SNMP, ICP, HTCP listeners and outbound connections currently default to IPv4-only on these systems to retain backward-compatibility. But may be explicity configured to IPv6-only. There is no support as yet for dual-protocol behaviour in the sockets of these three protocols. --- src/forward.cc | 19 +++++++++++++++++++ src/htcp.cc | 19 +++++++++++++++++++ src/icp_v2.cc | 21 +++++++++++++++++++++ src/ip/tools.cc | 4 +--- src/snmp_core.cc | 22 ++++++++++++++++++++++ 5 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/forward.cc b/src/forward.cc index 92c6c55886..2559b1aab2 100644 --- a/src/forward.cc +++ b/src/forward.cc @@ -47,6 +47,7 @@ #include "Store.h" #include "icmp/net_db.h" #include "ip/IpIntercept.h" +#include "ip/tools.h" static PSC fwdStartCompleteWrapper; static PF fwdServerClosedWrapper; @@ -867,6 +868,24 @@ FwdState::connectStart() outgoing = getOutgoingAddr(request, fs->_peer); + // if IPv6 is disabled try to force IPv4-only outgoing. + if (!Ip::EnableIpv6 && !outgoing.SetIPv4()) { + debugs(50, 4, "fwdConnectStart: " << xstrerror()); + ErrorState *anErr = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request); + anErr->xerrno = errno; + fail(anErr); + self = NULL; // refcounted + return; + } + + // if IPv6 is split-stack, prefer IPv4 + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK) { + // NP: This is not a great choice of default, + // but with the current Internet being IPv4-majority has a higher success rate. + // if setting to IPv4 fails we dont care, that just means to use IPv6 outgoing. + outgoing.SetIPv4(); + } + tos = getOutgoingTOS(request); debugs(17, 3, "fwdConnectStart: got outgoing addr " << outgoing << ", tos " << tos); diff --git a/src/htcp.cc b/src/htcp.cc index 900110c33a..93ff7e9338 100644 --- a/src/htcp.cc +++ b/src/htcp.cc @@ -37,6 +37,7 @@ #include "htcp.h" #include "acl/FilledChecklist.h" #include "acl/Acl.h" +#include "ip/tools.h" #include "SquidTime.h" #include "Store.h" #include "StoreClient.h" @@ -1493,6 +1494,15 @@ htcpInit(void) IpAddress incomingAddr = Config.Addrs.udp_incoming; incomingAddr.SetPort(Config.Port.htcp); + if (!Ip::EnableIpv6 && !incomingAddr.SetIPv4()) { + debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << incomingAddr << " is not an IPv4 address."); + fatal("HTCP port cannot be opened."); + } + /* split-stack for now requires default IPv4-only HTCP */ + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && incomingAddr.IsAnyAddr()) { + incomingAddr.SetIPv4(); + } + enter_suid(); htcpInSocket = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, @@ -1512,6 +1522,15 @@ htcpInit(void) IpAddress outgoingAddr = Config.Addrs.udp_outgoing; outgoingAddr.SetPort(Config.Port.htcp); + if (!Ip::EnableIpv6 && !outgoingAddr.SetIPv4()) { + debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << outgoingAddr << " is not an IPv4 address."); + fatal("HTCP port cannot be opened."); + } + /* split-stack for now requires default IPv4-only HTCP */ + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && outgoingAddr.IsAnyAddr()) { + outgoingAddr.SetIPv4(); + } + enter_suid(); htcpOutSocket = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, diff --git a/src/icp_v2.cc b/src/icp_v2.cc index cbfed7a359..bb8143bece 100644 --- a/src/icp_v2.cc +++ b/src/icp_v2.cc @@ -48,6 +48,7 @@ #include "SwapDir.h" #include "icmp/net_db.h" #include "ip/IpAddress.h" +#include "ip/tools.h" #include "rfc1738.h" /// \ingroup ServerProtocolICPInternal2 @@ -665,6 +666,16 @@ icpConnectionsOpen(void) addr = Config.Addrs.udp_incoming; addr.SetPort(port); + + if (!Ip::EnableIpv6 && !addr.SetIPv4()) { + debugs(12, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << addr << " is not an IPv4 address."); + fatal("ICP port cannot be opened."); + } + /* split-stack for now requires default IPv4-only ICP */ + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && addr.IsAnyAddr()) { + addr.SetIPv4(); + } + theInIcpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, addr, @@ -691,6 +702,16 @@ icpConnectionsOpen(void) if ( !addr.IsNoAddr() ) { enter_suid(); addr.SetPort(port); + + if (!Ip::EnableIpv6 && !addr.SetIPv4()) { + debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << addr << " is not an IPv4 address."); + fatal("ICP port cannot be opened."); + } + /* split-stack for now requires default IPv4-only ICP */ + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && addr.IsAnyAddr()) { + addr.SetIPv4(); + } + theOutIcpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, addr, diff --git a/src/ip/tools.cc b/src/ip/tools.cc index 2c4daa19b4..d8ddf51efe 100644 --- a/src/ip/tools.cc +++ b/src/ip/tools.cc @@ -65,9 +65,7 @@ Ip::ProbeTransport() EnableIpv6 |= IPV6_SPECIAL_V4MAPPING; } else { debugs(3, 2, "Detected split IPv4 and IPv6 stacks ..."); - // EnableIpv6 |= IPV6_SPECIAL_SPLITSTACK; - // TODO: remove death when split-stack is supported. - EnableIpv6 = IPV6_OFF; + EnableIpv6 |= IPV6_SPECIAL_SPLITSTACK; } close(s); diff --git a/src/snmp_core.cc b/src/snmp_core.cc index 4fec167c6c..b491342073 100644 --- a/src/snmp_core.cc +++ b/src/snmp_core.cc @@ -286,6 +286,17 @@ snmpConnectionOpen(void) if (Config.Port.snmp > 0) { Config.Addrs.snmp_incoming.SetPort(Config.Port.snmp); + + if (!Ip::EnableIpv6 && !Config.Addrs.snmp_incoming.SetIPv4()) { + debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << Config.Addrs.snmp_incoming << " is not an IPv4 address."); + fatal("SNMP port cannot be opened."); + } + + /* split-stack for now requires IPv4-only SNMP */ + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && Config.Addrs.snmp_incoming.IsAnyAddr()) { + Config.Addrs.snmp_incoming.SetIPv4(); + } + enter_suid(); theInSnmpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, @@ -303,6 +314,17 @@ snmpConnectionOpen(void) if (!Config.Addrs.snmp_outgoing.IsNoAddr()) { Config.Addrs.snmp_outgoing.SetPort(Config.Port.snmp); + + if (!Ip::EnableIpv6 && !Config.Addrs.snmp_outgoing.SetIPv4()) { + debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << Config.Addrs.snmp_outgoing << " is not an IPv4 address."); + fatal("SNMP port cannot be opened."); + } + + /* split-stack for now requires IPv4-only SNMP */ + if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && Config.Addrs.snmp_outgoing.IsAnyAddr()) { + Config.Addrs.snmp_outgoing.SetIPv4(); + } + enter_suid(); theOutSnmpConnection = comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, -- 2.47.3