]> andersk Git - openssh.git/commitdiff
- markus@cvs.openbsd.org 2001/04/07 08:55:18
authormouring <mouring>
Sun, 8 Apr 2001 18:30:26 +0000 (18:30 +0000)
committermouring <mouring>
Sun, 8 Apr 2001 18:30:26 +0000 (18:30 +0000)
     [buffer.c channels.c channels.h readconf.c ssh.c]
     allow the ssh client act as a SOCKS4 proxy (dynamic local
     portforwarding).  work by Dan Kaminsky <dankamin@cisco.com> and me.
     thanks to Dan for this great patch: use 'ssh -D 1080 host' and make
     netscape use localhost:1080 as a socks proxy.

ChangeLog
buffer.c
channels.c
channels.h
readconf.c
ssh.c

index 6649ae49fc11d629e6c5c3fa8ea80faf3f0e6c19..57cd282c3630fe2ceca0225b7f0be8941e1ed91e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
      do gid/groups-swap in addition to uid-swap, should help if /home/group
      is chmod 750 + chgrp grp /home/group/, work be deraadt and me, thanks
      to olar@openwall.com is comments.  we had many requests for this.
+   - markus@cvs.openbsd.org 2001/04/07 08:55:18
+     [buffer.c channels.c channels.h readconf.c ssh.c]
+     allow the ssh client act as a SOCKS4 proxy (dynamic local 
+     portforwarding).  work by Dan Kaminsky <dankamin@cisco.com> and me. 
+     thanks to Dan for this great patch: use 'ssh -D 1080 host' and make 
+     netscape use localhost:1080 as a socks proxy.
 
 20010408
  - OpenBSD CVS Sync
index 68696fd3f745d927961ef46b5cc4274978976dcb..377d0c09f4075ddab549755a38262fc122a2f17e 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: buffer.c,v 1.11 2001/04/05 21:02:46 markus Exp $");
+RCSID("$OpenBSD: buffer.c,v 1.12 2001/04/07 08:55:15 markus Exp $");
 
 #include "xmalloc.h"
 #include "buffer.h"
@@ -156,5 +156,5 @@ buffer_dump(Buffer *buffer)
 
        for (i = buffer->offset; i < buffer->end; i++)
                fprintf(stderr, " %02x", ucp[i]);
-       fprintf(stderr, "\n");
+       fprintf(stderr, "\r\n");
 }
index d5526fb8374ac9d10cef91d31113862768a4cf19..0e334db88a24025549f2bf814851f3ab7e1f43a2 100644 (file)
@@ -40,7 +40,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.102 2001/04/06 21:00:10 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.103 2001/04/07 08:55:17 markus Exp $");
 
 #include <openssl/rsa.h>
 #include <openssl/dsa.h>
@@ -51,6 +51,7 @@ RCSID("$OpenBSD: channels.c,v 1.102 2001/04/06 21:00:10 markus Exp $");
 #include "packet.h"
 #include "xmalloc.h"
 #include "buffer.h"
+#include "bufaux.h"
 #include "uidswap.h"
 #include "log.h"
 #include "misc.h"
@@ -133,6 +134,8 @@ static int have_hostname_in_open = 0;
 /* AF_UNSPEC or AF_INET or AF_INET6 */
 extern int IPv4or6;
 
+void    port_open_helper(Channel *c, char *rtype);
+
 /* Sets specific protocol options. */
 
 void
@@ -539,6 +542,89 @@ channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)
        }
 }
 
