commit bb3b4f219f0685da10e0b95b36c181135c17f469 Author: George Kadianakis desnacked@gmail.com Date: Sat May 28 05:34:46 2011 +0200
Implemented nickm's comments.
* Used WSA error codes for Windows compatibility. * Used enum to turn socks5_handle_request returns into meaningful words. * 's/EVUTIL_SOCKET_ERROR()/evutil_socket_geterror()/g' --- src/network.c | 13 ++++++----- src/socks.c | 43 +++++++++++++++++++++-------------- src/socks.h | 12 ++++++++- src/test/test_socks_unsupported.py | 2 + src/test/unittest_socks.c | 16 ++++++------ 5 files changed, 53 insertions(+), 33 deletions(-)
diff --git a/src/network.c b/src/network.c index 1f68804..f1c4584 100644 --- a/src/network.c +++ b/src/network.c @@ -10,6 +10,7 @@ #include "util.h" #include "socks.h" #include "protocol.h" +#include "socks.h"
#include <assert.h> #include <stdlib.h> @@ -229,7 +230,7 @@ socks_read_cb(struct bufferevent *bev, void *arg) { conn_t *conn = arg; //struct bufferevent *other; - int r; + enum req_status r; assert(bev == conn->input); /* socks must be on the initial bufferevent */
//dbg(("Got data on the socks side (%d) \n", conn->socks_state->state)); @@ -262,13 +263,13 @@ socks_read_cb(struct bufferevent *bev, void *arg)
r = handle_socks(bufferevent_get_input(bev), bufferevent_get_output(bev), conn->socks_state); - } while (r == 1); + } while (r == SOCKS_GOOD);
- if (r == 0) + if (r == SOCKS_INCOMPLETE) return; /* need to read more data. */ - else if (r == -1) + else if (r == SOCKS_BROKEN) conn_free(conn); /* XXXX maybe send socks reply */ - else if (r == -2) { + else if (r == SOCKS_CMD_NOT_CONNECT) { bufferevent_enable(bev, EV_WRITE); bufferevent_disable(bev, EV_READ); socks5_send_reply(bufferevent_get_output(bev), conn->socks_state, @@ -367,7 +368,7 @@ output_event_cb(struct bufferevent *bev, short what, void *arg) bufferevent_enable(conn->input, EV_WRITE); bufferevent_disable(conn->input, EV_READ); socks_send_reply(conn->socks_state, bufferevent_get_output(conn->input), - EVUTIL_SOCKET_ERROR()); + evutil_socket_geterror()); bufferevent_setcb(conn->input, NULL, close_conn_on_flush, output_event_cb, conn); return; diff --git a/src/socks.c b/src/socks.c index 7ee44ee..8782a63 100644 --- a/src/socks.c +++ b/src/socks.c @@ -38,6 +38,7 @@ "Server reply" is done by: socks5_send_reply() */
+ static int socks5_do_negotiation(struct evbuffer *dest, unsigned int neg_was_success);
@@ -61,6 +62,12 @@ socks_state_free(socks_state_t *s) free(s); }
+#ifdef _WIN32 +#define ERR(e) WSA##e +#else +#define ERR(e) e +#endif + /** This function receives an errno(3) 'error' and returns the reply code that should be sent to the SOCKS client. @@ -80,11 +87,11 @@ socks_errno_to_reply(socks_state_t *state, int error) return SOCKS5_SUCCESS; else { switch (error) { - case ENETUNREACH: + case ERR(ENETUNREACH): return SOCKS5_FAILED_NETUNREACH; - case EHOSTUNREACH: + case ERR(EHOSTUNREACH): return SOCKS5_FAILED_HOSTUNREACH; - case ECONNREFUSED: + case ERR(ECONNREFUSED): return SOCKS5_FAILED_REFUSED; default: return SOCKS5_FAILED_GENERAL; @@ -94,6 +101,8 @@ socks_errno_to_reply(socks_state_t *state, int error) return -1; }
+#undef ERR + /** Takes a command request from 'source', it evaluates it and if it's legit it parses it into 'parsereq'. @@ -109,7 +118,7 @@ socks_errno_to_reply(socks_state_t *state, int error)
Client Request (Client -> Server) */ -int +enum req_status socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq) { /** XXX: max FQDN size is 255. */ @@ -121,7 +130,7 @@ socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq)
if (buflength < SIZEOF_SOCKS5_STATIC_REQ+1) { printf("socks: request packet is too small (1).\n"); - return 0; + return SOCKS_INCOMPLETE; }
/* We only need the socks5_req and an extra byte to get @@ -140,7 +149,7 @@ socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq) }
if (p[1] != SOCKS5_CMD_CONNECT) - return -2; /* We must send reply to the client. */ + return SOCKS_CMD_NOT_CONNECT; /* We must send reply to the client. */
unsigned int addrlen,af,extralen=0; /* p[3] is Address type field */ @@ -169,7 +178,7 @@ socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq) int minsize = SIZEOF_SOCKS5_STATIC_REQ + addrlen + extralen + 2; if (buflength < minsize) { printf("socks: request packet too small %d:%d (2)\n", buflength, minsize); - return 0; + return SOCKS_INCOMPLETE; }
/* Drain data from the buffer to get to the good part, the actual @@ -203,10 +212,10 @@ socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq) parsereq->port = ntohs(destport); parsereq->af = af;
- return 1; + return SOCKS_GOOD;
err: - return -1; + return SOCKS_BROKEN; }
/** @@ -446,7 +455,7 @@ int handle_socks(struct evbuffer *source, struct evbuffer *dest, socks_state_t *socks_state) { - int r; + enum req_status r; if (socks_state->broken) return -1;
@@ -496,15 +505,15 @@ handle_socks(struct evbuffer *source, struct evbuffer *dest, if (socks_state->state == ST_NEGOTIATION_DONE) { /* We know this connection. Let's see what it wants. */ r = socks5_handle_request(source,&socks_state->parsereq); - if (r == -2) { /* Request CMD != CONNECT. */ + if (r == SOCKS_GOOD) + socks_state->state = ST_HAVE_ADDR; + else if (r == SOCKS_INCOMPLETE) + return SOCKS_INCOMPLETE; + else if (r == SOCKS_CMD_NOT_CONNECT) { socks_state->broken = 1; - return -2; - } else if (r == -1) /* Broken request. */ + return SOCKS_CMD_NOT_CONNECT; + } else if (r == SOCKS_BROKEN) goto broken; - else if (r == 0) /* Incomplete. */ - return 0; - else if (r == 1) /* Neat request. */ - socks_state->state = ST_HAVE_ADDR; return r; } break; diff --git a/src/socks.h b/src/socks.h index d360982..7b35cb5 100644 --- a/src/socks.h +++ b/src/socks.h @@ -16,6 +16,14 @@ enum socks_status_t { /* Have sent reply */ ST_SENT_REPLY }; + +enum req_status { + SOCKS_GOOD=0, + SOCKS_INCOMPLETE, + SOCKS_CMD_NOT_CONNECT, + SOCKS_BROKEN +}; + int handle_socks(struct evbuffer *source, struct evbuffer *dest, socks_state_t *socks_state); socks_state_t *socks_state_new(void); @@ -90,10 +98,10 @@ struct socks_state_t {
int socks5_handle_negotiation(struct evbuffer *source, struct evbuffer *dest, socks_state_t *state); -int socks5_handle_request(struct evbuffer *source, - struct parsereq *parsereq); int socks5_send_reply(struct evbuffer *reply_dest, socks_state_t *state, int status); +enum req_status socks5_handle_request(struct evbuffer *source, struct parsereq *parsereq); +
int socks4_read_request(struct evbuffer *source, socks_state_t *state); int socks4_send_reply(struct evbuffer *dest, diff --git a/src/test/test_socks_unsupported.py b/src/test/test_socks_unsupported.py index c0d625c..d1afd02 100644 --- a/src/test/test_socks_unsupported.py +++ b/src/test/test_socks_unsupported.py @@ -13,4 +13,6 @@ s.send(request) data = s.recv(1024) if (struct.unpack('BBBBih', data)[1] == 7): print "Works." +else: + print "Fail!"
diff --git a/src/test/unittest_socks.c b/src/test/unittest_socks.c index 5ec28cc..d7706ee 100644 --- a/src/test/unittest_socks.c +++ b/src/test/unittest_socks.c @@ -158,7 +158,7 @@ test_socks_socks5_request(void *data)
evbuffer_add(source, "\x05", 1); evbuffer_add(source, req1, 7); - tt_int_op(0, ==, socks5_handle_request(source,&pr1)); /* 0: want more data*/ + tt_int_op(SOCKS_INCOMPLETE, ==, socks5_handle_request(source,&pr1)); /* 0: want more data*/
/* emptying source buffer before next test */ size_t buffer_len = evbuffer_get_length(source); @@ -175,7 +175,7 @@ test_socks_socks5_request(void *data)
evbuffer_add(source, "\x05", 1); evbuffer_add(source, req2, 7); - tt_int_op(0, ==, socks5_handle_request(source,&pr1)); /* 0: want more data*/ + tt_int_op(SOCKS_INCOMPLETE, ==, socks5_handle_request(source,&pr1)); /* 0: want more data*/
/* emptying source buffer before next test */ buffer_len = evbuffer_get_length(source); @@ -192,7 +192,7 @@ test_socks_socks5_request(void *data)
evbuffer_add(source, "\x05", 1); evbuffer_add(source, req3, 9); - tt_int_op(1, ==, socks5_handle_request(source,&pr1)); + tt_int_op(SOCKS_GOOD, ==, socks5_handle_request(source,&pr1)); tt_str_op(pr1.addr, ==, "127.0.0.1"); tt_int_op(pr1.port, ==, 80);
@@ -211,7 +211,7 @@ test_socks_socks5_request(void *data) memcpy(req4+20,&port,2);
evbuffer_add(source,req4,22); - tt_int_op(1, ==, socks5_handle_request(source,&pr1)); + tt_int_op(SOCKS_GOOD, ==, socks5_handle_request(source,&pr1)); tt_str_op(pr1.addr, ==, "d:1:5:e:a:5:e:0"); tt_int_op(pr1.port, ==, 80);
@@ -232,7 +232,7 @@ test_socks_socks5_request(void *data) memcpy(req5+5+strlen(fqdn),&port,2);
evbuffer_add(source, req5, 24); - tt_int_op(1, ==, socks5_handle_request(source,&pr1)); + tt_int_op(SOCKS_GOOD, ==, socks5_handle_request(source,&pr1)); tt_str_op(pr1.addr, ==, "www.test.example"); tt_int_op(pr1.port, ==, 80);
@@ -244,7 +244,7 @@ test_socks_socks5_request(void *data) req6[2] = 0;
evbuffer_add(source,req6,3); - tt_int_op(0, ==, socks5_handle_request(source,&pr1)); + tt_int_op(SOCKS_INCOMPLETE, ==, socks5_handle_request(source,&pr1));
/* emptying source buffer before next test */ buffer_len = evbuffer_get_length(source); @@ -260,7 +260,7 @@ test_socks_socks5_request(void *data) req7[4] = 42;
evbuffer_add(source,req7,5); - tt_int_op(-1, ==, socks5_handle_request(source,&pr1)); + tt_int_op(SOCKS_BROKEN, ==, socks5_handle_request(source,&pr1));
/* emptying source buffer before next test */ buffer_len = evbuffer_get_length(source); @@ -278,7 +278,7 @@ test_socks_socks5_request(void *data) evbuffer_add(source, "\x05", 1); evbuffer_add(source, req8, 9); /* '-2' means that we don't support the requested command. */ - tt_int_op(-2, ==, socks5_handle_request(source,&pr1)); + tt_int_op(SOCKS_CMD_NOT_CONNECT, ==, socks5_handle_request(source,&pr1));
end: