From d4b000090fd96be047f650daa492195fa3a9c826 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Sun, 28 Jul 2013 17:29:37 +0800 Subject: [PATCH] WiP --- src/encrypt.c | 60 +++++++- src/encrypt.h | 4 +- src/udprelay.c | 400 ++++++++++++++++++++++++------------------------- src/udprelay.h | 45 +++--- 4 files changed, 266 insertions(+), 243 deletions(-) diff --git a/src/encrypt.c b/src/encrypt.c index 67151a7c..558dd343 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -150,8 +150,29 @@ void enc_table_init(const char *pass) { } } -char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx *ctx) { - if (ctx != NULL) { +char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, int method) { + if (method > TABLE) { + + const EVP_CIPHER *cipher = EVP_get_cipherbyname(supported_ciphers[method]); + if (cipher == NULL) { + LOGE("Cipher %s not found in OpenSSL library", supported_ciphers[method]); + FATAL("Cannot initialize cipher"); + } + EVP_CIPHER_CTX evp; + EVP_CIPHER_CTX_init(&evp); + if (!EVP_CipherInit_ex&(evp, cipher, NULL, NULL, NULL, enc)) { + LOGE("Cannot initialize cipher %s", supported_ciphers[method]); + exit(EXIT_FAILURE); + } + if (!EVP_CIPHER_CTX_set_key_length(&evp, enc_key_len)) { + EVP_CIPHER_CTX_cleanup(&evp); + LOGE("Invalid key length: %d", enc_key_len); + exit(EXIT_FAILURE); + } + if (method > RC4) { + EVP_CIPHER_CTX_set_padding(&evp, 1); + } + int c_len = *len + BLOCK_SIZE; int iv_len = 0; int err = 0; @@ -160,9 +181,8 @@ char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx 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); + EVP_CipherInit_ex(&evp, NULL, NULL, enc_key, iv, 1); memcpy(ciphertext, iv, iv_len); - ctx->init = 1; #ifdef DEBUG dump("IV", iv); @@ -174,6 +194,7 @@ char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx if (!err) { free(ciphertext); free(plaintext); + EVP_CIPHER_CTX_cleanup(&evp); return NULL; } @@ -184,6 +205,8 @@ char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx *len = iv_len + c_len; free(plaintext); + EVP_CIPHER_CTX_cleanup(&evp); + return ciphertext; } else { @@ -240,8 +263,29 @@ char* ss_encrypt(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx *ct } } -char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *ctx) { - if (ctx != NULL) { +char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, int method) { + if (method > TABLE) { + + const EVP_CIPHER *cipher = EVP_get_cipherbyname(supported_ciphers[method]); + if (cipher == NULL) { + LOGE("Cipher %s not found in OpenSSL library", supported_ciphers[method]); + FATAL("Cannot initialize cipher"); + } + EVP_CIPHER_CTX evp; + EVP_CIPHER_CTX_init(&evp); + if (!EVP_CipherInit_ex&(evp, cipher, NULL, NULL, NULL, enc)) { + LOGE("Cannot initialize cipher %s", supported_ciphers[method]); + exit(EXIT_FAILURE); + } + if (!EVP_CIPHER_CTX_set_key_length(&evp, enc_key_len)) { + EVP_CIPHER_CTX_cleanup(&evp); + LOGE("Invalid key length: %d", enc_key_len); + exit(EXIT_FAILURE); + } + if (method > RC4) { + EVP_CIPHER_CTX_set_padding(&evp, 1); + } + int p_len = *len + BLOCK_SIZE; int iv_len = 0; int err = 0; @@ -250,7 +294,7 @@ char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, struct enc_ct 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); + EVP_CipherInit_ex(&evp, NULL, NULL, enc_key, iv, 0); #ifdef DEBUG dump("IV", iv); @@ -261,6 +305,7 @@ char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, struct enc_ct if (!err) { free(ciphertext); free(plaintext); + EVP_CIPHER_CTX_cleanup(&evp); return NULL; } @@ -271,6 +316,7 @@ char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, struct enc_ct *len = p_len; free(ciphertext); + EVP_CIPHER_CTX_cleanup(&evp); return plaintext; } else { char *begin = ciphertext; diff --git a/src/encrypt.h b/src/encrypt.h index cb2e2358..8a754908 100644 --- a/src/encrypt.h +++ b/src/encrypt.h @@ -43,8 +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_all(char *plaintext, ssize_t *len, int method); +char* ss_decrypt_all(char *ciphertext, ssize_t *len, int method); 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/udprelay.c b/src/udprelay.c index 2153e20a..c7620393 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -38,6 +38,7 @@ struct udprelay_header { uint16_t rsv; uint8_t frag; } +struct remote *remote = NULL; #else #error "No UDPRELAY defined" #endif @@ -60,7 +61,7 @@ struct udprelay_header { #define BLOCK_SIZE MAX_UDP_PACKET_SIZE static int verbose = 0; -static int client_conn = 0; +static int remote_conn = 0; static int server_conn = 0; int setnonblocking(int fd) { @@ -81,7 +82,39 @@ int setinterface(int socket_fd, const char* interface_name) } #endif -int create_and_bind(const char *host, const char *port) { +int create_remote_socket() { + int s, remote_sock; + + // Try to bind IPv6 first + struct sockaddr_in6 addr_in6; + memset(&addr, 0, sizeof(addr_in6)); + addr_in6.sin_family = AF_INET6; + addr_in6.sin_addr.s_addr = htonl(IN6ADDR_ANY); + addr_in6.sin_port = htons(0); + remote_sock = socket(AF_INET6, SOCK_DGRAM , 0); + if (remote_sock != -1) { + if (bind(remote_sock, &addr_in6, sizeof(addr_in6)) != -1) { + return remote_sock; + } + } + + // Then bind to IPv4 + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(0); + remote_sock = socket(AF_INET, SOCK_DGRAM , 0); + if (remote_sock == -1) + FATAL("Cannot create socket."); + + if (bind(remote_sock, &addr, sizeof(addr)) != 0) + FATAL("Cannot bind remote."); + + return remote_sock; +} + +int create_server_socket(const char *host, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp; int s, server_sock; @@ -128,18 +161,18 @@ int create_and_bind(const char *host, const char *port) { return server_sock; } -struct client *send_to_client(struct addrinfo *res, const char *iface) { +struct remote *send_to_remote(struct addrinfo *res, const char *iface) { connect(sockfd, res->ai_addr, res->ai_addrlen); - return client; + return remote; } 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; - struct client *client = server->client; + struct remote *remote = server->remote; - if (client == NULL) { + if (remote == NULL) { LOGE("invalid server."); close_and_free_server(EV_A_ server); return; @@ -150,7 +183,7 @@ static void server_send_cb (EV_P_ ev_io *w, int revents) { if (verbose) { LOGD("server_send close the connection"); } - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { @@ -160,7 +193,7 @@ static void server_send_cb (EV_P_ ev_io *w, int revents) { if (s < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("server_send_send"); - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; @@ -174,12 +207,12 @@ static void server_send_cb (EV_P_ ev_io *w, int revents) { server->buf_len = 0; server->buf_idx = 0; ev_io_stop(EV_A_ &server_send_ctx->io); - if (client != NULL) { - ev_io_start(EV_A_ &client->recv_ctx->io); + if (remote != NULL) { + ev_io_start(EV_A_ &remote->recv_ctx->io); return; } else { - LOGE("invalid client."); - close_and_free_client(EV_A_ client); + LOGE("invalid remote."); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } @@ -190,13 +223,13 @@ 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 *server = (struct server *) (((void*)watcher) - sizeof(ev_timer)); - struct client *client = server->client; + struct remote *remote = server->remote; LOGE("UDP connection timeout"); ev_timer_stop(EV_A_ watcher); - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } @@ -247,7 +280,7 @@ static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) { int sockfd; int opt = 1; - // initilize client socks + // initilize remote socks sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) { ERROR("socket"); @@ -259,50 +292,50 @@ static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) { setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif - struct client *client = new_client(sockfd); + struct remote *remote = new_remote(sockfd); - // setup client socks + // setup remote 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); + ss_encrypt_all(BLOCK_SIZE, server->buf, &server->buf_len, server->recv_ctx->method); #endif - server->client = client; - client->server = server; + server->remote = remote; + remote->server = server; - // listen to client connected event - ev_io_start(EV_A_ &client->send_ctx->io); + // listen to remote connected event + ev_io_start(EV_A_ &remote->send_ctx->io); } // release addrinfo asyncns_freeaddrinfo(result); } -static void client_recv_cb (EV_P_ ev_io *w, int revents) { - struct client_ctx *client_recv_ctx = (struct client_ctx *)w; - struct client *client = client_recv_ctx->client; - struct server *server = client->server; +static void remote_recv_cb (EV_P_ ev_io *w, int revents) { + struct remote_ctx *remote_recv_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_recv_ctx->remote; + struct server *server = remote->server; if (server == NULL) { LOGE("invalid server."); - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); return; } ev_timer_again(EV_A_ &server->recv_ctx->watcher); - ssize_t r = recv(client->fd, server->buf, BUF_SIZE, 0); + ssize_t r = recv(remote->fd, server->buf, BUF_SIZE, 0); if (r == 0) { // connection closed if (verbose) { - LOGD("client_recv close the connection"); + LOGD("remote_recv close the connection"); } - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r < 0) { @@ -311,8 +344,8 @@ static void client_recv_cb (EV_P_ ev_io *w, int revents) { // continue to wait for recv return; } else { - ERROR("client recv"); - close_and_free_client(EV_A_ client); + ERROR("remote recv"); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } @@ -322,7 +355,7 @@ static void client_recv_cb (EV_P_ ev_io *w, int revents) { if (server->buf == NULL) { LOGE("invalid password or cipher"); - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } @@ -334,101 +367,101 @@ static void client_recv_cb (EV_P_ ev_io *w, int revents) { // no data, wait for send server->buf_len = r; server->buf_idx = 0; - ev_io_stop(EV_A_ &client_recv_ctx->io); + ev_io_stop(EV_A_ &remote_recv_ctx->io); ev_io_start(EV_A_ &server->send_ctx->io); } else { - ERROR("client_recv_send"); - close_and_free_client(EV_A_ client); + ERROR("remote_recv_send"); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < r) { server->buf_len = r - s; server->buf_idx = s; - ev_io_stop(EV_A_ &client_recv_ctx->io); + ev_io_stop(EV_A_ &remote_recv_ctx->io); ev_io_start(EV_A_ &server->send_ctx->io); return; } } -static void client_send_cb (EV_P_ ev_io *w, int revents) { - struct client_ctx *client_send_ctx = (struct client_ctx *)w; - struct client *client = client_send_ctx->client; - struct server *server = client->server; +static void remote_send_cb (EV_P_ ev_io *w, int revents) { + struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; + struct remote *remote = remote_send_ctx->remote; + struct server *server = remote->server; if (server == NULL) { LOGE("invalid server."); - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); return; } - if (!client_send_ctx->connected) { + if (!remote_send_ctx->connected) { struct sockaddr_storage addr; socklen_t len = sizeof addr; - int r = getpeername(client->fd, (struct sockaddr*)&addr, &len); + int r = getpeername(remote->fd, (struct sockaddr*)&addr, &len); if (r == 0) { if (verbose) { - LOGD("client connected."); + LOGD("remote connected."); } - client_send_ctx->connected = 1; + remote_send_ctx->connected = 1; - if (client->buf_len == 0) { + if (remote->buf_len == 0) { server->stage = 5; - ev_io_stop(EV_A_ &client_send_ctx->io); + ev_io_stop(EV_A_ &remote_send_ctx->io); ev_io_start(EV_A_ &server->recv_ctx->io); - ev_io_start(EV_A_ &client->recv_ctx->io); + ev_io_start(EV_A_ &remote->recv_ctx->io); return; } } else { ERROR("getpeername"); // not connected - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } - if (client->buf_len == 0) { + if (remote->buf_len == 0) { // close and free if (verbose) { - LOGD("client_send close the connection"); + LOGD("remote_send close the connection"); } - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send - ssize_t s = send(client->fd, client->buf + client->buf_idx, - client->buf_len, 0); + ssize_t s = send(remote->fd, remote->buf + remote->buf_idx, + remote->buf_len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - ERROR("client_send_send"); + ERROR("remote_send_send"); // close and free - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; - } else if (s < client->buf_len) { + } else if (s < remote->buf_len) { // partly sent, move memory, wait for the next time to send - client->buf_len -= s; - client->buf_idx += s; + remote->buf_len -= s; + remote->buf_idx += s; return; } else { // all sent out, wait for reading - client->buf_len = 0; - client->buf_idx = 0; - ev_io_stop(EV_A_ &client_send_ctx->io); + remote->buf_len = 0; + remote->buf_idx = 0; + ev_io_stop(EV_A_ &remote_send_ctx->io); if (server != NULL) { ev_io_start(EV_A_ &server->recv_ctx->io); if (server->stage == 4) { server->stage = 5; - ev_io_start(EV_A_ &client->recv_ctx->io); + ev_io_start(EV_A_ &remote->recv_ctx->io); } } else { LOGE("invalid server."); - close_and_free_client(EV_A_ client); + close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; @@ -436,125 +469,39 @@ static void client_send_cb (EV_P_ ev_io *w, int revents) { } } -struct client* new_client(int fd) { - client_conn++; - struct client *client; - client = malloc(sizeof(struct client)); - client->buf = malloc(BUF_SIZE); - client->recv_ctx = malloc(sizeof(struct client_ctx)); - client->send_ctx = malloc(sizeof(struct client_ctx)); - client->fd = fd; - ev_io_init(&client->recv_ctx->io, client_recv_cb, fd, EV_READ); - ev_io_init(&client->send_ctx->io, client_send_cb, fd, EV_WRITE); - client->recv_ctx->client = client; - client->recv_ctx->connected = 0; - client->send_ctx->client = client; - client->send_ctx->connected = 0; - client->buf_len = 0; - client->buf_idx = 0; - client->server = NULL; - return client; -} - -void free_client(struct client *client) { - client_conn--; - if (client != NULL) { - if (client->server != NULL) { - client->server->client = NULL; - } - if (client->buf != NULL) { - free(client->buf); - } - free(client->recv_ctx); - free(client->send_ctx); - free(client); - } +struct remote_ctx *new_remote_ctx(int fd) { + struct remote_ctx *ctx = malloc(sizeof(struct remote_ctx)); + ctx->buf = malloc(BUF_SIZE); + ctx->buf_len = 0; + ctx->server_ctx = NULL; + ctx->fd = fd; } -void close_and_free_client(EV_P_ struct client *client) { - if (client != NULL) { - ev_io_stop(EV_A_ &client->send_ctx->io); - ev_io_stop(EV_A_ &client->recv_ctx->io); - close(client->fd); - free_client(client); - } - if (verbose) { - LOGD("current client connection: %d", client_conn); - } +struct server_ctx * new_server_ctx(int fd) { + struct server_ctx *ctx = malloc(sizeof(struct server_ctx)); + ctx->remote_ctx = NULL; + ctx->fd = fd; } -struct server* new_server(int fd, struct server_ctx *ctx) { - server_conn++; - struct server *server; - server = malloc(sizeof(struct server)); - server->buf = malloc(BUF_SIZE); - 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->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(ctx->method, server->e_ctx, 1); - enc_ctx_init(ctx->method, server->d_ctx, 0); - } else { - server->e_ctx = NULL; - server->d_ctx = NULL; - } - server->buf_len = 0; - server->buf_idx = 0; - server->client = NULL; - return server; -} - -void free_server(struct server *server) { - server_conn--; - if (server != NULL) { - if (server->client != NULL) { - server->client->server = NULL; - } - if (server->e_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->e_ctx->evp); - free(server->e_ctx); - } - if (server->d_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->d_ctx->evp); - free(server->d_ctx); - } - if (server->buf != NULL) { - free(server->buf); - } - free(server->recv_ctx); - free(server->send_ctx); - free(server); - } -} - -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->resolve_watcher); - ev_timer_stop(EV_A_ &server->timeout_watcher); - close(server->fd); - free_server(server); - } - if (verbose) { - LOGD("current server connection: %d", server_conn); - } +#ifdef UDPRELAY_REMOTE +struct query_ctx *new_query_ctx() { + struct query_ctx *ctx = malloc(sizeof(struct query_ctx)) + ctx->buf = malloc(BUF_SIZE); + ctx->buf_len = 0; + ev_timer_init(&ctx->watcher, server_resolve_cb, 0.2, 0.5); + ctx->query = NULL; } +#endif 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 server_ctx *server_ctx = (struct server_ctx *)w; struct udprelay_header *header; + uint8_t *buf = malloc(BUF_SIZE); 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, + ssize_t r = recvfrom(server_ctx->fd, buf, BUF_SIZE, 0, &server->src_addr, &addr_len); if (r == -1) { @@ -571,10 +518,10 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } #ifdef UDPRELAY_REMOTE - server->buf = ss_decrypt_all(BUF_SIZE, server->buf, &r, server->d_ctx) -#endif; + server->buf = ss_decrypt_all(BUF_SIZE, buf, &r, server_ctx->method); +#endif - header = (struct udprelay_header *)server->buf; + header = (struct udprelay_header *)buf; offset += sizeof(struct udprelay_header); /* @@ -618,21 +565,28 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { #ifdef UDPRELAY_LOCAL + struct remote_ctx = server_ctx->remote_ctx; + if (header->frag) { LOGE("drop a message since frag is not 0"); return; } - int index = rand() % server_recv_ctx->remote_num; - if (verbose) { - LOGD("send to remote: %s", server_recv_ctx->remote_host[index]); + r -= offset; + memmove(buf, buf + offset, r); + + int w = sendto(remote_ctx->fd, buf, r, 0, &remote_ctx->addr, sizeof(remote_ctx->addr)); + + if (w == -1) { + ERROR("udprelay_server_sendto"); } - strcpy(host, server_recv_ctx->remote_host[index]); - strcpy(port, server_recv_ctx->remote_port); #else - // get client addr and port + char host[256] = {0}; + char port[64] = {0}; + + // get remote addr and port if (header->atyp == 1) { // IP V4 size_t in_addr_len = sizeof(struct in_addr); @@ -668,10 +622,9 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { ntohs(*(uint16_t *)(server->buf + offset))); offset += 2; -#endif - r -= offset; memmove(server->buf, server->buf + offset, r); + server->buf_len = r; if (verbose) { LOGD("send to: %s:%s", host, port); @@ -683,7 +636,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - query = asyncns_getaddrinfo(server_recv_ctx->asyncns, + query = asyncns_getaddrinfo(server_ctx->asyncns, host, port, &hints); if (query == NULL) { @@ -692,37 +645,70 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } ev_timer_start(EV_A_ &server->resolve_watcher); + +#endif } -int udprelay(const char *server_host, int server_num, const char *server_port, - int method, int timeout, const char *iface) { +int udprelay(const char *server_host, const char *server_port, +#ifdef UDPRELAY_LOCAL + const char *remote_host, const char *remote_port, +#endif + int method, const char *iface) { // inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; - // bind to each interface - while (server_num > 0) { - int index = --server_num; - const char* host = server_host[index]; + ////////////////////////////////////////////////// + // Setup server context - // Bind to port - int serverfd = create_and_bind(host, server_port); - if (serverfd < 0) { - FATAL("udprelay bind() error.."); - } - setnonblocking(serverfd); - - // Setup proxy context - struct server_ctx *server_ctx = malloc(sizeof(struct server_ctx)); - server_ctx->fd = serverfd; - server_ctx->timeout = timeout; - server_ctx->method = method; - server_ctx->iface = iface; - server_ctx->asyncns = asyncns; - - ev_io_init (&server_ctx.io, server_recv_cb, serverfd, EV_READ); - ev_io_start (loop, &server_ctx.io); + // Bind to port + int serverfd = create_server_socket(host, server_port); + if (serverfd < 0) { + FATAL("udprelay bind() error.."); + } + setnonblocking(serverfd); + struct server_ctx *server_ctx = new_server_ctx(serverfd); + server_ctx->method = method; + server_ctx->iface = iface; + server_ctx->asyncns = asyncns; + + ev_io_init(&server_ctx.io, server_recv_cb, serverfd, EV_READ); + ev_io_start(loop, &server_ctx.io); + +#ifdef UDPRELAY_LOCAL + ////////////////////////////////////////////////// + // Setup remote context + + // Bind to any port + int remotefd = create_remote_socket(); + if (remote < 0) { + FATAL("udprelay bind() error.."); } + setnonblocking(remotefd); + + struct remote_ctx *remote_ctx = new_remote_ctx(remotefd); + + struct addrinfo hints; + struct addrinfo *result; + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */ + hints.ai_socktype = SOCK_DGRAM; /* We want a UDP socket */ + + int s = getaddrinfo(remote_host, remote_port, &hints, &result); + if (s != 0) { + LOGE("getaddrinfo: %s", gai_strerror(s)); + return -1; + } + remote_ctx->addr = *result->ai_addr; + freeaddrinfo(result); + + server_ctx->remote_ctx = remote_ctx; + remote_ctx->server_ctx = server_ctx; + + ev_io_init(&remote_ctx->io, remote_recv_cb, remotefd, EV_READ); + ev_io_start(loop, &remote_ctx->io); +#endif return 0; } diff --git a/src/udprelay.h b/src/udprelay.h index 8dc640a4..d8e77312 100644 --- a/src/udprelay.h +++ b/src/udprelay.h @@ -15,50 +15,41 @@ struct server_ctx { asyncns_t *asyncns; int fd; int method; - int timeout; char *iface; + struct sockaddr_in src_addr; + struct remote *remote; }; -struct server { +#ifdef UDPRELAY_CTX +struct query_ctx { 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 *recv_ctx; - struct client *client; -}; + char *buf; // server send from, remote recv into + struct server_ctx *server_ctx; + struct remote_ctx *remote_ctx; +} +#endif -struct client_ctx { +struct remote_ctx { ev_io io; - struct client *client; -}; - -struct client { int fd; int buf_len; - int buf_idx; - char *buf; // client send from, server recv into - struct sockaddr_in dest_addr; - struct client_ctx *recv_ctx; + char *buf; // remote send from, server recv into + struct sockaddr addr; struct server *server; }; static void server_recv_cb (EV_P_ ev_io *w, int revents); static void server_send_cb (EV_P_ ev_io *w, int revents); -static void client_recv_cb (EV_P_ ev_io *w, int revents); -static void client_send_cb (EV_P_ ev_io *w, int revents); -static void server_timeout_cb(EV_P_ ev_timer *watcher, int revents); +static void remote_recv_cb (EV_P_ ev_io *w, int revents); +static void remote_send_cb (EV_P_ ev_io *w, int revents); static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents); -struct client* new_client(int fd); -struct client *connect_to_client(struct addrinfo *res, const char *iface); -void free_client(struct client *client); -void close_and_free_client(EV_P_ struct client *client); +struct remote* new_remote(int fd); +struct remote *connect_to_remote(struct addrinfo *res, const char *iface); +void free_remote(struct remote *remote); +void close_and_free_remote(EV_P_ struct remote *remote); struct server* new_server(int fd, struct listen_ctx *listener); void free_server(struct server *server); void close_and_free_server(EV_P_ struct server *server);