#include #include #include #include #include #include #include #include #include #ifndef __MINGW32__ #include #include #include #include #include #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(HAVE_SYS_IOCTL_H) && defined(HAVE_NET_IF_H) && defined(__linux__) #include #include #define SET_INTERFACE #endif #ifdef __MINGW32__ #include "win32.h" #endif #include "utils.h" #include "udprelay.h" #include "cache.h" #ifdef UDPRELAY_REMOTE #ifdef UDPRELAY_LOCAL #error "UDPRELAY_REMOTE and UDPRELAY_LOCAL should not be both defined" #endif #endif #ifndef EAGAIN #define EAGAIN EWOULDBLOCK #endif #ifndef EWOULDBLOCK #define EWOULDBLOCK EAGAIN #endif #define BUF_SIZE MAX_UDP_PACKET_SIZE extern int verbose; #ifndef __MINGW32__ static int setnonblocking(int fd) { int flags; if (-1 ==(flags = fcntl(fd, F_GETFL, 0))) flags = 0; return fcntl(fd, F_SETFL, flags | O_NONBLOCK); } #endif #ifdef SET_INTERFACE static int setinterface(int socket_fd, const char* interface_name) { struct ifreq interface; memset(&interface, 0, sizeof(interface)); strncpy(interface.ifr_name, interface_name, IFNAMSIZ); int res = setsockopt(socket_fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(struct ifreq)); return res; } #endif static char *hash_key(const char *header, const int header_len, const struct sockaddr *addr) { char key[384]; // calculate hash key // assert header_len < 256 memset(key, 0, 384); memcpy(key, addr, sizeof(struct sockaddr)); memcpy(key + sizeof(struct sockaddr), header, header_len); return (char*) enc_md5((const uint8_t *)key, sizeof(struct sockaddr) + header_len, NULL); } static int parse_udprealy_header(const char* buf, const int buf_len, char *host, char *port) { const uint8_t atyp = *(uint8_t*)buf; int offset = 1; // get remote addr and port if (atyp == 1) { // IP V4 size_t in_addr_len = sizeof(struct in_addr); if (buf_len > in_addr_len) { if (host != NULL) { inet_ntop(AF_INET, (const void *)(buf + offset), host, INET_ADDRSTRLEN); } offset += in_addr_len; } } else if (atyp == 3) { // Domain name uint8_t name_len = *(uint8_t *)(buf + offset); if (name_len < buf_len && name_len < 255 && name_len > 0) { if (host != NULL) { memcpy(host, 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 (buf_len > in6_addr_len) { if (host != NULL) { inet_ntop(AF_INET6, (const void*)(buf + offset), host, INET6_ADDRSTRLEN); } offset += in6_addr_len; } } if (offset == 1) { LOGE("invalid header with addr type %d", atyp); return 0; } if (port != NULL) { sprintf(port, "%d", ntohs(*(uint16_t *)(buf + offset))); } offset += 2; return offset; } static char *get_addr_str(const struct sockaddr *sa) { static char s[SS_ADDRSTRLEN]; memset(s, 0, SS_ADDRSTRLEN); char addr[INET6_ADDRSTRLEN] = {0}; char port[PORTSTRLEN] = {0}; uint16_t p; switch(sa->sa_family) { case AF_INET: inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), addr, INET_ADDRSTRLEN); p = ntohs(((struct sockaddr_in *)sa)->sin_port); sprintf(port, "%d", p); break; case AF_INET6: inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr, INET6_ADDRSTRLEN); p = ntohs(((struct sockaddr_in *)sa)->sin_port); sprintf(port, "%d", p); break; default: strncpy(s, "Unknown AF", SS_ADDRSTRLEN); } int addr_len = strlen(addr); int port_len = strlen(port); memcpy(s, addr, addr_len); memcpy(s + addr_len + 1, port, port_len); s[addr_len] = ':'; return s; } int create_remote_socket(int ipv6) { int remote_sock; if (ipv6) { // Try to bind IPv6 first struct sockaddr_in6 addr; memset(&addr, 0, sizeof(struct sockaddr_in6)); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_any; addr.sin6_port = htons(0); remote_sock = socket(AF_INET6, SOCK_DGRAM , 0); if (remote_sock != -1) { if (bind(remote_sock, (struct sockaddr *)&addr, sizeof(addr)) != -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) { ERROR("Cannot create socket."); return -1; } if (bind(remote_sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) { FATAL("Cannot bind remote."); return -1; } return remote_sock; } int create_server_socket(const char *host, const char *port) { struct addrinfo hints; struct addrinfo *result, *rp; int s, server_sock; 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 */ s = getaddrinfo(host, port, &hints, &result); if (s != 0) { LOGE("getaddrinfo: %s", gai_strerror(s)); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { server_sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (server_sock == -1) continue; int opt = 1; setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(server_sock, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif s = bind(server_sock, rp->ai_addr, rp->ai_addrlen); if (s == 0) { /* We managed to bind successfully! */ break; } else { ERROR("bind"); } close(server_sock); } if (rp == NULL) { LOGE("Could not bind"); return -1; } freeaddrinfo(result); return server_sock; } struct remote_ctx *new_remote(int fd, struct server_ctx *server_ctx) { struct remote_ctx *ctx = malloc(sizeof(struct remote_ctx)); memset(ctx, 0, sizeof(struct remote_ctx)); ctx->fd = fd; ctx->server_ctx = server_ctx; ev_io_init(&ctx->io, remote_recv_cb, fd, EV_READ); ev_timer_init(&ctx->watcher, remote_timeout_cb, server_ctx->timeout, server_ctx->timeout * 5); return ctx; } struct server_ctx * new_server_ctx(int fd) { struct server_ctx *ctx = malloc(sizeof(struct server_ctx)); memset(ctx, 0, sizeof(struct server_ctx)); ctx->fd = fd; ev_io_init(&ctx->io, server_recv_cb, fd, EV_READ); return ctx; } #ifdef UDPRELAY_REMOTE struct query_ctx *new_query_ctx(asyncns_query_t *query, const char *buf, const int buf_len) { struct query_ctx *ctx = malloc(sizeof(struct query_ctx)); memset(ctx, 0, sizeof(struct query_ctx)); ctx->buf = malloc(buf_len); ctx->buf_len = buf_len; memcpy(ctx->buf, buf, buf_len); ctx->query = query; return ctx; } void close_and_free_query(EV_P_ struct query_ctx *ctx) { if (ctx != NULL) { if (ctx->buf != NULL) { free(ctx->buf); } free(ctx); } } #endif void close_and_free_remote(EV_P_ struct remote_ctx *ctx) { if (ctx != NULL) { ev_timer_stop(EV_A_ &ctx->watcher); ev_io_stop(EV_A_ &ctx->io); close(ctx->fd); free(ctx); } } static void remote_timeout_cb(EV_P_ ev_timer *watcher, int revents) { struct remote_ctx *remote_ctx = (struct remote_ctx *) (((void*)watcher) - sizeof(ev_io)); if (verbose) { LOGD("UDP connection timeout"); } 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); } #ifdef UDPRELAY_REMOTE static void query_resolve_cb(EV_P_ ev_io *w, int revents) { int err; struct addrinfo *result, *rp; struct resolve_ctx *resolve_ctx = (struct resolve_ctx*)w; asyncns_t *asyncns = resolve_ctx->asyncns; err = asyncns_handle(asyncns); if (err == ASYNCNS_HANDLE_AGAIN) { // try again return; } else if (err == ASYNCNS_HANDLE_ERROR) { // asyncns error FATAL("asyncns exit unexpectedly."); } asyncns_query_t *query = asyncns_getnext(asyncns); struct query_ctx *query_ctx= (struct query_ctx*) asyncns_getuserdata(asyncns, query); if (!asyncns_isdone(asyncns, query)) { // wait reolver return; } if (verbose) { LOGD("[udp] asyncns resolved."); } query_ctx->query = NULL; err = asyncns_getaddrinfo_done(asyncns, query, &result); if (err) { ERROR("getaddrinfo"); } else { // Use IPV4 address if possible for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) break; } if (rp == NULL) { rp = result; } int remotefd = create_remote_socket(rp->ai_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_NOSIGPIPE int opt = 1; setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif #ifdef SET_INTERFACE if (query_ctx->server_ctx->iface) setinterface(remotefd, query_ctx->server_ctx->iface); #endif struct remote_ctx *remote_ctx = new_remote(remotefd, query_ctx->server_ctx); remote_ctx->src_addr = query_ctx->src_addr; remote_ctx->dst_addr = *rp->ai_addr; remote_ctx->server_ctx = query_ctx->server_ctx; remote_ctx->addr_header_len = query_ctx->addr_header_len; memcpy(remote_ctx->addr_header, query_ctx->addr_header, query_ctx->addr_header_len); // Add to conn cache char *key = hash_key(remote_ctx->addr_header, remote_ctx->addr_header_len, &remote_ctx->src_addr); cache_insert(query_ctx->server_ctx->conn_cache, key, (void *)remote_ctx); ev_io_start(EV_A_ &remote_ctx->io); int s = sendto(remote_ctx->fd, query_ctx->buf, query_ctx->buf_len, 0, &remote_ctx->dst_addr, sizeof(remote_ctx->dst_addr)); if (s == -1) { ERROR("udprelay_sendto_remote"); close_and_free_remote(EV_A_ remote_ctx); } } else { ERROR("udprelay bind() error.."); } } // clean up asyncns_freeaddrinfo(result); close_and_free_query(EV_A_ query_ctx); } #endif static void remote_recv_cb (EV_P_ ev_io *w, int revents) { struct remote_ctx *remote_ctx = (struct remote_ctx *)w; struct server_ctx *server_ctx = remote_ctx->server_ctx; // server has been closed if (server_ctx == NULL) { LOGE("invalid server."); close_and_free_remote(EV_A_ remote_ctx); return; } if (verbose) { LOGD("[udp] remote receive a packet"); } // triger the timer ev_timer_again(EV_A_ &remote_ctx->watcher); struct sockaddr src_addr; socklen_t src_addr_len = sizeof(src_addr); char *buf = malloc(BUF_SIZE); // recv ssize_t buf_len = recvfrom(remote_ctx->fd, buf, BUF_SIZE, 0, &src_addr, &src_addr_len); if (buf_len == -1) { // error on recv // simply drop that packet if (verbose) { ERROR("udprelay_server_recvfrom"); } goto CLEAN_UP; } #ifdef UDPRELAY_LOCAL buf = ss_decrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); if (buf == NULL) { if (verbose) { ERROR("udprelay_server_ss_decrypt_all"); } goto CLEAN_UP; } int len = parse_udprealy_header(buf, buf_len, NULL, NULL); if (len == 0) { LOGD("[udp] Error in parse header"); // error in parse header goto CLEAN_UP; } // server may return using a different address type other than the type we // have used during sending #ifdef UDPRELAY_TUNNEL // Construct packet buf_len -= len; memmove(buf, buf + len, buf_len); #else // Construct packet char *tmpbuf = malloc(buf_len + 3); memset(tmpbuf, 0, 3); memcpy(tmpbuf + 3, buf, buf_len); free(buf); buf = tmpbuf; buf_len += 3; #endif #endif #ifdef UDPRELAY_REMOTE unsigned int addr_header_len = remote_ctx->addr_header_len; // Construct packet char *tmpbuf = malloc(buf_len + addr_header_len); memcpy(tmpbuf, remote_ctx->addr_header, addr_header_len); memcpy(tmpbuf + addr_header_len, buf, buf_len); free(buf); buf = tmpbuf; buf_len += addr_header_len; buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); #endif int s = sendto(server_ctx->fd, buf, buf_len, 0, &remote_ctx->src_addr, sizeof(remote_ctx->src_addr)); if (s == -1) { ERROR("udprelay_sendto_local"); } CLEAN_UP: free(buf); } static void server_recv_cb (EV_P_ ev_io *w, int revents) { struct server_ctx *server_ctx = (struct server_ctx *)w; struct sockaddr src_addr; char *buf = malloc(BUF_SIZE); socklen_t src_addr_len = sizeof(src_addr); unsigned int offset = 0; ssize_t buf_len = recvfrom(server_ctx->fd, buf, BUF_SIZE, 0, &src_addr, &src_addr_len); if (buf_len == -1) { // error on recv // simply drop that packet if (verbose) { ERROR("udprelay_server_recvfrom"); } goto CLEAN_UP; } if (verbose) { LOGD("[udp] server receive a packet."); } #ifdef UDPRELAY_REMOTE buf = ss_decrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); if (buf == NULL) { if (verbose) { ERROR("udprelay_server_ss_decrypt_all"); } goto CLEAN_UP; } #endif #ifdef UDPRELAY_LOCAL #ifndef UDPRELAY_TUNNEL uint8_t frag = *(uint8_t*)(buf + 2); offset += 3; #endif #endif /* * * 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_TUNNEL char addr_header[256] = {0}; char* host = server_ctx->tunnel_addr.host; char* port = server_ctx->tunnel_addr.port; int host_len = strlen(host); uint16_t port_num = (uint16_t)atoi(port); uint16_t port_net_num = htons(port_num); int addr_header_len = 2 + host_len + 2; // initialize the addr header addr_header[0] = 3; addr_header[1] = host_len; memcpy(addr_header + 2, host, host_len); memcpy(addr_header + 2 + host_len, &port_net_num, 2); // reconstruct the buffer char *tmp = malloc(buf_len + addr_header_len); memcpy(tmp, addr_header, addr_header_len); memcpy(tmp + addr_header_len, buf, buf_len); free(buf); buf = tmp; buf_len += addr_header_len; #else char host[256] = {0}; char port[64] = {0}; int addr_header_len = parse_udprealy_header(buf + offset, buf_len - offset, host, port); if (addr_header_len == 0) { // error in parse header goto CLEAN_UP; } char *addr_header = buf + offset; #endif char *key = hash_key(addr_header, addr_header_len, &src_addr); struct cache *conn_cache = server_ctx->conn_cache; struct remote_ctx *remote_ctx = NULL; cache_lookup(conn_cache, key, (void*)&remote_ctx); if (remote_ctx != NULL) { if (memcmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr)) || strcmp(addr_header, remote_ctx->addr_header) != 0) { remote_ctx = NULL; } } if (remote_ctx == NULL) { if (verbose) { LOGD("[udp] cache missed: %s:%s <-> %s", host, port, get_addr_str(&src_addr)); } } else { if (verbose) { LOGD("[udp] cache hit: %s:%s <-> %s", host, port, get_addr_str(&src_addr)); } } #ifdef UDPRELAY_LOCAL #ifndef UDPRELAY_TUNNEL if (frag) { LOGE("drop a message since frag is not 0, but %d", frag); goto CLEAN_UP; } #endif if (remote_ctx == NULL) { 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(server_ctx->remote_host, server_ctx->remote_port, &hints, &result); if (s != 0 || result == NULL) { LOGE("getaddrinfo: %s", gai_strerror(s)); goto CLEAN_UP; } // Bind to any port int remotefd = create_remote_socket(result->ai_family == AF_INET6); if (remotefd < 0) { ERROR("udprelay bind() error.."); // remember to free addrinfo freeaddrinfo(result); goto CLEAN_UP; } setnonblocking(remotefd); #ifdef SO_NOSIGPIPE int opt = 1; setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif #ifdef SET_INTERFACE if (server_ctx->iface) setinterface(remotefd, server_ctx->iface); #endif // Init remote_ctx remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->dst_addr = *result->ai_addr; remote_ctx->addr_header_len = addr_header_len; memcpy(remote_ctx->addr_header, addr_header, addr_header_len); // Add to conn cache cache_insert(conn_cache, key, (void *)remote_ctx); // Start remote io ev_io_start(EV_A_ &remote_ctx->io); // clean up freeaddrinfo(result); } if (offset > 0) { buf_len -= offset; memmove(buf, buf + offset, buf_len); } buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method); int s = sendto(remote_ctx->fd, buf, buf_len, 0, &remote_ctx->dst_addr, sizeof(remote_ctx->dst_addr)); if (s == -1) { ERROR("udprelay_sendto_remote"); } #else if (remote_ctx == NULL) { 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_ctx->asyncns, host, port, &hints); if (query == NULL) { ERROR("udp_asyncns_getaddrinfo"); goto CLEAN_UP; } struct query_ctx *query_ctx = new_query_ctx(query, buf + addr_header_len, buf_len - addr_header_len); query_ctx->server_ctx = server_ctx; query_ctx->addr_header_len = addr_header_len; query_ctx->src_addr = src_addr; memcpy(query_ctx->addr_header, addr_header, addr_header_len); asyncns_setuserdata(server_ctx->asyncns, query, query_ctx); } else { int s = sendto(remote_ctx->fd, buf + addr_header_len, buf_len - addr_header_len, 0, &remote_ctx->dst_addr, sizeof(remote_ctx->dst_addr)); if (s == -1) { ERROR("udprelay_sendto_remote"); } } #endif CLEAN_UP: free(buf); } void free_cb(void *element) { struct remote_ctx *remote_ctx = (struct remote_ctx *)element; if (verbose) { LOGD("free a remote ctx"); } close_and_free_remote(EV_DEFAULT, remote_ctx); } int udprelay_init(const char *server_host, const char *server_port, #ifdef UDPRELAY_LOCAL const char *remote_host, const char *remote_port, #ifdef UDPRELAY_TUNNEL const ss_addr_t tunnel_addr, #endif #endif #ifdef UDPRELAY_REMOTE int dns_thread_num, #endif int method, int timeout, const char *iface) { // Inilitialize ev loop struct ev_loop *loop = EV_DEFAULT; // Inilitialize cache struct cache *conn_cache; cache_create(&conn_cache, MAX_UDP_CONN_NUM, free_cb); ////////////////////////////////////////////////// // Setup server context #ifdef UDPRELAY_REMOTE // setup asyncns asyncns_t *asyncns; if (!(asyncns = asyncns_new(dns_thread_num))) { FATAL("asyncns failed"); } struct resolve_ctx *resolve_ctx = malloc(sizeof(struct resolve_ctx)); resolve_ctx->asyncns = asyncns; int asyncnsfd = asyncns_fd(asyncns); ev_io_init (&resolve_ctx->io, query_resolve_cb, asyncnsfd, EV_READ); ev_io_start (loop, &resolve_ctx->io); #endif // Bind to port int serverfd = create_server_socket(server_host, server_port); if (serverfd < 0) { FATAL("udprelay bind() error.."); } setnonblocking(serverfd); struct server_ctx *server_ctx = new_server_ctx(serverfd); server_ctx->timeout = timeout; server_ctx->method = method; server_ctx->iface = iface; server_ctx->conn_cache = conn_cache; #ifdef UDPRELAY_LOCAL server_ctx->remote_host = remote_host; server_ctx->remote_port = remote_port; #ifdef UDPRELAY_TUNNEL server_ctx->tunnel_addr = tunnel_addr; #endif #endif #ifdef UDPRELAY_REMOTE server_ctx->asyncns = asyncns; #endif ev_io_start(loop, &server_ctx->io); return 0; }