From c2302b432a9a8d214ef0b6a2b593cace6fbaf86b Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sun, 28 Jul 2013 11:35:17 +0800 Subject: [PATCH] WiP --- src/encrypt.c | 98 ++++++++++- src/encrypt.h | 3 +- src/local.c | 8 +- src/redir.c | 8 +- src/server.c | 20 ++- src/udprelay.c | 453 ++++++++++++++++++++++--------------------------- src/udprelay.h | 8 +- 7 files changed, 326 insertions(+), 272 deletions(-) diff --git a/src/encrypt.c b/src/encrypt.c index 90e19d56..67151a7c 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -150,12 +150,58 @@ void enc_table_init(const char *pass) { } } -char* ss_encrypt(char *plaintext, ssize_t *len, struct enc_ctx *ctx) { +char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx *ctx) { if (ctx != NULL) { int c_len = *len + BLOCK_SIZE; int iv_len = 0; int err = 0; - char *ciphertext = malloc(max(iv_len + c_len, BUF_SIZE)); + char *ciphertext = malloc(max(iv_len + c_len, buf_size)); + + uint8_t iv[EVP_MAX_IV_LENGTH]; + iv_len = enc_iv_len; + RAND_bytes(iv, iv_len); + EVP_CipherInit_ex(&ctx->evp, NULL, NULL, enc_key, iv, 1); + memcpy(ciphertext, iv, iv_len); + ctx->init = 1; + +#ifdef DEBUG + dump("IV", iv); +#endif + + err = EVP_EncryptUpdate(&ctx->evp, (uint8_t*)(ciphertext+iv_len), + &c_len, (const uint8_t *)plaintext, *len); + + if (!err) { + free(ciphertext); + free(plaintext); + return NULL; + } + +#ifdef DEBUG + dump("PLAIN", plaintext); + dump("CIPHER", ciphertext); +#endif + + *len = iv_len + c_len; + free(plaintext); + return ciphertext; + + } else { + char *begin = plaintext; + while (plaintext < begin + *len) { + *plaintext = (char)enc_table[(uint8_t)*plaintext]; + plaintext++; + } + return begin; + } +} + +char* ss_encrypt(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx *ctx) { + if (ctx != NULL) { + int c_len = *len + BLOCK_SIZE; + int iv_len = 0; + int err = 0; + char *ciphertext = malloc(max(iv_len + c_len, buf_size)); if (!ctx->init) { uint8_t iv[EVP_MAX_IV_LENGTH]; @@ -163,7 +209,6 @@ char* ss_encrypt(char *plaintext, ssize_t *len, struct enc_ctx *ctx) { RAND_bytes(iv, iv_len); EVP_CipherInit_ex(&ctx->evp, NULL, NULL, enc_key, iv, 1); memcpy(ciphertext, iv, iv_len); - ctx->init = 1; #ifdef DEBUG dump("IV", iv); #endif @@ -171,7 +216,6 @@ char* ss_encrypt(char *plaintext, ssize_t *len, struct enc_ctx *ctx) { err = EVP_EncryptUpdate(&ctx->evp, (uint8_t*)(ciphertext+iv_len), &c_len, (const uint8_t *)plaintext, *len); - if (!err) { free(ciphertext); free(plaintext); @@ -196,12 +240,54 @@ char* ss_encrypt(char *plaintext, ssize_t *len, struct enc_ctx *ctx) { } } -char* ss_decrypt(char *ciphertext, ssize_t *len, struct enc_ctx *ctx) { +char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *ctx) { + if (ctx != NULL) { + int p_len = *len + BLOCK_SIZE; + int iv_len = 0; + int err = 0; + char *plaintext = malloc(max(p_len, buf_size)); + + uint8_t iv[EVP_MAX_IV_LENGTH]; + iv_len = enc_iv_len; + memcpy(iv, ciphertext, iv_len); + EVP_CipherInit_ex(&ctx->evp, NULL, NULL, enc_key, iv, 0); + +#ifdef DEBUG + dump("IV", iv); +#endif + + err = EVP_DecryptUpdate(&ctx->evp, (uint8_t*)plaintext, &p_len, + (const uint8_t*)(ciphertext + iv_len), *len - iv_len); + if (!err) { + free(ciphertext); + free(plaintext); + return NULL; + } + +#ifdef DEBUG + dump("PLAIN", plaintext); + dump("CIPHER", ciphertext); +#endif + + *len = p_len; + free(ciphertext); + return plaintext; + } else { + char *begin = ciphertext; + while (ciphertext < begin + *len) { + *ciphertext = (char)dec_table[(uint8_t)*ciphertext]; + ciphertext++; + } + return begin; + } +} + +char* ss_decrypt(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *ctx) { if (ctx != NULL) { int p_len = *len + BLOCK_SIZE; int iv_len = 0; int err = 0; - char *plaintext = malloc(max(p_len, BUF_SIZE)); + char *plaintext = malloc(max(p_len, buf_size)); if (!ctx->init) { uint8_t iv[EVP_MAX_IV_LENGTH]; diff --git a/src/encrypt.h b/src/encrypt.h index cbc8273b..cb2e2358 100644 --- a/src/encrypt.h +++ b/src/encrypt.h @@ -16,7 +16,6 @@ #include #endif -#define BUF_SIZE 512 #define BLOCK_SIZE 32 #define CIPHER_NUM 14 @@ -44,6 +43,8 @@ struct enc_ctx { EVP_CIPHER_CTX evp; }; +char* ss_encrypt_all(char *plaintext, ssize_t *len, struct enc_ctx *ctx); +char* ss_decrypt_all(char *ciphertext, ssize_t *len, struct enc_ctx *ctx); char* ss_encrypt(char *plaintext, ssize_t *len, struct enc_ctx *ctx); char* ss_decrypt(char *ciphertext, ssize_t *len, struct enc_ctx *ctx); void enc_ctx_init(int method, struct enc_ctx *ctx, int enc); diff --git a/src/local.c b/src/local.c index 305939e4..93b4a909 100644 --- a/src/local.c +++ b/src/local.c @@ -35,6 +35,10 @@ #define EWOULDBLOCK EAGAIN #endif +#ifndef BLOCK_SIZE +#define BLOCK_SIZE 512 +#endif + static int verbose = 0; int setnonblocking(int fd) { @@ -138,7 +142,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { // local socks5 server if (server->stage == 5) { - remote->buf = ss_encrypt(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); @@ -385,7 +389,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) { } } - server->buf = ss_decrypt(server->buf, &r, server->d_ctx); + server->buf = ss_decrypt(BLOCK_SIZE, server->buf, &r, server->d_ctx); if (server->buf == NULL) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); diff --git a/src/redir.c b/src/redir.c index bd3de626..05fde5a2 100644 --- a/src/redir.c +++ b/src/redir.c @@ -31,6 +31,10 @@ #define EWOULDBLOCK EAGAIN #endif +#ifndef BLOCK_SIZE +#define BLOCK_SIZE 512 +#endif + int getdestaddr(int fd, struct sockaddr_in *destaddr) { socklen_t socklen = sizeof(*destaddr); int error; @@ -257,7 +261,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) { } } - server->buf = ss_decrypt(server->buf, &r, server->d_ctx); + server->buf = ss_decrypt(BLOCK_SIZE, server->buf, &r, server->d_ctx); if (server->buf == NULL) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); @@ -315,7 +319,7 @@ static void remote_send_cb (EV_P_ ev_io *w, int revents) { addr_len += in_addr_len; memcpy(addr_to_send + addr_len, &server->destaddr.sin_port, 2); addr_len += 2; - addr_to_send = ss_encrypt(addr_to_send, &addr_len, server->e_ctx); + addr_to_send = ss_encrypt(BLOCK_SIZE, addr_to_send, &addr_len, server->e_ctx); if (addr_to_send == NULL) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); diff --git a/src/server.c b/src/server.c index b6cc7808..527bb587 100644 --- a/src/server.c +++ b/src/server.c @@ -35,6 +35,10 @@ #define EWOULDBLOCK EAGAIN #endif +#ifndef BLOCK_SIZE +#define BLOCK_SIZE 512 +#endif + static int verbose = 0; static int remote_conn = 0; static int server_conn = 0; @@ -189,7 +193,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } } - *buf = ss_decrypt(*buf, &r, server->d_ctx); + *buf = ss_decrypt(BUF_SIZE, *buf, &r, server->d_ctx); if (*buf == NULL) { LOGE("invalid password or cipher"); @@ -235,10 +239,8 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { int offset = 0; char atyp = server->buf[offset++]; - char host[256]; - char port[64]; - memset(host, 0, 256); - int p = 0; + char host[256] = {0}; + char port[64] = {0}; // get remote addr and port if (atyp == 1) { @@ -272,10 +274,10 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { return; } - p = ntohs(*(uint16_t *)(server->buf + offset)); - offset += 2; + sprintf(port, "%d", + ntohs(*(uint16_t *)(server->buf + offset))); - sprintf(port, "%d", p); + offset += 2; if (verbose) { LOGD("connect to: %s:%s", host, port); @@ -490,7 +492,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) { } } - server->buf = ss_encrypt(server->buf, &r, server->e_ctx); + server->buf = ss_encrypt(BLOCK_SIZE, server->buf, &r, server->e_ctx); if (server->buf == NULL) { LOGE("invalid password or cipher"); diff --git a/src/udprelay.c b/src/udprelay.c index ddfc17f4..2153e20a 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -28,6 +28,27 @@ #include "udprelay.h" #include "cache.h" +#ifdef UDPRELAY_REMOTE +struct udprelay_header { + uint8_t atyp; +} +#else +#ifdef UDPRELAY_LOCAL +struct udprelay_header { + uint16_t rsv; + uint8_t frag; +} +#else +#error "No UDPRELAY defined" +#endif +#endif + +#ifdef UDPRELAY_REMOTE +#ifdef UDPRELAY_LOCAL +#error "Both UDPRELAY_REMOTE and UDPRELAY_LOCAL defined" +#endif +#endif + #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif @@ -36,6 +57,8 @@ #define EWOULDBLOCK EAGAIN #endif +#define BLOCK_SIZE MAX_UDP_PACKET_SIZE + static int verbose = 0; static int client_conn = 0; static int server_conn = 0; @@ -105,215 +128,12 @@ int create_and_bind(const char *host, const char *port) { return server_sock; } -struct client *connect_to_client(struct addrinfo *res, const char *iface) { - int sockfd; - int opt = 1; - - // initilize client socks - sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sockfd < 0) { - ERROR("socket"); - close(sockfd); - return NULL; - } - - setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); -#ifdef SO_NOSIGPIPE - setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); -#endif - - struct client *client = new_client(sockfd); - - // setup client socks - setnonblocking(sockfd); -#ifdef SET_INTERFACE - if (iface) setinterface(sockfd, iface); -#endif - +struct client *send_to_client(struct addrinfo *res, const char *iface) { connect(sockfd, res->ai_addr, res->ai_addrlen); return client; } -static void server_recv_cb (EV_P_ ev_io *w, int revents) { - struct server_ctx *server_recv_ctx = (struct server_ctx *)w; - struct server *server = server_recv_ctx->server; - struct client *client = NULL; - - int len = server->buf_len; - char **buf = &server->buf; - - ev_timer_again(EV_A_ &server->recv_ctx->watcher); - - if (server->stage != 0) { - client = server->client; - buf = &client->buf; - len = 0; - } - - ssize_t r = recv(server->fd, *buf + len, BUF_SIZE - len, 0); - - if (r == 0) { - // connection closed - if (verbose) { - LOGD("server_recv close the connection"); - } - close_and_free_client(EV_A_ client); - close_and_free_server(EV_A_ server); - return; - } else if (r == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // no data - // continue to wait for recv - return; - } else { - ERROR("server recv"); - close_and_free_client(EV_A_ client); - close_and_free_server(EV_A_ server); - return; - } - } - - // handle incomplete header - if (server->stage == 0) { - r += server->buf_len; - if (r <= enc_get_iv_len()) { - // wait for more - if (verbose) { - LOGD("imcomplete header: %zu", r); - } - server->buf_len = r; - return; - } else { - server->buf_len = 0; - } - } - - *buf = ss_decrypt(*buf, &r, server->d_ctx); - - if (*buf == NULL) { - LOGE("invalid password or cipher"); - close_and_free_client(EV_A_ client); - close_and_free_server(EV_A_ server); - return; - } - - // handshake and transmit data - if (server->stage == 5) { - int s = send(client->fd, client->buf, r, 0); - if (s == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - // no data, wait for send - client->buf_len = r; - client->buf_idx = 0; - ev_io_stop(EV_A_ &server_recv_ctx->io); - ev_io_start(EV_A_ &client->send_ctx->io); - } else { - ERROR("server_recv_send"); - close_and_free_client(EV_A_ client); - close_and_free_server(EV_A_ server); - } - } else if (s < r) { - client->buf_len = r - s; - client->buf_idx = s; - ev_io_stop(EV_A_ &server_recv_ctx->io); - ev_io_start(EV_A_ &client->send_ctx->io); - } - return; - - } else if (server->stage == 0) { - - /* - * Shadowsocks Protocol: - * - * +------+----------+----------+ - * | ATYP | DST.ADDR | DST.PORT | - * +------+----------+----------+ - * | 1 | Variable | 2 | - * +------+----------+----------+ - */ - - int offset = 0; - char atyp = server->buf[offset++]; - char host[256]; - char port[64]; - memset(host, 0, 256); - int p = 0; - - // get client addr and port - if (atyp == 1) { - // IP V4 - size_t in_addr_len = sizeof(struct in_addr); - if (r > in_addr_len) { - inet_ntop(AF_INET, (const void *)(server->buf + offset), - host, INET_ADDRSTRLEN); - offset += in_addr_len; - } - } else if (atyp == 3) { - // Domain name - uint8_t name_len = *(uint8_t *)(server->buf + offset); - if (name_len < r && name_len < 255 && name_len > 0) { - memcpy(host, server->buf + offset + 1, name_len); - offset += name_len + 1; - } - } else if (atyp == 4) { - // IP V6 - size_t in6_addr_len = sizeof(struct in6_addr); - if (r > in6_addr_len) { - inet_ntop(AF_INET6, (const void*)(server->buf + offset), - host, INET6_ADDRSTRLEN); - offset += in6_addr_len; - } - } - - if (offset == 1) { - LOGE("invalid header with addr type %d", atyp); - close_and_free_server(EV_A_ server); - return; - } - - p = ntohs(*(uint16_t *)(server->buf + offset)); - offset += 2; - - sprintf(port, "%d", p); - - if (verbose) { - LOGD("connect to: %s:%s", host, port); - } - - struct addrinfo hints; - asyncns_query_t *query; - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - - query = asyncns_getaddrinfo(server->server_ctx->asyncns, - host, port, &hints); - - if (query == NULL) { - ERROR("asyncns_getaddrinfo"); - close_and_free_server(EV_A_ server); - return; - } - - // XXX: should handle buffer carefully - if (r > offset) { - server->buf_len = r - offset; - server->buf_idx = offset; - } - - server->stage = 4; - server->query = query; - - ev_io_stop(EV_A_ &server_recv_ctx->io); - ev_timer_start(EV_A_ &server->send_ctx->watcher); - - return; - } - // should not reach here - FATAL("server context error."); -} - static void server_send_cb (EV_P_ ev_io *w, int revents) { struct server_ctx *server_send_ctx = (struct server_ctx *)w; struct server *server = server_send_ctx->server; @@ -368,12 +188,11 @@ static void server_send_cb (EV_P_ ev_io *w, int revents) { } static void server_timeout_cb(EV_P_ ev_timer *watcher, int revents) { - struct server_ctx *server_ctx = (struct server_ctx *) (((void*)watcher) - - sizeof(ev_io)); - struct server *server = server_ctx->server; + struct server *server = (struct server *) (((void*)watcher) + - sizeof(ev_timer)); struct client *client = server->client; - LOGE("TCP connection timeout"); + LOGE("UDP connection timeout"); ev_timer_stop(EV_A_ watcher); @@ -425,27 +244,38 @@ static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) { rp = result; } - struct client *client = connect_to_client(rp, server->server_ctx->iface); - - if (client == NULL) { - LOGE("connect error."); - close_and_free_server(EV_A_ server); - } else { - server->client = client; - client->server = server; - - // XXX: should handel buffer carefully - if (server->buf_len > 0) { - memcpy(client->buf, server->buf + server->buf_idx, server->buf_len); - client->buf_len = server->buf_len; - client->buf_idx = 0; - server->buf_len = 0; - server->buf_idx = 0; - } + int sockfd; + int opt = 1; - // listen to client connected event - ev_io_start(EV_A_ &client->send_ctx->io); + // initilize client socks + sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sockfd < 0) { + ERROR("socket"); + close(sockfd); + return NULL; } + +#ifdef SO_NOSIGPIPE + setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); +#endif + + struct client *client = new_client(sockfd); + + // setup client socks + setnonblocking(sockfd); +#ifdef SET_INTERFACE + if (iface) setinterface(sockfd, iface); +#endif + +#ifdef UDPRELAY_LOCAL + ss_encrypt_all(BLOCK_SIZE, server->buf, &r, server->e_ctx); +#endif + + server->client = client; + client->server = server; + + // listen to client connected event + ev_io_start(EV_A_ &client->send_ctx->io); } // release addrinfo @@ -658,15 +488,15 @@ struct server* new_server(int fd, struct server_ctx *ctx) { struct server *server; server = malloc(sizeof(struct server)); server->buf = malloc(BUF_SIZE); - ev_timer_init(&server->send_ctx->watcher, server_resolve_cb, 0.2, 0.5); - ev_timer_init(&server->recv_ctx->watcher, server_timeout_cb, ctx->timeout, ctx->timeout * 5); + ev_timer_init(&server->resolve_watcher, server_resolve_cb, 0.2, 0.5); + ev_timer_init(&server->timeout_watcher, server_timeout_cb, ctx->timeout, ctx->timeout * 5); server->query = NULL; - server->server_ctx = ctx; + server->recv_ctx = ctx; if (ctx->method) { server->e_ctx = malloc(sizeof(struct enc_ctx)); server->d_ctx = malloc(sizeof(struct enc_ctx)); - enc_ctx_init(listener->method, server->e_ctx, 1); - enc_ctx_init(listener->method, server->d_ctx, 0); + enc_ctx_init(ctx->method, server->e_ctx, 1); + enc_ctx_init(ctx->method, server->d_ctx, 0); } else { server->e_ctx = NULL; server->d_ctx = NULL; @@ -704,8 +534,8 @@ void close_and_free_server(EV_P_ struct server *server) { if (server != NULL) { ev_io_stop(EV_A_ &server->send_ctx->io); ev_io_stop(EV_A_ &server->recv_ctx->io); - ev_timer_stop(EV_A_ &server->send_ctx->watcher); - ev_timer_stop(EV_A_ &server->recv_ctx->watcher); + ev_timer_stop(EV_A_ &server->resolve_watcher); + ev_timer_stop(EV_A_ &server->timeout_watcher); close(server->fd); free_server(server); } @@ -714,27 +544,154 @@ void close_and_free_server(EV_P_ struct server *server) { } } -static void server_cb (EV_P_ ev_io *w, int revents) { - struct server_ctx *listener = (struct server_ctx *)w; - int serverfd = accept(listener->fd, NULL, NULL); - if (serverfd == -1) { - ERROR("accept"); +static void server_recv_cb (EV_P_ ev_io *w, int revents) { + struct server_ctx *server_recv_ctx = (struct server_ctx *)w; + struct server *server = new_server(serverfd, server_recv_ctx); + struct udprelay_header *header; + + int addr_len = sizeof(server->src_addr); + int offset = 0; + char host[256] = {0}; + char port[64] = {0}; + + ssize_t r = recvfrom(server_recv_ctx->fd, server->buf, BUF_SIZE, + 0, &server->src_addr, &addr_len); + + if (r == -1) { + // error on recv + // simply drop that packet + if (verbose) { + ERROR("udprelay_server_recvfrom"); + } + return; + } + + if (verbose) { + LOGD("receive a packet."); + } + +#ifdef UDPRELAY_REMOTE + server->buf = ss_decrypt_all(BUF_SIZE, server->buf, &r, server->d_ctx) +#endif; + + header = (struct udprelay_header *)server->buf; + offset += sizeof(struct udprelay_header); + + /* + * + * SOCKS5 UDP Request + * +----+------+------+----------+----------+----------+ + * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | + * +----+------+------+----------+----------+----------+ + * | 2 | 1 | 1 | Variable | 2 | Variable | + * +----+------+------+----------+----------+----------+ + * + * SOCKS5 UDP Response + * +----+------+------+----------+----------+----------+ + * |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | + * +----+------+------+----------+----------+----------+ + * | 2 | 1 | 1 | Variable | 2 | Variable | + * +----+------+------+----------+----------+----------+ + * + * shadowsocks UDP Request (before encrypted) + * +------+----------+----------+----------+ + * | ATYP | DST.ADDR | DST.PORT | DATA | + * +------+----------+----------+----------+ + * | 1 | Variable | 2 | Variable | + * +------+----------+----------+----------+ + * + * shadowsocks UDP Response (before encrypted) + * +------+----------+----------+----------+ + * | ATYP | DST.ADDR | DST.PORT | DATA | + * +------+----------+----------+----------+ + * | 1 | Variable | 2 | Variable | + * +------+----------+----------+----------+ + * + * shadowsocks UDP Request and Response (after encrypted) + * +-------+--------------+ + * | IV | PAYLOAD | + * +-------+--------------+ + * | Fixed | Variable | + * +-------+--------------+ + * + */ + +#ifdef UDPRELAY_LOCAL + + if (header->frag) { + LOGE("drop a message since frag is not 0"); return; } - setnonblocking(serverfd); - int opt = 1; -#ifdef SO_NOSIGPIPE - setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); + int index = rand() % server_recv_ctx->remote_num; + if (verbose) { + LOGD("send to remote: %s", server_recv_ctx->remote_host[index]); + } + strcpy(host, server_recv_ctx->remote_host[index]); + strcpy(port, server_recv_ctx->remote_port); + +#else + + // get client addr and port + if (header->atyp == 1) { + // IP V4 + size_t in_addr_len = sizeof(struct in_addr); + if (r > in_addr_len) { + inet_ntop(AF_INET, (const void *)(server->buf + offset), + host, INET_ADDRSTRLEN); + offset += in_addr_len; + } + } else if (header->atyp == 3) { + // Domain name + uint8_t name_len = *(uint8_t *)(server->buf + offset); + if (name_len < r && name_len < 255 && name_len > 0) { + memcpy(host, server->buf + offset + 1, name_len); + offset += name_len + 1; + } + } else if (header->atyp == 4) { + // IP V6 + size_t in6_addr_len = sizeof(struct in6_addr); + if (r > in6_addr_len) { + inet_ntop(AF_INET6, (const void*)(server->buf + offset), + host, INET6_ADDRSTRLEN); + offset += in6_addr_len; + } + } + + if (offset == sizeof(struct udprelay_header)) { + LOGE("invalid header with addr type %d", atyp); + close_and_free_server(EV_A_ server); + return; + } + + sprintf(port, "%d", + ntohs(*(uint16_t *)(server->buf + offset))); + offset += 2; + #endif + r -= offset; + memmove(server->buf, server->buf + offset, r); + if (verbose) { - LOGD("accept a connection."); + LOGD("send to: %s:%s", host, port); + } + + struct addrinfo hints; + asyncns_query_t *query; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + query = asyncns_getaddrinfo(server_recv_ctx->asyncns, + host, port, &hints); + + if (query == NULL) { + ERROR("udp_asyncns_getaddrinfo"); + close_and_free_server(EV_A_ server); } - struct server *server = new_server(serverfd, listener); - ev_io_start(EV_A_ &server->recv_ctx->io); - ev_timer_start(EV_A_ &server->recv_ctx->watcher); + ev_timer_start(EV_A_ &server->resolve_watcher); } int udprelay(const char *server_host, int server_num, const char *server_port, @@ -767,8 +724,6 @@ int udprelay(const char *server_host, int server_num, const char *server_port, ev_io_start (loop, &server_ctx.io); } - // start ev loop - ev_run (loop, 0); return 0; } diff --git a/src/udprelay.h b/src/udprelay.h index b6e2f154..8dc640a4 100644 --- a/src/udprelay.h +++ b/src/udprelay.h @@ -20,14 +20,16 @@ struct server_ctx { }; struct server { - ev_timer watcher; + ev_timer resolve_watcher; + ev_timer timeout_watcher; asyncns_query_t *query; int buf_len; int buf_idx; char *buf; // server send from, client recv into + struct sockaddr_in src_addr; struct enc_ctx *e_ctx; struct enc_ctx *d_ctx; - struct server_ctx *server_ctx; + struct server_ctx *recv_ctx; struct client *client; }; @@ -41,8 +43,8 @@ struct client { int buf_len; int buf_idx; char *buf; // client send from, server recv into + struct sockaddr_in dest_addr; struct client_ctx *recv_ctx; - struct client_ctx *send_ctx; struct server *server; };