diff --git a/ChangeLog b/ChangeLog index 40cf07d41..9c960f13d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,11 @@ - markus@cvs.openbsd.org 2003/07/02 12:56:34 [channels.c] deny dynamic forwarding with -R for v1, too; ok djm@ + - markus@cvs.openbsd.org 2003/07/02 14:51:16 + [channels.c ssh.1 ssh_config.5] + (re)add socks5 suppport to -D; ok djm@ + now ssh(1) can act both as a socks 4 and socks 5 server and + dynamically forward ports. 20030630 - (djm) Search for support functions necessary to build our @@ -635,4 +640,4 @@ - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. Report from murple@murple.net, diagnosis from dtucker@zip.com.au -$Id: ChangeLog,v 1.2839 2003/07/03 03:52:04 dtucker Exp $ +$Id: ChangeLog,v 1.2840 2003/07/03 03:55:19 dtucker Exp $ diff --git a/channels.c b/channels.c index ce07db5c0..e5b2b8c51 100644 --- a/channels.c +++ b/channels.c @@ -39,7 +39,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: channels.c,v 1.192 2003/07/02 12:56:34 markus Exp $"); +RCSID("$OpenBSD: channels.c,v 1.193 2003/07/02 14:51:16 markus Exp $"); #include "ssh.h" #include "ssh1.h" @@ -54,7 +54,7 @@ RCSID("$OpenBSD: channels.c,v 1.192 2003/07/02 12:56:34 markus Exp $"); #include "key.h" #include "authfd.h" #include "pathnames.h" - +#include "bufaux.h" /* -- channel core */ @@ -941,6 +941,117 @@ 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 + +static 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)); + if (s5_req.atyp == SSH_SOCKS5_DOMAIN) + buffer_consume(&c->input, 1); /* host string length */ + 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 */ static void channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) @@ -953,7 +1064,7 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) debug2("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 < 4) { + if (have < 3) { /* need more */ FD_SET(c->sock, readset); return; @@ -964,6 +1075,9 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) case 0x04: ret = channel_decode_socks4(c, readset, writeset); break; + case 0x05: + ret = channel_decode_socks5(c, readset, writeset); + break; default: ret = -1; break; diff --git a/ssh.1 b/ssh.1 index defc0e640..8a7d2f428 100644 --- a/ssh.1 +++ b/ssh.1 @@ -34,7 +34,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. .\" -.\" $OpenBSD: ssh.1,v 1.173 2003/06/10 09:12:11 jmc Exp $ +.\" $OpenBSD: ssh.1,v 1.174 2003/07/02 14:51:16 markus Exp $ .Dd September 25, 1999 .Dt SSH 1 .Os @@ -649,9 +649,9 @@ on the local side, and whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. -Currently the SOCKS4 protocol is supported, and +Currently the SOCKS4 and SOCKS5 protocols are supported, and .Nm -will act as a SOCKS4 server. +will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file. .It Fl 1 diff --git a/ssh_config.5 b/ssh_config.5 index 56df3acec..79d05f018 100644 --- a/ssh_config.5 +++ b/ssh_config.5 @@ -34,7 +34,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. .\" -.\" $OpenBSD: ssh_config.5,v 1.14 2003/06/23 09:02:44 markus Exp $ +.\" $OpenBSD: ssh_config.5,v 1.15 2003/07/02 14:51:16 markus Exp $ .Dd September 25, 1999 .Dt SSH_CONFIG 5 .Os @@ -246,9 +246,9 @@ over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. The argument must be a port number. -Currently the SOCKS4 protocol is supported, and +Currently the SOCKS4 and SOCKS5 protocols are supported, and .Nm ssh -will act as a SOCKS4 server. +will act as a SOCKS server. Multiple forwardings may be specified, and additional forwardings can be given on the command line. Only the superuser can forward privileged ports.