Dynamic port forwarding by means of a local SOCKS server. Fully
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index b2abec4..7472625 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -1983,6 +1983,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
        ssh->version = 1;
        ssh->s_rdpkt = ssh1_rdpkt;
     }
+    update_specials_menu(ssh->frontend);
     ssh->state = SSH_STATE_BEFORE_SIZE;
 
     sfree(s->vstring);
@@ -3148,30 +3149,34 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                if (n < 255) sports[n++] = *ssh->portfwd_strptr++;
            }
            sports[n] = 0;
-           if (*ssh->portfwd_strptr == '\t')
-               ssh->portfwd_strptr++;
-           n = 0;
-           while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') {
-               if (n < 255) host[n++] = *ssh->portfwd_strptr++;
-           }
-           host[n] = 0;
-           if (*ssh->portfwd_strptr == ':')
+           if (type != 'D') {
+               if (*ssh->portfwd_strptr == '\t')
+                   ssh->portfwd_strptr++;
+               n = 0;
+               while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') {
+                   if (n < 255) host[n++] = *ssh->portfwd_strptr++;
+               }
+               host[n] = 0;
+               if (*ssh->portfwd_strptr == ':')
+                   ssh->portfwd_strptr++;
+               n = 0;
+               while (*ssh->portfwd_strptr) {
+                   if (n < 255) dports[n++] = *ssh->portfwd_strptr++;
+               }
+               dports[n] = 0;
                ssh->portfwd_strptr++;
-           n = 0;
-           while (*ssh->portfwd_strptr) {
-               if (n < 255) dports[n++] = *ssh->portfwd_strptr++;
-           }
-           dports[n] = 0;
-           ssh->portfwd_strptr++;
-           dport = atoi(dports);
-           dserv = 0;
-           if (dport == 0) {
-               dserv = 1;
-               dport = net_service_lookup(dports);
-               if (!dport) {
-                   logeventf(ssh, "Service lookup failed for"
-                             " destination port \"%s\"", dports);
+               dport = atoi(dports);
+               dserv = 0;
+               if (dport == 0) {
+                   dserv = 1;
+                   dport = net_service_lookup(dports);
+                   if (!dport) {
+                       logeventf(ssh, "Service lookup failed for"
+                                 " destination port \"%s\"", dports);
+                   }
                }
+           } else {
+               while (*ssh->portfwd_strptr) ssh->portfwd_strptr++;
            }
            sport = atoi(sports);
            sserv = 0;
@@ -3196,6 +3201,15 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                              host,
                              (int)(dserv ? strlen(dports) : 0), dports,
                              dserv, "(", dport, dserv, ")");
+               } else if (type == 'D') {
+                   pfd_addforward(NULL, -1, *saddr ? saddr : NULL,
+                                  sport, ssh, &ssh->cfg);
+                   logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
+                             " doing SOCKS dynamic forwarding",
+                             (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
+                             (int)(*saddr?1:0), ":",
+                             (int)(sserv ? strlen(sports) : 0), sports,
+                             sserv, "(", sport, sserv, ")");
                } else {
                    struct ssh_rportfwd *pf;
                    pf = snew(struct ssh_rportfwd);
@@ -5229,30 +5243,34 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                if (n < 255) sports[n++] = *ssh->portfwd_strptr++;
            }
            sports[n] = 0;
