struct remote *connect_to_remote(struct addrinfo *res, const char *iface) { int sockfd; int opt = 1; // initilize remote 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 remote *remote = new_remote(sockfd); // setup remote socks setnonblocking(sockfd); #ifdef SET_INTERFACE if (iface) setinterface(sockfd, iface); #endif connect(sockfd, res->ai_addr, res->ai_addrlen); return remote; }
static void accept_cb(EV_P_ ev_io *w, int revents) { struct listen_ctx *listener = (struct listen_ctx *)w; int serverfd = accept(listener->fd, NULL, NULL); if (serverfd == -1) { ERROR("accept"); return; } setnonblocking(serverfd); int opt = 1; setsockopt(serverfd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif int index = rand() % listener->remote_num; struct sockaddr *remote_addr = listener->remote_addr[index]; int remotefd = socket(remote_addr->sa_family, SOCK_STREAM, IPPROTO_TCP); if (remotefd < 0) { ERROR("socket"); return; } #ifdef ANDROID if (vpn) { if (protect_socket(remotefd) == -1) { ERROR("protect_socket"); close(remotefd); return; } } #endif setsockopt(remotefd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif // Setup setnonblocking(remotefd); #ifdef SET_INTERFACE if (listener->iface) { setinterface(remotefd, listener->iface); } #endif struct server *server = new_server(serverfd, listener->method); struct remote *remote = new_remote(remotefd, listener->timeout); server->destaddr = listener->tunnel_addr; server->remote = remote; remote->server = server; connect(remotefd, remote_addr, get_sockaddr_len(remote_addr)); // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); }
static void accept_cb (EV_P_ ev_io *w, int revents) { struct listen_ctx *listener = (struct listen_ctx *)w; int serverfd = accept(listener->fd, NULL, NULL); if (serverfd == -1) { ERROR("accept"); return; } setnonblocking(serverfd); int opt = 1; setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif struct addrinfo hints, *res; int sockfd; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int index = rand() % listener->remote_num; int err = getaddrinfo(listener->remote_host[index], listener->remote_port, &hints, &res); if (err) { ERROR("getaddrinfo"); return; } sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) { ERROR("socket"); close(sockfd); freeaddrinfo(res); return; } setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif // Setup setnonblocking(sockfd); #ifdef SET_INTERFACE if (listener->iface) setinterface(sockfd, listener->iface); #endif struct server *server = new_server(serverfd, listener->method); struct remote *remote = new_remote(sockfd, listener->timeout); server->remote = remote; remote->server = server; connect(sockfd, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); // listen to remote connected event ev_io_start(EV_A_ &remote->send_ctx->io); ev_timer_start(EV_A_ &remote->send_ctx->watcher); }
struct remote *connect_to_remote(struct addrinfo *res, struct server *server) { int sockfd; int opt = 1; const char *iface = server->listen_ctx->iface; // initilize remote 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 remote *remote = new_remote(sockfd); // setup remote socks setnonblocking(sockfd); #ifdef SET_INTERFACE if (iface) setinterface(sockfd, iface); #endif #ifdef TCP_FASTOPEN if (fast_open) { ssize_t s = sendto(sockfd, server->buf + server->buf_idx, server->buf_len, MSG_FASTOPEN, res->ai_addr, res->ai_addrlen); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // The remote server doesn't support tfo or it's the first connection to the server. // It will automatically fall back to conventional TCP. } else if (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT || errno == ENOPROTOOPT) { LOGE("fast open is not supported on this platform"); connect(sockfd, res->ai_addr, res->ai_addrlen); } else { ERROR("sendto"); } } else if (s < server->buf_len) { server->buf_idx += s; server->buf_len -= s; } else { server->buf_idx = 0; server->buf_len = 0; } } else #endif connect(sockfd, res->ai_addr, res->ai_addrlen); return remote; }
static struct remote * connect_to_remote(struct listen_ctx *listener, const char *host, const char *port) { int sockfd; struct addrinfo *remote_res; struct addrinfo hints; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; int index = rand() % listener->remote_num; int err; if (host == NULL || port == NULL) { if (verbose) { LOGD("connect to server: %s:%s", listener->remote_addr[index].host, listener->remote_addr[index].port); } err = getaddrinfo(listener->remote_addr[index].host, listener->remote_addr[index].port, &hints, &remote_res); } else { err = getaddrinfo(host, port, &hints, &remote_res); } if (err) { ERROR("getaddrinfo"); return NULL; } sockfd = socket(remote_res->ai_family, remote_res->ai_socktype, remote_res->ai_protocol); if (sockfd < 0) { ERROR("socket"); freeaddrinfo(remote_res); return NULL; } #ifdef SO_NOSIGPIPE int opt = 1; setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif // Setup setnonblocking(sockfd); #ifdef SET_INTERFACE if (listener->iface) { setinterface(sockfd, listener->iface); } #endif struct remote *remote = new_remote(sockfd, listener->timeout); remote->addr_info = remote_res; return remote; }
static remote_t *create_remote(listen_ctx_t *listener, struct sockaddr *addr) { struct sockaddr *remote_addr; int index = rand() % listener->remote_num; if (addr == NULL) { remote_addr = listener->remote_addr[index]; } else { remote_addr = addr; } int remotefd = socket(remote_addr->sa_family, SOCK_STREAM, IPPROTO_TCP); if (remotefd < 0) { ERROR("socket"); return NULL; } int opt = 1; setsockopt(remotefd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif // Setup setnonblocking(remotefd); #ifdef SET_INTERFACE if (listener->iface) { setinterface(remotefd, listener->iface); } #endif remote_t *remote = new_remote(remotefd, listener->timeout); remote->addr_len = get_sockaddr_len(remote_addr); memcpy(&(remote->addr), remote_addr, remote->addr_len); remote->remote_index = index; return remote; }
static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_ctx = (server_ctx_t *)w; struct sockaddr_storage src_addr; memset(&src_addr, 0, sizeof(struct sockaddr_storage)); buffer_t *buf = ss_malloc(sizeof(buffer_t)); balloc(buf, buf_size); socklen_t src_addr_len = sizeof(struct sockaddr_storage); unsigned int offset = 0; #ifdef MODULE_REDIR char control_buffer[64] = { 0 }; struct msghdr msg; memset(&msg, 0, sizeof(struct msghdr)); struct iovec iov[1]; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); msg.msg_name = &src_addr; msg.msg_namelen = src_addr_len; msg.msg_control = control_buffer; msg.msg_controllen = sizeof(control_buffer); iov[0].iov_base = buf->data; iov[0].iov_len = buf_size; msg.msg_iov = iov; msg.msg_iovlen = 1; buf->len = recvmsg(server_ctx->fd, &msg, 0); if (buf->len == -1) { ERROR("[udp] server_recvmsg"); goto CLEAN_UP; } else if (buf->len > packet_size) { if (verbose) { LOGI("[udp] UDP server_recv_recvmsg fragmentation"); } } if (get_dstaddr(&msg, &dst_addr)) { LOGE("[udp] unable to get dest addr"); goto CLEAN_UP; } src_addr_len = msg.msg_namelen; #else ssize_t r; r = recvfrom(server_ctx->fd, buf->data, buf_size, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (r == -1) { // error on recv // simply drop that packet ERROR("[udp] server_recv_recvfrom"); goto CLEAN_UP; } else if (r > packet_size) { if (verbose) { LOGI("[udp] server_recv_recvfrom fragmentation"); } } buf->len = r; #endif if (verbose) { LOGI("[udp] server receive a packet"); } #ifdef MODULE_REMOTE tx += buf->len; int err = server_ctx->crypto->decrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } #endif #ifdef MODULE_LOCAL #if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) #ifdef __ANDROID__ tx += buf->len; #endif uint8_t frag = *(uint8_t *)(buf->data + 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 MODULE_REDIR char addr_header[512] = { 0 }; int addr_header_len = construct_udprelay_header(&dst_addr, addr_header); if (addr_header_len == 0) { LOGE("[udp] failed to parse tproxy addr"); goto CLEAN_UP; } // reconstruct the buffer brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; #elif MODULE_TUNNEL char addr_header[512] = { 0 }; char *host = server_ctx->tunnel_addr.host; char *port = server_ctx->tunnel_addr.port; uint16_t port_num = (uint16_t)atoi(port); uint16_t port_net_num = htons(port_num); int addr_header_len = 0; struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { if (ip.version == 4) { // send as IPv4 struct in_addr host_addr; memset(&host_addr, 0, sizeof(struct in_addr)); int host_len = sizeof(struct in_addr); if (dns_pton(AF_INET, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 1; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else if (ip.version == 6) { // send as IPv6 struct in6_addr host_addr; memset(&host_addr, 0, sizeof(struct in6_addr)); int host_len = sizeof(struct in6_addr); if (dns_pton(AF_INET6, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 4; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else { FATAL("IP parser error"); } } else { // send as domain int host_len = strlen(host); addr_header[addr_header_len++] = 3; addr_header[addr_header_len++] = host_len; memcpy(addr_header + addr_header_len, host, host_len); addr_header_len += host_len; } memcpy(addr_header + addr_header_len, &port_net_num, 2); addr_header_len += 2; // reconstruct the buffer brealloc(buf, buf->len + addr_header_len, buf_size); memmove(buf->data + addr_header_len, buf->data, buf->len); memcpy(buf->data, addr_header, addr_header_len); buf->len += addr_header_len; #else char host[257] = { 0 }; char port[64] = { 0 }; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); int addr_header_len = parse_udprelay_header(buf->data + offset, buf->len - offset, host, port, &dst_addr); if (addr_header_len == 0) { // error in parse header goto CLEAN_UP; } char *addr_header = buf->data + offset; #endif #ifdef MODULE_LOCAL char *key = hash_key(server_ctx->remote_addr->sa_family, &src_addr); #else char *key = hash_key(dst_addr.ss_family, &src_addr); #endif struct cache *conn_cache = server_ctx->conn_cache; remote_ctx_t *remote_ctx = NULL; cache_lookup(conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); if (remote_ctx != NULL) { if (sockaddr_cmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr))) { remote_ctx = NULL; } } // reset the timer if (remote_ctx != NULL) { ev_timer_again(EV_A_ & remote_ctx->watcher); } if (remote_ctx == NULL) { if (verbose) { #ifdef MODULE_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr)); LOGI("[udp] cache miss: %s <-> %s", dst, src); #else LOGI("[udp] cache miss: %s:%s <-> %s", host, port, get_addr_str((struct sockaddr *)&src_addr)); #endif } } else { if (verbose) { #ifdef MODULE_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr)); LOGI("[udp] cache hit: %s <-> %s", dst, src); #else LOGI("[udp] cache hit: %s:%s <-> %s", host, port, get_addr_str((struct sockaddr *)&src_addr)); #endif } } #ifdef MODULE_LOCAL #if !defined(MODULE_TUNNEL) && !defined(MODULE_REDIR) if (frag) { LOGE("[udp] drop a message since frag is not 0, but %d", frag); goto CLEAN_UP; } #endif const struct sockaddr *remote_addr = server_ctx->remote_addr; const int remote_addr_len = server_ctx->remote_addr_len; if (remote_ctx == NULL) { // Bind to any port int remotefd = create_remote_socket(remote_addr->sa_family == AF_INET6); if (remotefd < 0) { ERROR("[udp] udprelay bind() error"); goto CLEAN_UP; } setnonblocking(remotefd); #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46; setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); #endif #ifdef SET_INTERFACE if (server_ctx->iface) { if (setinterface(remotefd, server_ctx->iface) == -1) ERROR("setinterface"); } #endif #ifdef __ANDROID__ if (vpn) { if (protect_socket(remotefd) == -1) { ERROR("protect_socket"); close(remotefd); goto CLEAN_UP; } } #endif // Init remote_ctx remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->af = remote_addr->sa_family; 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, HASH_KEY_LEN, (void *)remote_ctx); // Start remote io ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } if (offset > 0) { buf->len -= offset; memmove(buf->data, buf->data + offset, buf->len); } int err = server_ctx->crypto->encrypt_all(buf, server_ctx->crypto->cipher, buf_size); if (err) { // drop the packet silently goto CLEAN_UP; } if (buf->len > packet_size) { if (verbose) { LOGI("[udp] server_recv_sendto fragmentation"); } } int s = sendto(remote_ctx->fd, buf->data, buf->len, 0, remote_addr, remote_addr_len); if (s == -1) { ERROR("[udp] server_recv_sendto"); } #else int cache_hit = 0; int need_query = 0; if (buf->len - addr_header_len > packet_size) { if (verbose) { LOGI("[udp] server_recv_sendto fragmentation"); } } if (remote_ctx != NULL) { cache_hit = 1; // detect destination mismatch if (remote_ctx->addr_header_len != addr_header_len || memcmp(addr_header, remote_ctx->addr_header, addr_header_len) != 0) { if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { need_query = 1; } } else { memcpy(&dst_addr, &remote_ctx->dst_addr, sizeof(struct sockaddr_storage)); } } else { if (dst_addr.ss_family == AF_INET || dst_addr.ss_family == AF_INET6) { int remotefd = create_remote_socket(dst_addr.ss_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46; setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); #endif #ifdef SET_INTERFACE if (server_ctx->iface) { if (setinterface(remotefd, server_ctx->iface) == -1) ERROR("setinterface"); } #endif remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->server_ctx = server_ctx; remote_ctx->addr_header_len = addr_header_len; memcpy(remote_ctx->addr_header, addr_header, addr_header_len); memcpy(&remote_ctx->dst_addr, &dst_addr, sizeof(struct sockaddr_storage)); } else { ERROR("[udp] bind() error"); goto CLEAN_UP; } } } if (remote_ctx != NULL && !need_query) { size_t addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); int s = sendto(remote_ctx->fd, buf->data + addr_header_len, buf->len - addr_header_len, 0, (struct sockaddr *)&dst_addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); if (!cache_hit) { close_and_free_remote(EV_A_ remote_ctx); } } else { if (!cache_hit) { // Add to conn cache remote_ctx->af = dst_addr.ss_family; char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr); cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } } } else { struct addrinfo hints; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; struct query_ctx *query_ctx = new_query_ctx(buf->data + 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); if (need_query) { query_ctx->remote_ctx = remote_ctx; } struct ResolvQuery *query = resolv_query(host, query_resolve_cb, NULL, query_ctx, htons(atoi(port))); if (query == NULL) { ERROR("[udp] unable to create DNS query"); close_and_free_query(EV_A_ query_ctx); goto CLEAN_UP; } query_ctx->query = query; } #endif CLEAN_UP: bfree(buf); ss_free(buf); }
static void query_resolve_cb(struct sockaddr *addr, void *data) { struct query_ctx *query_ctx = (struct query_ctx *)data; struct ev_loop *loop = query_ctx->server_ctx->loop; if (verbose) { LOGI("[udp] udns resolved"); } query_ctx->query = NULL; if (addr == NULL) { LOGE("[udp] udns returned an error"); } else { remote_ctx_t *remote_ctx = query_ctx->remote_ctx; int cache_hit = 0; // Lookup in the conn cache if (remote_ctx == NULL) { char *key = hash_key(AF_UNSPEC, &query_ctx->src_addr); cache_lookup(query_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); } if (remote_ctx == NULL) { int remotefd = create_remote_socket(addr->sa_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef IP_TOS // Set QoS flag int tos = 46; setsockopt(remotefd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); #endif #ifdef SET_INTERFACE if (query_ctx->server_ctx->iface) { if (setinterface(remotefd, query_ctx->server_ctx->iface) == -1) ERROR("setinterface"); } #endif remote_ctx = new_remote(remotefd, query_ctx->server_ctx); remote_ctx->src_addr = query_ctx->src_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); } else { ERROR("[udp] bind() error"); } } else { cache_hit = 1; } if (remote_ctx != NULL) { memcpy(&remote_ctx->dst_addr, addr, sizeof(struct sockaddr_storage)); size_t addr_len = get_sockaddr_len(addr); int s = sendto(remote_ctx->fd, query_ctx->buf->data, query_ctx->buf->len, 0, addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); if (!cache_hit) { close_and_free_remote(EV_A_ remote_ctx); } } else { if (!cache_hit) { // Add to conn cache char *key = hash_key(AF_UNSPEC, &remote_ctx->src_addr); cache_insert(query_ctx->server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } } } } // clean up close_and_free_query(EV_A_ query_ctx); }
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 addr_len = sizeof(src_addr); unsigned int offset = 0; ssize_t buf_len = recvfrom(server_ctx->fd, buf, BUF_SIZE, 0, &src_addr, &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); #endif #ifdef UDPRELAY_LOCAL uint8_t frag = *(uint8_t*)(buf + 2); offset += 3; #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 | * +-------+--------------+ * */ 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; 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 (verbose) { LOGD("[udp] cache missed: %s:%s", host, port); } } else { if (verbose) { LOGD("[udp] cache hit: %s:%s", host, port); } } #ifdef UDPRELAY_LOCAL if (frag) { LOGE("drop a message since frag is not 0, but %d", frag); goto CLEAN_UP; } 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); } 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); ev_timer_start(EV_A_ &query_ctx->watcher); } 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); }
static void query_resolve_cb(EV_P_ ev_timer *watcher, int revents) { int err; struct addrinfo *result, *rp; struct query_ctx *query_ctx = (struct query_ctx *)((void*)watcher); asyncns_t *asyncns = query_ctx->server_ctx->asyncns; asyncns_query_t *query = query_ctx->query; if (asyncns == NULL || query == NULL) { LOGE("invalid dns query."); close_and_free_query(EV_A_ query_ctx); return; } if (asyncns_wait(asyncns, 0) == -1) { // asyncns error FATAL("asyncns exit unexpectedly."); } if (!asyncns_isdone(asyncns, query)) { // wait reolver return; } if (verbose) { LOGD("[udp] asyncns resolved."); } ev_timer_stop(EV_A_ watcher); 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); }
static void accept_cb(EV_P_ ev_io *w, int revents) { struct listen_ctx *listener = (struct listen_ctx *)w; int serverfd = accept(listener->fd, NULL, NULL); if (serverfd == -1) { ERROR("accept"); return; } setnonblocking(serverfd); int opt = 1; setsockopt(serverfd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(serverfd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif int index = rand() % listener->remote_num; struct sockaddr *remote_addr = listener->remote_addr[index]; int remotefd = socket(remote_addr->sa_family, SOCK_STREAM, IPPROTO_TCP); if (remotefd == -1) { ERROR("socket"); return; } #ifdef ANDROID if (vpn) { int not_protect = 0; if (remote_addr->sa_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)remote_addr; if (s->sin_addr.s_addr == inet_addr("127.0.0.1")) not_protect = 1; } if (!not_protect) { if (protect_socket(remotefd) == -1) { ERROR("protect_socket"); close(remotefd); return; } } } #endif setsockopt(remotefd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt)); #ifdef SO_NOSIGPIPE setsockopt(remotefd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt)); #endif if (listener->mptcp == 1) { int err = setsockopt(remotefd, SOL_TCP, MPTCP_ENABLED, &opt, sizeof(opt)); if (err == -1) { ERROR("failed to enable multipath TCP"); } } // Setup setnonblocking(remotefd); #ifdef SET_INTERFACE if (listener->iface) { if (setinterface(remotefd, listener->iface) == -1) ERROR("setinterface"); } #endif server_t *server = new_server(serverfd, listener->method); remote_t *remote = new_remote(remotefd, listener->timeout); server->destaddr = listener->tunnel_addr; server->remote = remote; remote->server = server; int r = connect(remotefd, remote_addr, get_sockaddr_len(remote_addr)); if (r == -1 && errno != CONNECT_IN_PROGRESS) { ERROR("connect"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); ev_timer_start(EV_A_ & remote->send_ctx->watcher); }
static void server_recv_cb(EV_P_ ev_io *w, int revents) { struct server_ctx *server_ctx = (struct server_ctx *)w; struct sockaddr_storage src_addr; memset(&src_addr, 0, sizeof(struct sockaddr_storage)); char *buf = malloc(BUF_SIZE); socklen_t src_addr_len = sizeof(struct sockaddr_storage); unsigned int offset = 0; #ifdef UDPRELAY_REDIR char control_buffer[64] = { 0 }; struct msghdr msg; struct iovec iov[1]; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); msg.msg_name = &src_addr; msg.msg_namelen = src_addr_len; msg.msg_control = control_buffer; msg.msg_controllen = sizeof(control_buffer); iov[0].iov_base = buf; iov[0].iov_len = BUF_SIZE; msg.msg_iov = iov; msg.msg_iovlen = 1; ssize_t buf_len = recvmsg(server_ctx->fd, &msg, 0); if (buf_len == -1) { ERROR("[udp] server_recvmsg"); goto CLEAN_UP; } if (get_dstaddr(&msg, &dst_addr)) { LOGE("[udp] unable to get dest addr"); goto CLEAN_UP; } src_addr_len = msg.msg_namelen; #else ssize_t buf_len = recvfrom(server_ctx->fd, buf, BUF_SIZE, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (buf_len == -1) { // error on recv // simply drop that packet ERROR("[udp] server_recvfrom"); goto CLEAN_UP; } #endif if (verbose) { LOGI("[udp] server receive a packet"); } #ifdef UDPRELAY_REMOTE tx += buf_len; buf = ss_decrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method, server_ctx->auth); if (buf == NULL) { ERROR("[udp] server_ss_decrypt_all"); goto CLEAN_UP; } #endif #ifdef UDPRELAY_LOCAL #if !defined(UDPRELAY_TUNNEL) && !defined(UDPRELAY_REDIR) uint8_t frag = *(uint8_t *)(buf + 2); offset += 3; #endif #endif // packet size > default MTU if (verbose && buf_len > MTU) { LOGE("[udp] possible ip fragment, size: %d", (int)buf_len); } /* * * 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 | HMAC-SHA1 | * +------+----------+----------+----------+-------------+ * | 1 | Variable | 2 | Variable | 10 | * +------+----------+----------+----------+-------------+ * * If ATYP & ONETIMEAUTH_FLAG(0x10) == 1, Authentication (HMAC-SHA1) is enabled. * * The key of HMAC-SHA1 is (IV + KEY) and the input is the whole packet. * The output of HMAC-SHA is truncated to 10 bytes (leftmost bits). * * 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_REDIR char addr_header[256] = { 0 }; int addr_header_len = construct_udprealy_header(&dst_addr, addr_header); if (addr_header_len == 0) { LOGE("[udp] failed to parse tproxy addr"); goto CLEAN_UP; } // reconstruct the buffer if (BUF_SIZE < buf_len + addr_header_len) { buf = realloc(buf, buf_len + addr_header_len); } memmove(buf + addr_header_len, buf, buf_len); memcpy(buf, addr_header, addr_header_len); buf_len += addr_header_len; char *key = hash_key(dst_addr.ss_family, &src_addr); #elif UDPRELAY_TUNNEL char addr_header[256] = { 0 }; char *host = server_ctx->tunnel_addr.host; char *port = server_ctx->tunnel_addr.port; uint16_t port_num = (uint16_t)atoi(port); uint16_t port_net_num = htons(port_num); int addr_header_len = 0; struct cork_ip ip; if (cork_ip_init(&ip, host) != -1) { if (ip.version == 4) { // send as IPv4 struct in_addr host_addr; int host_len = sizeof(struct in_addr); if (dns_pton(AF_INET, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 1; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else if (ip.version == 6) { // send as IPv6 struct in6_addr host_addr; int host_len = sizeof(struct in6_addr); if (dns_pton(AF_INET6, host, &host_addr) == -1) { FATAL("IP parser error"); } addr_header[addr_header_len++] = 4; memcpy(addr_header + addr_header_len, &host_addr, host_len); addr_header_len += host_len; } else { FATAL("IP parser error"); } } else { // send as domain int host_len = strlen(host); addr_header[addr_header_len++] = 3; addr_header[addr_header_len++] = host_len; memcpy(addr_header + addr_header_len, host, host_len); addr_header_len += host_len; } memcpy(addr_header + addr_header_len, &port_net_num, 2); addr_header_len += 2; // reconstruct the buffer if (BUF_SIZE < buf_len + addr_header_len) { buf = realloc(buf, buf_len + addr_header_len); } memmove(buf + addr_header_len, buf, buf_len); memcpy(buf, addr_header, addr_header_len); buf_len += addr_header_len; char *key = hash_key(ip.version == 4 ? AF_INET : AF_INET6, &src_addr); #else char host[256] = { 0 }; char port[64] = { 0 }; struct sockaddr_storage dst_addr; memset(&dst_addr, 0, sizeof(struct sockaddr_storage)); int addr_header_len = parse_udprealy_header(buf + offset, buf_len - offset, &server_ctx->auth, host, port, &dst_addr); if (addr_header_len == 0) { // error in parse header goto CLEAN_UP; } char *addr_header = buf + offset; char *key = hash_key(dst_addr.ss_family, &src_addr); #endif struct cache *conn_cache = server_ctx->conn_cache; struct remote_ctx *remote_ctx = NULL; cache_lookup(conn_cache, key, HASH_KEY_LEN, (void *)&remote_ctx); if (remote_ctx != NULL) { if (memcmp(&src_addr, &remote_ctx->src_addr, sizeof(src_addr))) { remote_ctx = NULL; } } // reset the timer if (remote_ctx != NULL) { ev_timer_again(EV_A_ & remote_ctx->watcher); } if (remote_ctx == NULL) { if (verbose) { #ifdef UDPRELAY_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr)); LOGI("[udp] cache miss: %s <-> %s", dst, src); #else LOGI("[udp] cache miss: %s:%s <-> %s", host, port, get_addr_str((struct sockaddr *)&src_addr)); #endif } } else { if (verbose) { #ifdef UDPRELAY_REDIR char src[SS_ADDRSTRLEN]; char dst[SS_ADDRSTRLEN]; strcpy(src, get_addr_str((struct sockaddr *)&src_addr)); strcpy(dst, get_addr_str((struct sockaddr *)&dst_addr)); LOGI("[udp] cache hit: %s <-> %s", dst, src); #else LOGI("[udp] cache hit: %s:%s <-> %s", host, port, get_addr_str((struct sockaddr *)&src_addr)); #endif } } #ifdef UDPRELAY_LOCAL #if !defined(UDPRELAY_TUNNEL) && !defined(UDPRELAY_REDIR) if (frag) { LOGE("[udp] drop a message since frag is not 0, but %d", frag); goto CLEAN_UP; } #endif const struct sockaddr *remote_addr = server_ctx->remote_addr; const int remote_addr_len = server_ctx->remote_addr_len; if (remote_ctx == NULL) { // Bind to any port int remotefd = create_remote_socket(remote_addr->sa_family == AF_INET6); if (remotefd < 0) { ERROR("[udp] udprelay bind() error"); goto CLEAN_UP; } setnonblocking(remotefd); #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef SET_INTERFACE if (server_ctx->iface) { setinterface(remotefd, server_ctx->iface); } #endif #ifdef ANDROID if (vpn) { if (protect_socket(remotefd) == -1) { ERROR("protect_socket"); close(remotefd); goto CLEAN_UP; } } #endif // Init remote_ctx remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->af = remote_addr->sa_family; 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, HASH_KEY_LEN, (void *)remote_ctx); // Start remote io ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } if (offset > 0) { buf_len -= offset; memmove(buf, buf + offset, buf_len); } if (server_ctx->auth) { buf[0] |= ONETIMEAUTH_FLAG; } buf = ss_encrypt_all(BUF_SIZE, buf, &buf_len, server_ctx->method, server_ctx->auth); int s = sendto(remote_ctx->fd, buf, buf_len, 0, remote_addr, remote_addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); } #else int cache_hit = 0; int need_query = 0; if (remote_ctx != NULL) { cache_hit = 1; // detect destination mismatch if (remote_ctx->addr_header_len != addr_header_len || memcmp(addr_header, remote_ctx->addr_header, addr_header_len) != 0) { if (dst_addr.ss_family != AF_INET && dst_addr.ss_family != AF_INET6) { need_query = 1; } } } else { if (dst_addr.ss_family == AF_INET || dst_addr.ss_family == AF_INET6) { int remotefd = create_remote_socket(dst_addr.ss_family == AF_INET6); if (remotefd != -1) { setnonblocking(remotefd); #ifdef SO_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #endif #ifdef SET_INTERFACE if (server_ctx->iface) { setinterface(remotefd, server_ctx->iface); } #endif remote_ctx = new_remote(remotefd, server_ctx); remote_ctx->src_addr = src_addr; remote_ctx->server_ctx = server_ctx; remote_ctx->addr_header_len = addr_header_len; memcpy(remote_ctx->addr_header, addr_header, addr_header_len); } else { ERROR("[udp] bind() error"); goto CLEAN_UP; } } } if (remote_ctx != NULL && !need_query) { size_t addr_len = get_sockaddr_len((struct sockaddr *)&dst_addr); int s = sendto(remote_ctx->fd, buf + addr_header_len, buf_len - addr_header_len, 0, (struct sockaddr *)&dst_addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); if (!cache_hit) { close_and_free_remote(EV_A_ remote_ctx); } } else { if (!cache_hit) { // Add to conn cache remote_ctx->af = dst_addr.ss_family; char *key = hash_key(remote_ctx->af, &remote_ctx->src_addr); cache_insert(server_ctx->conn_cache, key, HASH_KEY_LEN, (void *)remote_ctx); ev_io_start(EV_A_ & remote_ctx->io); ev_timer_start(EV_A_ & remote_ctx->watcher); } } } else { struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; struct query_ctx *query_ctx = new_query_ctx(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); if (need_query) { query_ctx->remote_ctx = remote_ctx; } struct ResolvQuery *query = resolv_query(host, query_resolve_cb, NULL, query_ctx, htons(atoi(port))); if (query == NULL) { ERROR("[udp] unable to create DNS query"); close_and_free_query(EV_A_ query_ctx); goto CLEAN_UP; } query_ctx->query = query; } #endif 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_storage src_addr; char *buf = malloc(BUF_SIZE); socklen_t src_addr_len = sizeof(struct sockaddr_storage); unsigned int offset = 0; ssize_t buf_len = recvfrom(server_ctx->fd, buf, BUF_SIZE, 0, (struct sockaddr *)&src_addr, &src_addr_len); if (buf_len == -1) { // error on recv // simply drop that packet if (verbose) { ERROR("[udp] 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("[udp] 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((struct sockaddr *)&src_addr)); } } else { if (verbose) { LOGD("[udp] cache hit: %s:%s <-> %s", host, port, get_addr_str((struct sockaddr *)&src_addr)); } } #ifdef UDPRELAY_LOCAL #ifndef UDPRELAY_TUNNEL if (frag) { LOGE("[udp] 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("[udp] 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("[udp] udprelay bind() error.."); // remember to free addrinfo freeaddrinfo(result); goto CLEAN_UP; } setnonblocking(remotefd); #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #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 = *((struct sockaddr_storage *)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); size_t addr_len = sizeof(struct sockaddr_in); if (remote_ctx->dst_addr.ss_family == AF_INET6) { addr_len = sizeof(struct sockaddr_in6); } int s = sendto(remote_ctx->fd, buf, buf_len, 0, (struct sockaddr *)&remote_ctx->dst_addr, addr_len); if (s == -1) { ERROR("[udp] 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_DGRAM; 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 { size_t addr_len = sizeof(struct sockaddr_in); if (remote_ctx->dst_addr.ss_family == AF_INET6) { addr_len = sizeof(struct sockaddr_in6); } int s = sendto(remote_ctx->fd, buf + addr_header_len, buf_len - addr_header_len, 0, (struct sockaddr *)&remote_ctx->dst_addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); } } #endif CLEAN_UP: free(buf); }
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("[udp] 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("[udp] asysncns_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_BROADCAST set_broadcast(remotefd); #endif #ifdef SO_NOSIGPIPE set_nosigpipe(remotefd); #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 = *((struct sockaddr_storage *)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); size_t addr_len = sizeof(struct sockaddr_in); if (remote_ctx->dst_addr.ss_family == AF_INET6) { addr_len = sizeof(struct sockaddr_in6); } int s = sendto(remote_ctx->fd, query_ctx->buf, query_ctx->buf_len, 0, (struct sockaddr *)&remote_ctx->dst_addr, addr_len); if (s == -1) { ERROR("[udp] sendto_remote"); close_and_free_remote(EV_A_ remote_ctx); } else { // 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); } } else { ERROR("[udp] bind() error.."); } } // clean up asyncns_freeaddrinfo(result); close_and_free_query(EV_A_ query_ctx); }