summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
authorDarren Tucker <dtucker@zip.com.au>2003-07-03 13:55:19 +1000
committerDarren Tucker <dtucker@zip.com.au>2003-07-03 13:55:19 +1000
commit46471c9a81bdd0d797149a20364645bc6ffcf2cc (patch)
treeb21df0ef269b109a7dd6c6baaf8477ae87f7d478 /channels.c
parent9189ff89c3c15f152d8daedb09c4101a96365da4 (diff)
- 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.
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c120
1 files changed, 117 insertions, 3 deletions
diff --git a/channels.c b/channels.c
index ce07db5c0..e5b2b8c51 100644
--- a/channels.c
+++ b/channels.c
@@ -39,7 +39,7 @@
39 */ 39 */
40 40
41#include "includes.h" 41#include "includes.h"
42RCSID("$OpenBSD: channels.c,v 1.192 2003/07/02 12:56:34 markus Exp $"); 42RCSID("$OpenBSD: channels.c,v 1.193 2003/07/02 14:51:16 markus Exp $");
43 43
44#include "ssh.h" 44#include "ssh.h"
45#include "ssh1.h" 45#include "ssh1.h"
@@ -54,7 +54,7 @@ RCSID("$OpenBSD: channels.c,v 1.192 2003/07/02 12:56:34 markus Exp $");
54#include "key.h" 54#include "key.h"
55#include "authfd.h" 55#include "authfd.h"
56#include "pathnames.h" 56#include "pathnames.h"
57 57#include "bufaux.h"
58 58
59/* -- channel core */ 59/* -- channel core */
60 60
@@ -941,6 +941,117 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
941 return 1; 941 return 1;
942} 942}
943 943
944/* try to decode a socks5 header */
945#define SSH_SOCKS5_AUTHDONE 0x1000
946#define SSH_SOCKS5_NOAUTH 0x00
947#define SSH_SOCKS5_IPV4 0x01
948#define SSH_SOCKS5_DOMAIN 0x03
949#define SSH_SOCKS5_IPV6 0x04
950#define SSH_SOCKS5_CONNECT 0x01
951#define SSH_SOCKS5_SUCCESS 0x00
952
953static int
954channel_decode_socks5(Channel *c, fd_set * readset, fd_set * writeset)
955{
956 struct {
957 u_int8_t version;
958 u_int8_t command;
959 u_int8_t reserved;
960 u_int8_t atyp;
961 } s5_req, s5_rsp;
962 u_int16_t dest_port;
963 u_char *p, dest_addr[255+1];
964 int i, have, found, nmethods, addrlen, af;
965
966 debug2("channel %d: decode socks5", c->self);
967 p = buffer_ptr(&c->input);
968 if (p[0] != 0x05)
969 return -1;
970 have = buffer_len(&c->input);
971 if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {
972 /* format: ver | nmethods | methods */
973 if (have < 2)
974 return 0;
975 nmethods = p[1];
976 if (have < nmethods + 2)
977 return 0;
978 /* look for method: "NO AUTHENTICATION REQUIRED" */
979 for (found = 0, i = 2 ; i < nmethods + 2; i++) {
980 if (p[i] == SSH_SOCKS5_NOAUTH ) {
981 found = 1;
982 break;
983 }
984 }
985 if (!found) {
986 debug("channel %d: method SSH_SOCKS5_NOAUTH not found",
987 c->self);
988 return -1;
989 }
990 buffer_consume(&c->input, nmethods + 2);
991 buffer_put_char(&c->output, 0x05); /* version */
992 buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */
993 FD_SET(c->sock, writeset);
994 c->flags |= SSH_SOCKS5_AUTHDONE;
995 debug2("channel %d: socks5 auth done", c->self);
996 return 0; /* need more */
997 }
998 debug2("channel %d: socks5 post auth", c->self);
999 if (have < sizeof(s5_req)+1)
1000 return 0; /* need more */
1001 memcpy((char *)&s5_req, p, sizeof(s5_req));
1002 if (s5_req.version != 0x05 ||
1003 s5_req.command != SSH_SOCKS5_CONNECT ||
1004 s5_req.reserved != 0x00) {
1005 debug("channel %d: only socks5 connect supported", c->self);
1006 return -1;
1007 }
1008 switch(s5_req.atyp){
1009 case SSH_SOCKS5_IPV4:
1010 addrlen = 4;
1011 af = AF_INET;
1012 break;
1013 case SSH_SOCKS5_DOMAIN:
1014 addrlen = p[sizeof(s5_req)];
1015 af = -1;
1016 break;
1017 case SSH_SOCKS5_IPV6:
1018 addrlen = 16;
1019 af = AF_INET6;
1020 break;
1021 default:
1022 debug("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);
1023 return -1;
1024 }
1025 if (have < 4 + addrlen + 2)
1026 return 0;
1027 buffer_consume(&c->input, sizeof(s5_req));
1028 if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1029 buffer_consume(&c->input, 1); /* host string length */
1030 buffer_get(&c->input, (char *)&dest_addr, addrlen);
1031 buffer_get(&c->input, (char *)&dest_port, 2);
1032 dest_addr[addrlen] = '\0';
1033 if (s5_req.atyp == SSH_SOCKS5_DOMAIN)
1034 strlcpy(c->path, dest_addr, sizeof(c->path));
1035 else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL)
1036 return -1;
1037 c->host_port = ntohs(dest_port);
1038
1039 debug("channel %d: dynamic request: socks5 host %s port %u command %u",
1040 c->self, c->path, c->host_port, s5_req.command);
1041
1042 s5_rsp.version = 0x05;
1043 s5_rsp.command = SSH_SOCKS5_SUCCESS;
1044 s5_rsp.reserved = 0; /* ignored */
1045 s5_rsp.atyp = SSH_SOCKS5_IPV4;
1046 ((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;
1047 dest_port = 0; /* ignored */
1048
1049 buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp));
1050 buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr));
1051 buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port));
1052 return 1;
1053}
1054
944/* dynamic port forwarding */ 1055/* dynamic port forwarding */
945static void 1056static void
946channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) 1057channel_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)
953 debug2("channel %d: pre_dynamic: have %d", c->self, have); 1064 debug2("channel %d: pre_dynamic: have %d", c->self, have);
954 /* buffer_dump(&c->input); */ 1065 /* buffer_dump(&c->input); */
955 /* check if the fixed size part of the packet is in buffer. */ 1066 /* check if the fixed size part of the packet is in buffer. */
956 if (have < 4) { 1067 if (have < 3) {
957 /* need more */ 1068 /* need more */
958 FD_SET(c->sock, readset); 1069 FD_SET(c->sock, readset);
959 return; 1070 return;
@@ -964,6 +1075,9 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
964 case 0x04: 1075 case 0x04:
965 ret = channel_decode_socks4(c, readset, writeset); 1076 ret = channel_decode_socks4(c, readset, writeset);
966 break; 1077 break;
1078 case 0x05:
1079 ret = channel_decode_socks5(c, readset, writeset);
1080 break;
967 default: 1081 default:
968 ret = -1; 1082 ret = -1;
969 break; 1083 break;