Bugzilla – Attachment 2744 Details for
Bug 2417
SOCKS5 should respond with appropriate error reply in error situations
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
tidied diff
bz2417.diff (text/plain), 8.07 KB, created by
Damien Miller
on 2015-10-31 09:18:27 AEDT
(
hide
)
Description:
tidied diff
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2015-10-31 09:18:27 AEDT
Size:
8.07 KB
patch
obsolete
>diff --git a/channels.c b/channels.c >index fdd89a5..267dcb8 100644 >--- a/channels.c >+++ b/channels.c >@@ -82,6 +82,7 @@ > #include "key.h" > #include "authfd.h" > #include "pathnames.h" >+#include "ssherr.h" > > /* -- channel core */ > >@@ -1161,17 +1162,41 @@ channel_decode_socks4(Channel *c, fd_set *readset, fd_set *writeset) > #define SSH_SOCKS5_IPV6 0x04 > #define SSH_SOCKS5_CONNECT 0x01 > #define SSH_SOCKS5_SUCCESS 0x00 >+#define SSH_SOCKS5_GENERICERROR 0x01 >+#define SSH_SOCKS5_RULESETBLOCK 0x02 >+#define SSH_SOCKS5_CONNREFUSED 0x05 >+#define SSH_SOCKS5_BADATYP 0x08 >+ >+struct socks5_msg { >+ u_int8_t version; >+ u_int8_t command; >+ u_int8_t reserved; >+ u_int8_t atyp; >+}; >+ >+static void >+socks5_error(Channel *c, u_int8_t code) >+{ >+ struct socks5_msg e; >+ int r; >+ >+ memset(&e, 0, sizeof(e)); >+ if ((r = sshbuf_put_u8(&c->output, 5)) != 0 || /* version */ >+ (r = sshbuf_put_u8(&c->output, code)) != 0 || >+ (r = sshbuf_put_u8(&c->output, 0)) != 0 || /* reserved */ >+ (r = sshbuf_put_u8(&c->output, SSH_SOCKS5_DOMAIN)) != 0 || >+ (r = sshbuf_put_u8(&c->output, 0)) != 0 || /* fake addr len = 0 */ >+ (r = sshbuf_put_u16(&c->output, 0)) != 0) /* fake port number */ >+ fatal("%s: construct SOCKS5 reply: %s", __func__, ssh_err(r)); >+ /* Don't try to do anything further with this request */ >+ sshbuf_reset(&c->input); >+} > > /* ARGSUSED */ > 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; >+ struct socks5_msg s5_req, s5_rsp; > u_int16_t dest_port; > char dest_addr[255+1], ntop[INET6_ADDRSTRLEN]; > u_char *p; >@@ -1199,6 +1224,8 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) > if (!found) { > debug("channel %d: method SSH_SOCKS5_NOAUTH not found", > c->self); >+ socks5_error(c, SSH_SOCKS5_GENERICERROR); >+ FD_SET(c->sock, writeset); > return -1; > } > buffer_consume(&c->input, nmethods + 2); >@@ -1217,6 +1244,8 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) > s5_req.command != SSH_SOCKS5_CONNECT || > s5_req.reserved != 0x00) { > debug2("channel %d: only socks5 connect supported", c->self); >+ socks5_error(c, SSH_SOCKS5_GENERICERROR); >+ FD_SET(c->sock, writeset); > return -1; > } > switch (s5_req.atyp){ >@@ -1234,6 +1263,8 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) > break; > default: > debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp); >+ socks5_error(c, SSH_SOCKS5_BADATYP); >+ FD_SET(c->sock, writeset); > return -1; > } > need = sizeof(s5_req) + addrlen + 2; >@@ -1253,12 +1284,19 @@ channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) > if (addrlen >= NI_MAXHOST) { > error("channel %d: dynamic request: socks5 hostname " > "\"%.100s\" too long", c->self, dest_addr); >+ socks5_error(c, SSH_SOCKS5_RULESETBLOCK); >+ FD_SET(c->sock, writeset); > return -1; > } > c->path = xstrdup(dest_addr); > } else { >- if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL) >+ if (inet_ntop(af, dest_addr, ntop, sizeof(ntop)) == NULL) { >+ error("channel %d: dynamic request: socks5 address " >+ "invalid", c->self); >+ socks5_error(c, SSH_SOCKS5_RULESETBLOCK); >+ FD_SET(c->sock, writeset); > return -1; >+ } > c->path = xstrdup(ntop); > } > c->host_port = ntohs(dest_port); >@@ -1333,7 +1371,8 @@ channel_pre_dynamic(Channel *c, fd_set *readset, fd_set *writeset) > break; > } > if (ret < 0) { >- chan_mark_dead(c); >+ chan_read_failed(c); >+ c->type = SSH_CHANNEL_OUTPUT_DRAINING; > } else if (ret == 0) { > debug2("channel %d: pre_dynamic: need more", c->self); > /* need more */ >@@ -2012,7 +2051,7 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset) > > /* ARGSUSED */ > static void >-channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset) >+channel_post_output_drain(Channel *c, fd_set *readset, fd_set *writeset) > { > int len; > >@@ -2043,6 +2082,7 @@ channel_handler_init_20(void) > channel_pre[SSH_CHANNEL_MUX_LISTENER] = &channel_pre_listener; > channel_pre[SSH_CHANNEL_MUX_CLIENT] = &channel_pre_mux_client; > >+ channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; > channel_post[SSH_CHANNEL_OPEN] = &channel_post_open; > channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; > channel_post[SSH_CHANNEL_RPORT_LISTENER] = &channel_post_port_listener; >@@ -2054,6 +2094,7 @@ channel_handler_init_20(void) > channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; > channel_post[SSH_CHANNEL_MUX_LISTENER] = &channel_post_mux_listener; > channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client; >+ channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain; > } > > static void >@@ -2073,7 +2114,7 @@ channel_handler_init_13(void) > channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; > channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; > 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_OUTPUT_DRAINING] = &channel_post_output_drain; > channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; > channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open; > } >@@ -2199,7 +2240,6 @@ channel_prepare_select(fd_set **readsetp, fd_set **writesetp, int *maxfdp, > u_int n, sz, nfdset; > > n = MAX(*maxfdp, channel_max_fd); >- > nfdset = howmany(n+1, NFDBITS); > /* Explicitly test here, because xrealloc isn't always called */ > if (nfdset && SIZE_MAX / nfdset < sizeof(fd_mask)) >@@ -2615,6 +2655,18 @@ reason2txt(int reason) > return "unknown reason"; > } > >+static int >+reason_to_socks5(int reason) >+{ >+ switch (reason) { >+ case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED: >+ return SSH_SOCKS5_RULESETBLOCK; >+ case SSH2_OPEN_CONNECT_FAILED: >+ return SSH_SOCKS5_CONNREFUSED; >+ } >+ return SSH_SOCKS5_GENERICERROR; >+} >+ > /* ARGSUSED */ > int > channel_input_open_failure(int type, u_int32_t seq, void *ctxt) >@@ -2626,7 +2678,7 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) > id = packet_get_int(); > c = channel_lookup(id); > >- if (c==NULL || c->type != SSH_CHANNEL_OPENING) >+ if (c == NULL || c->type != SSH_CHANNEL_OPENING) > packet_disconnect("Received open failure for " > "non-opening channel %d.", id); > if (compat20) { >@@ -2639,6 +2691,15 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) > reason2txt(reason), msg ? ": ": "", msg ? msg : ""); > free(msg); > free(lang); >+ >+ /* Translate failures to SOCKS codes */ >+ if (c->remote_name != NULL && >+ strcmp(c->remote_name, "dynamic-tcpip") == 0 && >+ (c->flags & SSH_SOCKS5_AUTHDONE)) { >+ socks5_error(c, reason_to_socks5(reason)); >+ /* XXX wakeup c->sock for reply */ >+ } >+ > if (c->open_confirm) { > debug2("callback start"); > c->open_confirm(c->self, 0, c->open_confirm_ctx); >@@ -2647,7 +2708,8 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt) > } > packet_check_eom(); > /* Schedule the channel for cleanup/deletion. */ >- chan_mark_dead(c); >+ chan_read_failed(c); >+ c->type = SSH_CHANNEL_OUTPUT_DRAINING; > return 0; > } > >diff --git a/regress/netcat.c b/regress/netcat.c >index 6234ba0..5bb4720 100644 >--- a/regress/netcat.c >+++ b/regress/netcat.c >@@ -1542,7 +1542,7 @@ socks_connect(const char *host, const char *port, > buf[0] = SOCKS_V5; > buf[1] = SOCKS_CONNECT; > buf[2] = 0; >- buf[3] = SOCKS_DOMAIN; >+ buf[3] = 99; > buf[4] = hlen; > memcpy(buf + 5, host, hlen); > memcpy(buf + 5 + hlen, &serverport, sizeof serverport); >@@ -1554,6 +1554,7 @@ socks_connect(const char *host, const char *port, > buf[1] = SOCKS_CONNECT; > buf[2] = 0; > buf[3] = SOCKS_IPV4; >+ buf[3] = 99; > memcpy(buf + 4, &in4->sin_addr, sizeof in4->sin_addr); > memcpy(buf + 8, &in4->sin_port, sizeof in4->sin_port); > wlen = 10; >@@ -1564,6 +1565,7 @@ socks_connect(const char *host, const char *port, > buf[1] = SOCKS_CONNECT; > buf[2] = 0; > buf[3] = SOCKS_IPV6; >+ buf[3] = 99; > memcpy(buf + 4, &in6->sin6_addr, sizeof in6->sin6_addr); > memcpy(buf + 20, &in6->sin6_port, > sizeof in6->sin6_port);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 2417
:
2656
|
2657
| 2744