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.
 #
+#  - 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
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);
     }
 
+    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 */
 }
 
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;
+    union control *addressfamily;
 };
 
 static void portfwd_handler(union control *ctrl, void *dlg,
@@ -690,25 +691,39 @@ static void portfwd_handler(union control *ctrl, void *dlg,
             * Default is Local.
             */
            dlg_radiobutton_set(ctrl, dlg, 0);
+        } else if (ctrl == pfd->addressfamily) {
+           dlg_radiobutton_set(ctrl, dlg, 0);
        }
     } else if (event == EVENT_ACTION) {
        if (ctrl == pfd->addbutton) {
            char str[sizeof(cfg->portfwd)];
            char *p;
-           int whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
+           int i, type;
+           int whichbutton;
+
+           i = 0;
+           whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
+           if (whichbutton == 1)
+               str[i++] = '4';
+           else if (whichbutton == 2)
+               str[i++] = '6';
+
+           whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
            if (whichbutton == 0)
-               str[0] = 'L';
+               type = 'L';
            else if (whichbutton == 1)
-               str[0] = 'R';
+               type = 'R';
            else
-               str[0] = 'D';
-           dlg_editbox_get(pfd->sourcebox, dlg, str+1, sizeof(str) - 2);
-           if (!str[1]) {
+               type = 'D';
+           str[i++] = type;
+
+           dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
+           if (!str[2]) {
                dlg_error_msg(dlg, "You need to specify a source port number");
                return;
            }
            p = str + strlen(str);
-           if (str[0] != 'D') {
+           if (type != 'D') {
                *p++ = '\t';
                dlg_editbox_get(pfd->destbox, dlg, p,
                                sizeof(str)-1 - (p - str));
@@ -1344,9 +1359,59 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
     if (protocol >= 0) {
        ctrl_settitle(b, "Connection", "Options controlling the connection");
 
+       s = ctrl_getset(b, "Connection", "keepalive",
+                       "Sending of null packets to keep session active");
+       ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
+                    HELPCTX(connection_keepalive),
+                    dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
+                    I(-1));
+
        if (!midsession) {
-           s = ctrl_getset(b, "Connection", "data",
-                           "Data to send to the server");
+           s = ctrl_getset(b, "Connection", "tcp",
+                           "Low-level TCP connection options");
+           ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
+                         'n', HELPCTX(connection_nodelay),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,tcp_nodelay)));
+           ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
+                         'p', HELPCTX(connection_tcpkeepalive),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,tcp_keepalives)));
+           s = ctrl_getset(b, "Connection", "ipversion",
+                         "Internet protocol version");
+           ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
+#ifndef NO_IPV6
+                         3,
+#else
+                         2,
+#endif
+                         HELPCTX(connection_ipversion),
+                         dlg_stdradiobutton_handler,
+                         I(offsetof(Config, addressfamily)),
+                         "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
+                         "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
+#ifndef NO_IPV6
+                         "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
+#endif
+                         NULL);
+       }
+
+       /*
+        * A sub-panel Connection/Data, containing options that
+        * decide on data to send to the server.
+        */
+       if (!midsession) {
+           ctrl_settitle(b, "Connection/Data", "Data to send to the server");
+
+           s = ctrl_getset(b, "Connection/Data", "login",
+                           "Login details");
+           ctrl_editbox(s, "Auto-login username", 'u', 50,
+                        HELPCTX(connection_username),
+                        dlg_stdeditbox_handler, I(offsetof(Config,username)),
+                        I(sizeof(((Config *)0)->username)));
+
+           s = ctrl_getset(b, "Connection/Data", "term",
+                           "Terminal details");
            ctrl_editbox(s, "Terminal-type string", 't', 50,
                         HELPCTX(connection_termtype),
                         dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
@@ -1355,12 +1420,9 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                         HELPCTX(connection_termspeed),
                         dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
                         I(sizeof(((Config *)0)->termspeed)));
-           ctrl_editbox(s, "Auto-login username", 'u', 50,
-                        HELPCTX(connection_username),
-                        dlg_stdeditbox_handler, I(offsetof(Config,username)),
-                        I(sizeof(((Config *)0)->username)));
 
-           ctrl_text(s, "Environment variables:", HELPCTX(telnet_environ));
+           s = ctrl_getset(b, "Connection/Data", "env",
+                           "Environment variables");
            ctrl_columns(s, 2, 80, 20);
            ed = (struct environ_data *)
                ctrl_alloc(b, sizeof(struct environ_data));
@@ -1391,26 +1453,6 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
            ed->listbox->listbox.percentages[1] = 70;
        }
 
-       s = ctrl_getset(b, "Connection", "keepalive",
-                       "Sending of null packets to keep session active");
-       ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20,
-                    HELPCTX(connection_keepalive),
-                    dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
-                    I(-1));
-
-       if (!midsession) {
-           s = ctrl_getset(b, "Connection", "tcp",
-                           "Low-level TCP connection options");
-           ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)",
-                         'n', HELPCTX(connection_nodelay),
-                         dlg_stdcheckbox_handler,
-                         I(offsetof(Config,tcp_nodelay)));
-           ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
-                         'p', HELPCTX(connection_tcpkeepalive),
-                         dlg_stdcheckbox_handler,
-                         I(offsetof(Config,tcp_keepalives)));
-       }
-
     }
 
     if (!midsession) {
@@ -1664,15 +1706,14 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                         dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));
        }
 
-       /*
-        * The Connection/SSH/Tunnels panel. Some of this _is_
-        * still available in mid-session.
-        */
-       ctrl_settitle(b, "Connection/SSH/Tunnels",
-                     "Options controlling SSH tunnelling");
-
        if (!midsession) {
-           s = ctrl_getset(b, "Connection/SSH/Tunnels", "x11", "X11 forwarding");
+           /*
+            * The Connection/SSH/X11 panel.
+            */
+           ctrl_settitle(b, "Connection/SSH/X11",
+                         "Options controlling SSH X11 forwarding");
+
+           s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding");
            ctrl_checkbox(s, "Enable X11 forwarding", 'e',
                          HELPCTX(ssh_tunnels_x11),
                          dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
@@ -1688,6 +1729,12 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                              "XDM-Authorization-1", I(X11_XDM), NULL);
        }
 
+       /*
+        * The Tunnels panel _is_ still available in mid-session.
+        */
+       ctrl_settitle(b, "Connection/SSH/Tunnels",
+                     "Options controlling SSH port forwarding");
+
        s = ctrl_getset(b, "Connection/SSH/Tunnels", "portfwd",
                        "Port forwarding");
        ctrl_checkbox(s, "Local ports accept connections from other hosts",'t',
@@ -1741,6 +1788,21 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                                           "Remote", 'm', P(NULL),
                                           "Dynamic", 'y', P(NULL),
                                           NULL);
