From cf04f73a987268ac66c94f5c518234eb4665ead0 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Fri, 1 Aug 2014 13:35:46 +0800 Subject: [PATCH] refine buffer handling --- libipset/bdd/Makefile.in | 0 libipset/map/Makefile.in | 0 libipset/set/Makefile.in | 0 src/local.c | 454 ++++++++++++++++++++------------------- src/local.h | 4 +- src/redir.h | 4 +- src/server.h | 4 +- src/tunnel.h | 4 +- 8 files changed, 242 insertions(+), 228 deletions(-) create mode 100644 libipset/bdd/Makefile.in create mode 100644 libipset/map/Makefile.in create mode 100644 libipset/set/Makefile.in diff --git a/libipset/bdd/Makefile.in b/libipset/bdd/Makefile.in new file mode 100644 index 00000000..e69de29b diff --git a/libipset/map/Makefile.in b/libipset/map/Makefile.in new file mode 100644 index 00000000..e69de29b diff --git a/libipset/set/Makefile.in b/libipset/set/Makefile.in new file mode 100644 index 00000000..e69de29b diff --git a/src/local.c b/src/local.c index fbe83d05..86bd505d 100644 --- a/src/local.c +++ b/src/local.c @@ -196,297 +196,311 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) } } - // local socks5 server - if (server->stage == 5) + while (r > 0) { - if (remote == NULL) + // local socks5 server + if (server->stage == 5) { - LOGE("invalid remote."); - close_and_free_server(EV_A_ server); - return; - } + if (remote == NULL) + { + LOGE("invalid remote."); + close_and_free_server(EV_A_ server); + return; + } - // insert shadowsocks header - if (!remote->direct) - { - if (!remote->send_ctx->connected) + // Copy to remote->buf + if (buf != remote->buf) { + memcpy(remote->buf, buf, r); + } + + // insert shadowsocks header + if (!remote->direct) { - char *tmp = malloc(max(BUF_SIZE, r + server->addr_len)); + if (!remote->send_ctx->connected) + { + char *tmp = malloc(max(BUF_SIZE, r + server->addr_len)); - memcpy(tmp, server->addr_to_send, server->addr_len); - memcpy(tmp + server->addr_len, remote->buf, r); - r += server->addr_len; + memcpy(tmp, server->addr_to_send, server->addr_len); + memcpy(tmp + server->addr_len, remote->buf, r); + r += server->addr_len; - // deallocate - free(remote->buf); - remote->buf = tmp; - } + // deallocate + free(remote->buf); + remote->buf = tmp; + } - remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx); + remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r, server->e_ctx); - if (remote->buf == NULL) - { - LOGE("invalid password or cipher"); - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; + if (remote->buf == NULL) + { + LOGE("invalid password or cipher"); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } } - } - else - { - memcpy(remote->buf, buf, r); - } - - remote->buf_idx = 0; - remote->buf_len = r; - if (!remote->send_ctx->connected) - { - if (!fast_open || remote->direct) + if (!remote->send_ctx->connected) { - // connecting, wait until connected - connect(remote->fd, remote->addr_info->ai_addr, remote->addr_info->ai_addrlen); - + if (!fast_open || remote->direct) + { + // connecting, wait until connected + connect(remote->fd, remote->addr_info->ai_addr, remote->addr_info->ai_addrlen); + } + else + { +#ifdef TCP_FASTOPEN + int s = sendto(remote->fd, remote->buf, r, MSG_FASTOPEN, + remote->addr_info->ai_addr, remote->addr_info->ai_addrlen); + if (s == -1) + { + if (errno == EINPROGRESS) + { + // in progress, wait until connected + remote->buf_idx = 0; + remote->buf_len = r; + ev_io_stop(EV_A_ &server_recv_ctx->io); + ev_io_start(EV_A_ &remote->send_ctx->io); + return; + } + else + { + ERROR("sendto"); + if (errno == ENOTCONN) + { + LOGE("fast open is not supported on this platform"); + // just turn it off + fast_open = 0; + } + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + } + else if (s < r) + { + remote->buf_len = r - s; + remote->buf_idx = s; + } +#else + // if TCP_FASTOPEN is not defined, fast_open will always be 0 + LOGE("can't come here"); + exit(1); +#endif + } // wait on remote connected event + remote->buf_idx = 0; + remote->buf_len = r; ev_io_stop(EV_A_ &server_recv_ctx->io); ev_io_start(EV_A_ &remote->send_ctx->io); ev_timer_start(EV_A_ &remote->send_ctx->watcher); } else { -#ifdef TCP_FASTOPEN - int s = sendto(remote->fd, remote->buf, r, MSG_FASTOPEN, - remote->addr_info->ai_addr, remote->addr_info->ai_addrlen); + int s = send(remote->fd, remote->buf, r, 0); if (s == -1) { - if (errno == EINPROGRESS) + if (errno == EAGAIN || errno == EWOULDBLOCK) { - // in progress, wait until connected + // no data, wait for send + remote->buf_idx = 0; + remote->buf_len = r; ev_io_stop(EV_A_ &server_recv_ctx->io); ev_io_start(EV_A_ &remote->send_ctx->io); return; } else { - ERROR("sendto"); - if (errno == ENOTCONN) - { - LOGE("fast open is not supported on this platform"); - // just turn it off - fast_open = 0; - } + ERROR("server_recv_cb_send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } - remote->send_ctx->connected = 1; - ev_timer_stop(EV_A_ &remote->send_ctx->watcher); - ev_io_start(EV_A_ &remote->recv_ctx->io); -#else - // if TCP_FASTOPEN is not defined, fast_open will always be 0 - LOGE("can't come here"); - exit(1); -#endif - } - } - else - { - int s = send(remote->fd, remote->buf, r, 0); - if (s == -1) - { - if (errno == EAGAIN || errno == EWOULDBLOCK) + else if (s < r) { - // no data, wait for send - remote->buf_len = r; - remote->buf_idx = 0; + remote->buf_len = r - s; + remote->buf_idx = s; ev_io_stop(EV_A_ &server_recv_ctx->io); ev_io_start(EV_A_ &remote->send_ctx->io); return; } - else - { - ERROR("server_recv_cb_send"); - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; - } - } - else if (s < r) - { - remote->buf_len = r - s; - remote->buf_idx = s; - ev_io_stop(EV_A_ &server_recv_ctx->io); - ev_io_start(EV_A_ &remote->send_ctx->io); - return; } - } - } - else if (server->stage == 0) - { - struct method_select_response response; - response.ver = SVERSION; - response.method = 0; - char *send_buf = (char *)&response; - send(server->fd, send_buf, sizeof(response), 0); - server->stage = 1; - return; - } - else if (server->stage == 1) - { - struct socks5_request *request = (struct socks5_request *)buf; - - struct sockaddr_in sock_addr; - memset(&sock_addr, 0, sizeof(sock_addr)); - if (udprelay && request->cmd == 3) - { - socklen_t addr_len = sizeof(sock_addr); - getsockname(server->fd, (struct sockaddr *)&sock_addr, - &addr_len); - if (verbose) - { - LOGD("udp assc request accepted."); - } + // all processed + r = 0; } - else if (request->cmd != 1) + else if (server->stage == 0) { - LOGE("unsupported cmd: %d", request->cmd); - struct socks5_response response; + struct method_select_response response; response.ver = SVERSION; - response.rep = CMD_NOT_SUPPORTED; - response.rsv = 0; - response.atyp = 1; + response.method = 0; char *send_buf = (char *)&response; - send(server->fd, send_buf, 4, 0); - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); + send(server->fd, send_buf, sizeof(response), 0); + server->stage = 1; + r -= 3; + buf += 3; return; } - else + else if (server->stage == 1) { - char *ss_addr_to_send = malloc(BUF_SIZE); - ssize_t addr_len = 0; - ss_addr_to_send[addr_len++] = request->atyp; - char host[256], port[16]; + struct socks5_request *request = (struct socks5_request *)buf; - // get remote addr and port - if (request->atyp == 1) - { - // IP V4 - size_t in_addr_len = sizeof(struct in_addr); - memcpy(ss_addr_to_send + addr_len, buf + 4, in_addr_len + 2); - addr_len += in_addr_len + 2; + struct sockaddr_in sock_addr; + memset(&sock_addr, 0, sizeof(sock_addr)); - if (acl || verbose) + if (udprelay && request->cmd == 3) + { + socklen_t addr_len = sizeof(sock_addr); + getsockname(server->fd, (struct sockaddr *)&sock_addr, + &addr_len); + if (verbose) { - uint16_t p = ntohs(*(uint16_t *)(buf + 4 + in_addr_len)); - inet_ntop(AF_INET, (const void *)(buf + 4), - host, INET_ADDRSTRLEN); - sprintf(port, "%d", p); + LOGD("udp assc request accepted."); } } - else if (request->atyp == 3) + else if (request->cmd != 1) { - // Domain name - uint8_t name_len = *(uint8_t *)(buf + 4); - ss_addr_to_send[addr_len++] = name_len; - memcpy(ss_addr_to_send + addr_len, buf + 4 + 1, name_len + 2); - addr_len += name_len + 2; + LOGE("unsupported cmd: %d", request->cmd); + struct socks5_response response; + response.ver = SVERSION; + response.rep = CMD_NOT_SUPPORTED; + response.rsv = 0; + response.atyp = 1; + char *send_buf = (char *)&response; + send(server->fd, send_buf, 4, 0); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; + } + else + { + char *ss_addr_to_send = malloc(BUF_SIZE); + ssize_t addr_len = 0; + ss_addr_to_send[addr_len++] = request->atyp; + char host[256], port[16]; - if (acl || verbose) + // get remote addr and port + if (request->atyp == 1) { - uint16_t p = ntohs(*(uint16_t *)(buf + 4 + 1 + name_len)); - memcpy(host, buf + 4 + 1, name_len); - host[name_len] = '\0'; - sprintf(port, "%d", p); + // IP V4 + size_t in_addr_len = sizeof(struct in_addr); + memcpy(ss_addr_to_send + addr_len, buf + 4, in_addr_len + 2); + addr_len += in_addr_len + 2; + + if (acl || verbose) + { + uint16_t p = ntohs(*(uint16_t *)(buf + 4 + in_addr_len)); + inet_ntop(AF_INET, (const void *)(buf + 4), + host, INET_ADDRSTRLEN); + sprintf(port, "%d", p); + } } - } - else if (request->atyp == 4) - { - // IP V6 - size_t in6_addr_len = sizeof(struct in6_addr); - memcpy(ss_addr_to_send + addr_len, buf + 4, in6_addr_len + 2); - addr_len += in6_addr_len + 2; + else if (request->atyp == 3) + { + // Domain name + uint8_t name_len = *(uint8_t *)(buf + 4); + ss_addr_to_send[addr_len++] = name_len; + memcpy(ss_addr_to_send + addr_len, buf + 4 + 1, name_len + 2); + addr_len += name_len + 2; - if (acl || verbose) + if (acl || verbose) + { + uint16_t p = ntohs(*(uint16_t *)(buf + 4 + 1 + name_len)); + memcpy(host, buf + 4 + 1, name_len); + host[name_len] = '\0'; + sprintf(port, "%d", p); + } + } + else if (request->atyp == 4) { - uint16_t p = ntohs(*(uint16_t *)(buf + 4 + in6_addr_len)); - inet_ntop(AF_INET6, (const void *)(buf + 4), - host, INET6_ADDRSTRLEN); - sprintf(port, "%d", p); + // IP V6 + size_t in6_addr_len = sizeof(struct in6_addr); + memcpy(ss_addr_to_send + addr_len, buf + 4, in6_addr_len + 2); + addr_len += in6_addr_len + 2; + + if (acl || verbose) + { + uint16_t p = ntohs(*(uint16_t *)(buf + 4 + in6_addr_len)); + inet_ntop(AF_INET6, (const void *)(buf + 4), + host, INET6_ADDRSTRLEN); + sprintf(port, "%d", p); + } + } + else + { + LOGE("unsupported addrtype: %d", request->atyp); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; } - } - else - { - LOGE("unsupported addrtype: %d", request->atyp); - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; - } - server->addr_to_send = ss_addr_to_send; - server->addr_len = addr_len; - server->stage = 5; + server->addr_to_send = ss_addr_to_send; + server->addr_len = addr_len; + server->stage = 5; - if (verbose) - { - LOGD("connect to %s:%s", host, port); - } + r -= (4 + addr_len); + buf += (4 + addr_len); - if ((acl && request->atyp == 1 && acl_contains_ip(host)) - || (acl && request->atyp == 3 && acl_contains_domain(host))) - { - remote = connect_to_remote(server->listener, host, port); - remote->direct = 1; if (verbose) { - LOGD("bypass %s:%s", host, port); + LOGD("connect to %s:%s", host, port); } + + if ((acl && request->atyp == 1 && acl_contains_ip(host)) + || (acl && request->atyp == 3 && acl_contains_domain(host))) + { + remote = connect_to_remote(server->listener, host, port); + remote->direct = 1; + if (verbose) + { + LOGD("bypass %s:%s", host, port); + } + } + else + { + remote = connect_to_remote(server->listener, NULL, NULL); + } + + if (remote == NULL) + { + LOGE("invalid remote addr."); + close_and_free_server(EV_A_ server); + return; + } + + server->remote = remote; + remote->server = server; } - else + + // Fake reply + struct socks5_response response; + response.ver = SVERSION; + response.rep = 0; + response.rsv = 0; + response.atyp = 1; + + memcpy(server->buf, &response, sizeof(struct socks5_response)); + memcpy(server->buf + sizeof(struct socks5_response), &sock_addr.sin_addr, sizeof(sock_addr.sin_addr)); + memcpy(server->buf + sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr), + &sock_addr.sin_port, sizeof(sock_addr.sin_port)); + + int reply_size = sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port); + int s = send(server->fd, server->buf, reply_size, 0); + if (s < reply_size) { - remote = connect_to_remote(server->listener, NULL, NULL); + LOGE("failed to send fake reply."); + close_and_free_remote(EV_A_ remote); + close_and_free_server(EV_A_ server); + return; } - if (remote == NULL) + if (request->cmd == 3) { - LOGE("invalid remote addr."); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } - - server->remote = remote; - remote->server = server; - } - - // Fake reply - struct socks5_response response; - response.ver = SVERSION; - response.rep = 0; - response.rsv = 0; - response.atyp = 1; - - memcpy(server->buf, &response, sizeof(struct socks5_response)); - memcpy(server->buf + sizeof(struct socks5_response), &sock_addr.sin_addr, sizeof(sock_addr.sin_addr)); - memcpy(server->buf + sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr), - &sock_addr.sin_port, sizeof(sock_addr.sin_port)); - - int reply_size = sizeof(struct socks5_response) + sizeof(sock_addr.sin_addr) + sizeof(sock_addr.sin_port); - int s = send(server->fd, server->buf, reply_size, 0); - if (s < reply_size) - { - LOGE("failed to send fake reply."); - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; - } - - if (request->cmd == 3) - { - close_and_free_remote(EV_A_ remote); - close_and_free_server(EV_A_ server); - return; } } } @@ -567,7 +581,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) close_and_free_server(EV_A_ server); return; } - else if(r < 0) + else if (r < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { diff --git a/src/local.h b/src/local.h index 330a1f66..c257d2ca 100644 --- a/src/local.h +++ b/src/local.h @@ -51,7 +51,7 @@ struct server_ctx struct server { int fd; - int buf_len; + ssize_t buf_len; int buf_idx; char *buf; // server send from, remote recv into int addr_len; @@ -76,7 +76,7 @@ struct remote_ctx struct remote { int fd; - int buf_len; + ssize_t buf_len; int buf_idx; int direct; char *buf; // remote send from, server recv into diff --git a/src/redir.h b/src/redir.h index 6cb75d25..cd2efaa8 100644 --- a/src/redir.h +++ b/src/redir.h @@ -48,7 +48,7 @@ struct server_ctx struct server { int fd; - int buf_len; + ssize_t buf_len; int buf_idx; char *buf; // server send from, remote recv into struct sockaddr_in destaddr; @@ -70,7 +70,7 @@ struct remote_ctx struct remote { int fd; - int buf_len; + ssize_t buf_len; int buf_idx; char *buf; // remote send from, server recv into struct remote_ctx *recv_ctx; diff --git a/src/server.h b/src/server.h index 62442118..16c3c6cf 100644 --- a/src/server.h +++ b/src/server.h @@ -55,7 +55,7 @@ struct server { int fd; int stage; - int buf_len; + ssize_t buf_len; int buf_idx; char *buf; // server send from, remote recv into asyncns_query_t *query; @@ -77,7 +77,7 @@ struct remote_ctx struct remote { int fd; - int buf_len; + ssize_t buf_len; int buf_idx; char *buf; // remote send from, server recv into struct remote_ctx *recv_ctx; diff --git a/src/tunnel.h b/src/tunnel.h index 99094059..dae51207 100644 --- a/src/tunnel.h +++ b/src/tunnel.h @@ -52,7 +52,7 @@ struct server_ctx struct server { int fd; - int buf_len; + ssize_t buf_len; int buf_idx; char *buf; // server send from, remote recv into struct enc_ctx *e_ctx; @@ -74,7 +74,7 @@ struct remote_ctx struct remote { int fd; - int buf_len; + ssize_t buf_len; int buf_idx; char *buf; // remote send from, server recv into struct remote_ctx *recv_ctx;