- markus@cvs.openbsd.org 2001/04/10 07:46:58
[channels.c]
cleanup socks4 handling
diff --git a/ChangeLog b/ChangeLog
index e59bf4e..0039e90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+20010412
+ - OpenBSD CVS Sync
+ - markus@cvs.openbsd.org 2001/04/10 07:46:58
+ [channels.c]
+ cleanup socks4 handling
+
20010410
- OpenBSD CVS Sync
- deraadt@cvs.openbsd.org 2001/04/08 20:52:55
@@ -4990,4 +4996,4 @@
- Wrote replacements for strlcpy and mkdtemp
- Released 1.0pre1
-$Id: ChangeLog,v 1.1093 2001/04/10 02:48:50 mouring Exp $
+$Id: ChangeLog,v 1.1094 2001/04/11 15:57:50 mouring Exp $
diff --git a/channels.c b/channels.c
index 0e334db..008ff64 100644
--- a/channels.c
+++ b/channels.c
@@ -40,7 +40,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.103 2001/04/07 08:55:17 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.104 2001/04/10 07:46:58 markus Exp $");
#include <openssl/rsa.h>
#include <openssl/dsa.h>
@@ -542,88 +542,142 @@
}
}
-#define SSH_SOCKS_HEAD 1+1+2+4
-void
-channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
+int
+channel_decode_helper(Channel *c, int start, int lookfor)
+{
+ u_char *p;
+ int i, have;
+
+ p = buffer_ptr(&c->input);
+ have = buffer_len(&c->input);
+ debug2("channel %d: decode_helper: start %d have %d lookfor %d",
+ c->self, start, have, lookfor);
+ if (have < start)
+ return 0;
+ for (i = start; i < have; i++) {
+ if (p[i] == lookfor) {
+ debug2("channel %d: decode_helper: matched at %d",
+ c->self, i);
+ if (lookfor == '\0' ||
+ (i+3 < have &&
+ p[i+1] == '\n' &&
+ p[i+2] == '\r' &&
+ p[i+3] == '\n'))
+ return i;
+ }
+ if (i > 4096) {
+ /* the peer is probably sending garbage */
+ debug("channel %d: decode_helper: too long",
+ c->self);
+ return -1;
+ }
+ }
+ return 0; /* need more */
+}
+
+/* try to decode a socks4 header */
+int
+channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset)
{
u_char *p, *host;
- int len, i, done, have;
- char username[256];
+ int len, have, ret;
+ char username[256];
struct {
u_int8_t version;
u_int8_t command;
u_int16_t dest_port;
- struct in_addr dest_ip;
+ struct in_addr dest_addr;
} s4_req, s4_rsp;
- have = buffer_len(&c->input);
-
- debug("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 < SSH_SOCKS_HEAD + 1) {
- /* need more */
- FD_SET(c->sock, readset);
- return;
- }
- /* Check for end of username */
- p = buffer_ptr(&c->input);
- done = 0;
- for (i = SSH_SOCKS_HEAD; i < have; i++) {
- if (p[i] == '\0') {
- done = 1;
- break;
- }
- }
- if (!done) {
- /* need more */
- FD_SET(c->sock, readset);
- return;
- }
+ debug2("channel %d: decode socks4", c->self);
+ ret = channel_decode_helper(c, sizeof(s4_req), '\0');
+ if (ret <= 0)
+ return ret;
buffer_get(&c->input, (char *)&s4_req.version, 1);
buffer_get(&c->input, (char *)&s4_req.command, 1);
buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
- buffer_get(&c->input, (char *)&s4_req.dest_ip, 4);
+ buffer_get(&c->input, (char *)&s4_req.dest_addr, 4);
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: pre_dynamic: user %s/%d", c->self, p, len);
if (len > have)
- fatal("channel %d: pre_dynamic: len %d > have %d",
+ fatal("channel %d: decode socks4: len %d > have %d",
c->self, len, have);
strlcpy(username, p, sizeof(username));
buffer_consume(&c->input, len);
buffer_consume(&c->input, 1); /* trailing '\0' */
- host = inet_ntoa(s4_req.dest_ip);
+ host = inet_ntoa(s4_req.dest_addr);
strlcpy(c->path, host, sizeof(c->path));
c->host_port = ntohs(s4_req.dest_port);
- debug("channel %d: dynamic request received: "
+ 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);
- if ((s4_req.version != 4) || (s4_req.command != 1)) {
- debug("channel %d: cannot handle: socks VN %d CN %d",
- c->self, s4_req.version, s4_req.command);
- channel_free(c->self);
- return;
+ if (s4_req.command != 1) {
+ debug("channel %d: cannot handle: socks4 cn %d",
+ c->self, s4_req.command);
+ return -1;
}
-
- s4_rsp.version = 0; /* VN: version of reply code */
- s4_rsp.command = 90; /* CD: request granted */
+ s4_rsp.version = 0; /* vn: 0 for reply */
+ s4_rsp.command = 90; /* cd: req granted */
s4_rsp.dest_port = 0; /* ignored */
- s4_rsp.dest_ip.s_addr = INADDR_ANY; /* ignored */
+ s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */
buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp));
-
- /* switch to next state */
- c->type = SSH_CHANNEL_OPENING;
- port_open_helper(c, "direct-tcpip");
+ return 1;
}
+/* dynamic port forwarding */
+void
+channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
+{
+ u_char *p;
+ int have, ret;
+
+ have = buffer_len(&c->input);
+
+ 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) {
+ /* need more */
+ FD_SET(c->sock, readset);
+ return;
+ }
+ /* 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 0x05:
+ ret = channel_decode_socks5(c, readset, writeset);
+ break;
+#endif
+ default:
+ ret = -1;
+ break;
+ }
+ if (ret < 0) {
+ channel_free(c->self);
+ } else if (ret == 0) {
+ debug2("channel %d: pre_dynamic: need more", c->self);
+ /* need more */
+ FD_SET(c->sock, readset);
+ } else {
+ /* switch to the next state */
+ c->type = SSH_CHANNEL_OPENING;
+ port_open_helper(c, "direct-tcpip");
+ }
+}
/* This is our fake X11 server socket. */
void
@@ -846,16 +900,11 @@
if (len <= 0) {
debug("channel %d: read<=0 rfd %d len %d",
c->self, c->rfd, len);
- if (c->type == SSH_CHANNEL_DYNAMIC) {
- /*
- * we are not yet connected to a remote peer,
- * so the connection-close protocol won't work
- */
- debug("channel %d: dynamic: closed", c->self);
+ if (c->type != SSH_CHANNEL_OPEN) {
+ debug("channel %d: not open", c->self);
channel_free(c->self);
return -1;
- }
- if (compat13) {
+ } else if (compat13) {
buffer_consume(&c->output, buffer_len(&c->output));
c->type = SSH_CHANNEL_INPUT_DRAINING;
debug("Channel %d status set to input draining.", c->self);
@@ -890,7 +939,11 @@
if (len < 0 && (errno == EINTR || errno == EAGAIN))
return 1;
if (len <= 0) {
- if (compat13) {
+ if (c->type != SSH_CHANNEL_OPEN) {
+ debug("channel %d: not open", c->self);
+ channel_free(c->self);
+ return -1;
+ } else if (compat13) {
buffer_consume(&c->output, buffer_len(&c->output));
debug("Channel %d status set to input draining.", c->self);
c->type = SSH_CHANNEL_INPUT_DRAINING;
@@ -967,7 +1020,8 @@
int
channel_check_window(Channel *c)
{
- if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
+ if (c->type == SSH_CHANNEL_OPEN &&
+ !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) &&
c->local_window < c->local_window_max/2 &&
c->local_consumed > 0) {
packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
@@ -1016,12 +1070,6 @@
}
void
-channel_post_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
-{
- channel_handle_rfd(c, readset, writeset);
-}
-
-void
channel_handler_init_20(void)
{
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20;
@@ -1039,7 +1087,7 @@
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
- channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic;
+ channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_2;
}
void
@@ -1061,7 +1109,7 @@
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
- channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic;
+ channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1;
}
void
@@ -1080,7 +1128,7 @@
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1;
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
- channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic;
+ channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open_1;
}
void