+       pfd->addressfamily =
+           ctrl_radiobuttons(s, NULL, NO_SHORTCUT,
+#ifndef NO_IPV6
+                             3,
+#else
+                             2,
+#endif
+                             HELPCTX(ssh_tunnels_portfwd_ipversion),
+                             portfwd_handler, P(pfd),
+                             "Auto", NO_SHORTCUT, I(ADDRTYPE_UNSPEC),
+                             "IPv4", NO_SHORTCUT, I(ADDRTYPE_IPV4),
+#ifndef NO_IPV6
+                             "IPv6", NO_SHORTCUT, I(ADDRTYPE_IPV6),
+#endif
+                             NULL);
        ctrl_tabdelay(s, pfd->addbutton);
        ctrl_columns(s, 1, 100);
 
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.
 
-\S{config-termtype} \q{Terminal-type string}
-
-\cfg{winhelp-topic}{connection.termtype}
-
-Most servers you might connect to with PuTTY are designed to be
-connected to from lots of different types of terminal. In order to
-send the right control sequences to each one, the server will need
-to know what type of terminal it is dealing with. Therefore, each of
-the SSH, Telnet and Rlogin protocols allow a text string to be sent
-down the connection describing the terminal.
-
-PuTTY attempts to emulate the Unix \c{xterm} program, and by default
-it reflects this by sending \c{xterm} as a terminal-type string. If
-you find this is not doing what you want - perhaps the remote
-system reports \q{Unknown terminal type} - you could try setting
-this to something different, such as \c{vt220}.
-
-If you're not sure whether a problem is due to the terminal type
-setting or not, you probably need to consult the manual for your
-application or your server.
-
-\S{config-termspeed} \q{Terminal speeds}
-
-\cfg{winhelp-topic}{connection.termspeed}
-
-The Telnet, Rlogin, and SSH protocols allow the client to specify
-terminal speeds to the server.
-
-This parameter does \e{not} affect the actual speed of the connection,
-which is always \q{as fast as possible}; it is just a hint that is
-sometimes used by server software to modify its behaviour. For
-instance, if a slow speed is indicated, the server may switch to a
-less bandwidth-hungry display mode.
-
-The value is usually meaningless in a network environment, but
-PuTTY lets you configure it, in case you find the server is reacting
-badly to the default value.
-
-The format is a pair of numbers separated by a comma, for instance,
-\c{38400,38400}. The first number represents the output speed
-(\e{from} the server) in bits per second, and the second is the input
-speed (\e{to} the server). (Only the first is used in the Rlogin
-protocol.)
-
-This option has no effect on Raw connections.
-
-\S{config-username} \q{Auto-login username}
-
-\cfg{winhelp-topic}{connection.username}
-
-All three of the SSH, Telnet and Rlogin protocols allow you to
-specify what user name you want to log in as, without having to type
-it explicitly every time. (Some Telnet servers don't support this.)
-
-In this box you can type that user name.
-
-\S{config-environ} Setting environment variables on the server
-
-\cfg{winhelp-topic}{telnet.environ}
-
-The Telnet protocol provides a means for the client to pass
-environment variables to the server. Many Telnet servers have
-stopped supporting this feature due to security flaws, but PuTTY
-still supports it for the benefit of any servers which have found
-other ways around the security problems than just disabling the
-whole mechanism.
-
-Version 2 of the SSH protocol also provides a similar mechanism,
-which is easier to implement without security flaws. Newer SSH2
-servers are more likely to support it than older ones.
-
-This configuration data is not used in the SSHv1, rlogin or raw
-protocols.
-
-To add an environment variable to the list transmitted down the
-connection, you enter the variable name in the \q{Variable} box,
-enter its value in the \q{Value} box, and press the \q{Add} button.
-To remove one from the list, select it in the list box and press
-\q{Remove}.
-
 \S{config-keepalive} Using keepalives to prevent disconnection
 
 \cfg{winhelp-topic}{connection.keepalive}
@@ -1678,6 +1598,111 @@ are terminated than for keeping a connection alive.
 
 TCP keepalives are disabled by default.
 
+\S{config-address-family} \q{Internet protocol}
+
+\cfg{winhelp-topic}{connection.ipversion}
+
+This option allows the user to select between the old and new
+Internet protocols and addressing schemes (IPv4 and IPv6). The
+default setting is \q{Auto}, which means PuTTY will do something
+sensible and try to guess which protocol you wanted. (If you specify
+a literal Internet address, it will use whichever protocol that
+address implies. If you provide a hostname, it will see what kinds
+of address exist for that hostname; it will use IPv6 if there is an
+IPv6 address available, and fall back to IPv4 if not.)
+
+If you need to force PuTTY to use a particular protocol, you can
+explicitly set this to \q{IPv4} or \q{IPv6}.
+
+\H{config-data} The Data panel
+
+The Data panel allows you to configure various pieces of data which
+can be sent to the server to affect your connection at the far end.
+
+Each options on this panel applies to more than one protocol.
+Options which apply to only one protocol appear on that protocol's
+configuration panels.
+
+\S{config-username} \q{Auto-login username}
+
+\cfg{winhelp-topic}{connection.username}
+
+All three of the SSH, Telnet and Rlogin protocols allow you to
+specify what user name you want to log in as, without having to type
+it explicitly every time. (Some Telnet servers don't support this.)
+
+In this box you can type that user name.
+
+\S{config-termtype} \q{Terminal-type string}
+
+\cfg{winhelp-topic}{connection.termtype}
+
+Most servers you might connect to with PuTTY are designed to be
+connected to from lots of different types of terminal. In order to
+send the right control sequences to each one, the server will need
+to know what type of terminal it is dealing with. Therefore, each of
+the SSH, Telnet and Rlogin protocols allow a text string to be sent
+down the connection describing the terminal.
+
+PuTTY attempts to emulate the Unix \c{xterm} program, and by default
+it reflects this by sending \c{xterm} as a terminal-type string. If
+you find this is not doing what you want - perhaps the remote
+system reports \q{Unknown terminal type} - you could try setting
+this to something different, such as \c{vt220}.
+
+If you're not sure whether a problem is due to the terminal type
+setting or not, you probably need to consult the manual for your
+application or your server.
+
+\S{config-termspeed} \q{Terminal speeds}
+
+\cfg{winhelp-topic}{connection.termspeed}
+
+The Telnet, Rlogin, and SSH protocols allow the client to specify
+terminal speeds to the server.
+
+This parameter does \e{not} affect the actual speed of the connection,
+which is always \q{as fast as possible}; it is just a hint that is
+sometimes used by server software to modify its behaviour. For
+instance, if a slow speed is indicated, the server may switch to a
+less bandwidth-hungry display mode.
+
+The value is usually meaningless in a network environment, but
+PuTTY lets you configure it, in case you find the server is reacting
+badly to the default value.
+
+The format is a pair of numbers separated by a comma, for instance,
+\c{38400,38400}. The first number represents the output speed
+(\e{from} the server) in bits per second, and the second is the input
+speed (\e{to} the server). (Only the first is used in the Rlogin
+protocol.)
+
+This option has no effect on Raw connections.
+
+\S{config-environ} Setting environment variables on the server
+
+\cfg{winhelp-topic}{telnet.environ}
+
+The Telnet protocol provides a means for the client to pass
+environment variables to the server. Many Telnet servers have
+stopped supporting this feature due to security flaws, but PuTTY
+still supports it for the benefit of any servers which have found
+other ways around the security problems than just disabling the
+whole mechanism.
+
+Version 2 of the SSH protocol also provides a similar mechanism,
+which is easier to implement without security flaws. Newer SSH2
+servers are more likely to support it than older ones.
+
+This configuration data is not used in the SSHv1, rlogin or raw
+protocols.
+
+To add an environment variable to the list transmitted down the
+connection, you enter the variable name in the \q{Variable} box,
+enter its value in the \q{Value} box, and press the \q{Add} button.
+To remove one from the list, select it in the list box and press
+\q{Remove}.
+
 \H{config-proxy} The Proxy panel
 
 \cfg{winhelp-topic}{proxy.main}
@@ -2298,15 +2323,13 @@ about public key authentication in SSH.
 
 This key must be in PuTTY's native format (\c{*.PPK}).
 
-\H{config-ssh-tunnels} The Tunnels panel
-
-The Tunnels panel allows you to configure tunnelling of other
-connection types through an SSH connection.
-
-\S{config-ssh-x11} X11 forwarding
+\H{config-ssh-x11} The X11 panel
 
 \cfg{winhelp-topic}{ssh.tunnels.x11}
 
+The X11 panel allows you to configure forwarding of X11 over an
+SSH connection.
+
 If your server lets you run X Window System applications, X11
 forwarding allows you to securely give those applications access to
 a local X display on your PC.
@@ -2320,7 +2343,7 @@ primary local display (\c{:0}) if that fails.
 See \k{using-x-forwarding} for more information about X11
 forwarding.
 
-\S2{config-ssh-x11auth} Remote X11 authentication
+\S{config-ssh-x11auth} Remote X11 authentication
 
 \cfg{winhelp-topic}{ssh.tunnels.x11auth}
 
@@ -2367,10 +2390,13 @@ connections fail.
 PuTTY's default is \cw{MIT-MAGIC-COOKIE-1}. If you change it, you
 should be sure you know what you're doing.
 
-\S{config-ssh-portfwd} Port forwarding
+\H{config-ssh-portfwd} The Tunnels panel
 
 \cfg{winhelp-topic}{ssh.tunnels.portfwd}
 
+The Tunnels panel allows you to configure tunnelling of arbitrary
+connection types through an SSH connection.
+
 Port forwarding allows you to tunnel other types of network
 connection down an SSH session. See \k{using-port-forwarding} for a
 general discussion of port forwarding and how it works.
@@ -2453,6 +2479,28 @@ SSH server machine can connect to the forwarded port.) Note that
 this feature is only available in the SSH 2 protocol, and not all
 SSH 2 servers support it (OpenSSH 3.0 does not, for example).
 
+\S{config-ssh-portfwd-address-family} Selecting Internet protocol
+version for forwarded ports
+
+\cfg{winhelp-topic}{ssh.tunnels.portfwd.ipversion}
+
+This switch allows you to select a specific Internet protocol (IPv4
+or IPv6) for the local end of a forwarded port. By default, it is
+set on \q{Auto}, which means that:
+
+\b for a local-to-remote port forwarding, PuTTY will listen for
+incoming connections in both IPv4 and (if available) IPv6
+
+\b for a remote-to-local port forwarding, PuTTY will choose a
+sensible protocol for the outgoing connection.
+
+\# FIXME: work out what this paragraph means, reword it for clarity,
+\# and reinstate it.
+Note that on Windows the address space for IPv4 and IPv6 is
+completely disjunct, so listening on IPv6 won't make PuTTY listen on
+IPv4. This behaviour may be different on most remote hosts when they
+are not operating Windows.
+
 \H{config-ssh-bugs} The Bugs panel
 
 Not all SSH servers work properly. Various existing servers have
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   -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)
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   -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
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}).
 
