1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00: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

5
Recipe
View File

@ -72,6 +72,11 @@
# build, since at the time of writing this <multimon.h> is
# known not to be available in Cygwin.
#
# - COMPAT=/DNO_IPV6
# Disables PuTTY's ability to make IPv6 connections, enabling
# it to compile under development environments which do not
# support IPv6 in their header files.
#
# - COMPAT=/DMSVC4
# - RCFL=/DMSVC4
# Makes a couple of minor changes so that PuTTY compiles using

View File

@ -348,6 +348,17 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg)
cfg->keyfile = filename_from_str(value);
}
if (!strcmp(p, "-4") || !strcmp(p, "-ipv4")) {
RETURN(1);
SAVEABLE(1);
cfg->addressfamily = ADDRTYPE_IPV4;
}
if (!strcmp(p, "-6") || !strcmp(p, "-ipv6")) {
RETURN(1);
SAVEABLE(1);
cfg->addressfamily = ADDRTYPE_IPV6;
}
return ret; /* unrecognised */
}

146
config.c
View File

@ -666,6 +666,7 @@ static void environ_handler(union control *ctrl, void *dlg,
struct portfwd_data {
union control *addbutton, *rembutton, *listbox;
union control *sourcebox, *destbox, *direction;
union control *addressfamily;
};
static void portfwd_handler(union control *ctrl, void *dlg,
@ -690,25 +691,39 @@ static void portfwd_handler(union control *ctrl, void *dlg,
* Default is Local.
*/
dlg_radiobutton_set(ctrl, dlg, 0);
} else if (ctrl == pfd->addressfamily) {
dlg_radiobutton_set(ctrl, dlg, 0);
}
} else if (event == EVENT_ACTION) {
if (ctrl == pfd->addbutton) {
char str[sizeof(cfg->portfwd)];
char *p;
int whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
int i, type;
int whichbutton;
i = 0;
whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
if (whichbutton == 1)
str[i++] = '4';
else if (whichbutton == 2)
str[i++] = '6';
whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
if (whichbutton == 0)
str[0] = 'L';
type = 'L';
else if (whichbutton == 1)
str[0] = 'R';
type = 'R';
else
str[0] = 'D';
dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
if (!str[1]) {
type = 'D';
str[i++] = type;
dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
if (!str[2]) {
dlg_error_msg(dlg, "You need to specify a source port number");
return;
}
p = str + strlen(str);
if (str[0] != 'D') {
if (type != 'D') {
*p++ = '\t';
dlg_editbox_get(pfd->destbox, dlg, p,
sizeof(str)-1 - (p - str));
@ -1344,9 +1359,59 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
if (protocol >= 0) {
ctrl_settitle(b, "Connection", "Options controlling the connection");
s = ctrl_getset(b, "Connection", "keepalive",
"Sending of null packets to keep session active");
ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
HELPCTX(connection_keepalive),
dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
I(-1));
if (!midsession) {
s = ctrl_getset(b, "Connection", "data",
"Data to send to the server");
s = ctrl_getset(b, "Connection", "tcp",
"Low-level TCP connection options");
ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
'n', HELPCTX(connection_nodelay),
dlg_stdcheckbox_handler,
I(offsetof(Config,tcp_nodelay)));
ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
'p', HELPCTX(connection_tcpkeepalive),
dlg_stdcheckbox_handler,
I(offsetof(Config,tcp_keepalives)));
s = ctrl_getset(b, "Connection", "ipversion",
"Internet protocol version");
ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
#ifndef NO_IPV6
3,
#else
2,
#endif
HELPCTX(connection_ipversion),
dlg_stdradiobutton_handler,
I(offsetof(Config, addressfamily)),
"Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
"IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
#ifndef NO_IPV6
"IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
#endif
NULL);
}
/*
* A sub-panel Connection/Data, containing options that
* decide on data to send to the server.
*/
if (!midsession) {
ctrl_settitle(b, "Connection/Data", "Data to send to the server");
s = ctrl_getset(b, "Connection/Data", "login",
"Login details");
ctrl_editbox(s, "Auto-login username", 'u', 50,
HELPCTX(connection_username),
dlg_stdeditbox_handler, I(offsetof(Config,username)),
I(sizeof(((Config *)0)->username)));
s = ctrl_getset(b, "Connection/Data", "term",
"Terminal details");
ctrl_editbox(s, "Terminal-type string", 't', 50,
HELPCTX(connection_termtype),
dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
@ -1355,12 +1420,9 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
HELPCTX(connection_termspeed),
dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
I(sizeof(((Config *)0)->termspeed)));
ctrl_editbox(s, "Auto-login username", 'u', 50,
HELPCTX(connection_username),
dlg_stdeditbox_handler, I(offsetof(Config,username)),
I(sizeof(((Config *)0)->username)));
ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
s = ctrl_getset(b, "Connection/Data", "env",
"Environment variables");
ctrl_columns(s, 2, 80, 20);
ed = (struct environ_data *)
ctrl_alloc(b, sizeof(struct environ_data));
@ -1391,26 +1453,6 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
ed->listbox->listbox.percentages[1] = 70;
}
s = ctrl_getset(b, "Connection", "keepalive",
"Sending of null packets to keep session active");
ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
HELPCTX(connection_keepalive),
dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
I(-1));
if (!midsession) {
s = ctrl_getset(b, "Connection", "tcp",
"Low-level TCP connection options");
ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
'n', HELPCTX(connection_nodelay),
dlg_stdcheckbox_handler,
I(offsetof(Config,tcp_nodelay)));
ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
'p', HELPCTX(connection_tcpkeepalive),
dlg_stdcheckbox_handler,
I(offsetof(Config,tcp_keepalives)));
}
}
if (!midsession) {
@ -1664,15 +1706,14 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
}
/*
* The Connection/SSH/Tunnels panel. Some of this _is_
* still available in mid-session.
*/
ctrl_settitle(b, "Connection/SSH/Tunnels",
"Options controlling SSH tunnelling");
if (!midsession) {
s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
/*
* The Connection/SSH/X11 panel.
*/
ctrl_settitle(b, "Connection/SSH/X11",
"Options controlling SSH X11 forwarding");
s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
ctrl_checkbox(s, "Enable X11 forwarding", 'e',
HELPCTX(ssh_tunnels_x11),
dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
@ -1688,6 +1729,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
"XDM-Authorization-1", I(X11_XDM), NULL);
}
/*
* The Tunnels panel _is_ still available in mid-session.
*/
ctrl_settitle(b, "Connection/SSH/Tunnels",
"Options controlling SSH port forwarding");
s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
"Port forwarding");
ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
@ -1741,6 +1788,21 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
"Remote", 'm', P(NULL),
"Dynamic", 'y', P(NULL),
NULL);
pfd->addressfamily =
ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
#ifndef NO_IPV6
3,
#else
2,
#endif
HELPCTX(ssh_tunnels_portfwd_ipversion),
portfwd_handler, P(pfd),
"Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
"IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
#ifndef NO_IPV6
"IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
#endif
NULL);
ctrl_tabdelay(s, pfd->addbutton);
ctrl_columns(s, 1, 100);

