Integrate unfix.org's IPv6 patches up to level 10, with rather a lot
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 30 Dec 2004 16:45:11 +0000 (16:45 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 30 Dec 2004 16:45:11 +0000 (16:45 +0000)
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.

git-svn-id: svn://svn.tartarus.org/sgt/putty@5047 cda61777-01e9-0310-a592-d414129be87e

30 files changed:
Recipe
cmdline.c
config.c
doc/config.but
doc/plink.but
doc/pscp.but
doc/using.but
mac/macnet.c
network.h
portfwd.c
proxy.c
pscp.c
psftp.c
putty.h
raw.c
rlogin.c
settings.c
ssh.c
ssh.h
telnet.c
unix/uxnet.c
unix/uxplink.c
windows/win_res.rc
windows/windlg.c
windows/window.c
windows/winhelp.h
windows/winmisc.c
windows/winnet.c
windows/winplink.c
x11fwd.c

diff --git a/Recipe b/Recipe
index 5d13c2c..7987049 100644 (file)
--- a/Recipe
+++ b/Recipe
 #      build, since at the time of writing this <multimon.h> is
 #      known not to be available in Cygwin.
 #
 #      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
 #  - COMPAT=/DMSVC4
 #  - RCFL=/DMSVC4
 #      Makes a couple of minor changes so that PuTTY compiles using
index 82cd4f8..d306959 100644 (file)
--- a/cmdline.c
+++ b/cmdline.c
@@ -348,6 +348,17 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg)
        cfg->keyfile = filename_from_str(value);
     }
 
        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 */
 }
 
     return ret;                               /* unrecognised */
 }
 
index 1dbdfac..e269e1f 100644 (file)
--- a/config.c
+++ b/config.c
@@ -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;
 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,
 };
 
 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);
             * 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;
        }
     } 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)
            if (whichbutton == 0)
-               str[0] = 'L';
+               type = 'L';
            else if (whichbutton == 1)
            else if (whichbutton == 1)
-               str[0] = 'R';
+               type = 'R';
            else
            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);
                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));
                *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");
 
     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) {
        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)),
            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)));
                         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));
            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;
        }
 
            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) {
     }
 
     if (!midsession) {
@@ -1664,15 +1706,14 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                         dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
        }
 
                         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) {
        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)));
            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);
        }
 
                              "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',
        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);
                                           "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);
 
        ctrl_tabdelay(s, pfd->addbutton);
        ctrl_columns(s, 1, 100);
 
index 361d68e..4a2d382 100644 (file)
@@ -1506,86 +1506,6 @@ background.)
 The Connection panel allows you to configure options that apply to
 more than one type of connection.
 
 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}
 \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.
 
 
 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}
 \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}).
 
 
 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}
 
 
 \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.
 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.
 
 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}
 
 
 \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.
 
 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}
 
 
 \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.
 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).
 
 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
 \H{config-ssh-bugs} The Bugs panel
 
 Not all SSH servers work properly. Various existing servers have
index abcf42f..7e27800 100644 (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   -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)
 \c   -C        enable compression
 \c   -i key    private key file for authentication
 \c   -s        remote command is an SSH subsystem (SSH-2 only)
index 78a5afb..4485b9b 100644 (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   -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
 \c   -C        enable compression
 \c   -i key    private key file for authentication
 \c   -batch    disable all interactive prompts
index 8ab8b40..db457ed 100644 (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}).
 
 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
 \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
index 9fab15b..63d0cc4 100644 (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.
  */
  * 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)
 {
 
     if (stack != NULL)
@@ -137,7 +137,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     return NULL;
 }
 
     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)
 {
 
     if (stack != NULL)
index 4574207..a97a6c4 100644 (file)
--- a/network.h
+++ b/network.h
@@ -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,
                      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,
 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()) */
 
 /* 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 */
 
 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);
 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);
 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_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);
 
 
 Socket sk_register(OSSocket sock, Plug plug);
 