+#define SSH_SOCKS_HEAD 1+1+2+4
+
+void
+channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       u_char *p, *host;
+       int len, i, done, have;
+       char username[256];
+       struct {
+               u_int8_t version;
+               u_int8_t command;
+               u_int16_t dest_port;
+               struct in_addr dest_ip;
+       } s4_req, s4_rsp;
+
+       have = buffer_len(&c->input);
+
+       debug("channel %d: pre_dynamic have: %d", c->self, have);
+       /*buffer_dump(&c->input);*/
+
+       /* Check if the fixed size part of the packet is in buffer. */
+       if (have < SSH_SOCKS_HEAD + 1) {
+               /* need more */
+               FD_SET(c->sock, readset);
+               return;
+       }
+       /* Check for end of username */
+       p = buffer_ptr(&c->input);
+       done = 0;
+       for (i = SSH_SOCKS_HEAD; i < have; i++) {
+               if (p[i] == '\0') {
+                       done = 1;
+                       break;
+               }
+       }
+       if (!done) {
+               /* need more */
+               FD_SET(c->sock, readset);
+               return;
+       }
+       buffer_get(&c->input, (char *)&s4_req.version, 1);
+       buffer_get(&c->input, (char *)&s4_req.command, 1);
+       buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
+       buffer_get(&c->input, (char *)&s4_req.dest_ip, 4);
+       p = buffer_ptr(&c->input);
+       len = strlen(p);
+       have = buffer_len(&c->input);
+       debug2("channel %d: pre_dynamic user: %s/%d", c->self, p, len);
+       if (len > have)
+               fatal("channel %d: pre_dynamic: len %d > have %d",
+                   c->self, len, have);
+       strlcpy(username, p, sizeof(username));
+       buffer_consume(&c->input, len);
+       buffer_consume(&c->input, 1);           /* trailing '\0' */
+
+       host = inet_ntoa(s4_req.dest_ip);
+       strlcpy(c->path, host, sizeof(c->path));
+       c->host_port = ntohs(s4_req.dest_port);
+       
+       debug("channel %d: dynamic request received: "
+           "socks%x://%s@%s:%u/command?%u",
+           c->self, s4_req.version, username, host, c->host_port,
+           s4_req.command);
+
+       if ((s4_req.version != 4) || (s4_req.command != 1)) {
+               debug("channel %d: cannot handle: socks VN %d CN %d",
+                   c->self, s4_req.version, s4_req.command);
+               channel_free(c->self);
+               return;
+       }
+
+       s4_rsp.version = 0;                     /* VN: version of reply code */
+       s4_rsp.command = 90;                    /* CD: request granted */
+       s4_rsp.dest_port = 0;                   /* ignored */
+       s4_rsp.dest_ip.s_addr = INADDR_ANY;     /* ignored */
+       buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp));
+
+       /* switch to next state */
+       c->type = SSH_CHANNEL_OPENING;
+       port_open_helper(c, "direct-tcpip");
+}
+
+
 /* This is our fake X11 server socket. */
 void
 channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
@@ -591,73 +677,100 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset)
        }
 }
 
