summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2001-04-11 13:56:14 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2001-04-11 13:56:14 +0000
commite02f92519b42c735e1513a55492f3ec43fb9b910 (patch)
tree8f04208cd967484e273799a013b84a3bf381b778
parent3f75b15a3b687ade538896912d65a6f0e4b48ed1 (diff)
https-connect and socks5 support. i feel so bad.
-rw-r--r--usr.bin/ssh/channels.c160
-rw-r--r--usr.bin/ssh/ssh.c7
2 files changed, 153 insertions, 14 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index 583d6b0c3a0..0ba7199d47b 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/channels.c
@@ -40,7 +40,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.105 2001/04/10 12:15:23 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.106 2001/04/11 13:56:13 markus Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
@@ -576,6 +576,39 @@ channel_decode_helper(Channel *c, int start, int lookfor)
return 0; /* need more */
}
+/* try to decode a http connect header */
+int
+channel_decode_https(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ u_char *p, *host, *buf;
+ int port, ret;
+ char httpok[] = "HTTP/1.0 200\r\n\r\n";
+
+ debug2("channel %d: decode https connect", c->self);
+ ret = channel_decode_helper(c, strlen("connect "), '\r');
+ if (ret <= 0)
+ return ret;
+ p = buffer_ptr(&c->input);
+ buf = xmalloc(ret+1);
+ host = xmalloc(ret);
+ memcpy(buf, p, ret);
+ buf[ret] = '\0';
+ if (sscanf(buf, "CONNECT %[^:]:%u HTTP/", host, &port) != 2) {
+ debug("channel %d: cannot parse http header", c->self);
+ return -1;
+ }
+ debug("channel %d: dynamic request: https host %s port %u",
+ c->self, host, port);
+ strlcpy(c->path, host, sizeof(c->path));
+ c->host_port = port;
+ xfree(host);
+ xfree(buf);
+ buffer_consume(&c->input, ret+4);
+ buffer_append(&c->output, httpok, strlen(httpok));
+
+ return 1;
+}
+
/* try to decode a socks4 header */
int
channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
@@ -601,7 +634,7 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
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);
+ debug2("channel %d: decode socks4: user %s/%d", c->self, p, len);
if (len > have)
fatal("channel %d: decode socks4: len %d > have %d",
c->self, len, have);
@@ -613,10 +646,8 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
strlcpy(c->path, host, sizeof(c->path));
c->host_port = ntohs(s4_req.dest_port);
- debug("channel %d: dynamic request: "
- "socks%x://%s@%s:%u/command?%u",
- c->self, s4_req.version, username, host, c->host_port,
- s4_req.command);
+ debug("channel %d: dynamic request: socks4 host %s port %u command %u",
+ c->self, host, c->host_port, s4_req.command);
if (s4_req.command != 1) {
debug("channel %d: cannot handle: socks4 cn %d",
@@ -631,6 +662,115 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
return 1;
}
+/* try to decode a socks5 header */
+#define SSH_SOCKS5_AUTHDONE 0x1000
+#define SSH_SOCKS5_NOAUTH 0x00
+#define SSH_SOCKS5_IPV4 0x01
+#define SSH_SOCKS5_DOMAIN 0x03
+#define SSH_SOCKS5_IPV6 0x04
+#define SSH_SOCKS5_CONNECT 0x01
+#define SSH_SOCKS5_SUCCESS 0x00
+
+int
+channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ struct {
+ u_int8_t version;
+ u_int8_t command;
+ u_int8_t reserved;
+ u_int8_t atyp;
+ } s5_req, s5_rsp;
+ u_int16_t dest_port;
+ u_char *p, dest_addr[255+1];
+ int i, have, found, nmethods, addrlen, af;
+
+ debug2("channel %d: decode socks5", c->self);
+ p = buffer_ptr(&c->input);
+ if (p[0] != 0x05)
+ return -1;
+ have = buffer_len(&c->input);
+ if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
+ /* format: ver | nmethods | methods */
+ if (have < 2)
+ return 0;
+ nmethods = p[1];
+ if (have < nmethods + 2)
+ return 0;
+ /* look for method: "NO AUTHENTICATION REQUIRED" */
+ for (found = 0, i = 2 ; i < nmethods + 2; i++) {
+ if (p[i] == SSH_SOCKS5_NOAUTH ) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
+ c->self);
+ return -1;
+ }
+ buffer_consume(&c->input, nmethods + 2);
+ buffer_put_char(&c->output, 0x05); /* version */
+ buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */
+ FD_SET(c->sock, writeset);
+ c->flags |= SSH_SOCKS5_AUTHDONE;
+ debug2("channel %d: socks5 auth done", c->self);
+ return 0; /* need more */
+ }
+ debug2("channel %d: socks5 post auth", c->self);
+ if (have < sizeof(s5_req)+1)
+ return 0; /* need more */
+ memcpy((char *)&s5_req, p, sizeof(s5_req));
+ if (s5_req.version != 0x05 ||
+ s5_req.command != SSH_SOCKS5_CONNECT ||
+ s5_req.reserved != 0x00) {
+ debug("channel %d: only socks5 connect supported", c->self);
+ return -1;
+ }
+ switch(s5_req.atyp){
+ case SSH_SOCKS5_IPV4:
+ addrlen = 4;
+ af = AF_INET;
+ break;
+ case SSH_SOCKS5_DOMAIN:
+ addrlen = p[sizeof(s5_req)];
+ af = -1;
+ break;
+ case SSH_SOCKS5_IPV6:
+ addrlen = 16;
+ af = AF_INET6;
+ break;
+ default:
+ debug("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
+ return -1;
+ }
+ if (have < 4 + addrlen + 2)
+ return 0;
+ buffer_consume(&c->input, sizeof(s5_req));
+ buffer_get(&c->input, (char *)&dest_addr, addrlen);
+ buffer_get(&c->input, (char *)&dest_port, 2);
+ dest_addr[addrlen] = '\0';
+ if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
+ strlcpy(c->path, dest_addr, sizeof(c->path));
+ else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL)
+ return -1;
+ c->host_port = ntohs(dest_port);
+
+ debug("channel %d: dynamic request: socks5 host %s port %u command %u",
+ c->self, c->path, c->host_port, s5_req.command);
+
+ s5_rsp.version = 0x05;
+ s5_rsp.command = SSH_SOCKS5_SUCCESS;
+ s5_rsp.reserved = 0; /* ignored */
+ s5_rsp.atyp = SSH_SOCKS5_IPV4;
+ ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;
+ dest_port = 0; /* ignored */
+
+ buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp));
+ buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr));
+ buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port));
+ return 1;
+}
+
/* dynamic port forwarding */
void
channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
@@ -651,17 +791,15 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
/* try to guess the protocol */
p = buffer_ptr(&c->input);
switch (p[0]) {
- case 0x04:
- ret = channel_decode_socks4(c, readset, writeset);
- break;
-#if 0
case 'C':
ret = channel_decode_https(c, readset, writeset);
break;
+ case 0x04:
+ ret = channel_decode_socks4(c, readset, writeset);
+ break;
case 0x05:
ret = channel_decode_socks5(c, readset, writeset);
break;
-#endif
default:
ret = -1;
break;
diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c
index 68658acaf98..bd4765c6914 100644
--- a/usr.bin/ssh/ssh.c
+++ b/usr.bin/ssh/ssh.c
@@ -39,7 +39,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh.c,v 1.109 2001/04/11 10:59:01 markus Exp $");
+RCSID("$OpenBSD: ssh.c,v 1.110 2001/04/11 13:56:13 markus Exp $");
#include <openssl/evp.h>
#include <openssl/err.h>
@@ -171,8 +171,9 @@ usage(void)
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, " Allows %s to act as an application-layer proxy.\n",
+ __progname);
+ fprintf(stderr, " Protocols supported: SOCKS4, SOCKS5, HTTPS\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");