Пример #1
0
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;
}
Пример #2
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);
}
Пример #3
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);
    }
}
Пример #4
0
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;
}
Пример #5
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;
}
Пример #6
0
Файл: util.c Проект: cdlz/xsocks
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;
}
Пример #7
0
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);
}
Пример #8
0
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;
}
Пример #9
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
}
Пример #10
0
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);
}
Пример #11
0
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;
}
Пример #12
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;
}
Пример #13
0
Файл: util.c Проект: lparam/xTun
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;
}
Пример #14
0
Файл: acl.c Проект: 52M/xSocks
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;
}
Пример #15
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;
    }
}
Пример #16
0
Файл: util.c Проект: lparam/xTun
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;
}
Пример #17
0
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;
}
Пример #18
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);
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
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);
}
Пример #22
0
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);
        }
    }
}