int udprelay_start(uv_loop_t *loop, struct server_context *server) { int rc; if (server->dest_addr->sa_family == AF_INET6) { addrlen = IPV6_HEADER_LEN; } uv_udp_init(loop, &server->udp); if ((rc = uv_udp_open(&server->udp, server->udp_fd))) { logger_stderr("udp open error: %s", uv_strerror(rc)); return 1; } rc = uv_udp_bind(&server->udp, server->local_addr, UV_UDP_REUSEADDR); if (rc) { logger_stderr("bind error: %s", uv_strerror(rc)); return 1; } uv_udp_recv_start(&server->udp, client_alloc_cb, client_recv_cb); return 0; }
int already_running(const char *pidfile) { int fd; char buf[16]; fd = open(pidfile, O_RDWR | O_CREAT, LOCKMODE); if (fd < 0) { logger_stderr("open \"%s\" failed (%d: %s)", pidfile, errno, strerror(errno)); exit(1); } if (lockfile(fd) < 0) { if (errno == EACCES || errno == EAGAIN) { close(fd); return(1); } logger_stderr("can't lock %s: %s", pidfile, strerror(errno)); exit(1); } /* * create pid file */ if (ftruncate(fd, 0)) { logger_stderr("can't truncate %s: %s", pidfile, strerror(errno)); exit(1); } sprintf(buf, "%ld\n", (long)getpid()); if (write(fd, buf, strlen(buf)+1) == -1) { logger_stderr("can't write %s: %s", pidfile, strerror(errno)); exit(1); } return(0); }
static void tcp_bind(uv_loop_t *loop, struct server_context *server) { int rc; uv_tcp_init(loop, &server->tcp); rc = uv_tcp_open(&server->tcp, server->tcp_fd); if (rc) { logger_stderr("tcp open error: %s", uv_strerror(rc)); } uv_async_init(loop, &server->async_handle, consumer_close); rc = uv_tcp_bind(&server->tcp, server->local_addr, 0); if (rc || errno) { logger_stderr("bind error: %s", rc ? uv_strerror(rc) : strerror(errno)); exit(1); } rc = uv_listen((uv_stream_t*)&server->tcp, SOMAXCONN, server->accept_cb); if (rc) { logger_stderr("listen error: %s", rc ? uv_strerror(rc) : strerror(errno)); exit(1); } }
int udprelay_start(uv_loop_t *loop, struct server_context *server) { int rc, yes = 1; if (setsockopt(server->udp_fd, SOL_IP, IP_TRANSPARENT, &yes, sizeof(int))) { logger_stderr("setsockopt IP_TRANSPARENT error: %s", strerror(errno)); } if (setsockopt(server->udp_fd, IPPROTO_IP, IP_RECVORIGDSTADDR, &yes, sizeof(int))) { logger_stderr("setsockopt IP_RECVORIGDSTADDR error: %s", strerror(errno)); } uv_udp_init(loop, &server->udp); if ((rc = uv_udp_open(&server->udp, server->udp_fd))) { logger_stderr("udp open error: %s", uv_strerror(rc)); return 1; } if ((rc = uv_udp_bind(&server->udp, server->local_addr, UV_UDP_REUSEADDR))) { logger_stderr("udp bind error: %s", uv_strerror(rc)); return 1; } uv_poll_init_socket(loop, &server->watcher, server->udp_fd); uv_poll_start(&server->watcher, UV_READABLE, poll_cb); return 0; }
int tcp_server_start(struct tundev_context *ctx, uv_loop_t *loop) { int rc; uv_tcp_init(loop, &ctx->inet_tcp.tcp); ctx->inet_tcp_fd = create_socket(SOCK_STREAM, 1); if ((rc = uv_tcp_open(&ctx->inet_tcp.tcp, ctx->inet_tcp_fd))) { logger_stderr("tcp open error: %s", uv_strerror(rc)); exit(1); } uv_tcp_bind(&ctx->inet_tcp.tcp, &ctx->tun->addr, 0); if (rc) { logger_stderr("tcp bind error: %s", uv_strerror(rc)); exit(1); } ctx->inet_tcp.tcp.data = ctx; rc = uv_listen(&ctx->inet_tcp.stream, 128, accept_cb); if (rc) { logger_stderr("tcp listen error: %s", uv_strerror(rc)); exit(1); } return rc; }
uv_os_sock_t create_socket(int type, int reuse) { uv_os_sock_t sock; sock = socket(AF_INET, type, IPPROTO_IP); if (sock < 0) { logger_stderr("socket error: %s", strerror(errno)); return -1; } if (reuse) { int yes = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) { logger_stderr("setsockopt SO_REUSEPORT error: %s", strerror(errno)); } } return sock; }
int udp_start(struct tundev_context *ctx, uv_loop_t *loop) { int rc; ctx->network_buffer = malloc(ctx->tun->mtu + PRIMITIVE_BYTES); uv_udp_init(loop, &ctx->inet_udp); ctx->inet_udp_fd = create_socket(SOCK_DGRAM, mode == xTUN_SERVER ? 1 : 0); if ((rc = uv_udp_open(&ctx->inet_udp, ctx->inet_udp_fd))) { logger_log(LOG_ERR, "udp open error: %s", uv_strerror(rc)); exit(1); } #ifdef ANDROID rc = protect_socket(ctx->inet_udp_fd); logger_log(rc ? LOG_INFO : LOG_ERR, "Protect socket %s", rc ? "successful" : "failed"); #endif if (mode == xTUN_SERVER) { rc = uv_udp_bind(&ctx->inet_udp, &ctx->tun->addr, UV_UDP_REUSEADDR); if (rc) { logger_stderr("udp bind error: %s", uv_strerror(rc)); exit(1); } } return uv_udp_recv_start(&ctx->inet_udp, inet_alloc_cb, inet_recv_cb); }
int daemonize(void) { int fd; pid_t pid; switch (pid = fork()) { case -1: fprintf(stderr, "fork() failed.\n"); return -1; case 0: break; default: exit(0); } setsid(); if ((fd = open("/dev/null", O_RDWR, 0)) == -1) { logger_stderr("open [/dev/null] failed (%d: %s)", errno, strerror(errno)); return -1; } else { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); /* dup2(fd, STDERR_FILENO); */ } return 0; }
static void init(void) { #ifdef ANDROID logger_init(0); #else logger_init(daemon_mode); #endif setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); #if !defined(_WIN32) signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); signal(SIGABRT, SIG_IGN); #endif if (crypto_init(password)) { logger_stderr("crypto init failed"); exit(1); } if (idle_timeout == 0) { idle_timeout = 60; } #if !defined(_WIN32) if (acl_file != NULL) { acl = !acl_init(acl_file); } #endif }
static void close_tunfd(int fd) { /* valgrind may generate a false alarm here */ if(ioctl(fd, TUNSETPERSIST, 0) < 0) { logger_stderr("ioctl(TUNSETPERSIST): %s", strerror(errno)); } close(fd); }
int tun_config(struct tundev *tun, const char *ifconf, int fd, int mtu, int prot, int global, int v, const char *server, int port, const char *dns) { struct sockaddr addr; struct tundev_context *ctx = tun->contexts; if (resolve_addr(server, port, &addr)) { logger_stderr("Invalid server address"); return 1; } char *cidr = strchr(ifconf, '/'); if(!cidr) { logger_stderr("ifconf syntax error: %s", ifconf); exit(0); } uint8_t ipaddr[16] = {0}; memcpy(ipaddr, ifconf, (uint32_t) (cidr - ifconf)); in_addr_t netmask = 0xffffffff; netmask = netmask << (32 - atoi(++cidr)); tun->netmask = netmask; tun->network = inet_addr((const char *) ipaddr) & htonl(netmask); verbose = v; protocol = prot; struct sockaddr_in dns_server; uv_ip4_addr(dns, DNS_PORT, &dns_server); tun->dns_server = *((struct sockaddr *) &dns_server); tun->mtu = mtu; tun->addr = addr; tun->global = global; ctx->tunfd = fd; uv_async_init(uv_default_loop(), &ctx->async_handle, tun_close); uv_unref((uv_handle_t *) &ctx->async_handle); return 0; }
struct tundev * tun_alloc(char *iface, uint32_t parallel) { int i, err, fd, nqueues; struct tundev *tun; nqueues = 1; size_t ctxsz = sizeof(struct tundev_context) * nqueues; tun = malloc(sizeof(*tun) + ctxsz); memset(tun, 0, sizeof(*tun) + ctxsz); tun->queues = nqueues; strcpy(tun->iface, iface); struct ifreq ifr; memset(&ifr, 0, sizeof ifr); ifr.ifr_flags = IFF_TUN | IFF_NO_PI | IFF_MULTI_QUEUE; strncpy(ifr.ifr_name, tun->iface, IFNAMSIZ); for (i = 0; i < nqueues; i++) { if ((fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0 ) { logger_stderr("Open /dev/net/tun: %s", strerror(errno)); goto err; } err = ioctl(fd, TUNSETIFF, (void *)&ifr); if (err) { logger_stderr("Cannot allocate TUN: %s", strerror(errno)); close(fd); goto err; } struct tundev_context *ctx = &tun->contexts[i]; ctx->tun = tun; ctx->tunfd = fd; } return tun; err: for (--i; i >= 0; i--) { struct tundev_context *ctx = &tun->contexts[i]; close(ctx->tunfd); } free(tun); return NULL; }
int create_socket(int type, int reuse) { int sock; sock = socket(AF_INET, type, IPPROTO_IP); if (sock < 0) { logger_stderr("socket error: %s", strerror(errno)); return -1; } if (reuse) { int yes = 1; #ifdef SO_REUSEPORT if (setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes))) { logger_stderr("setsockopt SO_REUSEPORT error: %s", strerror(errno)); } #else if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))) { logger_stderr("setsockopt SO_REUSEADDR error: %s", strerror(errno)); } #endif } return sock; }
int acl_init(const char *path) { // initialize ipset ipset_init_library(); ipset_init(&acl_ipv4_set); ipset_init(&acl_ipv6_set); FILE *f = fopen(path, "r"); if (f == NULL) { logger_stderr("Invalid acl path"); return -1; } char line[256]; while (!feof(f)) { if (fgets(line, 256, f)) { // Trim the newline int len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; } char host[256]; int cidr; parse_addr_cidr(line, host, &cidr); struct cork_ip addr; int err = cork_ip_init(&addr, host); if (!err) { if (addr.version == 4) { if (cidr >= 0) { ipset_ipv4_add_network(&acl_ipv4_set, &(addr.ip.v4), cidr); } else { ipset_ipv4_add(&acl_ipv4_set, &(addr.ip.v4)); } } else if (addr.version == 6) { if (cidr >= 0) { ipset_ipv6_add_network(&acl_ipv6_set, &(addr.ip.v6), cidr); } else { ipset_ipv6_add(&acl_ipv6_set, &(addr.ip.v6)); } } } } } fclose(f); return 0; }
static void init(void) { logger_init(daemon_mode); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); signal(SIGPIPE, SIG_IGN); if (crypto_init(password)) { logger_stderr("crypto init failed"); exit(1); } if (idle_timeout == 0) { idle_timeout = 60; } }
int resolve_addr(const char *buf, int port, struct sockaddr *addr) { int rc = 0; struct sockaddr_in addr4; struct sockaddr_in6 addr6; if ((port <= 0) || (port >= 65536)) { logger_log(LOG_ERR, "Invalid port number: %d", port); rc = 1; goto err; } /* If the IP address contains ':', it's IPv6; otherwise, IPv4 or domain. */ if (strchr(buf, ':') == NULL) { rc = uv_ip4_addr(buf, port, &addr4); if (rc) { struct addrinfo hints; struct addrinfo *result, *rp; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; rc = 0; char service[6] = {0}; snprintf(service, 6, "%d", port); int err = getaddrinfo(buf, service, &hints, &result); if (err != 0) { logger_stderr("Resolve %s error: %s", buf, gai_strerror(err)); rc = 1; goto err; } /* IPV4 priority */ for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) { memcpy(addr, rp->ai_addr, sizeof(struct sockaddr_in)); break; } } if (rp == NULL) { for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET6) { memcpy(addr, rp->ai_addr, sizeof(struct sockaddr_in6)); break; } } } if (rp == NULL) { logger_stderr("resolve address failed: %s", buf); rc = 1; } freeaddrinfo(result); goto err; } else { *addr = *((struct sockaddr *) &addr4); } } else { uv_ip6_addr(buf, port, &addr6); *addr = *((struct sockaddr *) &addr6); } err: return rc; }
int main(int argc, char *argv[]) { int rc; uv_loop_t *loop; parse_opts(argc, argv); #if !defined(_WIN32) if (xsignal) { return signal_process(xsignal, pidfile); } #endif if (!password || !server_addr_buf) { print_usage(argv[0]); return 1; } init(); #if !defined(_WIN32) if (daemon_mode) { if (daemonize()) { return 1; } if (already_running(pidfile)) { logger_stderr("xsocks already running."); return 1; } } #endif loop = uv_default_loop(); rc = resolve_addr(local_addr, &bind_addr); if (rc) { logger_stderr("invalid local address"); return 1; } rc = resolve_addr(server_addr_buf, &server_addr); if (rc) { logger_stderr("invalid server address"); return 1; } udprelay_init(); if (concurrency <= 1) { struct server_context ctx; ctx.udprelay = 1; ctx.udp_fd = create_socket(SOCK_DGRAM, 0); ctx.local_addr = &bind_addr; ctx.server_addr = &server_addr; uv_tcp_init(loop, &ctx.tcp); rc = uv_tcp_bind(&ctx.tcp, &bind_addr, 0); if (rc) { logger_stderr("bind error: %s", uv_strerror(rc)); return 1; } rc = uv_listen((uv_stream_t*)&ctx.tcp, 128, client_accept_cb); if (rc == 0) { logger_log(LOG_INFO, "listening on %s", local_addr); #if !defined(_WIN32) setup_signal(loop, signal_cb, &ctx); #endif udprelay_start(loop, &ctx); uv_run(loop, UV_RUN_DEFAULT); close_loop(loop); } else { logger_stderr("listen error: %s", uv_strerror(rc)); } } else { #if !defined(_WIN32) struct server_context *servers = calloc(concurrency, sizeof(servers[0])); for (int i = 0; i < concurrency; i++) { struct server_context *ctx = servers + i; ctx->index = i; ctx->tcp_fd = create_socket(SOCK_STREAM, 1); ctx->udp_fd = create_socket(SOCK_DGRAM, 1); ctx->udprelay = 1; ctx->accept_cb = client_accept_cb; ctx->local_addr = &bind_addr; ctx->server_addr = &server_addr; rc = uv_sem_init(&ctx->semaphore, 0); rc = uv_thread_create(&ctx->thread_id, consumer_start, ctx); } logger_log(LOG_INFO, "listening on %s", local_addr); setup_signal(loop, signal_cb, servers); uv_run(loop, UV_RUN_DEFAULT); close_loop(loop); for (int i = 0; i < concurrency; i++) { uv_sem_wait(&servers[i].semaphore); } free(servers); #else logger_stderr("don't support multithreading."); return 1; #endif } udprelay_destroy(); #if !defined(_WIN32) if (daemon_mode) { delete_pidfile(pidfile); } #endif logger_exit(); return 0; }
void tun_config(struct tundev *tun, const char *ifconf, int mtu, struct sockaddr *addr) { tun->mtu = mtu; strcpy(tun->ifconf, ifconf); tun->addr = *addr; char *cidr = strchr(ifconf, '/'); if(!cidr) { logger_stderr("ifconf syntax error: %s", ifconf); exit(0); } uint8_t ipaddr[16] = {0}; memcpy(ipaddr, ifconf, (uint32_t) (cidr - ifconf)); in_addr_t netmask = 0xffffffff; netmask = netmask << (32 - atoi(++cidr)); tun->netmask = netmask; tun->network = inet_addr((const char *) ipaddr) & htonl(netmask); int inet4 = socket(AF_INET, SOCK_DGRAM, 0); if (inet4 < 0) { logger_stderr("Can't create tun device (udp socket): %s", strerror(errno)); exit(1); } struct ifreq ifr; memset(&ifr, 0, sizeof ifr); strncpy(ifr.ifr_name, tun->iface, IFNAMSIZ); struct sockaddr_in *saddr; saddr = (struct sockaddr_in *) &ifr.ifr_addr; saddr->sin_family = AF_INET; saddr->sin_addr.s_addr = inet_addr((const char *) ipaddr); if(saddr->sin_addr.s_addr == INADDR_NONE) { logger_stderr("Invalid IP address: %s", ifconf); exit(1); } if(ioctl(inet4, SIOCSIFADDR, (void *) &ifr) < 0) { logger_stderr("ioctl(SIOCSIFADDR): %s", strerror(errno)); exit(1); } saddr = (struct sockaddr_in *)&ifr.ifr_netmask; saddr->sin_family = AF_INET; saddr->sin_addr.s_addr = htonl(netmask); if(ioctl(inet4, SIOCSIFNETMASK, (void *) &ifr) < 0) { logger_stderr("ioctl(SIOCSIFNETMASK): %s", strerror(errno)); exit(1); } /* Activate interface. */ ifr.ifr_flags |= IFF_UP | IFF_RUNNING; if(ioctl(inet4, SIOCSIFFLAGS, (void *) &ifr) < 0) { logger_stderr("ioctl(SIOCSIFFLAGS): %s", strerror(errno)); exit(1); } /* Set MTU if it is specified. */ ifr.ifr_mtu = mtu; if(ioctl(inet4, SIOCSIFMTU, (void *) &ifr) < 0) { logger_stderr("ioctl(SIOCSIFMTU): %s", strerror(errno)); exit(1); } close(inet4); }
int resolve_addr(const char *buf, struct sockaddr *addr) { char *p; char *tmp = strdup(buf); int rc = 0; long port; struct sockaddr_in addr4; struct sockaddr_in6 addr6; if ((p = strrchr(tmp, ':')) == NULL) { logger_log(LOG_ERR, "Address must contain port number: %s", tmp); rc = 1; goto err; } *p++ = '\0'; port = strtol(p, NULL, 10); if ((port <= 0) || (port >= 65536)) { logger_log(LOG_ERR, "Invalid port number: %s", p); rc = 1; goto err; } /* If the IP address contains ':', it's IPv6; otherwise, IPv4 or domain. */ if (strchr(tmp, ':') == NULL) { rc = uv_ip4_addr(tmp, port, &addr4); if (rc) { struct addrinfo hints; struct addrinfo *result, *rp; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; rc = 0; int err = getaddrinfo(tmp, p, &hints, &result); if (err != 0) { logger_stderr("Resolve %s error: %s", tmp, gai_strerror(err)); rc = 1; goto err; } // IPV4 priority for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) { memcpy(addr, rp->ai_addr, sizeof(struct sockaddr_in)); break; } } if (rp == NULL) { for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET6) { memcpy(addr, rp->ai_addr, sizeof(struct sockaddr_in6)); break; } } } if (rp == NULL) { logger_stderr("Failed to resolve address: %s", tmp); rc = 1; } freeaddrinfo(result); goto err; } else { *addr = *(struct sockaddr*)&addr4; } } else { uv_ip6_addr(tmp, port, &addr6); *addr = *(struct sockaddr*)&addr6; } err: free(tmp); return rc; }
int main(int argc, char *argv[]) { int rc; uv_loop_t *loop; struct sockaddr bind_addr; parse_opts(argc, argv); if (xsignal) { return signal_process(xsignal, pidfile); } if (!tunnel_mode || !dest_addr || !password) { print_usage(argv[0]); return 1; } if (init()) { return 1; } if (daemon_mode) { if (daemonize()) { return 1; } if (already_running(pidfile)) { logger_stderr("xtunnel already running."); return 1; } } loop = uv_default_loop(); rc = resolve_addr(source_addr, &bind_addr); if (rc) { logger_stderr("invalid local address"); return 1; } rc = resolve_addr(dest_addr, &target_addr); if (rc) { logger_stderr("invalid target address"); return 1; } if (concurrency <= 1) { struct server_context ctx; uv_tcp_init(loop, &ctx.tcp); rc = uv_tcp_bind(&ctx.tcp, &bind_addr, 0); if (rc) { logger_stderr("bind error: %s", uv_strerror(rc)); return 1; } rc = uv_listen((uv_stream_t*)&ctx.tcp, SOMAXCONN, source_accept_cb); if (rc == 0) { logger_log(LOG_INFO, "listening on %s", source_addr); setup_signal(loop, signal_cb, &ctx); uv_run(loop, UV_RUN_DEFAULT); close_loop(loop); } else { logger_stderr("listen error: %s", uv_strerror(rc)); } } else { struct server_context *servers = calloc(concurrency, sizeof(servers[0])); for (int i = 0; i < concurrency; i++) { struct server_context *ctx = servers + i; ctx->index = i; ctx->tcp_fd = create_socket(SOCK_STREAM, 1); ctx->accept_cb = source_accept_cb; ctx->nameserver_num = -1; ctx->local_addr = &bind_addr; rc = uv_sem_init(&ctx->semaphore, 0); rc = uv_thread_create(&ctx->thread_id, consumer_start, ctx); } logger_log(LOG_INFO, "listening on %s", source_addr); setup_signal(loop, signal_cb, servers); uv_run(loop, UV_RUN_DEFAULT); close_loop(loop); for (int i = 0; i < concurrency; i++) { uv_sem_wait(&servers[i].semaphore); } free(servers); } if (daemon_mode) { delete_pidfile(pidfile); } return 0; }
static void server_recv_cb(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf, const struct sockaddr *addr, unsigned flags) { if (nread > 0) { struct client_context *client = handle->data; reset_timer(client); int mlen = nread - PRIMITIVE_BYTES; uint8_t *m = (uint8_t *)buf->base; int rc = crypto_decrypt(m, (uint8_t *)buf->base, nread); if (rc) { logger_log(LOG_ERR, "invalid udp packet"); goto err; } /* * * xsocks UDP Response * +------+----------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | DATA | * +------+----------+----------+----------+ * | 1 | Variable | 2 | Variable | * +------+----------+----------+----------+ * */ union { struct sockaddr addr; struct sockaddr_in addr4; struct sockaddr_in6 addr6; } dest_addr; if (m[0] == ATYP_IPV4) { dest_addr.addr4.sin_family = AF_INET; memcpy(&dest_addr.addr4.sin_addr, m + 1, 4); memcpy(&dest_addr.addr4.sin_port, m + 5, 2); } else { dest_addr.addr6.sin6_family = AF_INET6; memcpy(&dest_addr.addr6.sin6_addr, m + 1, 16); memcpy(&dest_addr.addr6.sin6_port, m + 17, 2); } int addrlen = m[0] == ATYP_IPV4 ? IPV4_HEADER_LEN : IPV6_HEADER_LEN; memmove(m, m + addrlen, mlen - addrlen); mlen -= addrlen; if (!client->bind_server) { uv_os_sock_t sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); if (sock < 0) { logger_stderr("socket error: %s\n", strerror(errno)); } int yes = 1; if (setsockopt(sock, SOL_IP, IP_TRANSPARENT, &yes, sizeof(int))) { logger_stderr("setsockop IP_TRANSPARENT error: %s)", strerror(errno)); } client->dest_handle = malloc(sizeof(uv_udp_t)); uv_udp_init(handle->loop, client->dest_handle); rc = uv_udp_open(client->dest_handle, sock); if (rc) { logger_stderr("udp open error: %s", uv_strerror(rc)); } rc = uv_udp_bind(client->dest_handle, &dest_addr.addr, UV_UDP_REUSEADDR); if (rc) { logger_stderr("udp server bind error: %s", uv_strerror(rc)); } client->bind_server = 1; } forward_to_client(client, m , mlen); } else { goto err; } return; err: free(buf->base); }
static void poll_cb(uv_poll_t *watcher, int status, int events) { char buffer[1024] = {0}; char control_buffer[64] = {0}; struct iovec iov[1]; struct msghdr msg; struct sockaddr client_addr; struct server_context *server = container_of(watcher, struct server_context, watcher); if (status >= 0) { msg.msg_name = &client_addr; msg.msg_namelen = sizeof(client_addr); msg.msg_control = control_buffer; msg.msg_controllen = sizeof(control_buffer); iov[0].iov_base = buffer; iov[0].iov_len = sizeof(buffer); msg.msg_iov = iov; msg.msg_iovlen = 1; int msglen = recvmsg(watcher->io_watcher.fd, &msg, 0); if (msglen <= 0) { logger_stderr("receive from client error: %s", strerror(errno)); } struct sockaddr dest_addr; if (getdestaddr(&msg, &dest_addr)) { logger_stderr("can not get destination address"); } int addrlen = dest_addr.sa_family == AF_INET ? IPV4_HEADER_LEN : IPV6_HEADER_LEN; int mlen = addrlen + msglen; int clen = PRIMITIVE_BYTES + mlen; uint8_t *c = malloc(clen); uint8_t *m = c + PRIMITIVE_BYTES; /* * * xsocks UDP Request * +------+----------+----------+----------+ * | ATYP | DST.ADDR | DST.PORT | DATA | * +------+----------+----------+----------+ * | 1 | Variable | 2 | Variable | * +------+----------+----------+----------+ * */ if (dest_addr.sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)&dest_addr; m[0] = ATYP_IPV4; memcpy(m + 1, &addr->sin_addr, 4); memcpy(m + 1 + 4, &addr->sin_port, 2); } else { struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&dest_addr; m[0] = ATYP_IPV6; memcpy(m + 1, &addr->sin6_addr, 16); memcpy(m + 1 + 16, &addr->sin6_port, 2); } memcpy(m + addrlen, buffer, msglen); int rc = crypto_encrypt(c, m, mlen); if (!rc) { char key[KEY_BYTES + 1] = {0}; crypto_generickey((uint8_t *)key, sizeof(key) -1, (uint8_t *)&client_addr, sizeof(client_addr), NULL, 0); struct client_context *client = NULL; uv_mutex_lock(&mutex); cache_lookup(cache, key, (void *)&client); uv_mutex_unlock(&mutex); if (client == NULL) { client = new_client(); client->addr = client_addr; memcpy(client->key, key, sizeof(key)); uv_timer_init(watcher->loop, client->timer); uv_udp_init(watcher->loop, &client->server_handle); client->server_handle.data = client; uv_udp_recv_start(&client->server_handle, server_alloc_cb, server_recv_cb); uv_mutex_lock(&mutex); cache_insert(cache, client->key, (void *)client); uv_mutex_unlock(&mutex); } reset_timer(client); forward_to_server(server->server_addr, client, c, clen); } } }