X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/615cdc1fec47b39c0b272e564e5199d0060850d0..533c7491240f2fd71d026e91f0a940f4729992fd:/windows/winnet.c diff --git a/windows/winnet.c b/windows/winnet.c index 8a7580b2..f8838bec 100644 --- a/windows/winnet.c +++ b/windows/winnet.c @@ -115,7 +115,7 @@ static int cmpforsearch(void *av, void *bv) typedef rettype (WINAPI *t_##name) params; \ linkage t_##name p_##name #define GET_WINSOCK_FUNCTION(module, name) \ - p_##name = (t_##name) GetProcAddress(module, #name) + p_##name = module ? (t_##name) GetProcAddress(module, #name) : NULL DECL_WINSOCK_FUNCTION(NOTHING, int, WSAAsyncSelect, (SOCKET, HWND, u_int, long)); @@ -166,34 +166,87 @@ DECL_WINSOCK_FUNCTION(static, int, getnameinfo, (const struct sockaddr FAR * sa, socklen_t salen, char FAR * host, size_t hostlen, char FAR * serv, size_t servlen, int flags)); +DECL_WINSOCK_FUNCTION(static, char *, gai_strerror, (int ecode)); +DECL_WINSOCK_FUNCTION(static, int, WSAAddressToStringA, + (LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFO, + LPTSTR, LPDWORD)); #endif -static HMODULE winsock_module; +static HMODULE winsock_module = NULL; +static WSADATA wsadata; #ifndef NO_IPV6 -static HMODULE wship6_module; +static HMODULE winsock2_module = NULL; +static HMODULE wship6_module = NULL; #endif -void sk_init(void) +int sk_startup(int hi, int lo) { WORD winsock_ver; - WSADATA wsadata; - winsock_ver = MAKEWORD(2, 0); - winsock_module = LoadLibrary("WS2_32.DLL"); + winsock_ver = MAKEWORD(hi, lo); + + if (p_WSAStartup(winsock_ver, &wsadata)) { + return FALSE; + } + + if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) { + return FALSE; + } + +#ifdef NET_SETUP_DIAGNOSTICS + { + char buf[80]; + sprintf(buf, "Using WinSock %d.%d", hi, lo); + logevent(NULL, buf); + } +#endif + return TRUE; +} + +void sk_init(void) +{ +#ifndef NO_IPV6 + winsock2_module = +#endif + winsock_module = LoadLibrary("WS2_32.DLL"); if (!winsock_module) { winsock_module = LoadLibrary("WSOCK32.DLL"); - winsock_ver = MAKEWORD(1, 1); } if (!winsock_module) fatalbox("Unable to load any WinSock library"); #ifndef NO_IPV6 - wship6_module = LoadLibrary("wship6.dll"); - if (wship6_module) { - GET_WINSOCK_FUNCTION(wship6_module, getaddrinfo); - GET_WINSOCK_FUNCTION(wship6_module, freeaddrinfo); - GET_WINSOCK_FUNCTION(wship6_module, getnameinfo); + /* Check if we have getaddrinfo in Winsock */ + if (GetProcAddress(winsock_module, "getaddrinfo") != NULL) { +#ifdef NET_SETUP_DIAGNOSTICS + logevent(NULL, "Native WinSock IPv6 support detected"); +#endif + GET_WINSOCK_FUNCTION(winsock_module, getaddrinfo); + GET_WINSOCK_FUNCTION(winsock_module, freeaddrinfo); + GET_WINSOCK_FUNCTION(winsock_module, getnameinfo); + GET_WINSOCK_FUNCTION(winsock_module, gai_strerror); + } else { + /* Fall back to wship6.dll for Windows 2000 */ + wship6_module = LoadLibrary("wship6.dll"); + if (wship6_module) { +#ifdef NET_SETUP_DIAGNOSTICS + logevent(NULL, "WSH IPv6 support detected"); +#endif + GET_WINSOCK_FUNCTION(wship6_module, getaddrinfo); + GET_WINSOCK_FUNCTION(wship6_module, freeaddrinfo); + GET_WINSOCK_FUNCTION(wship6_module, getnameinfo); + GET_WINSOCK_FUNCTION(wship6_module, gai_strerror); + } else { +#ifdef NET_SETUP_DIAGNOSTICS + logevent(NULL, "No IPv6 support detected"); +#endif + } } + GET_WINSOCK_FUNCTION(winsock2_module, WSAAddressToStringA); +#else +#ifdef NET_SETUP_DIAGNOSTICS + logevent(NULL, "PuTTY was built without IPv6 support"); +#endif #endif GET_WINSOCK_FUNCTION(winsock_module, WSAAsyncSelect); @@ -223,14 +276,12 @@ void sk_init(void) GET_WINSOCK_FUNCTION(winsock_module, recv); GET_WINSOCK_FUNCTION(winsock_module, WSAIoctl); - if (p_WSAStartup(winsock_ver, &wsadata)) { + /* Try to get the best WinSock version we can get */ + if (!sk_startup(2,2) && + !sk_startup(2,0) && + !sk_startup(1,1)) { fatalbox("Unable to initialise WinSock"); } - if (LOBYTE(wsadata.wVersion) != LOBYTE(winsock_ver)) { - p_WSACleanup(); - fatalbox("WinSock version is incompatible with %d.%d", - LOBYTE(winsock_ver), HIBYTE(winsock_ver)); - } sktree = newtree234(cmpfortree); } @@ -356,6 +407,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, #ifndef NO_IPV6 ret->ai = ret->ais = NULL; #endif + ret->addresses = NULL; ret_family = AF_UNSPEC; *realhost = '\0'; @@ -366,14 +418,21 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, */ if (p_getaddrinfo) { struct addrinfo hints; +#ifdef NET_SETUP_DIAGNOSTICS + logevent(NULL, "Using getaddrinfo() for resolving"); +#endif memset(&hints, 0, sizeof(hints)); hints.ai_family = ret->family; + hints.ai_flags = AI_CANONNAME; if ((err = p_getaddrinfo(host, NULL, &hints, &ret->ais)) == 0) ret_family = ret->ais->ai_family; ret->ai = ret->ais; } else #endif { +#ifdef NET_SETUP_DIAGNOSTICS + logevent(NULL, "Using gethostbyname() for resolving"); +#endif /* * Otherwise use the IPv4-only gethostbyname... * (NOTE: we don't use gethostbyname as a fallback!) @@ -389,7 +448,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, err == WSAHOST_NOT_FOUND ? "Host does not exist" : err == WSATRY_AGAIN ? "Host not found" : #ifndef NO_IPV6 - p_getaddrinfo ? "getaddrinfo: unknown error" : + p_getaddrinfo&&p_gai_strerror ? p_gai_strerror(err) : #endif "gethostbyname: unknown error"); } else { @@ -406,17 +465,10 @@ SockAddr sk_namelookup(const char *host, char **canonicalname, (char *) &((SOCKADDR_IN *) ret->ai-> ai_addr)->sin_addr, sizeof(a)); - /* Now let's find that canonicalname... */ - if (p_getnameinfo) { - if (p_getnameinfo - ((struct sockaddr *) ret->ai->ai_addr, - ret->family == - AF_INET ? sizeof(SOCKADDR_IN) : - sizeof(SOCKADDR_IN6), realhost, - sizeof(realhost), NULL, 0, 0) != 0) { - strncpy(realhost, host, sizeof(realhost)); - } - } + if (ret->ai->ai_canonname) + strncpy(realhost, ret->ai->ai_canonname, lenof(realhost)); + else + strncpy(realhost, host, lenof(realhost)); } /* We used the IPv4-only gethostbyname()... */ else @@ -462,6 +514,7 @@ SockAddr sk_nonamelookup(const char *host) #ifndef NO_IPV6 ret->ai = ret->ais = NULL; #endif + ret->addresses = NULL; ret->naddresses = 0; strncpy(ret->hostname, host, lenof(ret->hostname)); ret->hostname[lenof(ret->hostname)-1] = '\0'; @@ -492,28 +545,11 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen) { #ifndef NO_IPV6 if (addr->ai) { - /* Try to get the WSAAddressToStringA() function from wship6.dll */ - /* This way one doesn't need to have IPv6 dll's to use PuTTY and - * it will fallback to IPv4. */ - typedef int (CALLBACK * FADDRTOSTR) (LPSOCKADDR lpsaAddress, - DWORD dwAddressLength, - LPWSAPROTOCOL_INFO lpProtocolInfo, - OUT LPTSTR lpszAddressString, - IN OUT LPDWORD lpdwAddressStringLength - ); - FADDRTOSTR fAddrToStr = NULL; - - HINSTANCE dllWS2 = LoadLibrary("ws2_32.dll"); - if (dllWS2) { - fAddrToStr = (FADDRTOSTR)GetProcAddress(dllWS2, - "WSAAddressToStringA"); - if (fAddrToStr) { - fAddrToStr(addr->ai->ai_addr, addr->ai->ai_addrlen, - NULL, buf, &buflen); - } - else strncpy(buf, "IPv6", buflen); - FreeLibrary(dllWS2); - } + if (p_WSAAddressToStringA) { + p_WSAAddressToStringA(addr->ai->ai_addr, addr->ai->ai_addrlen, + NULL, buf, &buflen); + } else + strncpy(buf, "IPv6", buflen); } else #endif if (addr->family == AF_INET) { @@ -572,10 +608,18 @@ int sk_address_is_local(SockAddr addr) } else #endif if (addr->family == AF_INET) { - struct in_addr a; - assert(addr->addresses && addr->curraddr < addr->naddresses); - a.s_addr = p_htonl(addr->addresses[addr->curraddr]); - return ipv4_is_local_addr(a); +#ifndef NO_IPV6 + if (addr->ai) { + return ipv4_is_local_addr(((struct sockaddr_in *)addr->ai->ai_addr) + ->sin_addr); + } else +#endif + { + struct in_addr a; + assert(addr->addresses && addr->curraddr < addr->naddresses); + a.s_addr = p_htonl(addr->addresses[addr->curraddr]); + return ipv4_is_local_addr(a); + } } else { assert(addr->family == AF_UNSPEC); return 0; /* we don't know; assume not */ @@ -833,6 +877,8 @@ static DWORD try_connect(Actual_Socket sock) a6.sin6_port = p_htons((short) sock->port); a6.sin6_addr = ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_addr; + a6.sin6_flowinfo = ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_flowinfo; + a6.sin6_scope_id = ((struct sockaddr_in6 *) sock->addr->ai->ai_addr)->sin6_scope_id; } else { a.sin_family = AF_INET; a.sin_addr =