diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/channels.c b/channels.c index d138882b3..2319afd4b 100644 --- a/channels.c +++ b/channels.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: channels.c,v 1.291 2009/01/01 21:14:35 djm Exp $ */ | 1 | /* $OpenBSD: channels.c,v 1.292 2009/01/14 01:38:06 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -980,7 +980,7 @@ static int | |||
980 | channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | 980 | channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) |
981 | { | 981 | { |
982 | char *p, *host; | 982 | char *p, *host; |
983 | u_int len, have, i, found; | 983 | u_int len, have, i, found, need; |
984 | char username[256]; | 984 | char username[256]; |
985 | struct { | 985 | struct { |
986 | u_int8_t version; | 986 | u_int8_t version; |
@@ -996,10 +996,20 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
996 | if (have < len) | 996 | if (have < len) |
997 | return 0; | 997 | return 0; |
998 | p = buffer_ptr(&c->input); | 998 | p = buffer_ptr(&c->input); |
999 | |||
1000 | need = 1; | ||
1001 | /* SOCKS4A uses an invalid IP address 0.0.0.x */ | ||
1002 | if (p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] != 0) { | ||
1003 | debug2("channel %d: socks4a request", c->self); | ||
1004 | /* ... and needs an extra string (the hostname) */ | ||
1005 | need = 2; | ||
1006 | } | ||
1007 | /* Check for terminating NUL on the string(s) */ | ||
999 | for (found = 0, i = len; i < have; i++) { | 1008 | for (found = 0, i = len; i < have; i++) { |
1000 | if (p[i] == '\0') { | 1009 | if (p[i] == '\0') { |
1001 | found = 1; | 1010 | found++; |
1002 | break; | 1011 | if (found == need) |
1012 | break; | ||
1003 | } | 1013 | } |
1004 | if (i > 1024) { | 1014 | if (i > 1024) { |
1005 | /* the peer is probably sending garbage */ | 1015 | /* the peer is probably sending garbage */ |
@@ -1008,7 +1018,7 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1008 | return -1; | 1018 | return -1; |
1009 | } | 1019 | } |
1010 | } | 1020 | } |
1011 | if (!found) | 1021 | if (found < need) |
1012 | return 0; | 1022 | return 0; |
1013 | buffer_get(&c->input, (char *)&s4_req.version, 1); | 1023 | buffer_get(&c->input, (char *)&s4_req.version, 1); |
1014 | buffer_get(&c->input, (char *)&s4_req.command, 1); | 1024 | buffer_get(&c->input, (char *)&s4_req.command, 1); |
@@ -1018,23 +1028,41 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) | |||
1018 | p = buffer_ptr(&c->input); | 1028 | p = buffer_ptr(&c->input); |
1019 | len = strlen(p); | 1029 | len = strlen(p); |
1020 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); | 1030 | debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); |
1031 | len++; /* trailing '\0' */ | ||
1021 | if (len > have) | 1032 | if (len > have) |
1022 | fatal("channel %d: decode socks4: len %d > have %d", | 1033 | fatal("channel %d: decode socks4: len %d > have %d", |
1023 | c->self, len, have); | 1034 | c->self, len, have); |
1024 | strlcpy(username, p, sizeof(username)); | 1035 | strlcpy(username, p, sizeof(username)); |
1025 | buffer_consume(&c->input, len); | 1036 | buffer_consume(&c->input, len); |
1026 | buffer_consume(&c->input, 1); /* trailing '\0' */ | ||
1027 | 1037 | ||
1028 | host = inet_ntoa(s4_req.dest_addr); | 1038 | if (need == 1) { /* SOCKS4: one string */ |
1029 | strlcpy(c->path, host, sizeof(c->path)); | 1039 | host = inet_ntoa(s4_req.dest_addr); |
1040 | strlcpy(c->path, host, sizeof(c->path)); | ||
1041 | } else { /* SOCKS4A: two strings */ | ||
1042 | have = buffer_len(&c->input); | ||
1043 | p = buffer_ptr(&c->input); | ||
1044 | len = strlen(p); | ||
1045 | debug2("channel %d: decode socks4a: host %s/%d", | ||
1046 | c->self, p, len); | ||
1047 | len++; /* trailing '\0' */ | ||
1048 | if (len > have) | ||
1049 | fatal("channel %d: decode socks4a: len %d > have %d", | ||
1050 | c->self, len, have); | ||
1051 | if (strlcpy(c->path, p, sizeof(c->path)) >= sizeof(c->path)) { | ||
1052 | error("channel %d: hostname \"%.100s\" too long", | ||
1053 | c->self, p); | ||
1054 | return -1; | ||
1055 | } | ||
1056 | buffer_consume(&c->input, len); | ||
1057 | } | ||
1030 | c->host_port = ntohs(s4_req.dest_port); | 1058 | c->host_port = ntohs(s4_req.dest_port); |
1031 | 1059 | ||
1032 | debug2("channel %d: dynamic request: socks4 host %s port %u command %u", | 1060 | debug2("channel %d: dynamic request: socks4 host %s port %u command %u", |
1033 | c->self, host, c->host_port, s4_req.command); | 1061 | c->self, c->path, c->host_port, s4_req.command); |
1034 | 1062 | ||
1035 | if (s4_req.command != 1) { | 1063 | if (s4_req.command != 1) { |
1036 | debug("channel %d: cannot handle: socks4 cn %d", | 1064 | debug("channel %d: cannot handle: %s cn %d", |
1037 | c->self, s4_req.command); | 1065 | c->self, need == 1 ? "SOCKS4" : "SOCKS4A", s4_req.command); |
1038 | return -1; | 1066 | return -1; |
1039 | } | 1067 | } |
1040 | s4_rsp.version = 0; /* vn: 0 for reply */ | 1068 | s4_rsp.version = 0; /* vn: 0 for reply */ |