index e6934d4..1239f67 100644 (file)
--- a/portfwd.c
+++ b/portfwd.c
@@ -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,
  * 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,
 {
     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.
      */
     /*
      * 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;
     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,
  */
 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,
 {
     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,
     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;
     if ((err = sk_socket_error(s)) != NULL) {
        sfree(pr);
        return err;
diff --git a/proxy.c b/proxy.c
index 190b8c9..f21c17b 100644 (file)
--- a/proxy.c
+++ b/proxy.c
@@ -342,7 +342,7 @@ static int proxy_for_destination (SockAddr addr, char *hostname, int port,
 }
 
 SockAddr name_lookup(char *host, int port, char **canonicalname,
 }
 
 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) &&
 {
     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_nonamelookup(host);
     }
 
-    return sk_namelookup(host, canonicalname);
+    return sk_namelookup(host, canonicalname, addressfamily);
 }
 
 Socket new_connection(SockAddr addr, char *hostname,
 }
 
 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,
 
        /* 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;
        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,
 }
 
 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.
      */
 
 {
     /* 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);
 }
 
 /* ----------------------------------------------------------------------
 }
 
 /* ----------------------------------------------------------------------
diff --git a/pscp.c b/pscp.c
index 0fa1839..d0e045f 100644 (file)
--- a/pscp.c
+++ b/pscp.c
@@ -322,6 +322,17 @@ static void do_cmd(char *host, char *user, char *cmd)
        bump("Empty host name");
 
     /*
        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".
      */
      * If we haven't loaded session details already (e.g., from -load),
      * try looking for a session called "host".
      */
@@ -382,11 +393,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.
      */
     {
      * 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)
 {
  */
 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. */
     /* 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 = ".";
     *targ++ = '\0';
     if (*targ == '\0')
        targ = ".";
-    /* Substitute "." for emtpy target */
+    /* Substitute "." for empty target */
 
     /* Separate host and username */
     user = host;
 
     /* 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("  -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");
     printf("  -C        enable compression\n");
     printf("  -i key    private key file for authentication\n");
     printf("  -batch    disable all interactive prompts\n");
diff --git a/psftp.c b/psftp.c
index dc5073e..ab07679 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -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("  -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");
     printf("  -C        enable compression\n");
     printf("  -i key    private key file for authentication\n");
     printf("  -batch    disable all interactive prompts\n");
diff --git a/putty.h b/putty.h
index 0d74e94..6f62afe 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -314,6 +314,16 @@ enum {
     FUNKY_SCO
 };
 
     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,
 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;
     char host[512];
     int port;
     int protocol;
+    int addressfamily;
     int close_on_exit;
     int warn_on_close;
     int ping_interval;                /* in seconds */
     int close_on_exit;
     int warn_on_close;
     int ping_interval;                /* in seconds */
diff --git a/raw.c b/raw.c
index 631320c..8619446 100644 (file)
--- a/raw.c
+++ b/raw.c
@@ -94,11 +94,14 @@ static const char *raw_init(void *frontend_handle, void **backend_handle,
      */
     {
        char *buf;
      */
     {
        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);
     }
        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;
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
index 2f26230..29d7be5 100644 (file)
--- a/rlogin.c
+++ b/rlogin.c
@@ -126,11 +126,14 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle,
      */
     {
        char *buf;
      */
     {
        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);
     }
        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;
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
index 5143bef..4a93400 100644 (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);
 
     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);
     /* 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;
        }
 
            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;
     /* 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;
diff --git a/ssh.c b/ssh.c
index 3a7f695..170253b 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -521,6 +521,7 @@ struct ssh_portfwd {
     unsigned sport, dport;
     char *saddr, *daddr;
     struct ssh_rportfwd *remote;
     unsigned sport, dport;
     char *saddr, *daddr;
     struct ssh_rportfwd *remote;
+    int addressfamily;
     void *local;
 };
 #define free_portfwd(pf) ( \
     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.
      */
     /*
      * 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;
     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)
 {
 
 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];
     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) {
     }
 
     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';
        saddr[0] = '\0';
+
        n = 0;
        while (*portfwd_strptr && *portfwd_strptr != '\t') {
            if (*portfwd_strptr == ':') {
        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->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) {
 
            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,
                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,
                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;
 
            } 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;
     /* 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];
     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;
     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);
        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,
                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);
        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,
            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) {
            logeventf(ssh, "Attempting to forward remote port to "
                      "%s:%d", realpf->dhost, realpf->dport);
            if (e != NULL) {
diff --git a/ssh.h b/ssh.h
index cd0f883..9a57205 100644 (file)
--- a/ssh.h
+++ b/ssh.h
@@ -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,
 
 /* 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,
 /* 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);
 extern void pfd_close(Socket s);
 extern void pfd_terminate(void *sockdata);
 extern int pfd_send(Socket s, char *data, int len);
index 13c2d3c..6789e5d 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -715,11 +715,14 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle,
      */
     {
        char *buf;
      */
     {
        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);
     }
        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;
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
index 08fb4e1..f1ef98b 100644 (file)
@@ -69,7 +69,7 @@ struct SockAddr_tag {
      * in this SockAddr structure.
      */
     int family;
      * in this SockAddr structure.
      */
     int family;
-#ifdef IPV6
+#ifndef NO_IPV6
     struct addrinfo *ai;              /* Address IPv6 style. */
 #else
     unsigned long address;            /* Address IPv4 style. */
     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);
 }
 
     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);
 {
     SockAddr ret = snew(struct SockAddr_tag);
-#ifdef IPV6
+#ifndef NO_IPV6
     struct addrinfo hints;
     int err;
 #else
     struct addrinfo hints;
     int err;
 #else
@@ -143,9 +143,9 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
     *realhost = '\0';
     ret->error = NULL;
 
     *realhost = '\0';
     ret->error = NULL;
 
-#ifdef IPV6
+#ifndef NO_IPV6
     hints.ai_flags = AI_CANONNAME;
     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;
     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 {
        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';
        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 {
     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);
        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 :
 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);
            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)
 {
 
 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));
     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)
 {
 
 void sk_addr_free(SockAddr addr)
 {
 
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->ai != NULL)
        freeaddrinfo(addr->ai);
 #endif
     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;
              int nodelay, int keepalive, Plug plug)
 {
     int s;
-#ifdef IPV6
+#ifndef NO_IPV6
     struct sockaddr_in6 a6;
 #endif
     struct sockaddr_in a;
     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));
 
     /* 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
 
     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;
 
        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;
            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) {
      * 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 =
       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;
 }
 
     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;
 {
     int s;
-#ifdef IPV6
-#if 0
-    struct sockaddr_in6 a6;
-#endif
+#ifndef NO_IPV6
     struct addrinfo hints, *ai;
     char portstr[6];
 #endif
     struct addrinfo hints, *ai;
     char portstr[6];
 #endif
@@ -598,9 +595,31 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
     ret->listener = 1;
 
     /*
     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.
      */
      * 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) {
     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));
 
     /* 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;
 #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;
     hints.ai_socktype = 0;
     hints.ai_protocol = 0;
     hints.ai_addrlen = 0;
index 6f17b5a..fdc0f66 100644 (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("  -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");
     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");
index d30672b..80a3754 100644 (file)
@@ -49,7 +49,7 @@ BEGIN
 END
 
 /* Accelerators used: aco */
 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"
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "PuTTY Configuration"
 FONT 8, "MS Shell Dlg"