+void
+port_open_helper(Channel *c, char *rtype)
+{
+       int direct;
+       char buf[1024];
+       char *remote_ipaddr = get_peer_ipaddr(c->sock);
+       u_short remote_port = get_peer_port(c->sock);
+
+       direct = (strcmp(rtype, "direct-tcpip") == 0);
+
+       snprintf(buf, sizeof buf,
+           "%s: listening port %d for %.100s port %d, "
+           "connect from %.200s port %d",
+           rtype, c->listening_port, c->path, c->host_port,
+           remote_ipaddr, remote_port);
+
+       xfree(c->remote_name);
+       c->remote_name = xstrdup(buf);
+
+       if (compat20) {
+               packet_start(SSH2_MSG_CHANNEL_OPEN);
+               packet_put_cstring(rtype);
+               packet_put_int(c->self);
+               packet_put_int(c->local_window_max);
+               packet_put_int(c->local_maxpacket);
+               if (direct) {
+                       /* target host, port */
+                       packet_put_cstring(c->path);
+                       packet_put_int(c->host_port);
+               } else {
+                       /* listen address, port */
+                       packet_put_cstring(c->path);
+                       packet_put_int(c->listening_port);
+               }
+               /* originator host and port */
+               packet_put_cstring(remote_ipaddr);
+               packet_put_int(remote_port);
+               packet_send();
+       } else {
+               packet_start(SSH_MSG_PORT_OPEN);
+               packet_put_int(c->self);
+               packet_put_cstring(c->path);
+               packet_put_int(c->host_port);
+               if (have_hostname_in_open)
+                       packet_put_cstring(c->remote_name);
+               packet_send();
+       }
+       xfree(remote_ipaddr);
+}
+
 /*
  * This socket is listening for connections to a forwarded TCP/IP port.
  */
 void
 channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
 {
+       Channel *nc;
        struct sockaddr addr;
-       int newsock, newch;
+       int newsock, newch, nextstate;
        socklen_t addrlen;
-       char buf[1024], *remote_ipaddr, *rtype;
-       int remote_port;
-
-       rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
-           "forwarded-tcpip" : "direct-tcpip";
+       char *rtype;
 
        if (FD_ISSET(c->sock, readset)) {
                debug("Connection to port %d forwarding "
                    "to %.100s port %d requested.",
                    c->listening_port, c->path, c->host_port);
+
+               rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
+                   "forwarded-tcpip" : "direct-tcpip";
+               nextstate = (c->host_port == 0) ? SSH_CHANNEL_DYNAMIC :
+                   SSH_CHANNEL_OPENING;
+
                addrlen = sizeof(addr);
                newsock = accept(c->sock, &addr, &addrlen);
                if (newsock < 0) {
                        error("accept: %.100s", strerror(errno));
                        return;
                }
-               remote_ipaddr = get_peer_ipaddr(newsock);
-               remote_port = get_peer_port(newsock);
-               snprintf(buf, sizeof buf,
-                   "listen port %d for %.100s port %d, "
-                   "connect from %.200s port %d",
-                   c->listening_port, c->path, c->host_port,
-                   remote_ipaddr, remote_port);
-
                newch = channel_new(rtype,
-                   SSH_CHANNEL_OPENING, newsock, newsock, -1,
+                   nextstate, newsock, newsock, -1,
                    c->local_window_max, c->local_maxpacket,
-                   0, xstrdup(buf), 1);
-               if (compat20) {
-                       packet_start(SSH2_MSG_CHANNEL_OPEN);
-                       packet_put_cstring(rtype);
-                       packet_put_int(newch);
-                       packet_put_int(c->local_window_max);
-                       packet_put_int(c->local_maxpacket);
-                       if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
-                               /* listen address, port */
-                               packet_put_string(c->path, strlen(c->path));
-                               packet_put_int(c->listening_port);
-                       } else {
-                               /* target host, port */
-                               packet_put_string(c->path, strlen(c->path));
-                               packet_put_int(c->host_port);
-                       }
-                       /* originator host and port */
-                       packet_put_cstring(remote_ipaddr);
-                       packet_put_int(remote_port);
-                       packet_send();
-               } else {
-                       packet_start(SSH_MSG_PORT_OPEN);
-                       packet_put_int(newch);
-                       packet_put_string(c->path, strlen(c->path));
-                       packet_put_int(c->host_port);
-                       if (have_hostname_in_open) {
-                               packet_put_string(buf, strlen(buf));
-                       }
-                       packet_send();
+                   0, xstrdup(rtype), 1);
+
+               nc = channel_lookup(newch);
+               if (nc == NULL) {
+                       error("xxx: no new channel:");
+                       return;
                }
-               xfree(remote_ipaddr);
+               nc->listening_port = c->listening_port;
+               nc->host_port = c->host_port;
+               strlcpy(nc->path, c->path, sizeof(nc->path));
+
+               if (nextstate != SSH_CHANNEL_DYNAMIC)
+                       port_open_helper(nc, rtype);
        }
 }
 
