Пример #1
0
int main (int argc, char **argv)
{

    int i, c;
    int pid_flags = 0;
    char *user = NULL;
    char *local_port = NULL;
    char *local_addr = NULL;
    char *password = NULL;
    char *timeout = NULL;
    char *method = NULL;
    char *pid_path = NULL;
    char *conf_path = NULL;
    char *iface = NULL;

    int remote_num = 0;
    ss_addr_t remote_addr[MAX_REMOTE_NUM];
    char *remote_port = NULL;

    opterr = 0;

    while ((c = getopt (argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uv")) != -1)
    {
        switch (c)
        {
        case 's':
            remote_addr[remote_num].host = optarg;
            remote_addr[remote_num++].port = NULL;
            break;
        case 'p':
            remote_port = optarg;
            break;
        case 'l':
            local_port = optarg;
            break;
        case 'k':
            password = optarg;
            break;
        case 'f':
            pid_flags = 1;
            pid_path = optarg;
            break;
        case 't':
            timeout = optarg;
            break;
        case 'm':
            method = optarg;
            break;
        case 'c':
            conf_path = optarg;
            break;
        case 'i':
            iface = optarg;
            break;
        case 'b':
            local_addr = optarg;
            break;
        case 'a':
            user = optarg;
            break;
        case 'u':
            udprelay = 1;
            break;
        case 'v':
            verbose = 1;
            break;
        }
    }

    if (opterr)
    {
        usage();
        exit(EXIT_FAILURE);
    }

    if (conf_path != NULL)
    {
        jconf_t *conf = read_jconf(conf_path);
        if (remote_num == 0)
        {
            remote_num = conf->remote_num;
            for (i = 0; i < remote_num; i++)
            {
                remote_addr[i] = conf->remote_addr[i];
            }
        }
        if (remote_port == NULL) remote_port = conf->remote_port;
        if (local_addr == NULL) local_addr = conf->local_addr;
        if (local_port == NULL) local_port = conf->local_port;
        if (password == NULL) password = conf->password;
        if (method == NULL) method = conf->method;
        if (timeout == NULL) timeout = conf->timeout;
    }

    if (remote_num == 0 || remote_port == NULL ||
            local_port == NULL || password == NULL)
    {
        usage();
        exit(EXIT_FAILURE);
    }

    if (timeout == NULL) timeout = "10";

    if (local_addr == NULL) local_addr = "0.0.0.0";

    if (pid_flags)
    {
        USE_SYSLOG(argv[0]);
        demonize(pid_path);
    }

#ifdef __MINGW32__
    winsock_init();
#else
    // ignore SIGPIPE
    signal(SIGPIPE, SIG_IGN);
    signal(SIGABRT, SIG_IGN);
#endif

    // Setup keys
    LOGD("initialize ciphers... %s", method);
    int m = enc_init(password, method);

    // Setup socket
    int listenfd;
    listenfd = create_and_bind(local_addr, local_port);
    if (listenfd < 0)
    {
        FATAL("bind() error..");
    }
    if (listen(listenfd, SOMAXCONN) == -1)
    {
        FATAL("listen() error.");
    }
    setnonblocking(listenfd);
    LOGD("server listening at port %s.", local_port);

    // Setup proxy context
    struct listen_ctx listen_ctx;
    listen_ctx.remote_num = remote_num;
    listen_ctx.remote_addr = malloc(sizeof(ss_addr_t) * remote_num);
    while (remote_num > 0)
    {
        int index = --remote_num;
        if (remote_addr[index].port == NULL) remote_addr[index].port = remote_port;
        listen_ctx.remote_addr[index] = remote_addr[index];
    }
    listen_ctx.timeout = atoi(timeout);
    listen_ctx.fd = listenfd;
    listen_ctx.iface = iface;
    listen_ctx.method = m;

    struct ev_loop *loop = ev_default_loop(0);
    if (!loop)
    {
        FATAL("ev_loop error.");
    }
    ev_io_init (&listen_ctx.io, accept_cb, listenfd, EV_READ);
    ev_io_start (loop, &listen_ctx.io);

    // Setup UDP
    if (udprelay)
    {
        LOGD("udprelay enabled.");
        udprelay_init(local_addr, local_port, remote_addr[0].host, remote_addr[0].port, m, listen_ctx.timeout, iface);
    }

    // setuid
    if (user != NULL)
        run_as(user);

    ev_run (loop, 0);

#ifdef __MINGW32__
    winsock_cleanup();
#endif

    return 0;
}
Пример #2
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;
}
Пример #3
0
int main (int argc, char **argv)
{

    int i, c;
    int pid_flags = 0;
    char *user = NULL;
    char *password = NULL;
    char *timeout = NULL;
    char *method = NULL;
    char *pid_path = NULL;
    char *conf_path = NULL;
    char *iface = NULL;

    int server_num = 0;
    const char *server_host[MAX_REMOTE_NUM];
    const char *server_port = NULL;

    int dns_thread_num = DNS_THREAD_NUM;

    int option_index = 0;
    static struct option long_options[] =
    {
        {"fast-open", no_argument, 0,  0 },
        {"port-start", required_argument, 0, 0 },
        {"port-end", required_argument, 0, 0 },
        {0,           0,           0,  0 }
    };

    opterr = 0;

    while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uv",
                            long_options, &option_index)) != -1)
    {
        printf("option_index %d\n", option_index);
        switch (c)
        {
        case 0:

            if (option_index == 0)
            {
#ifdef TCP_FASTOPEN
                fast_open = 1;
                LOGD("using tcp fast open");
#else
                LOGE("tcp fast open is not supported by this environment");
#endif
            } else
            if (option_index == 1) 
            {
                start_port = atoi(optarg);
            } else
            if (option_index == 2) 
            {
                end_port = atoi(optarg);
            }

            break;
        case 's':
            server_host[server_num++] = optarg;
            break;
        case 'p':
            server_port = optarg;
            break;
        case 'k':
            password = optarg;
            break;
        case 'f':
            pid_flags = 1;
            pid_path = optarg;
            break;
        case 't':
            timeout = optarg;
            break;
        case 'm':
            method = optarg;
            break;
        case 'c':
            conf_path = optarg;
            break;
        case 'i':
            iface = optarg;
            break;
        case 'd':
            dns_thread_num = atoi(optarg);
            if (!dns_thread_num) FATAL("Invalid DNS thread number");
            break;
        case 'a':
            user = optarg;
            break;
        case 'u':
            udprelay = 1;
            break;
        case 'v':
            verbose = 1;
            break;
        }
    }

    printf("start %d end %d\n", start_port, end_port);

    if (opterr)
    {
        usage();
        exit(EXIT_FAILURE);
    }

    if (conf_path != NULL)
    {
        jconf_t *conf = read_jconf(conf_path);
        if (server_num == 0)
        {
            server_num = conf->remote_num;
            for (i = 0; i < server_num; i++)
            {
                server_host[i] = conf->remote_addr[i].host;
            }
        }
        if (server_port == NULL) server_port = conf->remote_port;
        if (password == NULL) password = conf->password;
        if (method == NULL) method = conf->method;
        if (timeout == NULL) timeout = conf->timeout;
#ifdef TCP_FASTOPEN
        if (fast_open == 0) fast_open = conf->fast_open;
#endif
#ifdef HAVE_SETRLIMIT
        if (nofile == 0) nofile = conf->nofile;
        /*
         * no need to check the return value here since we will show
         * the user an error message if setrlimit(2) fails
         */
        if (nofile)
        {
            if (verbose)
            {
                LOGD("setting NOFILE to %d", nofile);
            }
            set_nofile(nofile);
        }
#endif
    }

    if ((start_port > 0 && end_port <= 0) || (start_port <= 0 && end_port > 0)) {
        printf("Both start_prot and end_port needs to be specified\n");
        usage();
        exit(EXIT_FAILURE);
    }

    if (server_port != NULL && start_port > 0) {
        printf("server port can't be set if you want to use a port range\n");
        usage();
        exit(EXIT_FAILURE);
    }

    if (server_num == 0 || (server_port == NULL && start_port <= 0) || password == NULL)
    {
        usage();
        exit(EXIT_FAILURE);
    }

    if (timeout == NULL) timeout = "60";

    if (pid_flags)
    {
        USE_SYSLOG(argv[0]);
        daemonize(pid_path);
    }

    // ignore SIGPIPE
    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);
    signal(SIGABRT, SIG_IGN);

    // setup asyncns
    asyncns_t *asyncns;
    if (!(asyncns = asyncns_new(dns_thread_num)))
    {
        FATAL("asyncns failed");
    }

    // setup keys
    LOGD("initialize ciphers... %s", method);
    int m = enc_init(password, method);

    // inilitialize ev loop
    struct ev_loop *loop = EV_DEFAULT;

    // inilitialize listen context
    struct listen_ctx listen_ctx_list[server_num + 1];

    // bind to each interface
    while (server_num > 0)
    {
        int index = --server_num;
        const char* host = server_host[index];
        int success = 1;
        int listenfd;

        if (start_port > 0) {
            server_port = itoa(start_port);
        }
        do {
            // Bind to port
            
            listenfd = create_and_bind(host, server_port);
            success = 1;
            if (listenfd < 0)
            {
                success = 0;
            }
            if (listen(listenfd, SOMAXCONN) == -1)
            {
                success = 0;
            }
            if (!success) {
                if (start_port < end_port) {
                    start_port++;
                    server_port = itoa(start_port);
                } else
                {
                    FATAL("Out of listen ports!");
                    exit(1);
                }
            }
        } while (!success);
        setnonblocking(listenfd);
        LOGD("server listening at port %s.", server_port);

        struct listen_ctx *listen_ctx = &listen_ctx_list[index + 1];

        // Setup proxy context
        listen_ctx->timeout = atoi(timeout);
        listen_ctx->asyncns = asyncns;
        listen_ctx->fd = listenfd;
        listen_ctx->method = m;
        listen_ctx->iface = iface;

        ev_io_init (&listen_ctx->io, accept_cb, listenfd, EV_READ);
        ev_io_start (loop, &listen_ctx->io);
    }

    // initialize the DNS
    struct listen_ctx *listen_ctx = &listen_ctx_list[0];
    int asyncnsfd = asyncns_fd(asyncns);
    listen_ctx->timeout = atoi(timeout);
    listen_ctx->asyncns = asyncns;
    listen_ctx->fd = asyncnsfd;
    listen_ctx->method = m;
    listen_ctx->iface = iface;
    ev_io_init (&listen_ctx->io, server_resolve_cb, asyncnsfd, EV_READ);
    ev_io_start (loop, &listen_ctx->io);

    // Setup UDP
    if (udprelay)
    {
        LOGD("udprelay enabled.");
        udprelay_init(server_host[0], server_port, dns_thread_num, m, listen_ctx->timeout, iface);
    }

    // setuid
    if (user != NULL)
        run_as(user);

    // start ev loop
    ev_run (loop, 0);
    return 0;
}