From: Nick Mathewson Date: Wed, 21 Apr 2010 15:57:55 +0000 (-0400) Subject: Fix getaddrinfo with protocol unset on Solaris 9. Found by Dagobert Michelsen X-Git-Tag: release-2.0.5-beta~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2cf2a286e42356601514d754acbcefc3cf0b23ad;p=libevent Fix getaddrinfo with protocol unset on Solaris 9. Found by Dagobert Michelsen Apparently when you call Solaris 9's getaddrinfo(), it likes to leave ai_protocol unset in the result. This is no way to behave, if I'm reading RFC3493 right. This patch makes us check for a getaddrinfo() that's broken in this way, and work around it by trying to infer socktype and protocol from one another. Partial bugfix for 2987542 --- diff --git a/evutil.c b/evutil.c index af5b069a..5fc90a86 100644 --- a/evutil.c +++ b/evutil.c @@ -959,6 +959,10 @@ evutil_adjust_hints_for_addrconfig(struct evutil_addrinfo *hints) } #ifdef USE_NATIVE_GETADDRINFO +static int need_numeric_port_hack_=0; +static int need_socktype_protocol_hack_=0; +static int tested_for_getaddrinfo_hacks=0; + /* Some older BSDs (like OpenBSD up to 4.6) used to believe that giving a numeric port without giving an ai_socktype was verboten. We test for this so we can apply an appropriate workaround. If it @@ -973,17 +977,17 @@ evutil_adjust_hints_for_addrconfig(struct evutil_addrinfo *hints) We test for this bug at runtime, since otherwise we can't have the same binary run on multiple BSD versions. + + - Some versions of Solaris believe that it's nice to leave to protocol + field set to 0. We test for this so we can apply an appropriate + workaround. */ -static int -need_numeric_port_hack(void) +static void +test_for_getaddrinfo_hacks(void) { - static int tested=0; - static int need_hack=0; int r, r2; struct evutil_addrinfo *ai=NULL, *ai2=NULL; struct evutil_addrinfo hints; - if (tested) - return need_hack; memset(&hints,0,sizeof(hints)); hints.ai_family = PF_UNSPEC; @@ -999,21 +1003,40 @@ need_numeric_port_hack(void) hints.ai_socktype = SOCK_STREAM; r2 = getaddrinfo("1.2.3.4", "80", &hints, &ai2); if (r2 == 0 && r != 0) { - need_hack=1; + need_numeric_port_hack_=1; } + if (ai2 && ai2->ai_protocol == 0) { + need_socktype_protocol_hack_=1; + } + if (ai) freeaddrinfo(ai); if (ai2) freeaddrinfo(ai2); - tested = 1; - return need_hack; + tested_for_getaddrinfo_hacks=1; +} + +static inline int +need_numeric_port_hack(void) +{ + if (!tested_for_getaddrinfo_hacks) + test_for_getaddrinfo_hacks(); + return need_numeric_port_hack_; +} + +static inline int +need_socktype_protocol_hack(void) +{ + if (!tested_for_getaddrinfo_hacks) + test_for_getaddrinfo_hacks(); + return need_socktype_protocol_hack_; } static void apply_numeric_port_hack(int port, struct evutil_addrinfo **ai) { /* Now we run through the list and set the ports on all of the - * results where ports */ + * results where ports would make sense. */ for ( ; *ai; ai = &(*ai)->ai_next) { struct sockaddr *sa = (*ai)->ai_addr; if (sa && sa->sa_family == AF_INET) { @@ -1100,6 +1123,10 @@ evutil_getaddrinfo(const char *nodename, const char *servname, servname = NULL; } + if (need_socktype_protocol_hack()) { + evutil_getaddrinfo_infer_protocols(&hints); + } + /* Make sure that we didn't actually steal any AI_FLAGS values that * the system is using. (This is a constant expression, and should ge * optimized out.) @@ -1115,6 +1142,12 @@ evutil_getaddrinfo(const char *nodename, const char *servname, err = getaddrinfo(nodename, servname, &hints, res); if (need_np_hack) apply_numeric_port_hack(portnum, res); + + if (need_socktype_protocol_hack()) { + struct evutil_addrinfo *ai; + for (ai = *res; ai; ai = ai->ai_next) + evutil_getaddrinfo_infer_protocols(ai); + } return err; #else int port=0, err;