@@ -733,6 +846,15 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
                if (len <= 0) {
                        debug("channel %d: read<=0 rfd %d len %d",
                            c->self, c->rfd, len);
+                       if (c->type == SSH_CHANNEL_DYNAMIC) {
+                               /*
+                                * we are not yet connected to a remote peer,
+                                * so the connection-close protocol won't work
+                                */
+                               debug("channel %d: dynamic: closed", c->self);
+                               channel_free(c->self);
+                               return -1;
+                       }
                        if (compat13) {
                                buffer_consume(&c->output, buffer_len(&c->output));
                                c->type = SSH_CHANNEL_INPUT_DRAINING;
@@ -893,6 +1015,12 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
        }
 }
 
+void
+channel_post_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       channel_handle_rfd(c, readset, writeset);
+}
+
 void
 channel_handler_init_20(void)
 {
@@ -903,6 +1031,7 @@ channel_handler_init_20(void)
        channel_pre[SSH_CHANNEL_X11_LISTENER] =         &channel_pre_listener;
        channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
        channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
 
        channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_2;
        channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
@@ -910,6 +1039,7 @@ channel_handler_init_20(void)
        channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
        channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
        channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_dynamic;
 }
 
 void
@@ -923,6 +1053,7 @@ channel_handler_init_13(void)
        channel_pre[SSH_CHANNEL_INPUT_DRAINING] =       &channel_pre_input_draining;
        channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =      &channel_pre_output_draining;
        channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
 
        channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
        channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
@@ -930,6 +1061,7 @@ channel_handler_init_13(void)
        channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
        channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =     &channel_post_output_drain_13;
        channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_dynamic;
 }
 
 void
@@ -941,12 +1073,14 @@ channel_handler_init_15(void)
        channel_pre[SSH_CHANNEL_PORT_LISTENER] =        &channel_pre_listener;
        channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
        channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
 
        channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
        channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
        channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
        channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
        channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_dynamic;
 }
 
 void
@@ -1500,6 +1634,7 @@ channel_still_open()
                case SSH_CHANNEL_RPORT_LISTENER:
                case SSH_CHANNEL_CLOSED:
                case SSH_CHANNEL_AUTH_SOCKET:
+               case SSH_CHANNEL_DYNAMIC:
                case SSH_CHANNEL_CONNECTING:    /* XXX ??? */
                        continue;
                case SSH_CHANNEL_LARVAL:
@@ -1551,6 +1686,7 @@ channel_open_message()
                case SSH_CHANNEL_LARVAL:
                case SSH_CHANNEL_OPENING:
                case SSH_CHANNEL_CONNECTING:
+               case SSH_CHANNEL_DYNAMIC:
                case SSH_CHANNEL_OPEN:
                case SSH_CHANNEL_X11_OPEN:
                case SSH_CHANNEL_INPUT_DRAINING:
index 2cd82148e55259824403ca88a2eb1b31e64b0019..23e6ece839d11f17bde4b91533120ad6f90e1b38 100644 (file)
@@ -32,7 +32,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/* RCSID("$OpenBSD: channels.h,v 1.29 2001/04/04 20:25:36 markus Exp $"); */
+/* RCSID("$OpenBSD: channels.h,v 1.30 2001/04/07 08:55:17 markus Exp $"); */
 
 #ifndef CHANNELS_H
 #define CHANNELS_H
@@ -53,7 +53,8 @@
 #define SSH_CHANNEL_LARVAL             10      /* larval session */
 #define SSH_CHANNEL_RPORT_LISTENER     11      /* Listening to a R-style port  */
 #define SSH_CHANNEL_CONNECTING         12
