summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorMarkus Friedl <markus@cvs.openbsd.org>2003-07-02 14:51:17 +0000
committerMarkus Friedl <markus@cvs.openbsd.org>2003-07-02 14:51:17 +0000
commit29ebacc0b66b26eb95385e94a5d114cf4b417a32 (patch)
treec35e3a180f3bc4dcb0771c75a6c447da95e25d65 /usr.bin
parent6e14a59edc291fb2ea7f912bf4dfae58ef0e5b5d (diff)
(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.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/ssh/channels.c120
-rw-r--r--usr.bin/ssh/ssh.16
-rw-r--r--usr.bin/ssh/ssh_config.56
3 files changed, 123 insertions, 9 deletions
diff --git a/usr.bin/ssh/channels.c b/usr.bin/ssh/channels.c
index 66e49d5ea59..48d3752f502 100644
--- a/usr.bin/ssh/channels.c
+++ b/usr.bin/ssh/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 */
@@ -940,6 +940,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)
@@ -952,7 +1063,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;
@@ -963,6 +1074,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/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1
index defc0e6409e..8a7d2f42854 100644
--- a/usr.bin/ssh/ssh.1
+++ b/usr.bin/ssh/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/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5
index 56df3acec7c..79d05f018ae 100644
--- a/usr.bin/ssh/ssh_config.5
+++ b/usr.bin/ssh/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.