1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-01 03:22:48 -05:00

Integrate unfix.org's IPv6 patches up to level 10, with rather a lot

of polishing to bring them to what I think should in principle be
release quality. Unlike the unfix.org patches themselves, this
checkin enables IPv6 by default; if you want to leave it out, you
have to build with COMPAT=-DNO_IPV6.

I have tested that this compiles on Visual C 7 (so the nightlies
_should_ acquire IPv6 support without missing a beat), but since I
don't have IPv6 set up myself I haven't actually tested that it
_works_. It still seems to make correct IPv4 connections, but that's
all I've been able to verify for myself. Further testing is needed.

[originally from svn r5047]
[this svn revision also touched putty-wishlist]
This commit is contained in:
Simon Tatham
2004-12-30 16:45:11 +00:00
parent 7573f3733f
commit 6daf6faede
30 changed files with 583 additions and 309 deletions

View File

@ -49,7 +49,7 @@ BEGIN
END
/* Accelerators used: aco */
IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 280, 252
IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 300, 252
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "PuTTY Configuration"
FONT 8, "MS Shell Dlg"

View File

@ -300,7 +300,7 @@ static void create_controls(HWND hwnd, char *path)
* Otherwise, we're creating the controls for a particular
* panel.
*/
ctlposinit(&cp, hwnd, 80, 3, 13);
ctlposinit(&cp, hwnd, 100, 3, 13);
wc = &ctrls_panel;
base_id = IDCX_PANELBASE;
}
@ -361,7 +361,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
HWND tvstatic;
r.left = 3;
r.right = r.left + 75;
r.right = r.left + 95;
r.top = 3;
r.bottom = r.top + 10;
MapDialogRect(hwnd, &r);
@ -375,7 +375,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
r.left = 3;
r.right = r.left + 75;
r.right = r.left + 95;
r.top = 13;
r.bottom = r.top + 219;
MapDialogRect(hwnd, &r);

View File

@ -542,9 +542,20 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
}
/*
* Trim a colon suffix off the hostname if it's there.
* Trim a colon suffix off the hostname if it's there. In
* order to protect IPv6 address literals against this
* treatment, we do not do this if there's _more_ than one
* colon.
*/
cfg.host[strcspn(cfg.host, ":")] = '\0';
{
char *c = strchr(cfg.host, ':');
if (c) {
char *d = strchr(c+1, ':');
if (!d)
*c = '\0';
}
}
/*
* Remove any remaining whitespace from the hostname.

View File

@ -66,6 +66,7 @@
#define WINHELP_CTX_connection_username "connection.username"
#define WINHELP_CTX_connection_keepalive "connection.keepalive"
#define WINHELP_CTX_connection_nodelay "connection.nodelay"
#define WINHELP_CTX_connection_ipversion "connection.ipversion"
#define WINHELP_CTX_connection_tcpkeepalive "connection.tcpkeepalive"
#define WINHELP_CTX_proxy_type "proxy.type"
#define WINHELP_CTX_proxy_main "proxy.main"
@ -112,6 +113,7 @@
#define WINHELP_CTX_ssh_tunnels_x11auth "ssh.tunnels.x11auth"
#define WINHELP_CTX_ssh_tunnels_portfwd "ssh.tunnels.portfwd"
#define WINHELP_CTX_ssh_tunnels_portfwd_localhost "ssh.tunnels.portfwd.localhost"
#define WINHELP_CTX_ssh_tunnels_portfwd_ipversion "ssh.tunnels.portfwd.ipversion"
#define WINHELP_CTX_ssh_bugs_ignore1 "ssh.bugs.ignore1"
#define WINHELP_CTX_ssh_bugs_plainpw1 "ssh.bugs.plainpw1"
#define WINHELP_CTX_ssh_bugs_rsa1 "ssh.bugs.rsa1"

View File

@ -50,8 +50,14 @@ char *get_username(void)
char *user;
namelen = 0;
if (GetUserName(NULL, &namelen) == FALSE)
return NULL;
if (GetUserName(NULL, &namelen) == FALSE) {
/*
* Apparently this doesn't work at least on Windows XP SP2.
* Thus assume a maximum of 256. It will fail again if it
* doesn't fit.
*/
namelen = 256;
}
user = snewn(namelen, char);
GetUserName(user, &namelen);

View File

