version 1.105, 2001/04/10 12:15:23 |
version 1.106, 2001/04/11 13:56:13 |
|
|
return 0; /* need more */ |
return 0; /* need more */ |
} |
} |
|
|
|
/* try to decode a http connect header */ |
|
int |
|
channel_decode_https(Channel *c, fd_set * readset, fd_set * writeset) |
|
{ |
|
u_char *p, *host, *buf; |
|
int port, ret; |
|
char httpok[] = "HTTP/1.0 200\r\n\r\n"; |
|
|
|
debug2("channel %d: decode https connect", c->self); |
|
ret = channel_decode_helper(c, strlen("connect "), '\r'); |
|
if (ret <= 0) |
|
return ret; |
|
p = buffer_ptr(&c->input); |
|
buf = xmalloc(ret+1); |
|
host = xmalloc(ret); |
|
memcpy(buf, p, ret); |
|
buf[ret] = '\0'; |
|
if (sscanf(buf, "CONNECT %[^:]:%u HTTP/", host, &port) != 2) { |
|
debug("channel %d: cannot parse http header", c->self); |
|
return -1; |
|
} |
|
debug("channel %d: dynamic request: https host %s port %u", |
|
c->self, host, port); |
|
strlcpy(c->path, host, sizeof(c->path)); |
|
c->host_port = port; |
|
xfree(host); |
|
xfree(buf); |
|
buffer_consume(&c->input, ret+4); |
|
buffer_append(&c->output, httpok, strlen(httpok)); |
|
|
|
return 1; |
|
} |
|
|
/* try to decode a socks4 header */ |
/* try to decode a socks4 header */ |
int |
int |
channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) |
channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) |
|
|
p = buffer_ptr(&c->input); |
p = buffer_ptr(&c->input); |
len = strlen(p); |
len = strlen(p); |
have = buffer_len(&c->input); |
have = buffer_len(&c->input); |
debug2("channel %d: pre_dynamic: user %s/%d", c->self, p, len); |
debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); |
if (len > have) |
if (len > have) |
fatal("channel %d: decode socks4: len %d > have %d", |
fatal("channel %d: decode socks4: len %d > have %d", |
c->self, len, have); |
c->self, len, have); |
|
|
strlcpy(c->path, host, sizeof(c->path)); |
strlcpy(c->path, host, sizeof(c->path)); |
c->host_port = ntohs(s4_req.dest_port); |
c->host_port = ntohs(s4_req.dest_port); |
|
|
debug("channel %d: dynamic request: " |
debug("channel %d: dynamic request: socks4 host %s port %u command %u", |
"socks%x://%s@%s:%u/command?%u", |
c->self, host, c->host_port, s4_req.command); |
c->self, s4_req.version, username, host, c->host_port, |
|
s4_req.command); |
|
|
|
if (s4_req.command != 1) { |
if (s4_req.command != 1) { |
debug("channel %d: cannot handle: socks4 cn %d", |
debug("channel %d: cannot handle: socks4 cn %d", |
|
|
return 1; |
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 |
|
|
|
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)); |
|
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 */ |
/* dynamic port forwarding */ |
void |
void |
channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) |
channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) |
|
|
/* try to guess the protocol */ |
/* try to guess the protocol */ |
p = buffer_ptr(&c->input); |
p = buffer_ptr(&c->input); |
switch (p[0]) { |
switch (p[0]) { |
case 0x04: |
|
ret = channel_decode_socks4(c, readset, writeset); |
|
break; |
|
#if 0 |
|
case 'C': |
case 'C': |
ret = channel_decode_https(c, readset, writeset); |
ret = channel_decode_https(c, readset, writeset); |
break; |
break; |
|
case 0x04: |
|
ret = channel_decode_socks4(c, readset, writeset); |
|
break; |
case 0x05: |
case 0x05: |
ret = channel_decode_socks5(c, readset, writeset); |
ret = channel_decode_socks5(c, readset, writeset); |
break; |
break; |
#endif |
|
default: |
default: |
ret = -1; |
ret = -1; |
break; |
break; |