-           if (*ssh->portfwd_strptr == '\t')
-               ssh->portfwd_strptr++;
-           n = 0;
-           while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') {
-               if (n < 255) host[n++] = *ssh->portfwd_strptr++;
-           }
-           host[n] = 0;
-           if (*ssh->portfwd_strptr == ':')
+           if (type != 'D') {
+               if (*ssh->portfwd_strptr == '\t')
+                   ssh->portfwd_strptr++;
+               n = 0;
+               while (*ssh->portfwd_strptr && *ssh->portfwd_strptr != ':') {
+                   if (n < 255) host[n++] = *ssh->portfwd_strptr++;
+               }
+               host[n] = 0;
+               if (*ssh->portfwd_strptr == ':')
+                   ssh->portfwd_strptr++;
+               n = 0;
+               while (*ssh->portfwd_strptr) {
+                   if (n < 255) dports[n++] = *ssh->portfwd_strptr++;
+               }
+               dports[n] = 0;
                ssh->portfwd_strptr++;
-           n = 0;
-           while (*ssh->portfwd_strptr) {
-               if (n < 255) dports[n++] = *ssh->portfwd_strptr++;
-           }
-           dports[n] = 0;
-           ssh->portfwd_strptr++;
-           dport = atoi(dports);
-           dserv = 0;
-           if (dport == 0) {
-               dserv = 1;
-               dport = net_service_lookup(dports);
-               if (!dport) {
-                   logeventf(ssh, "Service lookup failed for destination"
-                             " port \"%s\"", dports);
+               dport = atoi(dports);
+               dserv = 0;
+               if (dport == 0) {
+                   dserv = 1;
+                   dport = net_service_lookup(dports);
+                   if (!dport) {
+                       logeventf(ssh, "Service lookup failed for destination"
+                                 " port \"%s\"", dports);
+                   }
                }
+           } else {
+               while (*ssh->portfwd_strptr) ssh->portfwd_strptr++;
            }
            sport = atoi(sports);
            sserv = 0;
@@ -5277,6 +5295,15 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                              host,
                              (int)(dserv ? strlen(dports) : 0), dports,
                              dserv, "(", dport, dserv, ")");
+               } else if (type == 'D') {
+                   pfd_addforward(NULL, -1, *saddr ? saddr : NULL,
+                                  sport, ssh, &ssh->cfg);
+                   logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
+                             " doing SOCKS dynamic forwarding",
+                             (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
+                             (int)(*saddr?1:0), ":",
+                             (int)(sserv ? strlen(sports) : 0), sports,
+                             sserv, "(", sport, sserv, ")");
                } else {
                    struct ssh_rportfwd *pf;
                    pf = snew(struct ssh_rportfwd);
@@ -5967,6 +5994,7 @@ static char *ssh_init(void *frontend_handle, void **backend_handle,
 
     ssh = snew(struct ssh_tag);
     ssh->cfg = *cfg;                  /* STRUCTURE COPY */
+    ssh->version = 0;                 /* when not ready yet */
     ssh->s = NULL;
     ssh->cipher = NULL;
     ssh->v1_cipher_ctx = NULL;
@@ -6213,6 +6241,31 @@ static void ssh_size(void *handle, int width, int height)
 }
 
 /*
+ * Return a list of the special codes that make sense in this
+ * protocol.
+ */
+static const struct telnet_special *ssh_get_specials(void *handle)
+{
+    Ssh ssh = (Ssh) handle;
+
+    if (ssh->version == 1) {
+       static const struct telnet_special ssh1_specials[] = {
+           {"IGNORE message", TS_NOP},
+           {NULL, 0}
+       };
+       return ssh1_specials;
+    } else if (ssh->version == 2) {
+       static const struct telnet_special ssh2_specials[] = {
+           {"Break", TS_BRK},
+           {"IGNORE message", TS_NOP},
+           {NULL, 0}
+       };
+       return ssh2_specials;
+    } else
+       return NULL;
+}
+
+/*
  * Send Telnet special codes. TS_EOF is useful for `plink', so you
  * can send an EOF and collect resulting output (e.g. `plink
  * hostname sort').
@@ -6239,7 +6292,7 @@ static void ssh_special(void *handle, Telnet_Special code)
            ssh2_pkt_send(ssh);
        }
        logevent("Sent EOF message");
-    } else if (code == TS_PING) {
+    } else if (code == TS_PING || code == TS_NOP) {
        if (ssh->state == SSH_STATE_CLOSED
            || ssh->state == SSH_STATE_PREPACKET) return;
        if (ssh->version == 1) {
@@ -6250,6 +6303,19 @@ static void ssh_special(void *handle, Telnet_Special code)
            ssh2_pkt_addstring_start(ssh);
            ssh2_pkt_send(ssh);
        }
+    } else if (code == TS_BRK) {
+       if (ssh->state == SSH_STATE_CLOSED
+           || ssh->state == SSH_STATE_PREPACKET) return;
+       if (ssh->version == 1) {
+           logevent("Unable to send BREAK signal in SSH1");
+       } else {
+           ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST);
+           ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid);
+           ssh2_pkt_addstring(ssh, "break");
+           ssh2_pkt_addbool(ssh, 0);
+           ssh2_pkt_adduint32(ssh, 0);   /* default break length */
+           ssh2_pkt_send(ssh);
+       }
     } else {
        /* do nothing */
     }
@@ -6390,6 +6456,7 @@ Backend ssh_backend = {
     ssh_sendbuffer,
     ssh_size,
     ssh_special,
+    ssh_get_specials,
     ssh_socket,
     ssh_return_exitcode,
     ssh_sendok,