-#define SSH_CHANNEL_MAX_TYPE           13
+#define SSH_CHANNEL_DYNAMIC            13
+#define SSH_CHANNEL_MAX_TYPE           14
 
 /*
  * Data structure for channel data.  This is iniailized in channel_allocate
index 365f67eb0068fcaeb42e27bbea2ac6d42ccc2505..007056d4d47d9e5ae15363d93bd0fb4306546052 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.70 2001/04/02 14:20:23 stevesk Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.71 2001/04/07 08:55:17 markus Exp $");
 
 #include "ssh.h"
 #include "xmalloc.h"
@@ -110,7 +110,7 @@ typedef enum {
        oUsePrivilegedPort, oLogLevel, oCiphers, oProtocol, oMacs,
        oGlobalKnownHostsFile2, oUserKnownHostsFile2, oPubkeyAuthentication,
        oKbdInteractiveAuthentication, oKbdInteractiveDevices, oHostKeyAlias,
-       oPreferredAuthentications
+       oDynamicForward, oPreferredAuthentications
 } OpCodes;
 
 /* Textual representations of the tokens. */
@@ -172,6 +172,7 @@ static struct {
        { "keepalive", oKeepAlives },
        { "numberofpasswordprompts", oNumberOfPasswordPrompts },
        { "loglevel", oLogLevel },
+       { "dynamicforward", oDynamicForward },
        { "preferredauthentications", oPreferredAuthentications },
        { NULL, 0 }
 };
@@ -583,6 +584,18 @@ parse_int:
                        add_local_forward(options, fwd_port, buf, fwd_host_port);
                break;
 
+       case oDynamicForward:
+               arg = strdelim(&s);
+               if (!arg || *arg == '\0')
+                       fatal("%.200s line %d: Missing port argument.",
+                           filename, linenum);
+               if (arg[0] < '0' || arg[0] > '9')
+                       fatal("%.200s line %d: Badly formatted port number.",
+                           filename, linenum);
+               fwd_port = atoi(arg);
+               add_local_forward(options, fwd_port, "socks4", 0);
+                break;
+
        case oHost:
                *activep = 0;
                while ((arg = strdelim(&s)) != NULL && *arg != '\0')
diff --git a/ssh.c b/ssh.c
index 294bcf39d0c58b854f8254c8b437a525e7358093..75094a106d7422fe457aec5bb004f7176188f33d 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -39,7 +39,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.107 2001/04/06 21:00:13 markus Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.108 2001/04/07 08:55:18 markus Exp $");
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
@@ -178,6 +178,9 @@ usage(void)
        fprintf(stderr, "  -R listen-port:host:port   Forward remote port to local address\n");
        fprintf(stderr, "              These cause %s to listen for connections on a port, and\n", __progname);
        fprintf(stderr, "              forward them to the other side by connecting to host:port.\n");
+       fprintf(stderr, "  -D port     Dynamically forward local port to multiple remote addresses.\n");
+       fprintf(stderr, "              Allows SSH to act as an application-layer proxy.\n");
+       fprintf(stderr, "              Protocols Supported: SOCKS4\n");
        fprintf(stderr, "  -C          Enable compression.\n");
        fprintf(stderr, "  -N          Do not execute a shell or command.\n");
        fprintf(stderr, "  -g          Allow remote hosts to connect to forwarded ports.\n");
@@ -314,7 +317,7 @@ main(int ac, char **av)
                opt = av[optind][1];
                if (!opt)
                        usage();
-               if (strchr("eilcmpLRo", opt)) { /* options with arguments */
+               if (strchr("eilcmpLRDo", opt)) {   /* options with arguments */
                        optarg = av[optind] + 2;
                        if (strcmp(optarg, "") == 0) {
                                if (optind >= ac - 1)
@@ -480,6 +483,12 @@ main(int ac, char **av)
                        }
                        add_local_forward(&options, fwd_port, buf, fwd_host_port);
                        break;
+
+               case 'D':
+                       fwd_port = atoi(optarg);
+                       add_local_forward(&options, fwd_port, "socks4", 0);
+                       break;
+
                case 'C':
                        options.compression = 1;
                        break;
This page took 2.383112 seconds and 5 git commands to generate.