View File

@ -1506,86 +1506,6 @@ background.)
The Connection panel allows you to configure options that apply to
more than one type of connection.
\S{config-termtype} \q{Terminal-type string}
\cfg{winhelp-topic}{connection.termtype}
Most servers you might connect to with PuTTY are designed to be
connected to from lots of different types of terminal. In order to
send the right control sequences to each one, the server will need
to know what type of terminal it is dealing with. Therefore, each of
the SSH, Telnet and Rlogin protocols allow a text string to be sent
down the connection describing the terminal.
PuTTY attempts to emulate the Unix \c{xterm} program, and by default
it reflects this by sending \c{xterm} as a terminal-type string. If
you find this is not doing what you want - perhaps the remote
system reports \q{Unknown terminal type} - you could try setting
this to something different, such as \c{vt220}.
If you're not sure whether a problem is due to the terminal type
setting or not, you probably need to consult the manual for your
application or your server.
\S{config-termspeed} \q{Terminal speeds}
\cfg{winhelp-topic}{connection.termspeed}
The Telnet, Rlogin, and SSH protocols allow the client to specify
terminal speeds to the server.
This parameter does \e{not} affect the actual speed of the connection,
which is always \q{as fast as possible}; it is just a hint that is
sometimes used by server software to modify its behaviour. For
instance, if a slow speed is indicated, the server may switch to a
less bandwidth-hungry display mode.
The value is usually meaningless in a network environment, but
PuTTY lets you configure it, in case you find the server is reacting
badly to the default value.
The format is a pair of numbers separated by a comma, for instance,
\c{38400,38400}. The first number represents the output speed
(\e{from} the server) in bits per second, and the second is the input
speed (\e{to} the server). (Only the first is used in the Rlogin
protocol.)
This option has no effect on Raw connections.
\S{config-username} \q{Auto-login username}
\cfg{winhelp-topic}{connection.username}
All three of the SSH, Telnet and Rlogin protocols allow you to
specify what user name you want to log in as, without having to type
it explicitly every time. (Some Telnet servers don't support this.)
In this box you can type that user name.
\S{config-environ} Setting environment variables on the server
\cfg{winhelp-topic}{telnet.environ}
The Telnet protocol provides a means for the client to pass
environment variables to the server. Many Telnet servers have
stopped supporting this feature due to security flaws, but PuTTY
still supports it for the benefit of any servers which have found
other ways around the security problems than just disabling the
whole mechanism.
Version 2 of the SSH protocol also provides a similar mechanism,
which is easier to implement without security flaws. Newer SSH2
servers are more likely to support it than older ones.
This configuration data is not used in the SSHv1, rlogin or raw
protocols.
To add an environment variable to the list transmitted down the
connection, you enter the variable name in the \q{Variable} box,
enter its value in the \q{Value} box, and press the \q{Add} button.
To remove one from the list, select it in the list box and press
\q{Remove}.
\S{config-keepalive} Using keepalives to prevent disconnection
\cfg{winhelp-topic}{connection.keepalive}
@ -1678,6 +1598,111 @@ are terminated than for keeping a connection alive.
TCP keepalives are disabled by default.
\S{config-address-family} \q{Internet protocol}
\cfg{winhelp-topic}{connection.ipversion}
This option allows the user to select between the old and new
Internet protocols and addressing schemes (IPv4 and IPv6). The
default setting is \q{Auto}, which means PuTTY will do something
sensible and try to guess which protocol you wanted. (If you specify
a literal Internet address, it will use whichever protocol that
address implies. If you provide a hostname, it will see what kinds
of address exist for that hostname; it will use IPv6 if there is an
IPv6 address available, and fall back to IPv4 if not.)
If you need to force PuTTY to use a particular protocol, you can
explicitly set this to \q{IPv4} or \q{IPv6}.
\H{config-data} The Data panel
The Data panel allows you to configure various pieces of data which
can be sent to the server to affect your connection at the far end.
Each options on this panel applies to more than one protocol.
Options which apply to only one protocol appear on that protocol's
configuration panels.
\S{config-username} \q{Auto-login username}
\cfg{winhelp-topic}{connection.username}
All three of the SSH, Telnet and Rlogin protocols allow you to
specify what user name you want to log in as, without having to type
it explicitly every time. (Some Telnet servers don't support this.)
In this box you can type that user name.
\S{config-termtype} \q{Terminal-type string}
\cfg{winhelp-topic}{connection.termtype}
Most servers you might connect to with PuTTY are designed to be
connected to from lots of different types of terminal. In order to
send the right control sequences to each one, the server will need
to know what type of terminal it is dealing with. Therefore, each of
the SSH, Telnet and Rlogin protocols allow a text string to be sent
down the connection describing the terminal.
PuTTY attempts to emulate the Unix \c{xterm} program, and by default
it reflects this by sending \c{xterm} as a terminal-type string. If
you find this is not doing what you want - perhaps the remote
system reports \q{Unknown terminal type} - you could try setting
this to something different, such as \c{vt220}.
If you're not sure whether a problem is due to the terminal type
setting or not, you probably need to consult the manual for your
application or your server.
\S{config-termspeed} \q{Terminal speeds}
\cfg{winhelp-topic}{connection.termspeed}
The Telnet, Rlogin, and SSH protocols allow the client to specify
terminal speeds to the server.
This parameter does \e{not} affect the actual speed of the connection,
which is always \q{as fast as possible}; it is just a hint that is
sometimes used by server software to modify its behaviour. For
instance, if a slow speed is indicated, the server may switch to a
less bandwidth-hungry display mode.
The value is usually meaningless in a network environment, but
PuTTY lets you configure it, in case you find the server is reacting
badly to the default value.
The format is a pair of numbers separated by a comma, for instance,
\c{38400,38400}. The first number represents the output speed
(\e{from} the server) in bits per second, and the second is the input
speed (\e{to} the server). (Only the first is used in the Rlogin
protocol.)
This option has no effect on Raw connections.
\S{config-environ} Setting environment variables on the server
\cfg{winhelp-topic}{telnet.environ}
The Telnet protocol provides a means for the client to pass
environment variables to the server. Many Telnet servers have
stopped supporting this feature due to security flaws, but PuTTY
still supports it for the benefit of any servers which have found
other ways around the security problems than just disabling the
whole mechanism.
Version 2 of the SSH protocol also provides a similar mechanism,
which is easier to implement without security flaws. Newer SSH2
servers are more likely to support it than older ones.
This configuration data is not used in the SSHv1, rlogin or raw
protocols.
To add an environment variable to the list transmitted down the
connection, you enter the variable name in the \q{Variable} box,
enter its value in the \q{Value} box, and press the \q{Add} button.
To remove one from the list, select it in the list box and press
\q{Remove}.
\H{config-proxy} The Proxy panel
\cfg{winhelp-topic}{proxy.main}
@ -2298,15 +2323,13 @@ about public key authentication in SSH.
This key must be in PuTTY's native format (\c{*.PPK}).
\H{config-ssh-tunnels} The Tunnels panel
The Tunnels panel allows you to configure tunnelling of other
connection types through an SSH connection.
\S{config-ssh-x11} X11 forwarding
\H{config-ssh-x11} The X11 panel
\cfg{winhelp-topic}{ssh.tunnels.x11}
The X11 panel allows you to configure forwarding of X11 over an
SSH connection.
If your server lets you run X Window System applications, X11
forwarding allows you to securely give those applications access to
a local X display on your PC.
@ -2320,7 +2343,7 @@ primary local display (\c{:0}) if that fails.
See \k{using-x-forwarding} for more information about X11
forwarding.
\S2{config-ssh-x11auth} Remote X11 authentication
\S{config-ssh-x11auth} Remote X11 authentication
\cfg{winhelp-topic}{ssh.tunnels.x11auth}
@ -2367,10 +2390,13 @@ connections fail.
PuTTY's default is \cw{MIT-MAGIC-COOKIE-1}. If you change it, you
should be sure you know what you're doing.
\S{config-ssh-portfwd} Port forwarding
\H{config-ssh-portfwd} The Tunnels panel
\cfg{winhelp-topic}{ssh.tunnels.portfwd}
The Tunnels panel allows you to configure tunnelling of arbitrary
connection types through an SSH connection.
Port forwarding allows you to tunnel other types of network
connection down an SSH session. See \k{using-port-forwarding} for a
general discussion of port forwarding and how it works.
@ -2453,6 +2479,28 @@ SSH server machine can connect to the forwarded port.) Note that
this feature is only available in the SSH 2 protocol, and not all
SSH 2 servers support it (OpenSSH 3.0 does not, for example).
\S{config-ssh-portfwd-address-family} Selecting Internet protocol
version for forwarded ports
\cfg{winhelp-topic}{ssh.tunnels.portfwd.ipversion}
This switch allows you to select a specific Internet protocol (IPv4
or IPv6) for the local end of a forwarded port. By default, it is
set on \q{Auto}, which means that:
\b for a local-to-remote port forwarding, PuTTY will listen for
incoming connections in both IPv4 and (if available) IPv6
\b for a remote-to-local port forwarding, PuTTY will choose a
sensible protocol for the outgoing connection.
\# FIXME: work out what this paragraph means, reword it for clarity,
\# and reinstate it.
Note that on Windows the address space for IPv4 and IPv6 is
completely disjunct, so listening on IPv6 won't make PuTTY listen on
IPv4. This behaviour may be different on most remote hosts when they
are not operating Windows.
\H{config-ssh-bugs} The Bugs panel
Not all SSH servers work properly. Various existing servers have

View File

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

View File

@ -55,6 +55,7 @@ use PSCP:
\c -l user connect with specified username
\c -pw passw login with specified password
\c -1 -2 force use of particular SSH protocol version
\c -4 -6 force use of IPv4 or IPv6
\c -C enable compression
\c -i key private key file for authentication
\c -batch disable all interactive prompts

View File

@ -754,6 +754,16 @@ These options are equivalent to selecting your preferred SSH
protocol version as \q{1 only} or \q{2 only} in the SSH panel of the
PuTTY configuration box (see \k{config-ssh-prot}).
\S2{using-cmdline-ipversion} \i\c{-4} and \i\c{-6}: specify an
\i{Internet protocol version}
The \c{-4} and \c{-6} options force PuTTY to use the older Internet
protocol \i{IPv4} or the newer \i{IPv6}.
These options are equivalent to selecting your preferred Internet
protocol version as \q{IPv4} or \q{IPv6} in the Connection panel of
the PuTTY configuration box (see \k{config-address-family}).
\S2{using-cmdline-identity} \i\c{-i}: specify an SSH \i{private key}
The \c{-i} option allows you to specify the name of a private key

View File

@ -56,7 +56,7 @@ void sk_init(void)
* Network functions exported to the world. These choose whether to call
* MacTCP or OpenTransport and behave accordingly.
*/
SockAddr sk_namelookup(char const *host, char **canonicalname)
SockAddr sk_namelookup(char const *host, char **canonicalname, int address_family)
{
if (stack != NULL)
@ -137,7 +137,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
return NULL;
}
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)
{
if (stack != NULL)

View File

@ -82,9 +82,9 @@ Socket new_connection(SockAddr addr, char *hostname,
int oobinline, int nodelay, int keepalive,
Plug plug, const Config *cfg);
Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only,
const Config *cfg);
const Config *cfg, int addressfamily);
SockAddr name_lookup(char *host, int port, char **canonicalname,
const Config *cfg);
const Config *cfg, int addressfamily);
/* platform-dependent callback from new_connection() */
/* (same caveat about addr as new_connection()) */
@ -98,12 +98,11 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
void sk_init(void); /* called once at program startup */
void sk_cleanup(void); /* called just before program exit */
SockAddr sk_namelookup(const char *host, char **canonicalname);
SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family);
SockAddr sk_nonamelookup(const char *host);
void sk_getaddr(SockAddr addr, char *buf, int buflen);
int sk_hostname_is_local(char *name);
int sk_address_is_local(SockAddr addr);
enum { ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME };
int sk_addrtype(SockAddr addr);
void sk_addrcopy(SockAddr addr, char *buf);
void sk_addr_free(SockAddr addr);
@ -113,7 +112,7 @@ void sk_addr_free(SockAddr addr);
Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
int nodelay, int keepalive, Plug p);
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);
Socket sk_register(OSSocket sock, Plug plug);

