From db6b156808a75e38a1c44a0420a191ccd9c1f939 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Mon, 15 Apr 2013 17:49:03 +0800 Subject: [PATCH] fix some weird data corruptions caused by optimized memcpy --- src/local.c | 41 ++++++++++++++++++++++++++--------------- src/server.c | 19 +++++++++---------- src/utils.c | 7 +++++++ src/utils.h | 1 + 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/src/local.c b/src/local.c index 1d9104e1..34436cf6 100644 --- a/src/local.c +++ b/src/local.c @@ -63,10 +63,11 @@ int create_and_bind(const char *port) { continue; int opt = 1; - int err = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); - if (err) { - ERROR("setsocket"); - } + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + setsockopt(listen_sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); +#ifdef SO_NOSIGPIPE + setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { @@ -141,7 +142,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } } else if(s < r) { remote->buf_len = r - s; - memcpy(remote->buf, remote->buf + s, remote->buf_len); + bufcpy(remote->buf, remote->buf + s, remote->buf_len); ev_io_stop(EV_A_ &server_recv_ctx->io); ev_io_start(EV_A_ &remote->send_ctx->io); return; @@ -179,14 +180,14 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { if (request->atyp == 1) { // IP V4 size_t in_addr_len = sizeof(struct in_addr); - memcpy(addr_to_send + addr_len, remote->buf + 4, in_addr_len + 2); + bufcpy(addr_to_send + addr_len, remote->buf + 4, in_addr_len + 2); addr_len += in_addr_len + 2; } else if (request->atyp == 3) { // Domain name uint8_t name_len = *(uint8_t *)(remote->buf + 4); addr_to_send[addr_len++] = name_len; - memcpy(addr_to_send + addr_len, remote->buf + 4 + 1, name_len); + bufcpy(addr_to_send + addr_len, remote->buf + 4 + 1, name_len); addr_len += name_len; // get port @@ -196,7 +197,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } else if (request->atyp == 4) { // IP V6 size_t in6_addr_len = sizeof(struct in6_addr); - memcpy(addr_to_send + addr_len, remote->buf + 4, in6_addr_len + 2); + bufcpy(addr_to_send + addr_len, remote->buf + 4, in6_addr_len + 2); addr_len += in6_addr_len + 2; } else { @@ -225,10 +226,10 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { struct in_addr sin_addr; inet_aton("0.0.0.0", &sin_addr); - memcpy(server->buf, &response, 4); - memset(server->buf + 4, 0, sizeof(struct in_addr) + sizeof(uint16_t)); + bufcpy(server->buf, &response, sizeof(struct socks5_response)); + memset(server->buf + sizeof(struct socks5_response), 0, sizeof(struct in_addr) + sizeof(uint16_t)); - int reply_size = 4 + sizeof(struct in_addr) + sizeof(uint16_t); + int reply_size = sizeof(struct socks5_response) + sizeof(struct in_addr) + sizeof(uint16_t); s = send(server->fd, server->buf, reply_size, 0); if (s < reply_size) { LOGE("failed to send fake reply."); @@ -238,6 +239,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } server->stage = 5; + ev_io_start(EV_A_ &remote->recv_ctx->io); } } @@ -264,7 +266,7 @@ static void server_send_cb (EV_P_ ev_io *w, int revents) { } else if (s < server->buf_len) { // partly sent, move memory, wait for the next time to send server->buf_len -= s; - memcpy(server->buf, server->buf + s, server->buf_len); + bufcpy(server->buf, server->buf + s, server->buf_len); return; } else { // all sent out, wait for reading @@ -349,7 +351,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) { } } else if (s < r) { server->buf_len = r - s; - memcpy(server->buf, server->buf + s, server->buf_len); + bufcpy(server->buf, server->buf + s, server->buf_len); ev_io_stop(EV_A_ &remote_recv_ctx->io); ev_io_start(EV_A_ &server->send_ctx->io); return; @@ -371,7 +373,6 @@ static void remote_send_cb (EV_P_ ev_io *w, int revents) { ev_io_stop(EV_A_ &remote_send_ctx->io); ev_timer_stop(EV_A_ &remote_send_ctx->watcher); ev_io_start(EV_A_ &server->recv_ctx->io); - ev_io_start(EV_A_ &remote->recv_ctx->io); return; } else { ERROR("getpeername"); @@ -401,7 +402,7 @@ static void remote_send_cb (EV_P_ ev_io *w, int revents) { } else if (s < remote->buf_len) { // partly sent, move memory, wait for the next time to send remote->buf_len -= s; - memcpy(remote->buf, remote->buf + s, remote->buf_len); + bufcpy(remote->buf, remote->buf + s, remote->buf_len); return; } else { // all sent out, wait for reading @@ -515,6 +516,11 @@ static void accept_cb (EV_P_ ev_io *w, int revents) { return; } setnonblocking(serverfd); + int opt = 1; + setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); +#ifdef SO_NOSIGPIPE + setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif struct addrinfo hints, *res; int sockfd; @@ -536,6 +542,11 @@ static void accept_cb (EV_P_ ev_io *w, int revents) { return; } + setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); +#ifdef SO_NOSIGPIPE + setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif + struct timeval timeout; timeout.tv_sec = listener->timeout; timeout.tv_usec = 0; diff --git a/src/server.c b/src/server.c index 83f42883..c22bf961 100644 --- a/src/server.c +++ b/src/server.c @@ -72,7 +72,6 @@ int create_and_bind(const char *host, const char *port) { setsockopt(listen_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif - s = bind(listen_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ @@ -173,7 +172,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } } else if (s < r) { remote->buf_len = r - s; - memcpy(remote->buf, remote->buf + s, remote->buf_len); + bufcpy(remote->buf, remote->buf + s, remote->buf_len); ev_io_stop(EV_A_ &server_recv_ctx->io); ev_io_start(EV_A_ &remote->send_ctx->io); } @@ -203,14 +202,14 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { size_t in_addr_len = sizeof(struct in_addr); if (r > in_addr_len) { char *a = inet_ntoa(*(struct in_addr*)(server->buf + offset)); - memcpy(host, a, strlen(a)); + bufcpy(host, a, strlen(a)); offset += in_addr_len; } } else if (atyp == 3) { // Domain name uint8_t name_len = *(uint8_t *)(server->buf + offset); - memcpy(host, server->buf + offset + 1, name_len); + bufcpy(host, server->buf + offset + 1, name_len); offset += name_len + 1; } else if (atyp == 4) { @@ -220,7 +219,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { char a[INET6_ADDRSTRLEN]; inet_ntop(AF_INET6, (const void*)(server->buf + offset), a, sizeof(a)); - memcpy(host, a, strlen(a)); + bufcpy(host, a, strlen(a)); offset += in6_addr_len; } @@ -258,7 +257,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { // XXX: should handel buffer carefully if (r > offset) { server->buf_len = r - offset; - memcpy(server->buf, server->buf + offset, server->buf_len); + bufcpy(server->buf, server->buf + offset, server->buf_len); } server->stage = 4; @@ -306,7 +305,7 @@ static void server_send_cb (EV_P_ ev_io *w, int revents) { } else if (s < server->buf_len) { // partly sent, move memory, wait for the next time to send server->buf_len -= s; - memcpy(server->buf, server->buf + s, server->buf_len); + bufcpy(server->buf, server->buf + s, server->buf_len); return; } else { // all sent out, wait for reading @@ -396,7 +395,7 @@ static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) { // XXX: should handel buffer carefully if (server->buf_len > 0) { - memcpy(remote->buf, server->buf, server->buf_len); + bufcpy(remote->buf, server->buf, server->buf_len); remote->buf_len = server->buf_len; server->buf_len = 0; } @@ -473,7 +472,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) { return; } else if (s < r) { server->buf_len = r - s; - memcpy(server->buf, server->buf + s, server->buf_len); + bufcpy(server->buf, server->buf + s, server->buf_len); ev_io_stop(EV_A_ &remote_recv_ctx->io); ev_io_start(EV_A_ &server->send_ctx->io); return; @@ -543,7 +542,7 @@ static void remote_send_cb (EV_P_ ev_io *w, int revents) { } else if (s < remote->buf_len) { // partly sent, move memory, wait for the next time to send remote->buf_len -= s; - memcpy(remote->buf, remote->buf + s, remote->buf_len); + bufcpy(remote->buf, remote->buf + s, remote->buf_len); return; } else { // all sent out, wait for reading diff --git a/src/utils.c b/src/utils.c index 1fd5a92e..918e1be6 100644 --- a/src/utils.c +++ b/src/utils.c @@ -22,6 +22,13 @@ void ERROR(const char *s) { } +void bufcpy(char *dest, const char *src, size_t n) { + int i; + for (i = 0; i < n; i++) { + *dest++ = *src++; + } +} + char *itoa(int i) { /* Room for INT_DIGITS digits, - and '\0' */ static char buf[INT_DIGITS + 2]; diff --git a/src/utils.h b/src/utils.h index 9dc610db..9987054f 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,5 +24,6 @@ void ERROR(const char *s); void usage(void); void demonize(const char* path); char *itoa(int i); +void bufcpy(char *dest, const char *src, size_t n); #endif // _UTILS_H