+\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
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.
  */
-SockAddr sk_namelookup(char const *host, char **canonicalname)
+SockAddr sk_namelookup(char const *host, char **canonicalname, int address_family)
 {
 
     if (stack != NULL)
@@ -137,7 +137,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     return NULL;
 }
 
-Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
+Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family)
 {
 
     if (stack != NULL)
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,
-                   const Config *cfg);
+                   const Config *cfg, int addressfamily);
 SockAddr name_lookup(char *host, int port, char **canonicalname,
-                    const Config *cfg);
+                    const Config *cfg, int addressfamily);
 
 /* platform-dependent callback from new_connection() */
 /* (same caveat about addr as new_connection()) */
@@ -98,12 +98,11 @@ Socket platform_new_connection(SockAddr addr, char *hostname,
 void sk_init(void);                   /* called once at program startup */
 void sk_cleanup(void);                /* called just before program exit */
 
-SockAddr sk_namelookup(const char *host, char **canonicalname);
+SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family);
 SockAddr sk_nonamelookup(const char *host);
 void sk_getaddr(SockAddr addr, char *buf, int buflen);
 int sk_hostname_is_local(char *name);
 int sk_address_is_local(SockAddr addr);
-enum { ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME };
 int sk_addrtype(SockAddr addr);
 void sk_addrcopy(SockAddr addr, char *buf);
 void sk_addr_free(SockAddr addr);
@@ -113,7 +112,7 @@ void sk_addr_free(SockAddr addr);
 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
              int nodelay, int keepalive, Plug p);
 
-Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only);
+Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family);
 
 Socket sk_register(OSSocket sock, Plug plug);
 
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,
-                          void *c, const Config *cfg)
+                          void *c, const Config *cfg, int addressfamily)
 {
     static const struct plug_function_table fn_table = {
        pfd_closing,
@@ -371,7 +371,7 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port,
     /*
      * Try to find host.
      */
-    addr = name_lookup(hostname, port, &dummy_realhost, cfg);
+    addr = name_lookup(hostname, port, &dummy_realhost, cfg, addressfamily);
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
@@ -463,7 +463,7 @@ static int pfd_accepting(Plug p, OSSocket sock)
  */
 const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
                           int port, void *backhandle, const Config *cfg,
-                          void **sockdata)
+                          void **sockdata, int address_family)
 {
     static const struct plug_function_table fn_table = {
        pfd_closing,
@@ -494,7 +494,7 @@ const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
     pr->backhandle = backhandle;
 
     pr->s = s = new_listener(srcaddr, port, (Plug) pr,
-                            !cfg->lport_acceptall, cfg);
+                            !cfg->lport_acceptall, cfg, address_family);
     if ((err = sk_socket_error(s)) != NULL) {
        sfree(pr);
        return err;
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,
-                    const Config *cfg)
+                    const Config *cfg, int addressfamily)
 {
     if (cfg->proxy_type != PROXY_NONE &&
        do_proxy_dns(cfg) &&
@@ -351,7 +351,7 @@ SockAddr name_lookup(char *host, int port, char **canonicalname,
        return sk_nonamelookup(host);
     }
 
-    return sk_namelookup(host, canonicalname);
+    return sk_namelookup(host, canonicalname, addressfamily);
 }
 
 Socket new_connection(SockAddr addr, char *hostname,
@@ -433,7 +433,7 @@ Socket new_connection(SockAddr addr, char *hostname,
 
        /* look-up proxy */
        proxy_addr = sk_namelookup(cfg->proxy_host,
-                                  &proxy_canonical_name);
+                                  &proxy_canonical_name, cfg->addressfamily);
        if (sk_addr_error(proxy_addr) != NULL) {
            ret->error = "Proxy error: Unable to resolve proxy host name";
            return (Socket)ret;
@@ -461,13 +461,13 @@ Socket new_connection(SockAddr addr, char *hostname,
 }
 
 Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only,
-                   const Config *cfg)
+                   const Config *cfg, int addressfamily)
 {
     /* TODO: SOCKS (and potentially others) support inbound
      * TODO: connections via the proxy. support them.
      */
 
-    return sk_newlistener(srcaddr, port, plug, local_host_only);
+    return sk_newlistener(srcaddr, port, plug, local_host_only, addressfamily);
 }
 
 /* ----------------------------------------------------------------------
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");
 
     /*
+     * 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".
      */
@@ -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.
      */
     {
@@ -533,6 +539,19 @@ static void print_stats(char *name, unsigned long size, unsigned long done,
  */
 static char *colon(char *str)
 {
+    /* Check and process IPv6 literal addresses
+     * (eg: 'jeroen@[2001:db8::1]:myfile.txt') */
+    char *ipv6 = strchr(str, '[');
+    if (ipv6) {
+       str = strchr(str, ']');
+       if (str) {
+           /* Terminate on the closing bracket */
+           *str++ = '\0';
+           return (str);
+       }
+       return (NULL);
+    }
+
     /* We ignore a leading colon, since the hostname cannot be
        empty. We also ignore a colon as second character because
        of filenames like f:myfile.txt. */
@@ -1928,7 +1947,7 @@ static void toremote(int argc, char *argv[])
     *targ++ = '\0';
     if (*targ == '\0')
        targ = ".";
-    /* Substitute "." for emtpy target */
+    /* Substitute "." for empty target */
 
     /* Separate host and username */
     user = host;
@@ -2129,6 +2148,7 @@ static void usage(void)
     printf("  -l user   connect with specified username\n");
     printf("  -pw passw login with specified password\n");
     printf("  -1 -2     force use of particular SSH protocol version\n");
+    printf("  -4 -6     force use of IPv4 or IPv6\n");
     printf("  -C        enable compression\n");
     printf("  -i key    private key file for authentication\n");
     printf("  -batch    disable all interactive prompts\n");
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("  -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");
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
 };
 
+enum {
+    /*
+     * Network address types. Used for specifying choice of IPv4/v6
+     * in config; also used in proxy.c to indicate whether a given
+     * host name has already been resolved or will be resolved at
+     * the proxy end.
+     */
+    ADDRTYPE_UNSPEC, ADDRTYPE_IPV4, ADDRTYPE_IPV6, ADDRTYPE_NAME
+};
+
 struct backend_tag {
     const char *(*init) (void *frontend_handle, void **backend_handle,
                         Config *cfg,
@@ -375,6 +385,7 @@ struct config_tag {
     char host[512];
     int port;
     int protocol;
+    int addressfamily;
     int close_on_exit;
     int warn_on_close;
     int ping_interval;                /* in seconds */
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;
-       buf = dupprintf("Looking up host \"%s\"", host);
+       buf = dupprintf("Looking up host \"%s\"%s", host,
+                       (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
+                        (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :
+                         "")));
        logevent(raw->frontend, buf);
        sfree(buf);
     }
-    addr = name_lookup(host, port, realhost, cfg);
+    addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily);
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
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;
-       buf = dupprintf("Looking up host \"%s\"", host);
+       buf = dupprintf("Looking up host \"%s\"%s", host,
+                       (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
+                        (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :
+                         "")));
        logevent(rlogin->frontend, buf);
        sfree(buf);
     }
-    addr = name_lookup(host, port, realhost, cfg);
+    addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily);
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
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);
 
+    /* Address family selection */
+    write_setting_i(sesskey, "AddressFamily", cfg->addressfamily);
+
     /* proxy settings */
     write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list);
     write_setting_i(sesskey, "ProxyDNS", (cfg->proxy_dns+2)%3);
@@ -420,6 +423,9 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
            break;
        }
 
+    /* Address family selection */
+    gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, &cfg->addressfamily);
+
     /* The CloseOnExit numbers are arranged in a different order from
      * the standard FORCE_ON / FORCE_OFF / AUTO. */
     gppi(sesskey, "CloseOnExit", 1, &i); cfg->close_on_exit = (i+1)%3;
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;
+    int addressfamily;
     void *local;
 };
 #define free_portfwd(pf) ( \