@ -1,43 +1,10 @@
/*
* Windows networking abstraction.
*
* Due to this clean abstraction it was possible
* to easily implement IPv6 support :)
*
* IPv6 patch 1 (27 October 2000) Jeroen Massar <jeroen@unfix.org>
* - Preliminary hacked IPv6 support.
* - Connecting to IPv6 address (eg fec0:4242:4242:100:2d0:b7ff:fe8f:5d42) works.
* - Connecting to IPv6 hostname (eg heaven.ipv6.unfix.org) works.
* - Compiles as either IPv4 or IPv6.
*
* IPv6 patch 2 (29 October 2000) Jeroen Massar <jeroen@unfix.org>
* - When compiled as IPv6 it also allows connecting to IPv4 hosts.
* - Added some more documentation.
*
* IPv6 patch 3 (18 November 2000) Jeroen Massar <jeroen@unfix.org>
* - It now supports dynamically loading the IPv6 resolver dll's.
* This way we should be able to distribute one (1) binary
* which supports both IPv4 and IPv6.
* - getaddrinfo() and getnameinfo() are loaded dynamicaly if possible.
* - in6addr_any is defined in this file so we don't need to link to wship6.lib
* - The patch is now more unified so that we can still
* remove all IPv6 support by undef'ing IPV6.
* But where it fallsback to IPv4 it uses the IPv4 code which is already in place...
* - Canonical name resolving works.
*
* IPv6 patch 4 (07 January 2001) Jeroen Massar <jeroen@unfix.org>
* - patch against CVS of today, will be submitted to the bugs list
* as a 'cvs diff -u' on Simon's request...
*
* For the IPv6 code in here I am indebted to Jeroen Massar and
* unfix.org.
*/
/*
* Define IPV6 to have IPv6 on-the-fly-loading support.
* This means that one doesn't have to have an IPv6 stack to use it.
* But if an IPv6 stack is found it is used with a fallback to IPv4.
*/
/* #define IPV6 1 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
@ -48,8 +15,10 @@
#include "tree234.h"
#include <ws2tcpip.h>
#ifdef IPV6
#include <tpipv6.h>
#ifndef NO_IPV6
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
#endif
#define ipv4_is_loopback(addr) \
@ -92,11 +61,16 @@ struct SockAddr_tag {
* IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name
* resolution has not been done and a simple host name is held
* in this SockAddr structure.
* The hostname field is also used when the hostname has both
* an IPv6 and IPv4 address and the IPv6 connection attempt
* fails. We then try the IPv4 address.
* This 'family' should become an option in the GUI and
* on the commandline for selecting a default protocol.
*/
int family;
unsigned long address; /* Address IPv4 style. */
#ifdef IPV6
struct addrinfo *ai; /* Address IPv6 style. */
#ifndef NO_IPV6
struct addrinfo *ai; /* Address AF-independent (IPv4+IPv6) style. */
#endif
char hostname[512]; /* Store an unresolved host name. */
};
@ -325,7 +299,8 @@ char *winsock_error_string(int error)
}
}
SockAddr sk_namelookup(const char *host, char **canonicalname)
SockAddr sk_namelookup(const char *host, char **canonicalname,
int address_family)
{
SockAddr ret = snew(struct SockAddr_tag);
unsigned long a;
@ -334,11 +309,15 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
/* Clear the structure and default to IPv4. */
memset(ret, 0, sizeof(struct SockAddr_tag));
ret->family = 0; /* We set this one when we have resolved the host. */
ret->family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
#ifndef NO_IPV6
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
AF_UNSPEC);
*realhost = '\0';
if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
#ifdef IPV6
#ifndef NO_IPV6
/* Try to get the getaddrinfo() function from wship6.dll */
/* This way one doesn't need to have IPv6 dll's to use PuTTY and
@ -356,56 +335,41 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
"getaddrinfo");
/*
* Use fGetAddrInfo when it's available (which usually also
* means IPv6 is installed...)
* Use fGetAddrInfo when it's available
*/
if (fGetAddrInfo) {
/*debug(("Resolving \"%s\" with getaddrinfo() (IPv4+IPv6 capable)...\n", host)); */
if (fGetAddrInfo(host, NULL, NULL, &ret->ai) == 0)
ret->family = ret->ai->ai_family;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = ret->family;
if (fGetAddrInfo(host, NULL, &hints, &ret->ai) == 0)
ret->family = ret->ai->ai_family;
} else
#endif
{
/*
* Otherwise use the IPv4-only gethostbyname...
* (NOTE: we don't use gethostbyname as a
* fallback!)
* (NOTE: we don't use gethostbyname as a fallback!)
*/
if (ret->family == 0) {
/*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
if ( (h = p_gethostbyname(host)) )
ret->family = AF_INET;
}
}
/*debug(("Done resolving...(family is %d) AF_INET = %d, AF_INET6 = %d\n", ret->family, AF_INET, AF_INET6)); */
if (ret->family == 0) {
if (ret->family == AF_UNSPEC) {
DWORD err = p_WSAGetLastError();
ret->error = (err == WSAENETDOWN ? "Network is down" :
err ==
WSAHOST_NOT_FOUND ? "Host does not exist" : err
== WSATRY_AGAIN ? "Host not found" :
#ifdef IPV6
#ifndef NO_IPV6
fGetAddrInfo ? "getaddrinfo: unknown error" :
#endif
"gethostbyname: unknown error");
#ifdef DEBUG
{
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) & lpMsgBuf, 0, NULL);
/*debug(("Error %ld: %s (h=%lx)\n", err, lpMsgBuf, h)); */
/* Free the buffer. */
LocalFree(lpMsgBuf);
}
#endif
} else {
ret->error = NULL;
#ifdef IPV6
#ifndef NO_IPV6
/* If we got an address info use that... */
if (ret->ai) {
typedef int (CALLBACK * FGETNAMEINFO)
@ -445,7 +409,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
strncpy(realhost, h->h_name, sizeof(realhost));
}
}
#ifdef IPV6
#ifndef NO_IPV6
FreeLibrary(dllWSHIP6);
#endif
} else {
@ -475,9 +439,30 @@ SockAddr sk_nonamelookup(const char *host)
void sk_getaddr(SockAddr addr, char *buf, int buflen)
{
#ifdef IPV6
#ifndef NO_IPV6
if (addr->family == AF_INET6) {
FIXME; /* I don't know how to get a text form of an IPv6 address. */
/* 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);
}
} else
#endif
if (addr->family == AF_INET) {
@ -486,7 +471,6 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen)
strncpy(buf, p_inet_ntoa(a), buflen);
buf[buflen-1] = '\0';
} else {
assert(addr->family == AF_UNSPEC);
strncpy(buf, addr->hostname, buflen);
buf[buflen-1] = '\0';
}
@ -530,9 +514,9 @@ static int ipv4_is_local_addr(struct in_addr addr)
int sk_address_is_local(SockAddr addr)
{
#ifdef IPV6
#ifndef NO_IPV6
if (addr->family == AF_INET6) {
FIXME; /* someone who can compile for IPV6 had better do this bit */
return IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)addr->ai->ai_addr);
} else
#endif
if (addr->family == AF_INET) {
@ -548,7 +532,7 @@ int sk_address_is_local(SockAddr addr)
int sk_addrtype(SockAddr addr)
{
return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
#ifdef IPV6
#ifndef NO_IPV6
addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
#endif
ADDRTYPE_NAME);
@ -557,7 +541,7 @@ int sk_addrtype(SockAddr addr)
void sk_addrcopy(SockAddr addr, char *buf)
{
assert(addr->family != AF_UNSPEC);
#ifdef IPV6
#ifndef NO_IPV6
if (addr->family == AF_INET6) {
memcpy(buf, (char*) addr->ai, 16);
} else
@ -673,7 +657,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
};
SOCKET s;
#ifdef IPV6
#ifndef NO_IPV6
SOCKADDR_IN6 a6;
#endif
SOCKADDR_IN a;
@ -701,7 +685,14 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
/*
* Open socket.
*/
assert(addr->family != AF_UNSPEC);
#ifndef NO_IPV6
/* Let's default to IPv6, this shouldn't hurt anybody
* If the stack supports IPv6 it will also allow IPv4 connections. */
if (addr->family == AF_UNSPEC) addr->family = AF_INET6;
#else
/* No other choice, default to IPv4 */
if (addr->family == AF_UNSPEC) addr->family = AF_INET;
#endif
s = p_socket(addr->family, SOCK_STREAM, 0);
ret->s = s;
@ -739,11 +730,11 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
while (1) {
int retcode;
#ifdef IPV6
#ifndef NO_IPV6
if (addr->family == AF_INET6) {
memset(&a6, 0, sizeof(a6));
a6.sin6_family = AF_INET6;
/*a6.sin6_addr = in6addr_any; *//* == 0 */
/*a6.sin6_addr = in6addr_any; */ /* == 0 done by memset() */
a6.sin6_port = p_htons(localport);
} else
#endif
@ -752,7 +743,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
a.sin_addr.s_addr = p_htonl(INADDR_ANY);
a.sin_port = p_htons(localport);
}
#ifdef IPV6
#ifndef NO_IPV6
retcode = p_bind(s, (addr->family == AF_INET6 ?
(struct sockaddr *) &a6 :
(struct sockaddr *) &a),
@ -785,7 +776,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
/*
* Connect to remote address.
*/
#ifdef IPV6
#ifndef NO_IPV6
if (addr->family == AF_INET6) {
memset(&a, 0, sizeof(a));
a6.sin6_family = AF_INET6;
@ -809,7 +800,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
}
if ((
#ifdef IPV6
#ifndef NO_IPV6
p_connect(s, ((addr->family == AF_INET6) ?
(struct sockaddr *) &a6 : (struct sockaddr *) &a),
(addr->family == AF_INET6) ? sizeof(a6) : sizeof(a))
@ -844,7 +835,8 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
return (Socket) ret;
}
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
int address_family)
{
static const struct socket_function_table fn_table = {
sk_tcp_plug,
@ -859,10 +851,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
};
SOCKET s;
#ifdef IPV6
#ifndef NO_IPV6
SOCKADDR_IN6 a6;
#endif
SOCKADDR_IN a;
DWORD err;
char *errstr;
Actual_Socket ret;
@ -884,10 +877,29 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
ret->localhost_only = local_host_only;
ret->pending_error = 0;
/*
* Translate address_family from platform-independent constants
* into local reality.
*/
address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
#ifndef NO_IPV6
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
#endif
AF_UNSPEC);
#ifndef NO_IPV6
/* Let's default to IPv6, this shouldn't hurt anybody
* If the stack supports IPv6 it will also allow IPv4 connections. */
if (address_family == AF_UNSPEC) address_family = AF_INET6;
#else
/* No other choice, default to IPv4 */
if (address_family == AF_UNSPEC) address_family = AF_INET;
#endif
/*
* Open socket.
*/
s = p_socket(AF_INET, SOCK_STREAM, 0);
s = p_socket(address_family, SOCK_STREAM, 0);
ret->s = s;
if (s == INVALID_SOCKET) {
@ -900,12 +912,15 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
p_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
#ifdef IPV6
if (addr->family == AF_INET6) {
#ifndef NO_IPV6
if (address_family == AF_INET6) {
memset(&a6, 0, sizeof(a6));
a6.sin6_family = AF_INET6;
/* FIXME: srcaddr is ignored for IPv6, because I (SGT) don't
* know how to do it. :-) */
* know how to do it. :-)
* (jeroen:) saddr is specified as an address.. eg 2001:db8::1
* Thus we need either a parser that understands [2001:db8::1]:80
* style addresses and/or enhance this to understand hostnames too. */
if (local_host_only)
a6.sin6_addr = in6addr_loopback;
else
@ -942,11 +957,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
a.sin_port = p_htons((short)port);
}
#ifdef IPV6
retcode = p_bind(s, (addr->family == AF_INET6 ?
#ifndef NO_IPV6
retcode = p_bind(s, (address_family == AF_INET6 ?
(struct sockaddr *) &a6 :
(struct sockaddr *) &a),
(addr->family ==
(address_family ==
AF_INET6 ? sizeof(a6) : sizeof(a)));
#else
retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
@ -1229,11 +1244,15 @@ int select_result(WPARAM wParam, LPARAM lParam)
return open;
case FD_ACCEPT:
{
#ifdef NO_IPV6
struct sockaddr_in isa;
int addrlen = sizeof(struct sockaddr_in);
#else
struct sockaddr_storage isa;
#endif
int addrlen = sizeof(isa);
SOCKET t; /* socket of connection */
memset(&isa, 0, sizeof(struct sockaddr_in));
memset(&isa, 0, sizeof(isa));
err = 0;
t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen);
if (t == INVALID_SOCKET)
@ -1242,8 +1261,13 @@ int select_result(WPARAM wParam, LPARAM lParam)
if (err == WSATRY_AGAIN)
break;
}
#ifndef NO_IPV6
if (isa.ss_family == AF_INET &&
s->localhost_only &&
!ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr)) {
#else
if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr)) {
#endif
p_closesocket(t); /* dodgy WinSock let nonlocal through */
} else if (plug_accepting(s->plug, (void*)t)) {
p_closesocket(t); /* denied or error */

View File

@ -231,6 +231,7 @@ static void usage(void)
printf(" -A -a enable / disable agent forwarding\n");
printf(" -t -T enable / disable pty allocation\n");
printf(" -1 -2 force use of particular protocol version\n");
printf(" -4 -6 force use of IPv4 or IPv6\n");
printf(" -C enable compression\n");
printf(" -i key private key file for authentication\n");
printf(" -s remote command is an SSH subsystem (SSH-2 only)\n");