From: Amos Jeffries Date: Thu, 8 May 2008 03:47:53 +0000 (+1200) Subject: Bug 2222 part 2: ipv4 client trying to view an ipv6 website crashes FreeBSD squid X-Git-Tag: SQUID_3_1_0_1~49^2~253 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9d92af86a056437fc92c13b968f9beaa0a09aede;p=thirdparty%2Fsquid.git Bug 2222 part 2: ipv4 client trying to view an ipv6 website crashes FreeBSD squid This one: - omits the v6-specific socket options on new addrinfo - correctly counts the failed connection - Resets the socket when a protocol error is found - retries without any delay --- diff --git a/lib/IPAddress.cc b/lib/IPAddress.cc index 4dea87589b..1b5deaf721 100644 --- a/lib/IPAddress.cc +++ b/lib/IPAddress.cc @@ -833,7 +833,21 @@ void IPAddress::GetAddrInfo(struct addrinfo *&dst, int force) const dst->ai_addrlen = sizeof(struct sockaddr_in6); dst->ai_family = ((struct sockaddr_in6*)dst->ai_addr)->sin6_family; + +#if 0 + /** + * Enable only if you must and please report to squid-dev if you find a need for this. + * + * Vista may need this to cope with dual-stack (unsetting IP6_V6ONLY). + * http://msdn.microsoft.com/en-us/library/ms738574(VS.85).aspx + * Linux appears to only do some things when its present. + * (93) Bad Protocol + * FreeBSD dies horribly when using dual-stack with it set. + * (43) Protocol not supported + */ dst->ai_protocol = IPPROTO_IPV6; +#endif + } else #endif if( force == AF_INET || (force == AF_UNSPEC && IsIPv4()) ) diff --git a/src/comm.cc b/src/comm.cc index 87de2530ed..9d227a6270 100644 --- a/src/comm.cc +++ b/src/comm.cc @@ -927,6 +927,7 @@ ConnectStateData::commResetFD() { struct addrinfo *AI = NULL; IPAddress nul; + int new_family = AF_UNSPEC; // XXX: do we have to check this? // @@ -936,7 +937,9 @@ ConnectStateData::commResetFD() statCounter.syscalls.sock.sockets++; /* setup a bare-bones addrinfo */ + /* TODO INET6: for WinXP we may need to check the local_addr type and setup the family properly. */ nul.GetAddrInfo(AI); + new_family = AI->ai_family; int fd2 = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol); @@ -973,6 +976,10 @@ ConnectStateData::commResetFD() close(fd2); fde *F = &fd_table[fd]; + + /* INET6: copy the new sockets family type to the FDE table */ + fd_table[fd].sock_family = new_family; + fd_table[fd].flags.called_connect = 0; /* * yuck, this has assumptions about comm_open() arguments for @@ -1067,6 +1074,16 @@ ConnectStateData::connect() callCallback(COMM_OK, 0); break; +#if USE_IPV6 + case COMM_ERR_PROTOCOL: + /* problem using the desired protocol over this socket. + * count the connection attempt, reset the socket, and immediately try again */ + tries++; + commResetFD(); + connect(); + break; +#endif + default: debugs(5, 5, HERE "FD " << fd << ": * - try again"); tries++; @@ -1165,7 +1182,19 @@ comm_connect_addr(int sock, const IPAddress &address) debugs(5, 9, "comm_connect_addr: connecting socket " << sock << " to " << address << " (want family: " << F->sock_family << ")"); - /* FIXME INET6 : Bug 2222: when sock is an IPv4-only socket IPv6 traffic will crash. */ + /* BUG 2222 FIX: reset the FD when its found to be IPv4 in IPv6 mode */ + /* inverse case of IPv4 failing to connect on IPv6 socket is handeld post-connect. + * this case must presently be handled here since the GetAddrInfo asserts on bad mappings. + * eventually we want it to throw a Must() that gets handled there instead of this if. + * NP: because commresetFD is private to ConnStateData we have to return an error and + * trust its handled properly. + */ +#if USE_IPV6 + if(F->sock_family == AF_INET && !address.IsIPv4()) { + return COMM_ERR_PROTOCOL; + } +#endif + address.GetAddrInfo(AI, F->sock_family); /* Establish connection. */ diff --git a/src/comm.h b/src/comm.h index b87df719b9..d1c249efcc 100644 --- a/src/comm.h +++ b/src/comm.h @@ -22,6 +22,9 @@ typedef enum { COMM_ERR_CONNECT = -8, COMM_ERR_DNS = -9, COMM_ERR_CLOSING = -10, +#if USE_IPV6 + COMM_ERR_PROTOCOL = -11, /* IPv4 or IPv6 cannot be used on the fd socket */ +#endif } comm_err_t; typedef void CNCB(int fd, comm_err_t status, int xerrno, void *data);