index ba67ef5..9edf110 100644 (file)
@@ -300,7 +300,7 @@ static void create_controls(HWND hwnd, char *path)
         * Otherwise, we're creating the controls for a particular
         * panel.
         */
         * 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;
     }
        wc = &ctrls_panel;
        base_id = IDCX_PANELBASE;
     }
@@ -361,7 +361,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
            HWND tvstatic;
 
            r.left = 3;
            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);
            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;
            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);
            r.top = 13;
            r.bottom = r.top + 219;
            MapDialogRect(hwnd, &r);
index c80a25d..17aaf1a 100644 (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.
 
        /*
         * Remove any remaining whitespace from the hostname.
index cb0afed..743852b 100644 (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_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"
 #define WINHELP_CTX_connection_tcpkeepalive "connection.tcpkeepalive"
 #define WINHELP_CTX_proxy_type "proxy.type"
 #define WINHELP_CTX_proxy_main "proxy.main"
 #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_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"
 #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"
index 518eb15..c8b92a6 100644 (file)
@@ -50,8 +50,14 @@ char *get_username(void)
     char *user;
 
     namelen = 0;
     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);
 
     user = snewn(namelen, char);
     GetUserName(user, &namelen);
index f2b2aaa..94b8460 100644 (file)
@@ -1,43 +1,10 @@
 /*
  * Windows networking abstraction.
  *
 /*
  * 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>
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
 #include "tree234.h"
 
 #include <ws2tcpip.h>
 #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) \
 #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.
      * 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. */
      */
     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. */
 };
 #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;
 {
     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));
 
     /* 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) {
     *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
 
        /* 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");
 
        /*
                                                         "getaddrinfo");
 
        /*
-        * Use fGetAddrInfo when it's available (which usually also
-        * means IPv6 is installed...)
+        * Use fGetAddrInfo when it's available
         */
        if (fGetAddrInfo) {
         */
        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...
        } 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) {
             */
            if (ret->family == 0) {
-               /*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
                if ( (h = p_gethostbyname(host)) )
                    ret->family = AF_INET;
            }
        }
                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" :
            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");
                          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;
 
        } else {
            ret->error = NULL;
 
-#ifdef IPV6
+#ifndef NO_IPV6
            /* If we got an address info use that... */
            if (ret->ai) {
                typedef int (CALLBACK * FGETNAMEINFO)
            /* 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));
            }
        }
                strncpy(realhost, h->h_name, sizeof(realhost));
            }
        }
-#ifdef IPV6
+#ifndef NO_IPV6
        FreeLibrary(dllWSHIP6);
 #endif
     } else {
        FreeLibrary(dllWSHIP6);
 #endif
     } else {
@@ -475,9 +439,30 @@ SockAddr sk_nonamelookup(const char *host)
 
 void sk_getaddr(SockAddr addr, char *buf, int buflen)
 {
 
 void sk_getaddr(SockAddr addr, char *buf, int buflen)
 {
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET6) {
     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) {
     } 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 {
        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';
     }
        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)
 {
 
 int sk_address_is_local(SockAddr addr)
 {
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET6) {
     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) {
     } 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 :
 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);
            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);
 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
     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;
     };
 
     SOCKET s;
-#ifdef IPV6
+#ifndef NO_IPV6
     SOCKADDR_IN6 a6;
 #endif
     SOCKADDR_IN a;
     SOCKADDR_IN6 a6;
 #endif
     SOCKADDR_IN a;
@@ -701,7 +685,14 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     /*
      * Open socket.
      */
     /*
      * 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;
 
     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;
 
     while (1) {
        int retcode;
 
-#ifdef IPV6
+#ifndef NO_IPV6
        if (addr->family == AF_INET6) {
            memset(&a6, 0, sizeof(a6));
            a6.sin6_family = AF_INET6;
        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
            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);
        }
            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),
        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.
      */
     /*
      * Connect to remote address.
      */
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET6) {
        memset(&a, 0, sizeof(a));
        a6.sin6_family = AF_INET6;
     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 ((
     }
 
     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))
            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;
 }
 
     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,
 {
     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;
     };
 
     SOCKET s;
-#ifdef IPV6
+#ifndef NO_IPV6
     SOCKADDR_IN6 a6;
 #endif
     SOCKADDR_IN a;
     SOCKADDR_IN6 a6;
 #endif
     SOCKADDR_IN a;
+
     DWORD err;
     char *errstr;
     Actual_Socket ret;
     DWORD err;
     char *errstr;
     Actual_Socket ret;
@@ -885,9 +878,28 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
     ret->pending_error = 0;
 
     /*
     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.
      */
      * 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) {
     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));
 
 
     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
            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
            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);
        }
 
            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),
                           (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));
                        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:
        {
        return open;
        case FD_ACCEPT:
        {
+#ifdef NO_IPV6
            struct sockaddr_in isa;
            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 */
 
            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)
            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;
            }
                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)) {
            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 */
                p_closesocket(t);      /* dodgy WinSock let nonlocal through */
            } else if (plug_accepting(s->plug, (void*)t)) {
                p_closesocket(t);      /* denied or error */
index 497ac92..c136697 100644 (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("  -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");
     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");
index d748da1..52b320d 100644 (file)
--- a/x11fwd.c
+++ b/x11fwd.c
@@ -301,7 +301,7 @@ const char *x11_init(Socket * s, char *display, void *c, void *auth,
        /*
         * Try to find host.
         */
        /*
         * 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;
        if ((err = sk_addr_error(addr)) != NULL) {
            sk_addr_free(addr);
            return err;