|
|
@ -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; |
|
|
|
} |
|
|
|