View File

@ -354,7 +354,7 @@ static void pfd_sent(Plug plug, int bufsize)
* Called when receiving a PORT OPEN from the server
*/
const char *pfd_newconnect(Socket *s, char *hostname, int port,
void *c, const Config *cfg)
void *c, const Config *cfg, int addressfamily)
{
static const struct plug_function_table fn_table = {
pfd_closing,
@ -371,7 +371,7 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port,
/*
* Try to find host.
*/
addr = name_lookup(hostname, port, &dummy_realhost, cfg);
addr = name_lookup(hostname, port, &dummy_realhost, cfg, addressfamily);
if ((err = sk_addr_error(addr)) != NULL) {
sk_addr_free(addr);
return err;
@ -463,7 +463,7 @@ static int pfd_accepting(Plug p, OSSocket sock)
*/
const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
int port, void *backhandle, const Config *cfg,
void **sockdata)
void **sockdata, int address_family)
{
static const struct plug_function_table fn_table = {
pfd_closing,
@ -494,7 +494,7 @@ const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
pr->backhandle = backhandle;
pr->s = s = new_listener(srcaddr, port, (Plug) pr,
!cfg->lport_acceptall, cfg);
!cfg->lport_acceptall, cfg, address_family);
if ((err = sk_socket_error(s)) != NULL) {
sfree(pr);
return err;

10
proxy.c
View File

@ -342,7 +342,7 @@ static int proxy_for_destination (SockAddr addr, char *hostname, int port,
}
SockAddr name_lookup(char *host, int port, char **canonicalname,
const Config *cfg)
const Config *cfg, int addressfamily)
{
if (cfg->proxy_type != PROXY_NONE &&
do_proxy_dns(cfg) &&
@ -351,7 +351,7 @@ SockAddr name_lookup(char *host, int port, char **canonicalname,
return sk_nonamelookup(host);
}
return sk_namelookup(host, canonicalname);
return sk_namelookup(host, canonicalname, addressfamily);
}
Socket new_connection(SockAddr addr, char *hostname,
@ -433,7 +433,7 @@ Socket new_connection(SockAddr addr, char *hostname,
/* look-up proxy */
proxy_addr = sk_namelookup(cfg->proxy_host,
&proxy_canonical_name);
&proxy_canonical_name, cfg->addressfamily);
if (sk_addr_error(proxy_addr) != NULL) {
ret->error = "Proxy error: Unable to resolve proxy host name";
return (Socket)ret;
@ -461,13 +461,13 @@ Socket new_connection(SockAddr addr, char *hostname,
}
Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only,
const Config *cfg)
const Config *cfg, int addressfamily)
{
/* TODO: SOCKS (and potentially others) support inbound
* TODO: connections via the proxy. support them.
*/
return sk_newlistener(srcaddr, port, plug, local_host_only);
return sk_newlistener(srcaddr, port, plug, local_host_only, addressfamily);
}
/* ----------------------------------------------------------------------

32
pscp.c
View File

@ -321,6 +321,17 @@ static void do_cmd(char *host, char *user, char *cmd)
if (host == NULL || host[0] == '\0')
bump("Empty host name");
/*
* Remove fiddly bits of address: remove a colon suffix, and
* the square brackets around an IPv6 literal address.
*/
if (host[0] == '[') {
host++;
host[strcspn(host, "]")] = '\0';
} else {
host[strcspn(host, ":")] = '\0';
}
/*
* If we haven't loaded session details already (e.g., from -load),
* try looking for a session called "host".
@ -381,11 +392,6 @@ static void do_cmd(char *host, char *user, char *cmd)
}
}
/*
* Trim a colon suffix off the hostname if it's there.
*/
cfg.host[strcspn(cfg.host, ":")] = '\0';
/*
* Remove any remaining whitespace from the hostname.
*/
@ -533,6 +539,19 @@ static void print_stats(char *name, unsigned long size, unsigned long done,
*/
static char *colon(char *str)
{
/* Check and process IPv6 literal addresses
* (eg: 'jeroen@[2001:db8::1]:myfile.txt') */
char *ipv6 = strchr(str, '[');
if (ipv6) {
str = strchr(str, ']');
if (str) {
/* Terminate on the closing bracket */
*str++ = '\0';
return (str);
}
return (NULL);
}
/* We ignore a leading colon, since the hostname cannot be
empty. We also ignore a colon as second character because
of filenames like f:myfile.txt. */
@ -1928,7 +1947,7 @@ static void toremote(int argc, char *argv[])
*targ++ = '\0';
if (*targ == '\0')
targ = ".";
/* Substitute "." for emtpy target */
/* Substitute "." for empty target */
/* Separate host and username */
user = host;
@ -2129,6 +2148,7 @@ static void usage(void)
printf(" -l user connect with specified username\n");
printf(" -pw passw login with specified password\n");
printf(" -1 -2 force use of particular SSH 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(" -batch disable all interactive prompts\n");

View File

@ -2446,6 +2446,7 @@ static void usage(void)
printf(" -P port connect to specified port\n");
printf(" -pw passw login with specified password\n");
printf(" -1 -2 force use of particular SSH 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(" -batch disable all interactive prompts\n");

11
putty.h
View File

@ -314,6 +314,16 @@ enum {
FUNKY_SCO
};
enum {
/*
* Network address types. Used for specifying choice of IPv4/v6
* in config; also used in proxy.c to indicate whether a given
* host name has already been resolved or will be resolved at
* the proxy end.
*/
ADDRTYPE_UNSPEC, ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME
};
struct backend_tag {
const char *(*init) (void *frontend_handle, void **backend_handle,
Config *cfg,
@ -375,6 +385,7 @@ struct config_tag {
char host[512];
int port;
int protocol;
int addressfamily;
int close_on_exit;
int warn_on_close;
int ping_interval; /* in seconds */

7
raw.c
View File

@ -94,11 +94,14 @@ static const char *raw_init(void *frontend_handle, void **backend_handle,
*/
{
char *buf;
buf = dupprintf("Looking up host \"%s\"", host);
buf = dupprintf("Looking up host \"%s\"%s", host,
(cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
(cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :
"")));
logevent(raw->frontend, buf);
sfree(buf);
}
addr = name_lookup(host, port, realhost, cfg);
addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily);
if ((err = sk_addr_error(addr)) != NULL) {
sk_addr_free(addr);
return err;

View File

@ -126,11 +126,14 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle,
*/
{
char *buf;
buf = dupprintf("Looking up host \"%s\"", host);
buf = dupprintf("Looking up host \"%s\"%s", host,
(cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
(cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :
"")));
logevent(rlogin->frontend, buf);
sfree(buf);
}
addr = name_lookup(host, port, realhost, cfg);
addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily);
if ((err = sk_addr_error(addr)) != NULL) {
sk_addr_free(addr);
return err;

View File

@ -197,6 +197,9 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg)
write_setting_s(sesskey, "TerminalType", cfg->termtype);
write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed);
/* Address family selection */
write_setting_i(sesskey, "AddressFamily", cfg->addressfamily);
/* proxy settings */
write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list);
write_setting_i(sesskey, "ProxyDNS", (cfg->proxy_dns+2)%3);
@ -420,6 +423,9 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
break;
}
/* Address family selection */
gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, &cfg->addressfamily);
/* The CloseOnExit numbers are arranged in a different order from
* the standard FORCE_ON / FORCE_OFF / AUTO. */
gppi(sesskey, "CloseOnExit", 1, &i); cfg->close_on_exit = (i+1)%3;

72
ssh.c
View File

@ -521,6 +521,7 @@ struct ssh_portfwd {
unsigned sport, dport;
char *saddr, *daddr;
struct ssh_rportfwd *remote;
int addressfamily;
void *local;
};
#define free_portfwd(pf) ( \
@ -2449,8 +2450,11 @@ static const char *connect_to_host(Ssh ssh, char *host, int port,
/*
* Try to find host.
*/
logeventf(ssh, "Looking up host \"%s\"", host);
addr = name_lookup(host, port, realhost, &ssh->cfg);
logeventf(ssh, "Looking up host \"%s\"%s", host,
(ssh->cfg.addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
(ssh->cfg.addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : "")));
addr = name_lookup(host, port, realhost, &ssh->cfg,
ssh->cfg.addressfamily);
if ((err = sk_addr_error(addr)) != NULL) {
sk_addr_free(addr);
return err;
@ -3666,7 +3670,7 @@ static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx)
static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
{
char type;
char address_family, type;
int n;
int sport,dport,sserv,dserv;
char sports[256], dports[256], saddr[256], host[256];
@ -3690,8 +3694,22 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
}
while (*portfwd_strptr) {
type = *portfwd_strptr++;
address_family = 'A';
type = 'L';
while (*portfwd_strptr && *portfwd_strptr != '\t') {
if (*portfwd_strptr == 'A' ||
*portfwd_strptr == '4' ||
*portfwd_strptr == '6')
address_family = *portfwd_strptr;
else if (*portfwd_strptr == 'L' ||
*portfwd_strptr == 'R' ||
*portfwd_strptr == 'D')
type = *portfwd_strptr;
portfwd_strptr++;
}
saddr[0] = '\0';
n = 0;
while (*portfwd_strptr && *portfwd_strptr != '\t') {
if (*portfwd_strptr == ':') {
@ -3774,6 +3792,9 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
pfrec->dport = dport;
pfrec->local = NULL;
pfrec->remote = NULL;
pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :
address_family == '6' ? ADDRTYPE_IPV6 :
ADDRTYPE_UNSPEC);
epfrec = add234(ssh->portfwds, pfrec);
if (epfrec != pfrec) {
@ -3793,27 +3814,28 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
const char *err = pfd_addforward(host, dport,
*saddr ? saddr : NULL,
sport, ssh, &ssh->cfg,
&pfrec->local);
if (err) {
logeventf(ssh, "Local port %s forward to %s"
" failed: %s", sportdesc, dportdesc, err);
} else {
logeventf(ssh, "Local port %s forwarding to %s",
sportdesc, dportdesc);
}
&pfrec->local,
pfrec->addressfamily);
logeventf(ssh, "Local %sport %s forward to %s%s%s",
pfrec->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
pfrec->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
sportdesc, dportdesc,
err ? " failed: " : "", err);
sfree(dportdesc);
} else if (type == 'D') {
const char *err = pfd_addforward(NULL, -1,
*saddr ? saddr : NULL,
sport, ssh, &ssh->cfg,
&pfrec->local);
if (err) {
logeventf(ssh, "Local port %s SOCKS dynamic forward"
" setup failed: %s", sportdesc, err);
} else {
logeventf(ssh, "Local port %s doing SOCKS"
" dynamic forwarding", sportdesc);
}
&pfrec->local,
pfrec->addressfamily);
logeventf(ssh, "Local %sport %s SOCKS dynamic forward%s%s",
pfrec->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
pfrec->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
sportdesc,
err ? " setup failed: " : "", err);
} else {
struct ssh_rportfwd *pf;
@ -4045,7 +4067,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
/* Remote side is trying to open a channel to talk to a
* forwarded port. Give them back a local channel number. */
struct ssh_channel *c;
struct ssh_rportfwd pf;
struct ssh_rportfwd pf, *pfp;
int remoteid;
int hostsize, port;
char *host, buf[1024];
@ -4062,8 +4084,9 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
memcpy(pf.dhost, host, hostsize);
pf.dhost[hostsize] = '\0';
pf.dport = port;
pfp = find234(ssh->rportfwds, &pf, NULL);
if (find234(ssh->rportfwds, &pf, NULL) == NULL) {
if (pfp == NULL) {
sprintf(buf, "Rejected remote port open request for %s:%d",
pf.dhost, port);
logevent(buf);
@ -4074,7 +4097,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
pf.dhost, port);
logevent(buf);
e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,
c, &ssh->cfg);
c, &ssh->cfg, pfp->pfrec->addressfamily);
if (e != NULL) {
char buf[256];
sprintf(buf, "Port open failed: %s", e);
@ -5799,7 +5822,8 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
const char *e = pfd_newconnect(&c->u.pfd.s,
realpf->dhost,
realpf->dport, c,
&ssh->cfg);
&ssh->cfg,
realpf->pfrec->addressfamily);
logeventf(ssh, "Attempting to forward remote port to "
"%s:%d", realpf->dhost, realpf->dport);
if (e != NULL) {

6
ssh.h
View File

@ -270,11 +270,13 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org);
/* Exports from portfwd.c */
extern const char *pfd_newconnect(Socket * s, char *hostname, int port,
void *c, const Config *cfg);
void *c, const Config *cfg,
int addressfamily);
/* desthost == NULL indicates dynamic (SOCKS) port forwarding */
extern const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
int port, void *backhandle,
const Config *cfg, void **sockdata);
const Config *cfg, void **sockdata,
int address_family);
extern void pfd_close(Socket s);
extern void pfd_terminate(void *sockdata);
extern int pfd_send(Socket s, char *data, int len);

View File

@ -715,11 +715,14 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle,
*/
{
char *buf;
buf = dupprintf("Looking up host \"%s\"", host);
buf = dupprintf("Looking up host \"%s\"%s", host,
(cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
(cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :
"")));
logevent(telnet->frontend, buf);
sfree(buf);
}
addr = name_lookup(host, port, realhost, &telnet->cfg);
addr = name_lookup(host, port, realhost, &telnet->cfg, cfg->addressfamily);
if ((err = sk_addr_error(addr)) != NULL) {
sk_addr_free(addr);
return err;

View File

@ -69,7 +69,7 @@ struct SockAddr_tag {
* in this SockAddr structure.
*/
int family;
#ifdef IPV6
#ifndef NO_IPV6
struct addrinfo *ai; /* Address IPv6 style. */
#else
unsigned long address; /* Address IPv4 style. */
@ -125,10 +125,10 @@ const char *error_string(int error)
return strerror(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);
#ifdef IPV6
#ifndef NO_IPV6
struct addrinfo hints;
int err;
#else
@ -143,9 +143,9 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
*realhost = '\0';
ret->error = NULL;
#ifdef IPV6
#ifndef NO_IPV6
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_UNSPEC;
hints.ai_family = address_family;
hints.ai_socktype = 0;
hints.ai_protocol = 0;
hints.ai_addrlen = 0;
@ -219,7 +219,7 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen)
strncpy(buf, addr->hostname, buflen);
buf[buflen-1] = '\0';
} else {
#ifdef IPV6
#ifndef NO_IPV6
if (getnameinfo(addr->ai->ai_addr, addr->ai->ai_addrlen, buf, buflen,
NULL, 0, NI_NUMERICHOST) != 0) {
buf[0] = '\0';
@ -246,7 +246,7 @@ int sk_address_is_local(SockAddr addr)
if (addr->family == AF_UNSPEC)
return 0; /* we don't know; assume not */
else {
#ifdef IPV6
#ifndef NO_IPV6
if (addr->family == AF_INET)
return ipv4_is_loopback(
((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr);
@ -267,7 +267,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);
@ -276,7 +276,7 @@ int sk_addrtype(SockAddr addr)
void sk_addrcopy(SockAddr addr, char *buf)
{
#ifdef IPV6
#ifndef NO_IPV6
if (addr->family == AF_INET)
memcpy(buf, &((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr,
sizeof(struct in_addr));
@ -297,7 +297,7 @@ void sk_addrcopy(SockAddr addr, char *buf)
void sk_addr_free(SockAddr addr)
{
#ifdef IPV6
#ifndef NO_IPV6
if (addr->ai != NULL)
freeaddrinfo(addr->ai);
#endif
@ -381,7 +381,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
int nodelay, int keepalive, Plug plug)
{
int s;
#ifdef IPV6
#ifndef NO_IPV6
struct sockaddr_in6 a6;
#endif
struct sockaddr_in a;
@ -448,7 +448,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
/* BSD IP stacks need sockaddr_in zeroed before filling in */
memset(&a,'\0',sizeof(struct sockaddr_in));
#ifdef IPV6
#ifndef NO_IPV6
memset(&a6,'\0',sizeof(struct sockaddr_in6));
#endif
@ -459,7 +459,7 @@ 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) {
/* XXX use getaddrinfo to get a local address? */
a6.sin6_family = AF_INET6;
@ -501,7 +501,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
* Connect to remote address.
*/
switch(addr->family) {
#ifdef IPV6
#ifndef NO_IPV6
case AF_INET:
/* XXX would be better to have got getaddrinfo() to fill in the port. */
((struct sockaddr_in *)addr->ai->ai_addr)->sin_port =
@ -564,13 +564,10 @@ 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)
{
int s;
#ifdef IPV6
#if 0
struct sockaddr_in6 a6;
#endif
#ifndef NO_IPV6
struct addrinfo hints, *ai;
char portstr[6];
#endif
@ -597,10 +594,32 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
ret->oobpending = FALSE;
ret->listener = 1;
/*
* Translate address_family from platform-independent constants
* into local reality.
*/
address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
address_family == ADDRTYPE_IPV6 ? AF_INET6 : AF_UNSPEC);
#ifndef NO_IPV6
/* Let's default to IPv6.
* If the stack doesn't support IPv6, we will fall back to IPv4. */
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 = socket(AF_INET, SOCK_STREAM, 0);
s = socket(address_family, SOCK_STREAM, 0);
/* If the host doesn't support IPv6 try fallback to IPv4. */
if (s < 0 && address_family == AF_INET6) {
address_family = AF_INET;
s = socket(address_family, SOCK_STREAM, 0);
}
ret->s = s;
if (s < 0) {
@ -614,12 +633,12 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
/* BSD IP stacks need sockaddr_in zeroed before filling in */
memset(&a,'\0',sizeof(struct sockaddr_in));
#ifdef IPV6
#ifndef NO_IPV6
#if 0
memset(&a6,'\0',sizeof(struct sockaddr_in6));
#endif
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = AF_UNSPEC;
hints.ai_family = address_family;
hints.ai_socktype = 0;
hints.ai_protocol = 0;
hints.ai_addrlen = 0;

View File

@ -227,6 +227,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");

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");

View File

@ -301,7 +301,7 @@ const char *x11_init(Socket * s, char *display, void *c, void *auth,
/*
* Try to find host.
*/
addr = name_lookup(host, port, &dummy_realhost, cfg);
addr = name_lookup(host, port, &dummy_realhost, cfg, ADDRTYPE_UNSPEC);
if ((err = sk_addr_error(addr)) != NULL) {
sk_addr_free(addr);
return err;