diff --git a/broker.c b/broker.c index c787abf..613fdc9 100644 --- a/broker.c +++ b/broker.c @@ -352,6 +352,20 @@ int broker(){ goto RETURN; } + }else if(message->header_type == DT_CONNECTION_HT_CONNECTED){ + + if((retval = handle_message_dt_connection_ht_connected()) == -1){ + report_error("broker(): handle_message_dt_connection_ht_connected(): %s", strerror(errno)); + goto RETURN; + } + + }else if(message->header_type == DT_CONNECTION_HT_REFUSED){ + + if((retval = handle_message_dt_connection_ht_refused()) == -1){ + report_error("broker(): handle_message_dt_connection_ht_refused(): %s", strerror(errno)); + goto RETURN; + } + }else{ // Unknown connection type. Report but soldier on. report_error("broker(): Unknown Connection Header Type: %d: Ignoring.", message->header_type); diff --git a/common.h b/common.h index ba9900d..04126cd 100644 --- a/common.h +++ b/common.h @@ -112,11 +112,13 @@ #define CON_DORMANT 4 /* Apparently reply strings for socks requests are static in the modern era. */ -#define SOCKS_V4_REPLY "\x00\x5a\x00\x00\x00\x00\x00\x00" +#define SOCKS_V4_REPLY_OK "\x00\x5a\x00\x00\x00\x00\x00\x00" +#define SOCKS_V4_REPLY_ERR "\x00\x5b\x00\x00\x00\x00\x00\x00" #define SOCKS_V4_REPLY_LEN 8 #define SOCKS_V5_AUTH_REPLY "\x05\x00" #define SOCKS_V5_AUTH_REPLY_LEN 2 -#define SOCKS_V5_REPLY "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00" +#define SOCKS_V5_REPLY_OK "\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00" +#define SOCKS_V5_REPLY_ERR "\x05\x01\x00\x01\x00\x00\x00\x00\x00\x00" #define SOCKS_V5_REPLY_LEN 10 /* Maximum possible size of a socks request. */ @@ -203,6 +205,8 @@ int handle_message_dt_connection_ht_create_tun_tap(); int handle_message_dt_connection_ht_response(); int handle_connection_activate(struct connection_node *cur_connection_node); int handle_message_dt_connection_ht_active_dormant(); +int handle_message_dt_connection_ht_connected(); +int handle_message_dt_connection_ht_refused(); int handle_message_dt_connection_ht_data(); int handle_proxy_read(struct proxy_node *cur_proxy_node); int handle_connection_write(struct connection_node *cur_connection_node); @@ -213,6 +217,8 @@ int handle_send_dt_proxy_ht_create(char *proxy_string, int proxy_type); int handle_send_dt_proxy_ht_report(struct proxy_node *cur_proxy_node); int handle_send_dt_connection_ht_destroy(unsigned short origin, unsigned short id, unsigned short header_errno); int handle_send_dt_connection_ht_create(struct connection_node *cur_connection_node); +int handle_send_dt_connection_ht_connected(unsigned short origin, unsigned short id); +int handle_send_dt_connection_ht_refused(unsigned short origin, unsigned short id); int handle_send_dt_nop(); struct connection_node *handle_tun_tap_init(int ifr_flag); @@ -253,6 +259,7 @@ struct connection_node *connection_node_create(); void connection_node_delete(struct connection_node *); struct connection_node *connection_node_find(unsigned short origin, unsigned short id); void connection_node_queue(struct connection_node *cur_connection_node); +void connection_node_socks_reply(struct connection_node *, int ok); int parse_socks_request(struct connection_node *cur_connection_node); char *addr_to_string(int atype, char *addr, char *port, int len); diff --git a/handler.c b/handler.c index 324df1d..155b2d8 100644 --- a/handler.c +++ b/handler.c @@ -445,6 +445,7 @@ int handle_message_dt_connection_ht_create(){ cur_connection_node->origin = message->header_origin; cur_connection_node->id = message->header_id; cur_connection_node->proxy_type = message->header_proxy_type; + cur_connection_node->socks_type = message->header_socks_type; if((cur_connection_node->rhost_rport = (char *) calloc(message->data_len + 1, sizeof(char))) == NULL){ report_error("handle_message_dt_connection_ht_create(): calloc(%d, %d): %s", message->data_len + 1, (int) sizeof(char), strerror(errno)); @@ -581,6 +582,11 @@ int handle_connection_activate(struct connection_node *cur_connection_node){ fprintf(stderr, "\rConnection failed: %s, %s\n", cur_connection_node->rhost_rport, strerror(optval)); } + if(handle_send_dt_connection_ht_refused(cur_connection_node->origin, cur_connection_node->id) == -1){ + report_error("handle_connection_activate(): handle_send_dt_connection_ht_refused(%d, %d, 0): %s", cur_connection_node->origin, cur_connection_node->id, strerror(errno)); + return(-1); + } + if(handle_send_dt_connection_ht_destroy(cur_connection_node->origin, cur_connection_node->id, 0) == -1){ report_error("handle_connection_activate(): handle_send_dt_connection_ht_destroy(%d, %d, 0): %s", cur_connection_node->origin, cur_connection_node->id, strerror(errno)); return(-1); @@ -592,6 +598,8 @@ int handle_connection_activate(struct connection_node *cur_connection_node){ cur_connection_node->state = CON_ACTIVE; + handle_send_dt_connection_ht_connected(cur_connection_node->origin, cur_connection_node->id); + return(0); } @@ -730,6 +738,64 @@ int handle_message_dt_connection_ht_data(){ } +/****************************************************************************** + * + * handle_message_dt_connection_ht_connected() + * + * Inputs: None, but we will leverage the global io struct. + * Outputs: 0 for success. -1 on fatal error. -2 on non-fatal error. + * + * Purpose: Handle the broker case where a connection has succeeded. + * + ******************************************************************************/ +int handle_message_dt_connection_ht_connected(){ + struct connection_node *cur_connection_node; + + + if((cur_connection_node = connection_node_find(message->header_origin, message->header_id)) == NULL){ + + if(handle_send_dt_connection_ht_destroy(message->header_origin, message->header_id, 0) == -1){ + report_error("handle_message_dt_connection(): handle_send_dt_connection_ht_destroy(%d, %d, 0): %s", message->header_origin, message->header_id, strerror(errno)); + return(-1); + } + return(-2); + } + + connection_node_socks_reply(cur_connection_node, 1); + + return(0); +} + + +/****************************************************************************** + * + * handle_message_dt_connection_ht_refused() + * + * Inputs: None, but we will leverage the global io struct. + * Outputs: 0 for success. -1 on fatal error. -2 on non-fatal error. + * + * Purpose: Handle the broker case where a connection was refused. + * + ******************************************************************************/ +int handle_message_dt_connection_ht_refused(){ + struct connection_node *cur_connection_node; + + + if((cur_connection_node = connection_node_find(message->header_origin, message->header_id)) == NULL){ + + if(handle_send_dt_connection_ht_destroy(message->header_origin, message->header_id, 0) == -1){ + report_error("handle_message_dt_connection(): handle_send_dt_connection_ht_destroy(%d, %d, 0): %s", message->header_origin, message->header_id, strerror(errno)); + return(-1); + } + return(-2); + } + + connection_node_socks_reply(cur_connection_node, 0); + + return(0); +} + + /****************************************************************************** * * handle_proxy_read() @@ -995,32 +1061,24 @@ int handle_connection_socks_init(struct connection_node *cur_connection_node){ if(new_state == CON_SOCKS_V5_AUTH){ reply_buff = SOCKS_V5_AUTH_REPLY; reply_buff_len = SOCKS_V5_AUTH_REPLY_LEN; - }else if(new_state == CON_ACTIVE){ - if(cur_connection_node->state == CON_SOCKS_INIT){ - reply_buff = SOCKS_V4_REPLY; - reply_buff_len = SOCKS_V4_REPLY_LEN; - }else if(cur_connection_node->state == CON_SOCKS_V5_AUTH){ - reply_buff = SOCKS_V5_REPLY; - reply_buff_len = SOCKS_V5_REPLY_LEN; - } - } - - retval = write(cur_connection_node->fd, reply_buff, reply_buff_len); + retval = write(cur_connection_node->fd, reply_buff, reply_buff_len); - if(retval == -1){ - report_error("handle_connection_socks_init(): write(%d, %lx, %d): %s", cur_connection_node->fd, (unsigned long) reply_buff, reply_buff_len, strerror(errno)); - return(-1); - } - - if(retval != reply_buff_len){ - report_error("handle_connection_socks_init(): write(%d, %lx, %d): Unable to send SOCKS reply.", cur_connection_node->fd, (unsigned long) reply_buff, reply_buff_len); - if(handle_send_dt_connection_ht_destroy(cur_connection_node->origin, cur_connection_node->id, 0) == -1){ - report_error("handle_connection_socks_init(): handle_send_dt_connection_ht_destroy(%d, %d, 0): %s", cur_connection_node->origin, cur_connection_node->id, strerror(errno)); + if(retval == -1){ + report_error("handle_connection_socks_init(): write(%d, %lx, %d): %s", cur_connection_node->fd, (unsigned long) reply_buff, reply_buff_len, strerror(errno)); return(-1); } - connection_node_delete(cur_connection_node); + + if(retval != reply_buff_len){ + report_error("handle_connection_socks_init(): write(%d, %lx, %d): Unable to send SOCKS reply.", cur_connection_node->fd, (unsigned long) reply_buff, reply_buff_len); + if(handle_send_dt_connection_ht_destroy(cur_connection_node->origin, cur_connection_node->id, 0) == -1){ + report_error("handle_connection_socks_init(): handle_send_dt_connection_ht_destroy(%d, %d, 0): %s", cur_connection_node->origin, cur_connection_node->id, strerror(errno)); + return(-1); + } + connection_node_delete(cur_connection_node); + } } + cur_connection_node->state = new_state; // Handle the case where we have a rude client that doesn't wait for data and just fills our buffer with both halves of the @@ -1179,7 +1237,6 @@ int handle_send_dt_proxy_ht_report(struct proxy_node *cur_proxy_node){ return(0); } - /****************************************************************************** * * handle_send_dt_connection_ht_destroy() @@ -1242,6 +1299,7 @@ int handle_send_dt_connection_ht_create(struct connection_node *cur_connection_n message->header_origin = cur_connection_node->origin; message->header_id = cur_connection_node->id; message->header_proxy_type = cur_connection_node->proxy_type; + message->header_socks_type = cur_connection_node->socks_type; memset(message->data, 0, io->message_data_size); count = strlen(cur_connection_node->rhost_rport); @@ -1288,6 +1346,68 @@ int handle_send_dt_nop(){ } +/****************************************************************************** + * + * handle_send_dt_connection_ht_connected() + * + * Inputs: The origin and id tuple that identify the related connection. + * We will also leverage the global io struct. + * Outputs: 0 for success. -1 on fatal error. + * + * Purpose: Handle the broker case where we need to notify the remote node + * that a connection has been successfully connected. + * + ******************************************************************************/ +int handle_send_dt_connection_ht_connected(unsigned short origin, unsigned short id){ + + int retval; + + message->data_type = DT_CONNECTION; + message->header_type = DT_CONNECTION_HT_CONNECTED; + message->header_origin = origin; + message->header_id = id; + message->data_len = 0; + + if((retval = message_push()) == -1){ + report_error("handle_send_dt_connection_ht_connected(): message_push(): %s", strerror(errno)); + return(-1); + } + + return(0); +} + + +/****************************************************************************** + * + * handle_send_dt_connection_ht_refused() + * + * Inputs: The origin and id tuple that identify the related connection. + * We will also leverage the global io struct. + * Outputs: 0 for success. -1 on fatal error. + * + * Purpose: Handle the broker case where we need to notify the remote node + * that a connection has been refused. + * + ******************************************************************************/ +int handle_send_dt_connection_ht_refused(unsigned short origin, unsigned short id){ + + int retval; + + message->data_type = DT_CONNECTION; + message->header_type = DT_CONNECTION_HT_REFUSED; + message->header_origin = origin; + message->header_id = id; + message->data_len = 0; + + if((retval = message_push()) == -1){ + report_error("handle_send_dt_connection_ht_refused(): message_push(): %s", strerror(errno)); + return(-1); + } + + return(0); +} + + /****************************************************************************** * * handle_tun_tap_init() diff --git a/helper_objects.h b/helper_objects.h index 99530ac..f634946 100644 --- a/helper_objects.h +++ b/helper_objects.h @@ -20,6 +20,8 @@ struct message_helper { // Proxy types are defined in the protocol.h file. unsigned short header_proxy_type; + unsigned short header_socks_type; + char *data; struct message_helper *next; @@ -122,6 +124,7 @@ struct connection_node { unsigned short origin; unsigned short id; unsigned short proxy_type; + unsigned short socks_type; int fd; // A copy of the original rhost_rport string in the related proxy_node struct, to simplify retry requests. diff --git a/message.c b/message.c index c701aba..8f75971 100644 --- a/message.c +++ b/message.c @@ -25,6 +25,7 @@ int message_push(){ header_len += sizeof(message->header_type) + sizeof(message->header_origin) + sizeof(message->header_id); if(message->header_type == DT_PROXY_HT_CREATE || message->header_type == DT_PROXY_HT_REPORT || message->header_type == DT_CONNECTION_HT_CREATE){ header_len += sizeof(message->header_proxy_type); + header_len += sizeof(message->header_socks_type); } } @@ -92,6 +93,12 @@ int message_push(){ (unsigned long) &tmp_short, (int) sizeof(tmp_short), strerror(errno)); return(-1); } + tmp_short = htons(message->header_socks_type); + if(io->remote_write(&tmp_short, sizeof(tmp_short)) == -1){ + report_error("message_push(): remote_write(%lx, %d): %s", \ + (unsigned long) &tmp_short, (int) sizeof(tmp_short), strerror(errno)); + return(-1); + } } } @@ -188,6 +195,13 @@ int message_pull(){ } message->header_proxy_type = ntohs(message->header_proxy_type); header_len -= sizeof(message->header_proxy_type); + if((retval = io->remote_read(&message->header_socks_type, sizeof(message->header_socks_type))) == -1){ + report_error("message_pull(): remote_read(%lx, %d): %s", \ + (unsigned long) &message->header_socks_type, (int) sizeof(message->header_socks_type), strerror(errno)); + return(-1); + } + message->header_socks_type = ntohs(message->header_socks_type); + header_len -= sizeof(message->header_socks_type); } } diff --git a/protocol.h b/protocol.h index b1848a2..0330b6a 100644 --- a/protocol.h +++ b/protocol.h @@ -10,7 +10,7 @@ */ #define PROTOCOL_MAJOR_VERSION 1 -#define PROTOCOL_MINOR_VERSION 0 +#define PROTOCOL_MINOR_VERSION 1 /********************************************************************************************************************** * @@ -167,6 +167,8 @@ // As such, this reporting is typically handled as a best effort without guarantee of delivery. #define DT_ERROR 6 +#define DT_CONNECTION_HT_CONNECTED 7 +#define DT_CONNECTION_HT_REFUSED 8 /* * Other protocol constants used in messaging. */ diff --git a/proxy.c b/proxy.c index 169286c..31716a4 100644 --- a/proxy.c +++ b/proxy.c @@ -410,6 +410,43 @@ struct connection_node *connection_node_create(){ return(cur_connection_node); } +/****************************************************************************** + * + * connection_node_socks_reply() + * + * Inputs: A pointer to the connection_node and the socks reply type to send (0 + * for error. 1 for ok). + * + * Outputs: None. + * + * Purpose: Report back to the socks client whether the requested connection + * request succeeded or not. + * + ******************************************************************************/ +void connection_node_socks_reply(struct connection_node *cur_connection_node, int ok){ + char *reply_buff = NULL; + int reply_buff_len = 0; + if (cur_connection_node->socks_type == 4) { + if(ok) { + reply_buff = SOCKS_V4_REPLY_OK; + } + else { + reply_buff = SOCKS_V4_REPLY_ERR; + } + reply_buff_len = SOCKS_V4_REPLY_LEN; + } else if (cur_connection_node->socks_type == 5) { + if(ok) { + reply_buff = SOCKS_V5_REPLY_OK; + } + else { + reply_buff = SOCKS_V5_REPLY_ERR; + } + reply_buff_len = SOCKS_V5_REPLY_LEN; + } + if(write(cur_connection_node->fd, reply_buff, reply_buff_len) == -1) { + report_error("connection_node_socks_reply(): write(%d, %lx, %d): %s", cur_connection_node->fd, (unsigned long) reply_buff, reply_buff_len, strerror(errno)); + } +} /****************************************************************************** * @@ -555,6 +592,7 @@ int parse_socks_request(struct connection_node *cur_connection_node){ // Socks 4 or 4a. if(head[index] == 4){ + cur_connection_node->socks_type = 4; /* * +----+----+----+----+----+----+----+----+----+----+....+----+ @@ -641,6 +679,7 @@ int parse_socks_request(struct connection_node *cur_connection_node){ // SOCKS 5 }else if(head[index] == 5){ + cur_connection_node->socks_type = 5; if(cur_connection_node->state == CON_SOCKS_INIT){ index += 1;