From 46afbdcfd65b3270cb027f581918a09d0a95057f Mon Sep 17 00:00:00 2001 From: Max Lv Date: Mon, 22 Aug 2016 21:04:32 +0800 Subject: [PATCH] Refine incomplete header handling --- src/local.c | 26 ++++++------ src/redir.c | 18 +++++---- src/server.c | 109 ++++++++++++++++++++++++++++++++++++++++++++------- src/server.h | 1 + src/tunnel.c | 21 +++++----- 5 files changed, 130 insertions(+), 45 deletions(-) diff --git a/src/local.c b/src/local.c index b3fdb790..4a42a703 100644 --- a/src/local.c +++ b/src/local.c @@ -78,7 +78,7 @@ #define BUF_SIZE 2048 #endif -int verbose = 0; +int verbose = 0; int keep_resolving = 1; #ifdef ANDROID @@ -267,7 +267,8 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) int not_protect = 0; if (remote->addr.ss_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)&remote->addr; - if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) not_protect = 1; + if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) + not_protect = 1; } if (!not_protect) { if (protect_socket(remote->fd) == -1) { @@ -294,7 +295,8 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) } if (r == 0) { - if (verbose) LOGI("connected immediately"); + if (verbose) + LOGI("connected immediately"); remote_send_cb(EV_A_ & remote->send_ctx->io, 0); } else { // wait on remote connected event @@ -302,7 +304,6 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); } - } else { #ifdef TCP_FASTOPEN #ifdef __APPLE__ @@ -986,7 +987,8 @@ void accept_cb(EV_P_ ev_io *w, int revents) ev_io_start(EV_A_ & server->recv_ctx->io); } -void resolve_int_cb(int dummy) { +void resolve_int_cb(int dummy) +{ keep_resolving = 0; } @@ -1015,11 +1017,11 @@ int main(int argc, char **argv) int option_index = 0; static struct option long_options[] = { - { "fast-open", no_argument , 0, 0 }, - { "acl" , required_argument, 0, 0 }, - { "mtu" , required_argument, 0, 0 }, - { "mptcp" , no_argument , 0, 0 }, - { "help" , no_argument , 0, 0 }, + { "fast-open", no_argument, 0, 0 }, + { "acl", required_argument, 0, 0 }, + { "mtu", required_argument, 0, 0 }, + { "mptcp", no_argument, 0, 0 }, + { "help", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; @@ -1228,7 +1230,7 @@ int main(int argc, char **argv) // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); - signal(SIGINT, resolve_int_cb); + signal(SIGINT, resolve_int_cb); signal(SIGTERM, resolve_int_cb); #endif @@ -1319,7 +1321,6 @@ int main(int argc, char **argv) ss_free(listen_ctx.remote_addr); } - if (mode != TCP_ONLY) { free_udprelay(); } @@ -1416,7 +1417,6 @@ int start_ss_local_server(profile_t profile) listen_ctx.mptcp = mptcp; if (mode != UDP_ONLY) { - // Setup socket int listenfd; listenfd = create_and_bind(local_addr, local_port_str); diff --git a/src/redir.c b/src/redir.c index ac38fb91..67977169 100644 --- a/src/redir.c +++ b/src/redir.c @@ -81,7 +81,7 @@ static void close_and_free_remote(EV_P_ remote_t *remote); static void free_server(server_t *server); static void close_and_free_server(EV_P_ server_t *server); -int verbose = 0; +int verbose = 0; int keep_resolving = 1; static int mode = TCP_ONLY; @@ -669,7 +669,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents) } if (r == 0) { - if (verbose) LOGI("connected immediately"); + if (verbose) + LOGI("connected immediately"); remote_send_cb(EV_A_ & remote->send_ctx->io, 0); } else { // listen to remote connected event @@ -680,7 +681,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents) ev_io_start(EV_A_ & server->recv_ctx->io); } -void signal_cb(int dummy) { +void signal_cb(int dummy) +{ keep_resolving = 0; exit(-1); } @@ -708,10 +710,10 @@ int main(int argc, char **argv) int option_index = 0; static struct option long_options[] = { - { "mtu", required_argument, 0, 0 }, - { "mptcp", no_argument , 0, 0 }, - { "help", no_argument , 0, 0 }, - { 0, 0 , 0, 0 } + { "mtu", required_argument, 0, 0 }, + { "mptcp", no_argument, 0, 0 }, + { "help", no_argument, 0, 0 }, + { 0, 0, 0, 0 } }; opterr = 0; @@ -880,7 +882,7 @@ int main(int argc, char **argv) // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); - signal(SIGINT, signal_cb); + signal(SIGINT, signal_cb); signal(SIGTERM, signal_cb); // Setup keys diff --git a/src/server.c b/src/server.c index 77837072..28039a7a 100644 --- a/src/server.c +++ b/src/server.c @@ -106,6 +106,7 @@ static void server_resolve_cb(struct sockaddr *addr, void *data); static void query_free_cb(void *data); static size_t parse_header_len(const char atyp, const char *data, size_t offset); +static int is_header_complete(const buffer_t *buf); int verbose = 0; @@ -235,6 +236,42 @@ static size_t parse_header_len(const char atyp, const char *data, size_t offset) return len; } +static int is_header_complete(const buffer_t *buf) +{ + size_t header_len = 0; + size_t buf_len = buf->len; + + char atyp = buf->array[header_len]; + + // 1 byte for atyp + header_len++; + + if ((atyp & ADDRTYPE_MASK) == 1) { + // IP V4 + header_len += sizeof(struct in_addr); + } else if ((atyp & ADDRTYPE_MASK) == 3) { + // Domain name + // domain len + len of domain + if (buf_len < header_len + 1) + return 0; + uint8_t name_len = *(uint8_t *)(buf->array + header_len); + header_len += name_len + 1; + } else if ((atyp & ADDRTYPE_MASK) == 4) { + // IP V6 + header_len += sizeof(struct in6_addr); + } + + // len of port + header_len += 2; + + // size of ONETIMEAUTH_BYTES + if (auth || (atyp & ONETIMEAUTH_FLAG)) { + header_len += ONETIMEAUTH_BYTES; + } + + return buf_len >= header_len; +} + static char *get_peer_name(int fd) { static char peer_name[INET6_ADDRSTRLEN] = { 0 }; @@ -513,7 +550,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) ev_timer_again(EV_A_ & server->recv_ctx->watcher); - if (server->stage != 0) { + if (server->stage > 2) { remote = server->remote; buf = remote->buf; len = 0; @@ -544,16 +581,16 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) tx += r; - // handle incomplete header + // handle incomplete header part 1 if (server->stage == 0) { buf->len += r; - if (buf->len <= enc_get_iv_len()) { + if (buf->len <= enc_get_iv_len() + 1) { // wait for more if (verbose) { #ifdef __MINGW32__ - LOGI("incomplete header: %u", r); + LOGI("incomplete IV: %u", r); #else - LOGI("incomplete header: %zu", r); + LOGI("incomplete IV: %zu", r); #endif } return; @@ -572,6 +609,42 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) return; } + // handle incomplete header part 2 + if (server->stage == 0) { + if (is_header_complete(server->buf)) { + bfree(server->header_buf); + ss_free(server->header_buf); + server->stage = 2; + } else { + server->stage = 1; + } + } + if (server->stage == 1) { + size_t header_len = server->header_buf->len; + brealloc(server->header_buf, server->buf->len + header_len, BUF_SIZE); + memcpy(server->header_buf->array + header_len, + server->buf->array, server->buf->len); + server->header_buf->len = server->buf->len + header_len; + + if (is_header_complete(server->header_buf)) { + brealloc(server->buf, server->header_buf->len, BUF_SIZE); + memcpy(server->buf->array, server->header_buf->array, server->header_buf->len); + server->buf->len = server->header_buf->len; + bfree(server->header_buf); + ss_free(server->header_buf); + server->stage = 2; + } else { +#ifdef __MINGW32__ + LOGI("incomplete header: %u", server->header_buf->len); +#else + LOGI("incomplete header: %zu", server->header_buf->len); +#endif + server->buf->len = 0; + server->buf->idx = 0; + return; + } + } + // handshake and transmit data if (server->stage == 5) { if (server->auth && !ss_check_hash(remote->buf, server->chunk, server->d_ctx, BUF_SIZE)) { @@ -600,7 +673,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) ev_io_start(EV_A_ & remote->send_ctx->io); } return; - } else if (server->stage == 0) { + } else if (server->stage == 2) { /* * Shadowsocks TCP Relay Header: * @@ -793,7 +866,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) } if (!need_query) { - int connected = 0; + int connected = 0; remote_t *remote = connect_to_remote(&info, server, &connected); if (remote == NULL) { @@ -830,7 +903,7 @@ static void server_recv_cb(EV_P_ ev_io *w, int revents) server->stage = 4; server->query = resolv_query(host, server_resolve_cb, - query_free_cb, query, port); + query_free_cb, query, port); ev_io_stop(EV_A_ & server_recv_ctx->io); } @@ -947,7 +1020,7 @@ static void server_resolve_cb(struct sockaddr *addr, void *data) info.ai_addrlen = sizeof(struct sockaddr_in6); } - int connected = 0; + int connected = 0; remote_t *remote = connect_to_remote(&info, server, &connected); if (remote == NULL) { @@ -1206,6 +1279,7 @@ static server_t *new_server(int fd, listen_ctx_t *listener) server->recv_ctx = ss_malloc(sizeof(server_ctx_t)); server->send_ctx = ss_malloc(sizeof(server_ctx_t)); server->buf = ss_malloc(sizeof(buffer_t)); + server->header_buf = ss_malloc(sizeof(buffer_t)); server->fd = fd; server->recv_ctx->server = server; server->recv_ctx->connected = 0; @@ -1232,6 +1306,7 @@ static server_t *new_server(int fd, listen_ctx_t *listener) min(MAX_CONNECT_TIMEOUT, listener->timeout), listener->timeout); balloc(server->buf, BUF_SIZE); + balloc(server->header_buf, BUF_SIZE); server->chunk = (chunk_t *)malloc(sizeof(chunk_t)); memset(server->chunk, 0, sizeof(chunk_t)); @@ -1269,6 +1344,10 @@ static void free_server(server_t *server) bfree(server->buf); ss_free(server->buf); } + if (server->header_buf != NULL) { + bfree(server->header_buf); + ss_free(server->header_buf); + } ss_free(server->recv_ctx); ss_free(server->send_ctx); @@ -1363,12 +1442,12 @@ int main(int argc, char **argv) int option_index = 0; static struct option long_options[] = { - { "fast-open" , no_argument , 0, 0 }, - { "acl" , required_argument, 0, 0 }, + { "fast-open", no_argument, 0, 0 }, + { "acl", required_argument, 0, 0 }, { "manager-address", required_argument, 0, 0 }, - { "mtu" , required_argument, 0, 0 }, - { "mptcp" , no_argument , 0, 0 }, - { "help" , no_argument , 0, 0 }, + { "mtu", required_argument, 0, 0 }, + { "mptcp", no_argument, 0, 0 }, + { "help", no_argument, 0, 0 }, { 0, 0, 0, 0 } }; @@ -1659,7 +1738,7 @@ int main(int argc, char **argv) // Setup UDP if (mode != TCP_ONLY) { init_udprelay(server_host[index], server_port, mtu, m, - auth, atoi(timeout), iface); + auth, atoi(timeout), iface); } LOGI("listening at %s:%s", host ? host : "*", server_port); diff --git a/src/server.h b/src/server.h index 12aa9d79..4388571d 100644 --- a/src/server.h +++ b/src/server.h @@ -53,6 +53,7 @@ typedef struct server { int fd; int stage; buffer_t *buf; + buffer_t *header_buf; int auth; struct chunk *chunk; diff --git a/src/tunnel.c b/src/tunnel.c index 532a723e..ac70bd98 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -90,7 +90,7 @@ int vpn = 0; char *prefix; #endif -int verbose = 0; +int verbose = 0; int keep_resolving = 1; static int mode = TCP_ONLY; @@ -636,7 +636,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents) int not_protect = 0; if (remote_addr->sa_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)remote_addr; - if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) not_protect = 1; + if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) + not_protect = 1; } if (!not_protect) { if (protect_socket(remotefd) == -1) { @@ -685,7 +686,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents) } if (r == 0) { - if (verbose) LOGI("connected immediately"); + if (verbose) + LOGI("connected immediately"); remote_send_cb(EV_A_ & remote->send_ctx->io, 0); } else { // listen to remote connected event @@ -694,7 +696,8 @@ static void accept_cb(EV_P_ ev_io *w, int revents) } } -void signal_cb(int dummy) { +void signal_cb(int dummy) +{ keep_resolving = 0; exit(-1); } @@ -726,10 +729,10 @@ int main(int argc, char **argv) int option_index = 0; static struct option long_options[] = { - { "mtu", required_argument, 0, 0 }, - { "mptcp",no_argument, 0, 0 }, - { "help", no_argument, 0, 0 }, - { 0, 0, 0, 0 } + { "mtu", required_argument, 0, 0 }, + { "mptcp", no_argument, 0, 0 }, + { "help", no_argument, 0, 0 }, + { 0, 0, 0, 0 } }; opterr = 0; @@ -935,7 +938,7 @@ int main(int argc, char **argv) // ignore SIGPIPE signal(SIGPIPE, SIG_IGN); signal(SIGABRT, SIG_IGN); - signal(SIGINT, signal_cb); + signal(SIGINT, signal_cb); signal(SIGTERM, signal_cb); #endif