@@ -2449,8 +2450,11 @@ static const char *connect_to_host(Ssh ssh, char *host, int port,
     /*
      * Try to find host.
      */
-    logeventf(ssh, "Looking up host \"%s\"", host);
-    addr = name_lookup(host, port, realhost, &ssh->cfg);
+    logeventf(ssh, "Looking up host \"%s\"%s", host,
+             (ssh->cfg.addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
+              (ssh->cfg.addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : "")));
+    addr = name_lookup(host, port, realhost, &ssh->cfg,
+                      ssh->cfg.addressfamily);
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
@@ -3666,7 +3670,7 @@ static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx)
 
 static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
 {
-    char type;
+    char address_family, type;
     int n;
     int sport,dport,sserv,dserv;
     char sports[256], dports[256], saddr[256], host[256];
@@ -3690,8 +3694,22 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
     }
 
     while (*portfwd_strptr) {
-       type = *portfwd_strptr++;
+       address_family = 'A';
+       type = 'L';
+       while (*portfwd_strptr && *portfwd_strptr != '\t') {
+           if (*portfwd_strptr == 'A' ||
+               *portfwd_strptr == '4' ||
+               *portfwd_strptr == '6')
+               address_family = *portfwd_strptr;
+           else if (*portfwd_strptr == 'L' ||
+               *portfwd_strptr == 'R' ||
+               *portfwd_strptr == 'D')
+               type = *portfwd_strptr;
+           portfwd_strptr++;
+       }
+
        saddr[0] = '\0';
+
        n = 0;
        while (*portfwd_strptr && *portfwd_strptr != '\t') {
            if (*portfwd_strptr == ':') {
@@ -3774,6 +3792,9 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
            pfrec->dport = dport;
            pfrec->local = NULL;
            pfrec->remote = NULL;
+           pfrec->addressfamily = (address_family == '4' ? ADDRTYPE_IPV4 :
+                                   address_family == '6' ? ADDRTYPE_IPV6 :
+                                   ADDRTYPE_UNSPEC);
 
            epfrec = add234(ssh->portfwds, pfrec);
            if (epfrec != pfrec) {
@@ -3793,27 +3814,28 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg)
                const char *err = pfd_addforward(host, dport,
                                                 *saddr ? saddr : NULL,
                                                 sport, ssh, &ssh->cfg,
-                                                &pfrec->local);
-               if (err) {
-                   logeventf(ssh, "Local port %s forward to %s"
-                             " failed: %s", sportdesc, dportdesc, err);
-               } else {
-                   logeventf(ssh, "Local port %s forwarding to %s",
-                             sportdesc, dportdesc);
-               }
+                                                &pfrec->local,
+                                                pfrec->addressfamily);
+
+               logeventf(ssh, "Local %sport %s forward to %s%s%s",
+                         pfrec->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
+                         pfrec->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
+                         sportdesc, dportdesc,
+                         err ? " failed: " : "", err);
+
                sfree(dportdesc);
            } else if (type == 'D') {
                const char *err = pfd_addforward(NULL, -1,
                                                 *saddr ? saddr : NULL,
                                                 sport, ssh, &ssh->cfg,
-                                                &pfrec->local);
-               if (err) {
-                   logeventf(ssh, "Local port %s SOCKS dynamic forward"
-                             " setup failed: %s", sportdesc, err);
-               } else {
-                   logeventf(ssh, "Local port %s doing SOCKS"
-                             " dynamic forwarding", sportdesc);
-               }
+                                                &pfrec->local,
+                                                pfrec->addressfamily);
+
+                       logeventf(ssh, "Local %sport %s SOCKS dynamic forward%s%s",
+                                 pfrec->addressfamily == ADDRTYPE_IPV4 ? "IPv4 " :
+                                 pfrec->addressfamily == ADDRTYPE_IPV6 ? "IPv6 " : "",
+                                 sportdesc,
+                                 err ? " setup failed: " : "", err);
            } else {
                struct ssh_rportfwd *pf;
 
@@ -4045,7 +4067,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
     /* Remote side is trying to open a channel to talk to a
      * forwarded port. Give them back a local channel number. */
     struct ssh_channel *c;
-    struct ssh_rportfwd pf;
+    struct ssh_rportfwd pf, *pfp;
     int remoteid;
     int hostsize, port;
     char *host, buf[1024];
@@ -4062,8 +4084,9 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
     memcpy(pf.dhost, host, hostsize);
     pf.dhost[hostsize] = '\0';
     pf.dport = port;
+    pfp = find234(ssh->rportfwds, &pf, NULL);
 
-    if (find234(ssh->rportfwds, &pf, NULL) == NULL) {
+    if (pfp == NULL) {
        sprintf(buf, "Rejected remote port open request for %s:%d",
                pf.dhost, port);
        logevent(buf);
@@ -4074,7 +4097,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
                pf.dhost, port);
        logevent(buf);
        e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,
-                          c, &ssh->cfg);
+                          c, &ssh->cfg, pfp->pfrec->addressfamily);
        if (e != NULL) {
            char buf[256];
            sprintf(buf, "Port open failed: %s", e);
@@ -5799,7 +5822,8 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
            const char *e = pfd_newconnect(&c->u.pfd.s,
                                           realpf->dhost,
                                           realpf->dport, c,
-                                          &ssh->cfg);
+                                          &ssh->cfg,
+                                          realpf->pfrec->addressfamily);
            logeventf(ssh, "Attempting to forward remote port to "
                      "%s:%d", realpf->dhost, realpf->dport);
            if (e != NULL) {
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,
-                                 void *c, const Config *cfg);
+                                 void *c, const Config *cfg,
+                                 int addressfamily);
 /* desthost == NULL indicates dynamic (SOCKS) port forwarding */
 extern const char *pfd_addforward(char *desthost, int destport, char *srcaddr,
                                  int port, void *backhandle,
-                                 const Config *cfg, void **sockdata);
+                                 const Config *cfg, void **sockdata,
+                                 int address_family);
 extern void pfd_close(Socket s);
 extern void pfd_terminate(void *sockdata);
 extern int pfd_send(Socket s, char *data, int len);
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;
-       buf = dupprintf("Looking up host \"%s\"", host);
+       buf = dupprintf("Looking up host \"%s\"%s", host,
+                       (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" :
+                        (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" :
+                         "")));
        logevent(telnet->frontend, buf);
        sfree(buf);
     }
-    addr = name_lookup(host, port, realhost, &telnet->cfg);
+    addr = name_lookup(host, port, realhost, &telnet->cfg, cfg->addressfamily);
     if ((err = sk_addr_error(addr)) != NULL) {
        sk_addr_free(addr);
        return err;
index 08fb4e1..f1ef98b 100644 (file)
@@ -69,7 +69,7 @@ struct SockAddr_tag {
      * in this SockAddr structure.
      */
     int family;
-#ifdef IPV6
+#ifndef NO_IPV6
     struct addrinfo *ai;              /* Address IPv6 style. */
 #else
     unsigned long address;            /* Address IPv4 style. */
@@ -125,10 +125,10 @@ const char *error_string(int error)
     return strerror(error);
 }
 
-SockAddr sk_namelookup(const char *host, char **canonicalname)
+SockAddr sk_namelookup(const char *host, char **canonicalname, int address_family)
 {
     SockAddr ret = snew(struct SockAddr_tag);
-#ifdef IPV6
+#ifndef NO_IPV6
     struct addrinfo hints;
     int err;
 #else
@@ -143,9 +143,9 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
     *realhost = '\0';
     ret->error = NULL;
 
-#ifdef IPV6
+#ifndef NO_IPV6
     hints.ai_flags = AI_CANONNAME;
-    hints.ai_family = AF_UNSPEC;
+    hints.ai_family = address_family;
     hints.ai_socktype = 0;
     hints.ai_protocol = 0;
     hints.ai_addrlen = 0;
@@ -219,7 +219,7 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen)
        strncpy(buf, addr->hostname, buflen);
        buf[buflen-1] = '\0';
     } else {
-#ifdef IPV6
+#ifndef NO_IPV6
        if (getnameinfo(addr->ai->ai_addr, addr->ai->ai_addrlen, buf, buflen,
                        NULL, 0, NI_NUMERICHOST) != 0) {
            buf[0] = '\0';
@@ -246,7 +246,7 @@ int sk_address_is_local(SockAddr addr)
     if (addr->family == AF_UNSPEC)
        return 0;                      /* we don't know; assume not */
     else {
-#ifdef IPV6
+#ifndef NO_IPV6
        if (addr->family == AF_INET)
            return ipv4_is_loopback(
                ((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr);
@@ -267,7 +267,7 @@ int sk_address_is_local(SockAddr addr)
 int sk_addrtype(SockAddr addr)
 {
     return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
-#ifdef IPV6
+#ifndef NO_IPV6
            addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
 #endif
            ADDRTYPE_NAME);
@@ -276,7 +276,7 @@ int sk_addrtype(SockAddr addr)
 void sk_addrcopy(SockAddr addr, char *buf)
 {
 
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET)
        memcpy(buf, &((struct sockaddr_in *)addr->ai->ai_addr)->sin_addr,
               sizeof(struct in_addr));
@@ -297,7 +297,7 @@ void sk_addrcopy(SockAddr addr, char *buf)
 void sk_addr_free(SockAddr addr)
 {
 
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->ai != NULL)
        freeaddrinfo(addr->ai);
 #endif
@@ -381,7 +381,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
              int nodelay, int keepalive, Plug plug)
 {
     int s;
-#ifdef IPV6
+#ifndef NO_IPV6
     struct sockaddr_in6 a6;
 #endif
     struct sockaddr_in a;
@@ -448,7 +448,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
 
     /* BSD IP stacks need sockaddr_in zeroed before filling in */
     memset(&a,'\0',sizeof(struct sockaddr_in));
-#ifdef IPV6
+#ifndef NO_IPV6
     memset(&a6,'\0',sizeof(struct sockaddr_in6));
 #endif
 
@@ -459,7 +459,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
        while (1) {
            int retcode;
 
-#ifdef IPV6
+#ifndef NO_IPV6
            if (addr->family == AF_INET6) {
                /* XXX use getaddrinfo to get a local address? */
                a6.sin6_family = AF_INET6;
@@ -501,7 +501,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
      * Connect to remote address.
      */
     switch(addr->family) {
-#ifdef IPV6
+#ifndef NO_IPV6
       case AF_INET:
        /* XXX would be better to have got getaddrinfo() to fill in the port. */
        ((struct sockaddr_in *)addr->ai->ai_addr)->sin_port =
@@ -564,13 +564,10 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     return (Socket) ret;
 }
 
-Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
+Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family)
 {
     int s;
-#ifdef IPV6
-#if 0
-    struct sockaddr_in6 a6;
-#endif
+#ifndef NO_IPV6
     struct addrinfo hints, *ai;
     char portstr[6];
 #endif
@@ -598,9 +595,31 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
     ret->listener = 1;
 
     /*
+     * Translate address_family from platform-independent constants
+     * into local reality.
+     */
+    address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
+                     address_family == ADDRTYPE_IPV6 ? AF_INET6 : AF_UNSPEC);
+
+#ifndef NO_IPV6
+    /* Let's default to IPv6.
+     * If the stack doesn't support IPv6, we will fall back to IPv4. */
+    if (address_family == AF_UNSPEC) address_family = AF_INET6;
+#else
+    /* No other choice, default to IPv4 */
+    if (address_family == AF_UNSPEC)  address_family = AF_INET;
+#endif
+
+    /*
      * Open socket.
      */
-    s = socket(AF_INET, SOCK_STREAM, 0);
+    s = socket(address_family, SOCK_STREAM, 0);
+
+    /* If the host doesn't support IPv6 try fallback to IPv4. */
+    if (s < 0 && address_family == AF_INET6) {
+       address_family = AF_INET;
+       s = socket(address_family, SOCK_STREAM, 0);
+    }
     ret->s = s;
 
     if (s < 0) {
@@ -614,12 +633,12 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
 
     /* BSD IP stacks need sockaddr_in zeroed before filling in */
     memset(&a,'\0',sizeof(struct sockaddr_in));
-#ifdef IPV6
+#ifndef NO_IPV6
 #if 0
     memset(&a6,'\0',sizeof(struct sockaddr_in6));
 #endif
     hints.ai_flags = AI_NUMERICHOST;
-    hints.ai_family = AF_UNSPEC;
+    hints.ai_family = address_family;
     hints.ai_socktype = 0;
     hints.ai_protocol = 0;
     hints.ai_addrlen = 0;
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("  -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");
index d30672b..80a3754 100644 (file)
@@ -49,7 +49,7 @@ BEGIN
 END
 
 /* Accelerators used: aco */
-IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 280, 252
+IDD_MAINBOX DIALOG DISCARDABLE 0, 0, 300, 252
 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION "PuTTY Configuration"
 FONT 8, "MS Shell Dlg"
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.
         */
-       ctlposinit(&cp, hwnd, 80, 3, 13);
+       ctlposinit(&cp, hwnd, 100, 3, 13);
        wc = &ctrls_panel;
        base_id = IDCX_PANELBASE;
     }
@@ -361,7 +361,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
            HWND tvstatic;
 
            r.left = 3;
-           r.right = r.left + 75;
+           r.right = r.left + 95;
            r.top = 3;
            r.bottom = r.top + 10;
            MapDialogRect(hwnd, &r);
@@ -375,7 +375,7 @@ static int CALLBACK GenericMainDlgProc(HWND hwnd, UINT msg,
            SendMessage(tvstatic, WM_SETFONT, font, MAKELPARAM(TRUE, 0));
 
            r.left = 3;
-           r.right = r.left + 75;
+           r.right = r.left + 95;
            r.top = 13;
            r.bottom = r.top + 219;
            MapDialogRect(hwnd, &r);
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.
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_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_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"
index 518eb15..c8b92a6 100644 (file)
@@ -50,8 +50,14 @@ char *get_username(void)
     char *user;
 
     namelen = 0;
-    if (GetUserName(NULL, &namelen) == FALSE)
-       return NULL;
+    if (GetUserName(NULL, &namelen) == FALSE) {
+       /*
+        * Apparently this doesn't work at least on Windows XP SP2.
+        * Thus assume a maximum of 256. It will fail again if it
+        * doesn't fit.
+        */
+       namelen = 256;
+    }
 
     user = snewn(namelen, char);
     GetUserName(user, &namelen);
index f2b2aaa..94b8460 100644 (file)
@@ -1,43 +1,10 @@
 /*
  * Windows networking abstraction.
  *
- * Due to this clean abstraction it was possible
- * to easily implement IPv6 support :)
- *
- * IPv6 patch 1 (27 October 2000) Jeroen Massar <jeroen@unfix.org>
- *  - Preliminary hacked IPv6 support.
- *    - Connecting to IPv6 address (eg fec0:4242:4242:100:2d0:b7ff:fe8f:5d42) works.
- *    - Connecting to IPv6 hostname (eg heaven.ipv6.unfix.org) works.
- *  - Compiles as either IPv4 or IPv6.
- *
- * IPv6 patch 2 (29 October 2000) Jeroen Massar <jeroen@unfix.org>
- *  - When compiled as IPv6 it also allows connecting to IPv4 hosts.
- *  - Added some more documentation.
- *
- * IPv6 patch 3 (18 November 2000) Jeroen Massar <jeroen@unfix.org>
- *  - It now supports dynamically loading the IPv6 resolver dll's.
- *    This way we should be able to distribute one (1) binary
- *    which supports both IPv4 and IPv6.
- *  - getaddrinfo() and getnameinfo() are loaded dynamicaly if possible.
- *  - in6addr_any is defined in this file so we don't need to link to wship6.lib
- *  - The patch is now more unified so that we can still
- *    remove all IPv6 support by undef'ing IPV6.
- *    But where it fallsback to IPv4 it uses the IPv4 code which is already in place...
- *  - Canonical name resolving works.
- *
- * IPv6 patch 4 (07 January 2001) Jeroen Massar <jeroen@unfix.org>
- *  - patch against CVS of today, will be submitted to the bugs list
- *    as a 'cvs diff -u' on Simon's request...
- *
+ * For the IPv6 code in here I am indebted to Jeroen Massar and
+ * unfix.org.
  */
 
-/*
- * Define IPV6 to have IPv6 on-the-fly-loading support.
- * This means that one doesn't have to have an IPv6 stack to use it.
- * But if an IPv6 stack is found it is used with a fallback to IPv4.
- */
-/* #define IPV6 1 */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
 #include "tree234.h"
 
 #include <ws2tcpip.h>
-#ifdef IPV6
-#include <tpipv6.h>
+
+#ifndef NO_IPV6
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 #endif
 
 #define ipv4_is_loopback(addr) \
@@ -92,11 +61,16 @@ struct SockAddr_tag {
      * IPv4; AF_INET6 for IPv6; AF_UNSPEC indicates that name
      * resolution has not been done and a simple host name is held
      * in this SockAddr structure.
+     * The hostname field is also used when the hostname has both
+     * an IPv6 and IPv4 address and the IPv6 connection attempt
+     * fails. We then try the IPv4 address.
+     * This 'family' should become an option in the GUI and
+     * on the commandline for selecting a default protocol.
      */
     int family;
     unsigned long address;            /* Address IPv4 style. */
-#ifdef IPV6
-    struct addrinfo *ai;              /* Address IPv6 style. */
+#ifndef NO_IPV6
+    struct addrinfo *ai;              /* Address AF-independent (IPv4+IPv6) style. */
 #endif
     char hostname[512];                       /* Store an unresolved host name. */
 };
@@ -325,7 +299,8 @@ char *winsock_error_string(int error)
     }
 }
 
-SockAddr sk_namelookup(const char *host, char **canonicalname)
+SockAddr sk_namelookup(const char *host, char **canonicalname,
+                      int address_family)
 {
     SockAddr ret = snew(struct SockAddr_tag);
     unsigned long a;
@@ -334,11 +309,15 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
 
     /* Clear the structure and default to IPv4. */
     memset(ret, 0, sizeof(struct SockAddr_tag));
-    ret->family = 0;                  /* We set this one when we have resolved the host. */
+    ret->family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
+#ifndef NO_IPV6
+                  address_family == ADDRTYPE_IPV6 ? AF_INET6 :
+#endif
+                  AF_UNSPEC);
     *realhost = '\0';
 
     if ((a = p_inet_addr(host)) == (unsigned long) INADDR_NONE) {
-#ifdef IPV6
+#ifndef NO_IPV6
 
        /* Try to get the getaddrinfo() function from wship6.dll */
        /* This way one doesn't need to have IPv6 dll's to use PuTTY and
@@ -356,56 +335,41 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
                                                         "getaddrinfo");
 
        /*
-        * Use fGetAddrInfo when it's available (which usually also
-        * means IPv6 is installed...)
+        * Use fGetAddrInfo when it's available
         */
        if (fGetAddrInfo) {
-           /*debug(("Resolving \"%s\" with getaddrinfo()  (IPv4+IPv6 capable)...\n", host)); */
-           if (fGetAddrInfo(host, NULL, NULL, &ret->ai) == 0)
-               ret->family = ret->ai->ai_family;
+               struct addrinfo hints;
+               memset(&hints, 0, sizeof(hints));
+               hints.ai_family = ret->family;
+               if (fGetAddrInfo(host, NULL, &hints, &ret->ai) == 0)
+                       ret->family = ret->ai->ai_family;
        } else
 #endif
        {
            /*
             * Otherwise use the IPv4-only gethostbyname...
-            * (NOTE: we don't use gethostbyname as a
-            * fallback!)
+            * (NOTE: we don't use gethostbyname as a fallback!)
             */
            if (ret->family == 0) {
-               /*debug(("Resolving \"%s\" with gethostbyname() (IPv4 only)...\n", host)); */
                if ( (h = p_gethostbyname(host)) )
                    ret->family = AF_INET;
            }
        }
-       /*debug(("Done resolving...(family is %d) AF_INET = %d, AF_INET6 = %d\n", ret->family, AF_INET, AF_INET6)); */
 
-       if (ret->family == 0) {
+       if (ret->family == AF_UNSPEC) {
            DWORD err = p_WSAGetLastError();
            ret->error = (err == WSAENETDOWN ? "Network is down" :
                          err ==
                          WSAHOST_NOT_FOUND ? "Host does not exist" : err
                          == WSATRY_AGAIN ? "Host not found" :
-#ifdef IPV6
+#ifndef NO_IPV6
                          fGetAddrInfo ? "getaddrinfo: unknown error" :
 #endif
                          "gethostbyname: unknown error");
-#ifdef DEBUG
-           {
-               LPVOID lpMsgBuf;
-               FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
-                             FORMAT_MESSAGE_FROM_SYSTEM |
-                             FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err,
-                             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-                             (LPTSTR) & lpMsgBuf, 0, NULL);
-               /*debug(("Error %ld: %s (h=%lx)\n", err, lpMsgBuf, h)); */
-               /* Free the buffer. */
-               LocalFree(lpMsgBuf);
-           }
-#endif
        } else {
            ret->error = NULL;
 
-#ifdef IPV6
+#ifndef NO_IPV6
            /* If we got an address info use that... */
            if (ret->ai) {
                typedef int (CALLBACK * FGETNAMEINFO)
@@ -445,7 +409,7 @@ SockAddr sk_namelookup(const char *host, char **canonicalname)
                strncpy(realhost, h->h_name, sizeof(realhost));
            }
        }
-#ifdef IPV6
+#ifndef NO_IPV6
        FreeLibrary(dllWSHIP6);
 #endif
     } else {
@@ -475,9 +439,30 @@ SockAddr sk_nonamelookup(const char *host)
 
 void sk_getaddr(SockAddr addr, char *buf, int buflen)
 {
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET6) {
-       FIXME; /* I don't know how to get a text form of an IPv6 address. */
+       /* Try to get the WSAAddressToStringA() function from wship6.dll */
+       /* This way one doesn't need to have IPv6 dll's to use PuTTY and
+        * it will fallback to IPv4. */
+       typedef int (CALLBACK * FADDRTOSTR) (LPSOCKADDR lpsaAddress,
+               DWORD dwAddressLength,
+               LPWSAPROTOCOL_INFO lpProtocolInfo,
+               OUT LPTSTR lpszAddressString,
+               IN OUT LPDWORD lpdwAddressStringLength
+       );
+       FADDRTOSTR fAddrToStr = NULL;
+
+       HINSTANCE dllWS2 = LoadLibrary("ws2_32.dll");
+       if (dllWS2) {
+           fAddrToStr = (FADDRTOSTR)GetProcAddress(dllWS2,
+                                                   "WSAAddressToStringA");
+           if (fAddrToStr) {
+               fAddrToStr(addr->ai->ai_addr, addr->ai->ai_addrlen,
+                          NULL, buf, &buflen);
+           }
+           else strncpy(buf, "IPv6", buflen);
+           FreeLibrary(dllWS2);
+       }
     } else
 #endif
     if (addr->family == AF_INET) {
@@ -486,7 +471,6 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen)
        strncpy(buf, p_inet_ntoa(a), buflen);
        buf[buflen-1] = '\0';
     } else {
-       assert(addr->family == AF_UNSPEC);
        strncpy(buf, addr->hostname, buflen);
        buf[buflen-1] = '\0';
     }
@@ -530,9 +514,9 @@ static int ipv4_is_local_addr(struct in_addr addr)
 
 int sk_address_is_local(SockAddr addr)
 {
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET6) {
-       FIXME;  /* someone who can compile for IPV6 had better do this bit */
+       return IN6_IS_ADDR_LOOPBACK((const struct in6_addr *)addr->ai->ai_addr);
     } else
 #endif
     if (addr->family == AF_INET) {
@@ -548,7 +532,7 @@ int sk_address_is_local(SockAddr addr)
 int sk_addrtype(SockAddr addr)
 {
     return (addr->family == AF_INET ? ADDRTYPE_IPV4 :
-#ifdef IPV6
+#ifndef NO_IPV6
            addr->family == AF_INET6 ? ADDRTYPE_IPV6 :
 #endif
            ADDRTYPE_NAME);
@@ -557,7 +541,7 @@ int sk_addrtype(SockAddr addr)
 void sk_addrcopy(SockAddr addr, char *buf)
 {
     assert(addr->family != AF_UNSPEC);
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET6) {
        memcpy(buf, (char*) addr->ai, 16);
     } else
@@ -673,7 +657,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     };
 
     SOCKET s;
-#ifdef IPV6
+#ifndef NO_IPV6
     SOCKADDR_IN6 a6;
 #endif
     SOCKADDR_IN a;
@@ -701,7 +685,14 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     /*
      * Open socket.
      */
-    assert(addr->family != AF_UNSPEC);
+#ifndef NO_IPV6
+    /* Let's default to IPv6, this shouldn't hurt anybody
+     * If the stack supports IPv6 it will also allow IPv4 connections. */
+    if (addr->family == AF_UNSPEC) addr->family = AF_INET6;
+#else
+    /* No other choice, default to IPv4 */
+    if (addr->family == AF_UNSPEC) addr->family = AF_INET;
+#endif
     s = p_socket(addr->family, SOCK_STREAM, 0);
     ret->s = s;
 
@@ -739,11 +730,11 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     while (1) {
        int retcode;
 
-#ifdef IPV6
+#ifndef NO_IPV6
        if (addr->family == AF_INET6) {
            memset(&a6, 0, sizeof(a6));
            a6.sin6_family = AF_INET6;
-/*a6.sin6_addr      = in6addr_any; *//* == 0 */
+          /*a6.sin6_addr = in6addr_any; */ /* == 0 done by memset() */
            a6.sin6_port = p_htons(localport);
        } else
 #endif
@@ -752,7 +743,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
            a.sin_addr.s_addr = p_htonl(INADDR_ANY);
            a.sin_port = p_htons(localport);
        }
-#ifdef IPV6
+#ifndef NO_IPV6
        retcode = p_bind(s, (addr->family == AF_INET6 ?
                           (struct sockaddr *) &a6 :
                           (struct sockaddr *) &a),
@@ -785,7 +776,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     /*
      * Connect to remote address.
      */
-#ifdef IPV6
+#ifndef NO_IPV6
     if (addr->family == AF_INET6) {
        memset(&a, 0, sizeof(a));
        a6.sin6_family = AF_INET6;
@@ -809,7 +800,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     }
 
     if ((
-#ifdef IPV6
+#ifndef NO_IPV6
            p_connect(s, ((addr->family == AF_INET6) ?
                        (struct sockaddr *) &a6 : (struct sockaddr *) &a),
                    (addr->family == AF_INET6) ? sizeof(a6) : sizeof(a))
@@ -844,7 +835,8 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
     return (Socket) ret;
 }
 
-Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
+Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
+                     int address_family)
 {
     static const struct socket_function_table fn_table = {
        sk_tcp_plug,
@@ -859,10 +851,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
     };
 
     SOCKET s;
-#ifdef IPV6
+#ifndef NO_IPV6
     SOCKADDR_IN6 a6;
 #endif
     SOCKADDR_IN a;
+
     DWORD err;
     char *errstr;
     Actual_Socket ret;
@@ -885,9 +878,28 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
     ret->pending_error = 0;
 
     /*
+     * Translate address_family from platform-independent constants
+     * into local reality.
+     */
+    address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
+#ifndef NO_IPV6
+                     address_family == ADDRTYPE_IPV6 ? AF_INET6 :
+#endif
+                     AF_UNSPEC);
+#ifndef NO_IPV6
+    /* Let's default to IPv6, this shouldn't hurt anybody
+     * If the stack supports IPv6 it will also allow IPv4 connections. */
+    if (address_family == AF_UNSPEC) address_family = AF_INET6;
+#else
+    /* No other choice, default to IPv4 */
+    if (address_family == AF_UNSPEC)  address_family = AF_INET;
+#endif
+
+    /*
      * Open socket.
      */
-    s = p_socket(AF_INET, SOCK_STREAM, 0);
+    s = p_socket(address_family, SOCK_STREAM, 0);
     ret->s = s;
 
     if (s == INVALID_SOCKET) {
@@ -900,12 +912,15 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
 
     p_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
 
-#ifdef IPV6
-       if (addr->family == AF_INET6) {
+#ifndef NO_IPV6
+       if (address_family == AF_INET6) {
            memset(&a6, 0, sizeof(a6));
            a6.sin6_family = AF_INET6;
            /* FIXME: srcaddr is ignored for IPv6, because I (SGT) don't
-            * know how to do it. :-) */
+            * know how to do it. :-)
+            * (jeroen:) saddr is specified as an address.. eg 2001:db8::1
+            * Thus we need either a parser that understands [2001:db8::1]:80
+            * style addresses and/or enhance this to understand hostnames too. */
            if (local_host_only)
                a6.sin6_addr = in6addr_loopback;
            else
@@ -942,11 +957,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only)
 
            a.sin_port = p_htons((short)port);
        }
-#ifdef IPV6
-       retcode = p_bind(s, (addr->family == AF_INET6 ?
+#ifndef NO_IPV6
+       retcode = p_bind(s, (address_family == AF_INET6 ?
                           (struct sockaddr *) &a6 :
                           (struct sockaddr *) &a),
-                      (addr->family ==
+                      (address_family ==
                        AF_INET6 ? sizeof(a6) : sizeof(a)));
 #else
        retcode = p_bind(s, (struct sockaddr *) &a, sizeof(a));
@@ -1229,11 +1244,15 @@ int select_result(WPARAM wParam, LPARAM lParam)
        return open;
        case FD_ACCEPT:
        {
+#ifdef NO_IPV6
            struct sockaddr_in isa;
-           int addrlen = sizeof(struct sockaddr_in);
+#else
+            struct sockaddr_storage isa;
+#endif
+           int addrlen = sizeof(isa);
            SOCKET t;  /* socket of connection */
 
-           memset(&isa, 0, sizeof(struct sockaddr_in));
+           memset(&isa, 0, sizeof(isa));
            err = 0;
            t = p_accept(s->s,(struct sockaddr *)&isa,&addrlen);
            if (t == INVALID_SOCKET)
@@ -1242,8 +1261,13 @@ int select_result(WPARAM wParam, LPARAM lParam)
                if (err == WSATRY_AGAIN)
                    break;
            }
-
+#ifndef NO_IPV6
+            if (isa.ss_family == AF_INET &&
+                s->localhost_only &&
+                !ipv4_is_local_addr(((struct sockaddr_in *)&isa)->sin_addr)) {
+#else
            if (s->localhost_only && !ipv4_is_local_addr(isa.sin_addr)) {
+#endif
                p_closesocket(t);      /* dodgy WinSock let nonlocal through */
            } else if (plug_accepting(s->plug, (void*)t)) {
                p_closesocket(t);      /* denied or error */
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("  -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");
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.
         */
-       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;