diff --git a/src/cache.c b/src/cache.c index bf83cfec..0f2aa05e 100644 --- a/src/cache.c +++ b/src/cache.c @@ -70,6 +70,32 @@ int cache_delete(struct cache *cache, int keep_data) return 0; } +/** Removes a cache entry + + @param cache + The cache object + + @param key + The key of the entry to remove + + @return EINVAL if cache is NULL, 0 otherwise +*/ +int cache_remove(struct cache *cache, char *key) +{ + struct cache_entry *tmp; + + if (!cache || !key) + return EINVAL; + + HASH_FIND_STR(cache->entries, key, tmp); + + if (tmp) { + HASH_DEL(cache->entries, tmp); + } + + return 0; +} + /** Checks if a given key is in the cache @param cache diff --git a/src/cache.h b/src/cache.h index 047ecd51..83ae79d4 100644 --- a/src/cache.h +++ b/src/cache.h @@ -33,5 +33,6 @@ extern int cache_create(struct cache **dst, const size_t capacity, extern int cache_delete(struct cache *cache, int keep_data); extern int cache_lookup(struct cache *cache, char *key, void *result); extern int cache_insert(struct cache *cache, char *key, void *data); +extern int cache_remove(struct cache *cache, char *key); #endif diff --git a/src/local.c b/src/local.c index 93b4a909..bede8ad8 100644 --- a/src/local.c +++ b/src/local.c @@ -182,7 +182,12 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } else if (server->stage == 1) { struct socks5_request *request = (struct socks5_request *)remote->buf; - if (request->cmd != 1) { + if (request->cmd == 3) { + if (verbose) { + LOGD("udp assc request accepted."); + } + goto fake_reply; + } else if (request->cmd != 1) { LOGE("unsupported cmd: %d", request->cmd); struct socks5_response response; response.ver = SVERSION; @@ -251,7 +256,6 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { return; } - addr_to_send = ss_encrypt(addr_to_send, &addr_len, server->e_ctx); if (addr_to_send == NULL) { LOGE("invalid password or cipher"); @@ -269,6 +273,11 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { return; } + server->stage = 5; + ev_io_start(EV_A_ &remote->recv_ctx->io); + +fake_reply: + // Fake reply struct socks5_response response; response.ver = SVERSION; @@ -290,9 +299,6 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { close_and_free_server(EV_A_ server); return; } - - server->stage = 5; - ev_io_start(EV_A_ &remote->recv_ctx->io); } } @@ -778,6 +784,10 @@ int main (int argc, char **argv) { } ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ); ev_io_start (loop, &listen_ctx.io); + + // Setup UDP + udprelay(local_addr, local_port, remote_host[0], remote_port, m, iface); + ev_run (loop, 0); return 0; } diff --git a/src/server.c b/src/server.c index 527bb587..dcdbd243 100644 --- a/src/server.c +++ b/src/server.c @@ -885,6 +885,9 @@ int main (int argc, char **argv) { ev_io_start (loop, &listen_ctx.io); } + // Setup UDP + udprelay(server_host[0], server_port, m, iface); + // start ev loop ev_run (loop, 0); return 0; diff --git a/src/udprelay.c b/src/udprelay.c index e3159b3b..71596801 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -49,7 +49,7 @@ struct remote *remote = NULL; #ifdef UDPRELAY_REMOTE #ifdef UDPRELAY_LOCAL -#error "Both UDPRELAY_REMOTE and UDPRELAY_LOCAL defined" +#error "UDPRELAY_REMOTE and UDPRELAY_LOCAL should not be both defined" #endif #endif @@ -89,11 +89,12 @@ static char *hash_key(const char *header, const int header_len, const sockaddr * char key[384]; // calculate hash key + // assert header_len < 256 memset(key, 0, 384); - memcpy(key, addr.sa_data, 14); - memcpy(key + 14, header, header_len); + memcpy(key, addr, sizeof(sockaddr)); + memcpy(key + sizeof(sockaddr), header, header_len); - return (char*) MD5((const uint8_t *)key, 14 + header_len, NULL); + return (char*) MD5((const uint8_t *)key, sizeof(sockaddr) + header_len, NULL); } static int parse_udprealy_header(const char* buf, const int buf_len, @@ -122,7 +123,7 @@ static int parse_udprealy_header(const char* buf, const int buf_len, } } else if (atyp == 4) { // IP V6 - size_t in6_addbuf_len_len = sizeof(stbuf_lenuct in6_addbuf_len); + size_t in6_addr_len = sizeof(struct in6_addr); if (buf_len > in6_addbuf_len_len) { if (host != NULL) { inet_ntop(AF_INET6, (const void*)(buf + offset), @@ -274,6 +275,8 @@ void close_and_free_query(EN_P_ struct query_ctx *ctx) { } } +#endif + void close_and_free_remote(EN_P_ struct remote_ctx *ctx) { if (ctx != NULL) { close(ctx->fd); @@ -287,7 +290,6 @@ void close_and_free_remote(EN_P_ struct remote_ctx *ctx) { free(ctx); } } -#endif static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { struct remote_ctx *remote_ctx = (struct remote_ctx *) (((void*)watcher) @@ -295,9 +297,10 @@ static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { LOGE("UDP connection timeout"); - ev_timer_stop(EV_A_ watcher); - - close_and_free_remote(EV_A_ remote_ctx); + char *key = hash_key(remote_ctx->addr_header, + remote_ctx->addr_header_len, &remote_ctx->src_addr); + cache_remove(remote_ctx->server_ctx->conn_cache, key); + close_and_free_remote(remote_ctx); } static void query_resolve_cb(EV_P_ ev_timer *watcher, int revents) { @@ -546,7 +549,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } struct remote_ctx *remote_ctx = NULL; - cache_lookup(conn_cache, key, (void*)remote_ctx); + cache_lookup(conn_cache, key, (void*)&remote_ctx); if (remote_ctx == NULL) { @@ -651,6 +654,11 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { } +void free_cb(void *element) { + struct remote_ctx *remote_ctx = (struct remote_ctx *)element; + close_and_free_remote(remote_ctx); +} + int udprelay(const char *server_host, const char *server_port, #ifdef UDPRELAY_LOCAL const char *remote_host, const char *remote_port,