Ejemplo n.º 1
0
static void socks5_recv_cb(EV_P_ ev_io *w, int revents)
{
	ctx_t *ctx = (ctx_t *)(w->data);

	UNUSED(revents);
	assert(ctx != NULL);

	ev_io_stop(EV_A_ w);

	bzero(ctx->buf, BUF_SIZE);
	ssize_t n = recv(ctx->sock, ctx->buf, BUF_SIZE, 0);
	if (n <= 0)
	{
		if (n < 0)
		{
			LOG("client reset");
		}
		close(ctx->sock);
		free(ctx);
		return;
	}

	switch (ctx->state)
	{
	case CLOSED:
	{
		// SOCKS5 HELLO
		// +-----+----------+----------+
		// | VER | NMETHODS | METHODS  |
		// +-----+----------+----------+
		// |  1  |    1     | 1 to 255 |
		// +-----+----------+----------+
		int error = 0;
		if (ctx->buf[0] != 0x05)
		{
			error = 1;
		}
		uint8_t nmethods = ctx->buf[1];
		uint8_t i;
		for (i = 0; i < nmethods; i++)
		{
			if (ctx->buf[2 + i] == 0x00)
			{
				break;
			}
		}
		if (i >= nmethods)
		{
			error = 2;
		}
		// SOCKS5 HELLO
		// +-----+--------+
		// | VER | METHOD |
		// +-----+--------+
		// |  1  |   1    |
		// +-----+--------+
		ctx->buf[0] = 0x05;
		ctx->buf[1] = 0x00;
		ctx->len = 2;
		ctx->state = HELLO_RCVD;
		if (error != 0)
		{
			ctx->state = HELLO_ERR;
			ctx->buf[1] = 0xff;
		}
		ev_io_start(EV_A_ &(ctx->w_write));
		break;
	}
	case HELLO_SENT:
	{
		// SOCKS5 REQUEST
		// +-----+-----+-------+------+----------+----------+
		// | VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
		// +-----+-----+-------+------+----------+----------+
		// |  1  |  1  | X'00' |  1   | Variable |    2     |
		// +-----+-----+-------+------+----------+----------+
		int error = 0;
		if (ctx->buf[0] != 0x05)
		{
			error = 1;
		}
		if (ctx->buf[1] != 0x01)
		{
			// 只支持 CONNECT 命令
			error = 2;
		}
		if (ctx->buf[3] == 0x01)
		{
			// IPv4 地址
			inet_ntop(AF_INET, (const void *)(ctx->buf + 4), ctx->host,
			          INET_ADDRSTRLEN);
			sprintf(ctx->port, "%u", ntohs(*(uint16_t *)(ctx->buf + 8)));
		}
		else if (ctx->buf[3] == 0x03)
		{
			// 域名
			memcpy(ctx->host, ctx->buf + 5, ctx->buf[4]);
			ctx->host[ctx->buf[4]] = '\0';
			sprintf(ctx->port, "%u",
			        ntohs(*(uint16_t *)(ctx->buf + ctx->buf[4] + 5)));
		}
		else if (ctx->buf[3] == 0x04)
		{
			// IPv6 地址
			inet_ntop(AF_INET6, (const void *)(ctx->buf + 4), ctx->host,
			          INET6_ADDRSTRLEN);
			sprintf(ctx->port, "%u", ntohs(*(uint16_t *)(ctx->buf + 20)));
		}
		else
		{
			// 不支持的地址类型
			error = 3;
		}

		// SOCKS5 REPLY
		// +-----+-----+-------+------+----------+----------+
		// | VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
		// +-----+-----+-------+------+----------+----------+
		// |  1  |  1  | X'00' |  1   | Variable |    2     |
		// +-----+-----+-------+------+----------+----------+
		bzero(ctx->buf, 10);
		ctx->buf[0] = 0x05;
		if (error == 0)
		{
			ctx->buf[1] = 0x00;
		}
		else if (error == 1)
		{
			ctx->buf[1] = 0x01;
		}
		else if (error == 2)
		{
			ctx->buf[1] = 0x07;
		}
		else
		{
			ctx->buf[1] = 0x08;
		}
		ctx->buf[2] = 0x00;
		ctx->buf[3] = 0x01;
		ctx->len = 10;
		ctx->state = REQ_RCVD;
		if (error != 0)
		{
			ctx->state = REQ_ERR;
		}
		ev_io_start(EV_A_ &ctx->w_write);
		break;
	}
	default:
	{
		// 不应该来到这里
		assert(0 != 0);
		break;
	}
	}
}
Ejemplo n.º 2
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;

    char * nameservers[MAX_DNS_NUM + 1];
    int nameserver_num = 0;

    int option_index = 0;
    static struct option long_options[] =
    {
        { "fast-open",    no_argument,       0, 0 },
        { "acl",          required_argument, 0, 0 },
#ifdef USE_CRYPTO_OPENSSL
        { "bitcoin-list", required_argument, 0, 0 },
#endif
        { 0,              0,                 0, 0 }
    };

    opterr = 0;

    USE_TTY();

    while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:c:i:d:a:uv",
                            long_options, &option_index)) != -1) {
        switch (c) {
        case 0:
            if (option_index == 0) {
                fast_open = 1;
            } else if (option_index == 1) {
                LOGI("initialize acl...");
                acl = !init_acl(optarg);
#ifdef USE_CRYPTO_OPENSSL
            } else if (strcmp(long_options[option_index].name, "bitcoin-list") == 0) {
                bitcoin_list = bitcoin_init_list(optarg);
#endif
            }
            break;
        case 's':
            if (server_num < MAX_REMOTE_NUM) {
                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':
            if (nameserver_num < MAX_DNS_NUM) {
                nameservers[nameserver_num++] = optarg;
            }
            break;
        case 'a':
            user = optarg;
            break;
        case 'u':
            udprelay = 1;
            break;
        case 'v':
            verbose = 1;
            break;
        }
    }

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

    if (argc == 1) {
        if (conf_path == NULL) {
            conf_path = DEFAULT_CONF_PATH;
        }
    }

    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 USE_CRYPTO_OPENSSL
        if (bitcoin_list == NULL) {
            bitcoin_list = bitcoin_init_list(conf->bitcoin_list);
        }
#endif
#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) {
                LOGI("setting NOFILE to %d", nofile);
            }
            set_nofile(nofile);
        }
#endif
        if (conf->nameserver != NULL) {
            nameservers[nameserver_num++] = conf->nameserver;
        }
    }
#ifdef USE_CRYPTO_OPENSSL
    if (bitcoin_list) {
        if (bitcoin_setup_update_thread(bitcoin_list) == 0) {
            FATAL("setup bitcoin check list thread failure");
        }
    }
#endif
    if (server_num == 0) {
        server_host[server_num++] = NULL;
    }

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

    if (method == NULL) {
        method = "table";
    }

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

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

    if (fast_open == 1) {
#ifdef TCP_FASTOPEN
        LOGI("using tcp fast open");
#else
        LOGE("tcp fast open is not supported by this environment");
#endif
    }

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

    struct ev_signal sigint_watcher;
    struct ev_signal sigterm_watcher;
    ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
    ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
    ev_signal_start(EV_DEFAULT, &sigint_watcher);
    ev_signal_start(EV_DEFAULT, &sigterm_watcher);

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

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

    // setup udns
    if (nameserver_num == 0) {
#ifdef __MINGW32__
        nameservers[nameserver_num++] = "8.8.8.8";
        resolv_init(loop, nameservers, nameserver_num);
#else
        resolv_init(loop, NULL, 0);
#endif
    } else {
        resolv_init(loop, nameservers, nameserver_num);
    }

    for (int i = 0; i < nameserver_num; i++) {
        LOGI("using nameserver: %s", nameservers[i]);
    }

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

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

        // Bind to port
        int listenfd;
        listenfd = create_and_bind(host, server_port);
        if (listenfd < 0) {
            FATAL("bind() error");
        }
        if (listen(listenfd, SSMAXCONN) == -1) {
            FATAL("listen() error");
        }
        setnonblocking(listenfd);
        LOGI("listening at %s:%s", host ? host : "*", server_port);

        struct listen_ctx *listen_ctx = &listen_ctx_list[index];

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

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

        // Setup UDP
        if (udprelay) {
            init_udprelay(server_host[index], server_port, m, atoi(timeout),
                          iface);
        }

    }

    if (udprelay) {
        LOGI("udprelay enabled");
    }

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

    // Init connections
    cork_dllist_init(&connections);

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

    if (verbose) {
        LOGI("closed gracefully");
    }

    // Clean up
    for (int i = 0; i <= server_num; i++) {
        struct listen_ctx *listen_ctx = &listen_ctx_list[i];
        ev_io_stop(loop, &listen_ctx->io);
        close(listen_ctx->fd);
    }

    free_connections(loop);

    if (udprelay) {
        free_udprelay();
    }

#ifdef USE_CRYPTO_OPENSSL
    if (bitcoin_list) {
        bitcoin_clean_update_thread(bitcoin_list);
    }
#endif

    resolv_shutdown(loop);

#ifdef __MINGW32__
    winsock_cleanup();
#endif

    ev_signal_stop(EV_DEFAULT, &sigint_watcher);
    ev_signal_stop(EV_DEFAULT, &sigterm_watcher);

    return 0;
}
Ejemplo n.º 3
0
static void remote_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct remote_ctx *remote_recv_ctx = (struct remote_ctx *)w;
    struct remote *remote = remote_recv_ctx->remote;
    struct server *server = remote->server;

    if (server == NULL) {
        LOGE("invalid server");
        close_and_free_remote(EV_A_ remote);
        return;
    }

    ev_timer_again(EV_A_ & server->recv_ctx->watcher);

    ssize_t r = recv(remote->fd, server->buf, BUF_SIZE, 0);

    if (r == 0) {
        // connection closed
        if (verbose) {
            LOGI("remote_recv close the connection");
        }
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r < 0) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("remote recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    server->buf = ss_encrypt(BUF_SIZE, server->buf, &r, server->e_ctx);

    if (server->buf == NULL) {
        LOGE("invalid password or cipher");
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    int s = send(server->fd, server->buf, r, 0);

    if (s == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data, wait for send
            server->buf_len = r;
            server->buf_idx = 0;
            ev_io_stop(EV_A_ & remote_recv_ctx->io);
            ev_io_start(EV_A_ & server->send_ctx->io);
        } else {
            ERROR("remote_recv_send");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
        }
        return;
    } else if (s < r) {
        server->buf_len = r - s;
        server->buf_idx = s;
        ev_io_stop(EV_A_ & remote_recv_ctx->io);
        ev_io_start(EV_A_ & server->send_ctx->io);
        return;
    }
}
Ejemplo n.º 4
0
static void close_connection(struct ev_loop *loop, ev_io *w) {
	ev_io_stop(loop, w);
	close(((struct jrpc_connection *) w)->fd);
	free(((struct jrpc_connection *) w)->buffer);
	free(((struct jrpc_connection *) w));
}
Ejemplo n.º 5
0
static void remote_send_cb(EV_P_ ev_io *w, int revents)
{
    struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w;
    struct remote *remote = remote_send_ctx->remote;
    struct server *server = remote->server;

    if (!remote_send_ctx->connected) {
        struct sockaddr_storage addr;
        socklen_t len = sizeof addr;
        int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        if (r == 0) {
            remote_send_ctx->connected = 1;
            ev_timer_stop(EV_A_ & remote_send_ctx->watcher);
            ev_timer_start(EV_A_ & remote->recv_ctx->watcher);
            ev_io_start(EV_A_ & remote->recv_ctx->io);

            // no need to send any data
            if (remote->buf_len == 0) {
                ev_io_stop(EV_A_ & remote_send_ctx->io);
                ev_io_start(EV_A_ & server->recv_ctx->io);
                return;
            }
        } else {
            // not connected
            ERROR("getpeername");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    if (remote->buf_len == 0) {
        // close and free
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else {
        // has data to send
        ssize_t s = send(remote->fd, remote->buf + remote->buf_idx,
                         remote->buf_len, 0);
        if (s < 0) {
            if (errno != EAGAIN && errno != EWOULDBLOCK) {
                ERROR("remote_send_cb_send");
                // close and free
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
            return;
        } else if (s < remote->buf_len) {
            // partly sent, move memory, wait for the next time to send
            remote->buf_len -= s;
            remote->buf_idx += s;
            return;
        } else {
            // all sent out, wait for reading
            remote->buf_len = 0;
            remote->buf_idx = 0;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_io_start(EV_A_ & server->recv_ctx->io);
        }
    }
}
Ejemplo n.º 6
0
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
{
    remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
    remote_t *remote              = remote_send_ctx->remote;
    server_t *server              = remote->server;

    if (!remote_send_ctx->connected) {
        int r = 0;
        if (remote->addr == NULL) {
            struct sockaddr_storage addr;
            memset(&addr, 0, sizeof(struct sockaddr_storage));
            socklen_t len = sizeof addr;
            r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        }
        if (r == 0) {
            remote_send_ctx->connected = 1;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_io_stop(EV_A_ & server->recv_ctx->io);
            ev_timer_stop(EV_A_ & remote_send_ctx->watcher);
            ev_timer_start(EV_A_ & remote->recv_ctx->watcher);

            // send destaddr
            buffer_t ss_addr_to_send;
            buffer_t *abuf = &ss_addr_to_send;
            balloc(abuf, BUF_SIZE);

            if (server->hostname_len > 0
                    && validate_hostname(server->hostname, server->hostname_len)) { // HTTP/SNI
                uint16_t port;
                if (AF_INET6 == server->destaddr.ss_family) { // IPv6
                    port = (((struct sockaddr_in6 *)&(server->destaddr))->sin6_port);
                } else {                             // IPv4
                    port = (((struct sockaddr_in *)&(server->destaddr))->sin_port);
                }

                abuf->data[abuf->len++] = 3;          // Type 3 is hostname
                abuf->data[abuf->len++] = server->hostname_len;
                memcpy(abuf->data + abuf->len, server->hostname, server->hostname_len);
                abuf->len += server->hostname_len;
                memcpy(abuf->data + abuf->len, &port, 2);
            } else if (AF_INET6 == server->destaddr.ss_family) { // IPv6
                abuf->data[abuf->len++] = 4;          // Type 4 is IPv6 address

                size_t in6_addr_len = sizeof(struct in6_addr);
                memcpy(abuf->data + abuf->len,
                       &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr),
                       in6_addr_len);
                abuf->len += in6_addr_len;
                memcpy(abuf->data + abuf->len,
                       &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port),
                       2);
            } else {                             // IPv4
                abuf->data[abuf->len++] = 1; // Type 1 is IPv4 address

                size_t in_addr_len = sizeof(struct in_addr);
                memcpy(abuf->data + abuf->len,
                       &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len);
                abuf->len += in_addr_len;
                memcpy(abuf->data + abuf->len,
                       &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2);
            }

            abuf->len += 2;

            int err = crypto->encrypt(abuf, server->e_ctx, BUF_SIZE);
            if (err) {
                LOGE("invalid password or cipher");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            err = crypto->encrypt(remote->buf, server->e_ctx, BUF_SIZE);
            if (err) {
                LOGE("invalid password or cipher");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            bprepend(remote->buf, abuf, BUF_SIZE);
            bfree(abuf);

            ev_io_start(EV_A_ & remote->recv_ctx->io);
        } else {
            ERROR("getpeername");
            // not connected
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    if (remote->buf->len == 0) {
        // close and free
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else {
        // has data to send
        ssize_t s;
        if (remote->addr != NULL) {
            s = sendto(remote->fd, remote->buf->data + remote->buf->idx,
                       remote->buf->len, MSG_FASTOPEN, remote->addr,
                       get_sockaddr_len(remote->addr));
            if (s == -1 && (errno == EOPNOTSUPP || errno == EPROTONOSUPPORT ||
                errno == ENOPROTOOPT)) {
                fast_open = 0;
                LOGE("fast open is not supported on this platform");
                s = connect(remote->fd, remote->addr,
                            get_sockaddr_len(remote->addr));
            }
            remote->addr = NULL;

            if (s == -1) {
                if (errno == CONNECT_IN_PROGRESS || errno == EAGAIN
                    || errno == EWOULDBLOCK) {
                    ev_io_start(EV_A_ & remote_send_ctx->io);
                    ev_timer_start(EV_A_ & remote_send_ctx->watcher);
                    return;
                } else {
                    ERROR("connect");
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                }
            }
        } else {
            s = send(remote->fd, remote->buf->data + remote->buf->idx,
                     remote->buf->len, 0);
        }

        if (s == -1) {
            if (errno != EAGAIN && errno != EWOULDBLOCK) {
                ERROR("send");
                // close and free
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
            return;
        } else if (s < remote->buf->len) {
            // partly sent, move memory, wait for the next time to send
            remote->buf->len -= s;
            remote->buf->idx += s;
            return;
        } else {
            // all sent out, wait for reading
            remote->buf->len = 0;
            remote->buf->idx = 0;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_io_start(EV_A_ & server->recv_ctx->io);
        }
    }
}
Ejemplo n.º 7
0
static void remote_send_cb(EV_P_ ev_io *w, int revents)
{
    struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w;
    struct remote *remote = remote_send_ctx->remote;
    struct server *server = remote->server;

    if (!remote_send_ctx->connected) {

        struct sockaddr_storage addr;
        socklen_t len = sizeof addr;
        int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        if (r == 0) {
            remote_send_ctx->connected = 1;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_timer_stop(EV_A_ & remote_send_ctx->watcher);

            // send destaddr
            char *ss_addr_to_send = malloc(BUF_SIZE);
            ssize_t addr_len = 0;
            if (AF_INET6 == server->destaddr.ss_family) { // IPv6
                ss_addr_to_send[addr_len++] = 4;          //Type 4 is IPv6 address

                size_t in_addr_len = sizeof(struct in6_addr);
                memcpy(ss_addr_to_send + addr_len,
                       &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr),
                       in_addr_len);
                addr_len += in_addr_len;
                memcpy(ss_addr_to_send + addr_len,
                       &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port),
                       2);
            } else {                             //IPv4
                ss_addr_to_send[addr_len++] = 1; //Type 1 is IPv4 address

                size_t in_addr_len = sizeof(struct in_addr);
                memcpy(ss_addr_to_send + addr_len,
                       &((struct sockaddr_in *)&(server->destaddr))->sin_addr,
                       in_addr_len);
                addr_len += in_addr_len;
                memcpy(ss_addr_to_send + addr_len,
                       &((struct sockaddr_in *)&(server->destaddr))->sin_port,
                       2);
            }
            addr_len += 2;
            ss_addr_to_send = ss_encrypt(BUF_SIZE, ss_addr_to_send, &addr_len,
                                         server->e_ctx);
            if (ss_addr_to_send == NULL) {
                LOGE("invalid password or cipher");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            int s = send(remote->fd, ss_addr_to_send, addr_len, 0);
            free(ss_addr_to_send);

            if (s < addr_len) {
                LOGE("failed to send remote addr.");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }

            ev_io_start(EV_A_ & server->recv_ctx->io);
            ev_io_start(EV_A_ & remote->recv_ctx->io);

            return;
        } else {
            ERROR("getpeername");
            // not connected
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    } else {
        if (remote->buf_len == 0) {
            // close and free
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        } else {
            // has data to send
            ssize_t s = send(remote->fd, remote->buf + remote->buf_idx,
                             remote->buf_len, 0);
            if (s < 0) {
                if (errno != EAGAIN && errno != EWOULDBLOCK) {
                    ERROR("send");
                    // close and free
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                }
                return;
            } else if (s < remote->buf_len) {
                // partly sent, move memory, wait for the next time to send
                remote->buf_len -= s;
                remote->buf_idx += s;
                return;
            } else {
                // all sent out, wait for reading
                remote->buf_len = 0;
                remote->buf_idx = 0;
                ev_io_stop(EV_A_ & remote_send_ctx->io);
                if (server != NULL) {
                    ev_io_start(EV_A_ & server->recv_ctx->io);
                } else {
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                    return;
                }
            }
        }

    }
}
Ejemplo n.º 8
0
/* XXX too much gotos */
static void
ev_io_on_write(struct ev_loop* mainloop, ev_io* watcher, const int events)
{
  Request* request = REQUEST_FROM_WATCHER(watcher);

  GIL_LOCK(0);

  if(request->state.use_sendfile) {
    /* sendfile */
    if(request->current_chunk) {
      /* current_chunk contains the HTTP headers */
      if(send_chunk(request))
        goto out;
      assert(!request->current_chunk_p);
      /* abuse current_chunk_p to store the file fd */
      request->current_chunk_p = PyObject_AsFileDescriptor(request->iterable);
      goto out;
    }
    if(do_sendfile(request))
      goto out;
  } else {
    /* iterable */
    if(send_chunk(request))
      goto out;

    if(request->iterator) {
      PyObject* next_chunk;
      next_chunk = wsgi_iterable_get_next_chunk(request);
      if(next_chunk) {
        if(request->state.chunked_response) {
          request->current_chunk = wrap_http_chunk_cruft_around(next_chunk);
          Py_DECREF(next_chunk);
        } else {
          request->current_chunk = next_chunk;
        }
        assert(request->current_chunk_p == 0);
        goto out;
      } else {
        if(PyErr_Occurred()) {
          PyErr_Print();
          /* We can't do anything graceful here because at least one
           * chunk is already sent... just close the connection */
          DBG_REQ(request, "Exception in iterator, can not recover");
          ev_io_stop(mainloop, &request->ev_watcher);
          close(request->client_fd);
          Request_free(request);
          goto out;
        }
        Py_CLEAR(request->iterator);
      }
    }

    if(request->state.chunked_response) {
      /* We have to send a terminating empty chunk + \r\n */
      request->current_chunk = PyString_FromString("0\r\n\r\n");
      assert(request->current_chunk_p == 0);
      request->state.chunked_response = false;
      goto out;
    }
  }

  ev_io_stop(mainloop, &request->ev_watcher);
  if(request->state.keep_alive) {
    DBG_REQ(request, "done, keep-alive");
    Request_clean(request);
    Request_reset(request);
    ev_io_init(&request->ev_watcher, &ev_io_on_read,
               request->client_fd, EV_READ);
    ev_io_start(mainloop, &request->ev_watcher);
  } else {
    DBG_REQ(request, "done, close");
    close(request->client_fd);
    Request_free(request);
  }

out:
  GIL_UNLOCK(0);
}
Ejemplo n.º 9
0
	void onready()
	{
		ev_io_stop(s_loop, this);
		proc();
	}
Ejemplo n.º 10
0
/**
 * Initializes the networking interfaces
 * @arg config Takes the server configuration
 * @arg mgr The manager to pass up to the connection handlers
 * @arg netconf Output. The configuration for the networking stack.
 */
int init_networking(hlld_config *config, void *mgr, hlld_networking **netconf_out) {
    // Make the netconf structure
    hlld_networking *netconf = calloc(1, sizeof(struct hlld_networking));

    // Initialize
    netconf->config = config;
    netconf->mgr = mgr;
    netconf->workers = calloc(config->worker_threads, sizeof(worker_ev_userdata*));
    if (!netconf->workers) {
        free(netconf);
        perror("Failed to calloc() for worker threads");
        return 1;
    }

    // Setup the barrier
    if (barrier_init(&netconf->thread_barrier, config->worker_threads + 1)) {
        free(netconf->workers);
        free(netconf);
        return 1;
    }

    /**
     * Check if we can use kqueue instead of select.
     * By default, libev will not use kqueue since it has
     * certain limitations that select doesn't, but which
     * we don't need.
     */
    int ev_mode = EVFLAG_AUTO;
    if (ev_supported_backends () & ~ev_recommended_backends () & EVBACKEND_KQUEUE) {
        ev_mode = EVBACKEND_KQUEUE;
    }
    netconf->ev_mode = ev_mode;

    if (!(netconf->default_loop = ev_loop_new (ev_mode))) {
        syslog(LOG_CRIT, "Failed to initialize libev!");
        free(netconf);
        return 1;
    }

    // Setup the TCP listener
    int res = setup_tcp_listener(netconf);
    if (res != 0) {
        free(netconf);
        return 1;
    }

    // Setup the UDP listener
    res = setup_udp_listener(netconf);
    if (res != 0) {
        ev_io_stop(netconf->default_loop, &netconf->tcp_client);
        close(netconf->tcp_client.fd);
        free(netconf);
        return 1;
    }

    // Prepare the conn handlers
    init_conn_handler();

    // Success!
    *netconf_out = netconf;
    return 0;
}
Ejemplo n.º 11
0
/**
 * Entry point for threads to join the networking
 * stack. This method blocks indefinitely until the
 * network stack is shutdown.
 * @arg netconf The configuration for the networking stack.
 */
void start_networking_worker(hlld_networking *netconf) {
    // Allocate our user data
    worker_ev_userdata data;
    data.netconf = netconf;
    data.should_run = 1;
    data.inactive = NULL;

    // Allocate our pipe
    if (pipe(data.pipefd)) {
        perror("failed to allocate worker pipes!");
        return;
    }

    // Create the event loop
    if (!(data.loop = ev_loop_new(netconf->ev_mode))) {
        syslog(LOG_ERR, "Failed to create event loop for worker!");
        return;
    }

    // Set the user data to be for this thread
    ev_set_userdata(data.loop, &data);

    // Setup the pipe listener
    ev_io_init(&data.pipe_client, handle_worker_notification,
                data.pipefd[0], EV_READ);
    ev_io_start(data.loop, &data.pipe_client);

    // Setup the periodic timers,
    ev_timer_init(&data.periodic, handle_periodic_timeout,
                PERIODIC_TIME_SEC, 1);
    ev_timer_start(data.loop, &data.periodic);

    // Syncronize until netconf->threads is available
    barrier_wait(&netconf->thread_barrier);

    // Register this thread so we can accept connections
    assert(netconf->threads);
    pthread_t id = pthread_self();
    for (int i=0; i < netconf->config->worker_threads; i++) {
        if (pthread_equal(id, netconf->threads[i])) {
            // Provide a pointer to our data
            netconf->workers[i] = &data;
            break;
        }
    }

    // Wait for everybody to be registered
    barrier_wait(&netconf->thread_barrier);

    // Run the event loop
    while (data.should_run) {
        ev_run(data.loop, EVRUN_ONCE);

        // Free inactive connections
        conn_info *c=data.inactive;
        while (c) {
            conn_info *n = c->next;
            close_client_connection(c);
            c = n;
        }
        data.inactive = NULL;
    }

    // Cleanup after exit
    ev_timer_stop(data.loop, &data.periodic);
    ev_io_stop(data.loop, &data.pipe_client);
    close(data.pipefd[0]);
    close(data.pipefd[1]);
    ev_loop_destroy(data.loop);
}
Ejemplo n.º 12
0
void IO::stop() {
    ev_io_stop(loop->base, &ev);
}
Ejemplo n.º 13
0
static PyObject*
IO_stop(libevwrapper_IO *self, PyObject *args) {
    ev_io_stop(self->loop->loop, &self->io);
    Py_RETURN_NONE;
}
Ejemplo n.º 14
0
Archivo: stud.c Proyecto: gyepisam/stud
/* Continue/complete the asynchronous connect() before starting data transmission
 * between front/backend */
static void handle_connect(struct ev_loop *loop, ev_io *w, int revents) {
    (void) revents;
    int t;
    proxystate *ps = (proxystate *)w->data;
    char tcp6_address_string[INET6_ADDRSTRLEN];
    size_t written = 0;
    t = connect(ps->fd_down, backaddr->ai_addr, backaddr->ai_addrlen);
    if (!t || errno == EISCONN || !errno) {
        /* INIT */
        ev_io_stop(loop, &ps->ev_w_down);
        ev_io_init(&ps->ev_r_down, back_read, ps->fd_down, EV_READ);
        ev_io_init(&ps->ev_w_down, back_write, ps->fd_down, EV_WRITE);
        start_handshake(ps, SSL_ERROR_WANT_READ); /* for client-first handshake */
        ev_io_start(loop, &ps->ev_r_down);
        if (OPTIONS.WRITE_PROXY_LINE) {
            char *ring_pnt = ringbuffer_write_ptr(&ps->ring_down);
            assert(ps->remote_ip.ss_family == AF_INET ||
		   ps->remote_ip.ss_family == AF_INET6);
	    if(ps->remote_ip.ss_family == AF_INET) {
	      struct sockaddr_in* addr = (struct sockaddr_in*)&ps->remote_ip;
	      written = snprintf(ring_pnt,
				 RING_DATA_LEN,
				 tcp_proxy_line,
				 "TCP4",
				 inet_ntoa(addr->sin_addr),
				 ntohs(addr->sin_port));
	    }
	    else if (ps->remote_ip.ss_family == AF_INET6) {
	      struct sockaddr_in6* addr = (struct sockaddr_in6*)&ps->remote_ip;
	      inet_ntop(AF_INET6,&(addr->sin6_addr),tcp6_address_string,INET6_ADDRSTRLEN);
	      written = snprintf(ring_pnt,
				 RING_DATA_LEN,
				 tcp_proxy_line,
				 "TCP6",
				 tcp6_address_string,
				 ntohs(addr->sin6_port));
	    }   
            ringbuffer_write_append(&ps->ring_down, written);
            ev_io_start(loop, &ps->ev_w_down);
        }
        else if (OPTIONS.WRITE_IP_OCTET) {
            char *ring_pnt = ringbuffer_write_ptr(&ps->ring_down);
            assert(ps->remote_ip.ss_family == AF_INET ||
                   ps->remote_ip.ss_family == AF_INET6);
            *ring_pnt++ = (unsigned char) ps->remote_ip.ss_family;
            if (ps->remote_ip.ss_family == AF_INET6) {
                memcpy(ring_pnt, &((struct sockaddr_in6 *) &ps->remote_ip)
                       ->sin6_addr.s6_addr, 16U);
                ringbuffer_write_append(&ps->ring_down, 1U + 16U);
            } else {
                memcpy(ring_pnt, &((struct sockaddr_in *) &ps->remote_ip)
                       ->sin_addr.s_addr, 4U);
                ringbuffer_write_append(&ps->ring_down, 1U + 4U);
            }
            ev_io_start(loop, &ps->ev_w_down);
        }
    }
    else if (errno == EINPROGRESS || errno == EINTR || errno == EALREADY) {
        /* do nothing, we'll get phoned home again... */
    }
    else {
        perror("{backend-connect}");
        shutdown_proxy(ps, SHUTDOWN_HARD);
    }
}
Ejemplo n.º 15
0
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
{
    server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
    server_t *server              = server_recv_ctx->server;
    remote_t *remote              = server->remote;

    ev_timer_stop(EV_A_ & server->delayed_connect_watcher);

    ssize_t r = recv(server->fd, remote->buf->data + remote->buf->len,
                     BUF_SIZE - remote->buf->len, 0);

    if (r == 0) {
        // connection closed
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    remote->buf->len += r;

    if (verbose) {
        uint16_t port = 0;
        char ipstr[INET6_ADDRSTRLEN];
        memset(&ipstr, 0, INET6_ADDRSTRLEN);

        if (AF_INET == server->destaddr.ss_family) {
            struct sockaddr_in *sa = (struct sockaddr_in *)&(server->destaddr);
            dns_ntop(AF_INET, &(sa->sin_addr), ipstr, INET_ADDRSTRLEN);
            port = ntohs(sa->sin_port);
        } else {
            // TODO: The code below need to be test in IPv6 envirment, which I
            //       don't have.
            struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(server->destaddr);
            dns_ntop(AF_INET6, &(sa->sin6_addr), ipstr, INET6_ADDRSTRLEN);
            port = ntohs(sa->sin6_port);
        }

        LOGI("redir to %s:%d, len=%zu, recv=%zd", ipstr, port, remote->buf->len, r);
    }

    if (!remote->send_ctx->connected) {
        // SNI
        int ret       = 0;
        uint16_t port = 0;

        if (AF_INET6 == server->destaddr.ss_family) { // IPv6
            port = ntohs(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port);
        } else {                             // IPv4
            port = ntohs(((struct sockaddr_in *)&(server->destaddr))->sin_port);
        }
        if (port == http_protocol->default_port)
            ret = http_protocol->parse_packet(remote->buf->data,
                                              remote->buf->len, &server->hostname);
        else if (port == tls_protocol->default_port)
            ret = tls_protocol->parse_packet(remote->buf->data,
                                             remote->buf->len, &server->hostname);
        if (ret > 0) {
            server->hostname_len = ret;
        }

        ev_io_stop(EV_A_ & server_recv_ctx->io);
        ev_io_start(EV_A_ & remote->send_ctx->io);
        return;
    }

    int err = crypto->encrypt(remote->buf, server->e_ctx, BUF_SIZE);

    if (err) {
        LOGE("invalid password or cipher");
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    int s = send(remote->fd, remote->buf->data, remote->buf->len, 0);

    if (s == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data, wait for send
            remote->buf->idx = 0;
            ev_io_stop(EV_A_ & server_recv_ctx->io);
            ev_io_start(EV_A_ & remote->send_ctx->io);
            return;
        } else {
            ERROR("send");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    } else if (s < remote->buf->len) {
        remote->buf->len -= s;
        remote->buf->idx  = s;
        ev_io_stop(EV_A_ & server_recv_ctx->io);
        ev_io_start(EV_A_ & remote->send_ctx->io);
        return;
    } else {
        remote->buf->idx = 0;
        remote->buf->len = 0;
    }
}
Ejemplo n.º 16
0
static void uv__read(uv_stream_t* stream) {
  uv_buf_t buf;
  ssize_t nread;
  struct msghdr msg;
  struct cmsghdr* cmsg;
  char cmsg_space[64];
  struct ev_loop* ev = stream->loop->ev;

  /* XXX: Maybe instead of having UV_READING we just test if
   * tcp->read_cb is NULL or not?
   */
  while ((stream->read_cb || stream->read2_cb) &&
         stream->flags & UV_READING) {
    assert(stream->alloc_cb);
    buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024);

    assert(buf.len > 0);
    assert(buf.base);
    assert(stream->fd >= 0);

    if (stream->read_cb) {
      do {
        nread = read(stream->fd, buf.base, buf.len);
      }
      while (nread < 0 && errno == EINTR);
    } else {
      assert(stream->read2_cb);
      /* read2_cb uses recvmsg */
      msg.msg_flags = 0;
      msg.msg_iov = (struct iovec*) &buf;
      msg.msg_iovlen = 1;
      msg.msg_name = NULL;
      msg.msg_namelen = 0;
      /* Set up to receive a descriptor even if one isn't in the message */
      msg.msg_controllen = 64;
      msg.msg_control = (void *) cmsg_space;

      do {
        nread = recvmsg(stream->fd, &msg, 0);
      }
      while (nread < 0 && errno == EINTR);
    }


    if (nread < 0) {
      /* Error */
      if (errno == EAGAIN) {
        /* Wait for the next one. */
        if (stream->flags & UV_READING) {
          ev_io_start(ev, &stream->read_watcher);
        }
        uv__set_sys_error(stream->loop, EAGAIN);

        if (stream->read_cb) {
          stream->read_cb(stream, 0, buf);
        } else {
          stream->read2_cb((uv_pipe_t*)stream, 0, buf, UV_UNKNOWN_HANDLE);
        }

        return;
      } else {
        /* Error. User should call uv_close(). */
        uv__set_sys_error(stream->loop, errno);

        if (stream->read_cb) {
          stream->read_cb(stream, -1, buf);
        } else {
          stream->read2_cb((uv_pipe_t*)stream, -1, buf, UV_UNKNOWN_HANDLE);
        }

        assert(!ev_is_active(&stream->read_watcher));
        return;
      }

    } else if (nread == 0) {
      /* EOF */
      uv__set_artificial_error(stream->loop, UV_EOF);
      ev_io_stop(ev, &stream->read_watcher);

      if (stream->read_cb) {
        stream->read_cb(stream, -1, buf);
      } else {
        stream->read2_cb((uv_pipe_t*)stream, -1, buf, UV_UNKNOWN_HANDLE);
      }
      return;
    } else {
      /* Successful read */
      ssize_t buflen = buf.len;

      if (stream->read_cb) {
        stream->read_cb(stream, nread, buf);
      } else {
        assert(stream->read2_cb);

        /*
         * XXX: Some implementations can send multiple file descriptors in a
         * single message. We should be using CMSG_NXTHDR() to walk the
         * chain to get at them all. This would require changing the API to
         * hand these back up the caller, is a pain.
         */

        for (cmsg = CMSG_FIRSTHDR(&msg);
             msg.msg_controllen > 0 && cmsg != NULL;
             cmsg = CMSG_NXTHDR(&msg, cmsg)) {

          if (cmsg->cmsg_type == SCM_RIGHTS) {
            if (stream->accepted_fd != -1) {
              fprintf(stderr, "(libuv) ignoring extra FD received\n");
            }

            stream->accepted_fd = *(int *) CMSG_DATA(cmsg);

          } else {
            fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
                cmsg->cmsg_type);
          }
        }


        if (stream->accepted_fd >= 0) {
          stream->read2_cb((uv_pipe_t*)stream, nread, buf, UV_TCP);
        } else {
          stream->read2_cb((uv_pipe_t*)stream, nread, buf, UV_UNKNOWN_HANDLE);
        }
      }

      /* Return if we didn't fill the buffer, there is no more data to read. */
      if (nread < buflen) {
        return;
      }
    }
  }
}
Ejemplo n.º 17
0
static void
remote_recv_cb(EV_P_ ev_io *w, int revents)
{
    remote_ctx_t *remote_recv_ctx = (remote_ctx_t *)w;
    remote_t *remote              = remote_recv_ctx->remote;
    server_t *server              = remote->server;

    ev_timer_again(EV_A_ & remote->recv_ctx->watcher);

    ssize_t r = recv(remote->fd, server->buf->data, BUF_SIZE, 0);

    if (r == 0) {
        // connection closed
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("remote recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    server->buf->len = r;

    int err = crypto->decrypt(server->buf, server->d_ctx, BUF_SIZE);
    if (err == CRYPTO_ERROR) {
        LOGE("invalid password or cipher");
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (err == CRYPTO_NEED_MORE) {
        return; // Wait for more
    }

    int s = send(server->fd, server->buf->data, server->buf->len, 0);

    if (s == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data, wait for send
            server->buf->idx = 0;
            ev_io_stop(EV_A_ & remote_recv_ctx->io);
            ev_io_start(EV_A_ & server->send_ctx->io);
        } else {
            ERROR("send");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    } else if (s < server->buf->len) {
        server->buf->len -= s;
        server->buf->idx  = s;
        ev_io_stop(EV_A_ & remote_recv_ctx->io);
        ev_io_start(EV_A_ & server->send_ctx->io);
    }

    // Disable TCP_NODELAY after the first response are sent
    if (!remote->recv_ctx->connected) {
        int opt = 0;
        setsockopt(server->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt));
        setsockopt(remote->fd, SOL_TCP, TCP_NODELAY, &opt, sizeof(opt));
        remote->recv_ctx->connected = 1;
    }
}
Ejemplo n.º 18
0
static void server_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct server_ctx *server_recv_ctx = (struct server_ctx *)w;
    struct server *server = server_recv_ctx->server;
    struct remote *remote = NULL;

    int len = server->buf_len;
    char **buf = &server->buf;

    ev_timer_again(EV_A_ & server->recv_ctx->watcher);

    if (server->stage != 0) {
        remote = server->remote;
        buf = &remote->buf;
        len = 0;
    }

    ssize_t r = recv(server->fd, *buf + len, BUF_SIZE - len, 0);

    if (r == 0) {
        // connection closed
        if (verbose) {
            LOGI("server_recv close the connection");
        }
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    tx += r;

    // handle incomplete header
    if (server->stage == 0) {
        r += server->buf_len;
        if (r <= enc_get_iv_len()) {
            // wait for more
            if (verbose) {
#ifdef __MINGW32__
                LOGI("imcomplete header: %u", r);
#else
                LOGI("imcomplete header: %zu", r);
#endif
            }
            server->buf_len = r;
            return;
        } else {
            server->buf_len = 0;
        }
    }

    *buf = ss_decrypt(BUF_SIZE, *buf, &r, server->d_ctx);

    if (*buf == NULL) {
        LOGE("invalid password or cipher");
        report_addr(server->fd);
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    // handshake and transmit data
    if (server->stage == 5) {
        if (server->auth && !ss_check_hash(&remote->buf, &r, server->chunk, server->d_ctx, BUF_SIZE)) {
            LOGE("hash error");
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            close_and_free_remote(EV_A_ remote);
            return;
        }
        int s = send(remote->fd, remote->buf, r, 0);
        if (s == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // no data, wait for send
                remote->buf_len = r;
                remote->buf_idx = 0;
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            } else {
                ERROR("server_recv_send");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
        } else if (s < r) {
            remote->buf_len = r - s;
            remote->buf_idx = s;
            ev_io_stop(EV_A_ & server_recv_ctx->io);
            ev_io_start(EV_A_ & remote->send_ctx->io);
        }
        return;

    } else if (server->stage == 0) {

        /*
         * Shadowsocks TCP Relay Header:
         *
         *    +------+----------+----------+----------------+
         *    | ATYP | DST.ADDR | DST.PORT |    HMAC-SHA1   |
         *    +------+----------+----------+----------------+
         *    |  1   | Variable |    2     |      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 header.
         *    The output of HMAC-SHA is truncated to 10 bytes (leftmost bits).
         */

        /*
         * Shadowsocks TCP Request's Chunk Authentication (Optional, no hash check for response's payload):
         *
         *    +------+-----------+-------------+------+
         *    | LEN  | HMAC-SHA1 |    DATA     |      ...
         *    +------+-----------+-------------+------+
         *    |  2   |    10     |  Variable   |      ...
         *    +------+-----------+-------------+------+
         *
         *    The key of HMAC-SHA1 is (IV + CHUNK ID)
         *    The output of HMAC-SHA is truncated to 10 bytes (leftmost bits).
         */

        int offset = 0;
        int need_query = 0;
        char atyp = server->buf[offset++];
        char host[256] = { 0 };
        uint16_t port = 0;
        struct addrinfo info;
        struct sockaddr_storage storage;
        memset(&info, 0, sizeof(struct addrinfo));
        memset(&storage, 0, sizeof(struct sockaddr_storage));

        // get remote addr and port
        if ((atyp & ADDRTYPE_MASK) == 1) {
            // IP V4
            struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
            size_t in_addr_len = sizeof(struct in_addr);
            addr->sin_family = AF_INET;
            if (r > in_addr_len) {
                addr->sin_addr = *(struct in_addr *)(server->buf + offset);
                dns_ntop(AF_INET, (const void *)(server->buf + offset),
                         host, INET_ADDRSTRLEN);
                offset += in_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in);
            info.ai_addr = (struct sockaddr *)addr;
        } else if ((atyp & ADDRTYPE_MASK) == 3) {
            // Domain name
            uint8_t name_len = *(uint8_t *)(server->buf + offset);
            if (name_len < r) {
                memcpy(host, server->buf + offset + 1, name_len);
                offset += name_len + 1;
            } else {
                LOGE("invalid name length: %d", name_len);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            struct cork_ip ip;
            if (cork_ip_init(&ip, host) != -1) {
                info.ai_socktype = SOCK_STREAM;
                info.ai_protocol = IPPROTO_TCP;
                if (ip.version == 4) {
                    struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
                    dns_pton(AF_INET, host, &(addr->sin_addr));
                    addr->sin_port = *(uint16_t *)(server->buf + offset);
                    addr->sin_family = AF_INET;
                    info.ai_family = AF_INET;
                    info.ai_addrlen = sizeof(struct sockaddr_in);
                    info.ai_addr = (struct sockaddr *)addr;
                } else if (ip.version == 6) {
                    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
                    dns_pton(AF_INET6, host, &(addr->sin6_addr));
                    addr->sin6_port = *(uint16_t *)(server->buf + offset);
                    addr->sin6_family = AF_INET6;
                    info.ai_family = AF_INET6;
                    info.ai_addrlen = sizeof(struct sockaddr_in6);
                    info.ai_addr = (struct sockaddr *)addr;
                }
            } else {
                need_query = 1;
            }
        } else if ((atyp & ADDRTYPE_MASK) == 4) {
            // IP V6
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
            size_t in6_addr_len = sizeof(struct in6_addr);
            addr->sin6_family = AF_INET6;
            if (r > in6_addr_len) {
                addr->sin6_addr = *(struct in6_addr *)(server->buf + offset);
                dns_ntop(AF_INET6, (const void *)(server->buf + offset),
                         host, INET6_ADDRSTRLEN);
                offset += in6_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin6_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET6;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in6);
            info.ai_addr = (struct sockaddr *)addr;
        }

        if (offset == 1) {
            LOGE("invalid header with addr type %d", atyp);
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            return;
        }

        if (acl && !need_query && acl_contains_ip(host)) {
            if (verbose) {
                LOGI("Access denied to %s", host);
            }
            close_and_free_server(EV_A_ server);
            return;
        }

        port = (*(uint16_t *)(server->buf + offset));

        offset += 2;

        if (auth || (atyp & ONETIMEAUTH_FLAG)) {
            if (ss_onetimeauth_verify(server->buf + offset, server->buf, offset, server->d_ctx->evp.iv)) {
                LOGE("authentication error %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            };
            offset += ONETIMEAUTH_BYTES;
            server->auth = 1;
        }

        if (verbose) {
            LOGI("connect to: %s:%d", host, ntohs(port));
        }

        // XXX: should handle buffer carefully
        if (r > offset) {
            server->buf_len = r - offset;
            memmove(server->buf, server->buf + offset, server->buf_len);
        }

        if (server->auth && !ss_check_hash(&server->buf, &server->buf_len, server->chunk, server->d_ctx, BUF_SIZE)) {
            LOGE("hash error");
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            return;
        }

        if (!need_query) {
            struct remote *remote = connect_to_remote(&info, server);

            if (remote == NULL) {
                LOGE("connect error");
                close_and_free_server(EV_A_ server);
                return;
            } else {
                server->remote = remote;
                remote->server = server;

                // XXX: should handle buffer carefully
                if (server->buf_len > 0) {
                    memcpy(remote->buf, server->buf + server->buf_idx, server->buf_len);
                    remote->buf_len = server->buf_len;
                    remote->buf_idx = 0;
                    server->buf_len = 0;
                    server->buf_idx = 0;
                }

                server->stage = 4;

                // listen to remote connected event
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            }
        } else {
            server->stage = 4;
            server->query = resolv_query(host, server_resolve_cb, NULL, server,
                                         port);

            ev_io_stop(EV_A_ & server_recv_ctx->io);
        }

        return;
    }
    // should not reach here
    FATAL("server context error");
}
Ejemplo n.º 19
0
static void proxy_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
	proxy_connection *pcon = (proxy_connection*) w->data;

	if (pcon->state == SS_CONNECTING) {
		if (LI_HANDLER_GO_ON != proxy_statemachine(pcon->vr, pcon)) {
			li_vrequest_error(pcon->vr);
		}
		return;
	}

	if (revents & EV_READ) {
		if (pcon->proxy_in->is_closed) {
			li_ev_io_rem_events(loop, w, EV_READ);
		} else {
			switch (li_network_read(pcon->vr, w->fd, pcon->proxy_in, &pcon->proxy_in_buffer)) {
			case LI_NETWORK_STATUS_SUCCESS:
				break;
			case LI_NETWORK_STATUS_FATAL_ERROR:
				VR_ERROR(pcon->vr, "(%s) network read fatal error", pcon->ctx->socket_str->str);
				li_vrequest_error(pcon->vr);
				return;
			case LI_NETWORK_STATUS_CONNECTION_CLOSE:
				pcon->proxy_in->is_closed = TRUE;
				ev_io_stop(loop, w);
				close(pcon->fd);
				pcon->fd = -1;
				li_vrequest_backend_finished(pcon->vr);
				break;
			case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
				break;
			}
		}
	}

	if (pcon->fd != -1 && (revents & EV_WRITE)) {
		if (pcon->proxy_out->length > 0) {
			switch (li_network_write(pcon->vr, w->fd, pcon->proxy_out, 256*1024)) {
			case LI_NETWORK_STATUS_SUCCESS:
				break;
			case LI_NETWORK_STATUS_FATAL_ERROR:
				VR_ERROR(pcon->vr, "(%s) network write fatal error", pcon->ctx->socket_str->str);
				li_vrequest_error(pcon->vr);
				return;
			case LI_NETWORK_STATUS_CONNECTION_CLOSE:
				pcon->proxy_in->is_closed = TRUE;
				ev_io_stop(loop, w);
				close(pcon->fd);
				pcon->fd = -1;
				li_vrequest_backend_finished(pcon->vr);
				break;
			case LI_NETWORK_STATUS_WAIT_FOR_EVENT:
				break;
			}
		}
		if (pcon->proxy_out->length == 0) {
			li_ev_io_rem_events(loop, w, EV_WRITE);
		}
	}

	if (!pcon->response_headers_finished && LI_HANDLER_GO_ON == li_http_response_parse(pcon->vr, &pcon->parse_response_ctx)) {
		/* "ignore" 1xx response headers */
		if (!(pcon->vr->response.http_status >= 100 && pcon->vr->response.http_status < 200)) {
			pcon->response_headers_finished = TRUE;
			li_vrequest_handle_response_headers(pcon->vr);
		}
	}

	if (pcon->response_headers_finished) {
		li_chunkqueue_steal_all(pcon->vr->out, pcon->proxy_in);
		pcon->vr->out->is_closed = pcon->proxy_in->is_closed;
		li_vrequest_handle_response_body(pcon->vr);
	}

	/* only possible if we didn't found a header */
	if (pcon->proxy_in->is_closed && !pcon->vr->out->is_closed) {
		VR_ERROR(pcon->vr, "(%s) unexpected end-of-file (perhaps the proxy process died)", pcon->ctx->socket_str->str);
		li_vrequest_error(pcon->vr);
	}
}
Ejemplo n.º 20
0
static void
server_recv_cb(EV_P_ ev_io *w, int revents)
{
    server_ctx_t *server_recv_ctx = (server_ctx_t *)w;
    server_t *server              = server_recv_ctx->server;
    remote_t *remote              = server->remote;

    if (remote == NULL) {
        close_and_free_server(EV_A_ server);
        return;
    }

    ssize_t r = recv(server->fd, remote->buf->array, BUF_SIZE, 0);

    if (r == 0) {
        // connection closed
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    remote->buf->len = r;

    if (auth) {
        ss_gen_hash(remote->buf, &remote->counter, server->e_ctx, BUF_SIZE);
    }

    int err = ss_encrypt(remote->buf, server->e_ctx, BUF_SIZE);

    if (err) {
        LOGE("invalid password or cipher");
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    int s = send(remote->fd, remote->buf->array, remote->buf->len, 0);

    if (s == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data, wait for send
            remote->buf->idx = 0;
            ev_io_stop(EV_A_ & server_recv_ctx->io);
            ev_io_start(EV_A_ & remote->send_ctx->io);
            return;
        } else {
            ERROR("send");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    } else if (s < remote->buf->len) {
        remote->buf->len -= s;
        remote->buf->idx  = s;
        ev_io_stop(EV_A_ & server_recv_ctx->io);
        ev_io_start(EV_A_ & remote->send_ctx->io);
        return;
    }
}
Ejemplo n.º 21
0
void evapi_recv_client(struct ev_loop *loop, struct ev_io *watcher, int revents)
{
#define CLIENT_BUFFER_SIZE	4096
	char rbuffer[CLIENT_BUFFER_SIZE];
	ssize_t rlen;
	int i, k;
	evapi_env_t evenv;
	str frame;

	if(EV_ERROR & revents) {
		perror("received invalid event\n");
		return;
	}

	/* read message from client */
	rlen = recv(watcher->fd, rbuffer, CLIENT_BUFFER_SIZE-1, 0);

	if(rlen < 0) {
		LM_ERR("cannot read the client message\n");
		return;
	}

	for(i=0; i<EVAPI_MAX_CLIENTS; i++) {
		if(_evapi_clients[i].connected==1 && _evapi_clients[i].sock==watcher->fd) {
			break;
		}
	}
	if(i==EVAPI_MAX_CLIENTS) {
		LM_ERR("cannot lookup client socket %d\n", watcher->fd);
		return;
	}

	evapi_env_reset(&evenv);
	if(rlen == 0) {
		/* client is gone */
		evenv.eset = 1;
		evenv.conidx = i;
		evapi_run_cfg_route(&evenv, _evapi_rts.con_closed);
		_evapi_clients[i].connected = 0;
		_evapi_clients[i].sock = 0;
		ev_io_stop(loop, watcher);
		free(watcher);
		LM_INFO("client closing connection - pos [%d] addr [%s:%d]\n",
				i, _evapi_clients[i].src_addr, _evapi_clients[i].src_port);
		return;
	}

	rbuffer[rlen] = '\0';

	LM_NOTICE("{%d} [%s:%d] - received [%.*s]\n",
			i, _evapi_clients[i].src_addr, _evapi_clients[i].src_port,
			(int)rlen, rbuffer);
	evenv.conidx = i;
	evenv.eset = 1;
	if(_evapi_netstring_format) {
		/* netstring decapsulation */
		k = 0;
		while(k<rlen) {
			frame.len = 0;
			while(k<rlen) {
				if(rbuffer[k]==' ' || rbuffer[k]=='\t'
						|| rbuffer[k]=='\r' || rbuffer[k]=='\n')
					k++;
				else break;
			}
			if(k==rlen) return;
			while(k<rlen) {
				if(rbuffer[k]>='0' && rbuffer[k]<='9') {
					frame.len = frame.len*10 + rbuffer[k] - '0';
				} else {
					if(rbuffer[k]==':')
						break;
					/* invalid character - discard the rest */
					return;
				}
				k++;
			}
			if(k==rlen || frame.len<=0) return;
			if(frame.len + k>=rlen) return;
			k++;
			frame.s = rbuffer + k;
			if(frame.s[frame.len]!=',') return;
			frame.s[frame.len] = '\0';
			k += frame.len ;
			evenv.msg.s = frame.s;
			evenv.msg.len = frame.len;
			evapi_run_cfg_route(&evenv, _evapi_rts.msg_received);
			k++;
		}
	} else {
		evenv.msg.s = rbuffer;
		evenv.msg.len = rlen;
		evapi_run_cfg_route(&evenv, _evapi_rts.msg_received);
	}
}
Ejemplo n.º 22
0
static void
remote_send_cb(EV_P_ ev_io *w, int revents)
{
    remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w;
    remote_t *remote              = remote_send_ctx->remote;
    server_t *server              = remote->server;

    if (!remote_send_ctx->connected) {
        struct sockaddr_storage addr;
        socklen_t len = sizeof addr;

        int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        if (r == 0) {
            remote_send_ctx->connected = 1;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            ev_timer_stop(EV_A_ & remote_send_ctx->watcher);

            buffer_t ss_addr_to_send;
            buffer_t *abuf = &ss_addr_to_send;
            balloc(abuf, BUF_SIZE);

            ss_addr_t *sa = &server->destaddr;
            struct cork_ip ip;
            if (cork_ip_init(&ip, sa->host) != -1) {
                if (ip.version == 4) {
                    // send as IPv4
                    struct in_addr host;
                    int host_len = sizeof(struct in_addr);

                    if (dns_pton(AF_INET, sa->host, &host) == -1) {
                        FATAL("IP parser error");
                    }
                    abuf->array[abuf->len++] = 1;
                    memcpy(abuf->array + abuf->len, &host, host_len);
                    abuf->len += host_len;
                } else if (ip.version == 6) {
                    // send as IPv6
                    struct in6_addr host;
                    int host_len = sizeof(struct in6_addr);

                    if (dns_pton(AF_INET6, sa->host, &host) == -1) {
                        FATAL("IP parser error");
                    }
                    abuf->array[abuf->len++] = 4;
                    memcpy(abuf->array + abuf->len, &host, host_len);
                    abuf->len += host_len;
                } else {
                    FATAL("IP parser error");
                }
            } else {
                // send as domain
                int host_len = strlen(sa->host);

                abuf->array[abuf->len++] = 3;
                abuf->array[abuf->len++] = host_len;
                memcpy(abuf->array + abuf->len, sa->host, host_len);
                abuf->len += host_len;
            }

            uint16_t port = htons(atoi(sa->port));
            memcpy(abuf->array + abuf->len, &port, 2);
            abuf->len += 2;

            if (auth) {
                abuf->array[0] |= ONETIMEAUTH_FLAG;
                ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE);
            }

            int err = ss_encrypt(abuf, server->e_ctx, BUF_SIZE);
            if (err) {
                bfree(abuf);
                LOGE("invalid password or cipher");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            int s = send(remote->fd, abuf->array, abuf->len, 0);

            bfree(abuf);

            if (s < abuf->len) {
                LOGE("failed to send addr");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            ev_io_start(EV_A_ & remote->recv_ctx->io);
            ev_io_start(EV_A_ & server->recv_ctx->io);

            return;
        } else {
            ERROR("getpeername");
            // not connected
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    } else {
        if (remote->buf->len == 0) {
            // close and free
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        } else {
            // has data to send
            ssize_t s = send(remote->fd, remote->buf->array + remote->buf->idx,
                             remote->buf->len, 0);
            if (s == -1) {
                if (errno != EAGAIN && errno != EWOULDBLOCK) {
                    ERROR("send");
                    // close and free
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                }
                return;
            } else if (s < remote->buf->len) {
                // partly sent, move memory, wait for the next time to send
                remote->buf->len -= s;
                remote->buf->idx += s;
                return;
            } else {
                // all sent out, wait for reading
                remote->buf->len = 0;
                remote->buf->idx = 0;
                ev_io_stop(EV_A_ & remote_send_ctx->io);
                ev_io_start(EV_A_ & server->recv_ctx->io);
            }
        }
    }
}
Ejemplo n.º 23
0
static void server_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct server_ctx *server_recv_ctx = (struct server_ctx *)w;
    struct server *server = server_recv_ctx->server;
    struct remote *remote = server->remote;
    char *buf;

    if (remote == NULL) {
        buf = server->buf;
    } else {
        buf = remote->buf;
    }

    ssize_t r;

    r = recv(server->fd, buf, BUF_SIZE, 0);

    if (r == 0) {
        // connection closed
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r < 0) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server_recv_cb_recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    while (1) {
        // local socks5 server
        if (server->stage == 5) {
            if (remote == NULL) {
                LOGE("invalid remote");
                close_and_free_server(EV_A_ server);
                return;
            }

            if (!remote->direct && remote->send_ctx->connected && auth) {
                remote->buf = ss_gen_hash(remote->buf, &r, &remote->counter, server->e_ctx, BUF_SIZE);
            }

            // insert shadowsocks header
            if (!remote->direct) {
                remote->buf = ss_encrypt(BUF_SIZE, remote->buf, &r,
                                         server->e_ctx);

                if (remote->buf == NULL) {
                    LOGE("invalid password or cipher");
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                    return;
                }
            }

            if (!remote->send_ctx->connected) {

#ifdef ANDROID
                if (vpn) {
                    if (protect_socket(remote->fd) == -1) {
                        ERROR("protect_socket");
                        close_and_free_remote(EV_A_ remote);
                        close_and_free_server(EV_A_ server);
                        return;
                    }
                }
#endif

                remote->buf_idx = 0;
                remote->buf_len = r;

                if (!fast_open || remote->direct) {
                    // connecting, wait until connected
                    connect(remote->fd, (struct sockaddr *)&(remote->addr), remote->addr_len);

                    // wait on remote connected event
                    ev_io_stop(EV_A_ & server_recv_ctx->io);
                    ev_io_start(EV_A_ & remote->send_ctx->io);
                    ev_timer_start(EV_A_ & remote->send_ctx->watcher);
                } else {
#ifdef TCP_FASTOPEN
                    int s = sendto(remote->fd, remote->buf, r, MSG_FASTOPEN,
                                   (struct sockaddr *)&(remote->addr), remote->addr_len);
                    if (s == -1) {
                        if (errno == EINPROGRESS) {
                            // in progress, wait until connected
                            remote->buf_idx = 0;
                            remote->buf_len = r;
                            ev_io_stop(EV_A_ & server_recv_ctx->io);
                            ev_io_start(EV_A_ & remote->send_ctx->io);
                            return;
                        } else {
                            ERROR("sendto");
                            if (errno == ENOTCONN) {
                                LOGE(
                                    "fast open is not supported on this platform");
                                // just turn it off
                                fast_open = 0;
                            }
                            close_and_free_remote(EV_A_ remote);
                            close_and_free_server(EV_A_ server);
                            return;
                        }
                    } else if (s < r) {
                        remote->buf_len = r - s;
                        remote->buf_idx = s;
                    }

                    // Just connected
                    remote->send_ctx->connected = 1;
                    ev_timer_stop(EV_A_ & remote->send_ctx->watcher);
                    ev_io_start(EV_A_ & remote->recv_ctx->io);
#else
                    // if TCP_FASTOPEN is not defined, fast_open will always be 0
                    LOGE("can't come here");
                    exit(1);
#endif
                }
            } else {
                int s = send(remote->fd, remote->buf, r, 0);
                if (s == -1) {
                    if (errno == EAGAIN || errno == EWOULDBLOCK) {
                        // no data, wait for send
                        remote->buf_idx = 0;
                        remote->buf_len = r;
                        ev_io_stop(EV_A_ & server_recv_ctx->io);
                        ev_io_start(EV_A_ & remote->send_ctx->io);
                        return;
                    } else {
                        ERROR("server_recv_cb_send");
                        close_and_free_remote(EV_A_ remote);
                        close_and_free_server(EV_A_ server);
                        return;
                    }
                } else if (s < r) {
                    remote->buf_len = r - s;
                    remote->buf_idx = s;
                    ev_io_stop(EV_A_ & server_recv_ctx->io);
                    ev_io_start(EV_A_ & remote->send_ctx->io);
                    return;
                }
            }

            // all processed
            return;
        } else if (server->stage == 0) {
            struct method_select_response response;
            response.ver = SVERSION;
            response.method = 0;
            char *send_buf = (char *)&response;
            send(server->fd, send_buf, sizeof(response), 0);
            server->stage = 1;
            return;
        } else if (server->stage == 1) {
            struct socks5_request *request = (struct socks5_request *)buf;

            struct sockaddr_in sock_addr;
            memset(&sock_addr, 0, sizeof(sock_addr));

            int udp_assc = 0;

            if (mode != TCP_ONLY && request->cmd == 3) {
                udp_assc = 1;
                socklen_t addr_len = sizeof(sock_addr);
                getsockname(server->fd, (struct sockaddr *)&sock_addr,
                            &addr_len);
                if (verbose) {
                    LOGI("udp assc request accepted");
                }
            } else if (request->cmd != 1) {
                LOGE("unsupported cmd: %d", request->cmd);
                struct socks5_response response;
                response.ver = SVERSION;
                response.rep = CMD_NOT_SUPPORTED;
                response.rsv = 0;
                response.atyp = 1;
                char *send_buf = (char *)&response;
                send(server->fd, send_buf, 4, 0);
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            } else {
                char host[256], port[16];
                char ss_addr_to_send[320];

                ssize_t addr_len = 0;
                ss_addr_to_send[addr_len++] = request->atyp;

                // get remote addr and port
                if (request->atyp == 1) {
                    // IP V4
                    size_t in_addr_len = sizeof(struct in_addr);
                    memcpy(ss_addr_to_send + addr_len, buf + 4, in_addr_len +
                           2);
                    addr_len += in_addr_len + 2;

                    if (acl || verbose) {
                        uint16_t p =
                            ntohs(*(uint16_t *)(buf + 4 + in_addr_len));
                        dns_ntop(AF_INET, (const void *)(buf + 4),
                                 host, INET_ADDRSTRLEN);
                        sprintf(port, "%d", p);
                    }
                } else if (request->atyp == 3) {
                    // Domain name
                    uint8_t name_len = *(uint8_t *)(buf + 4);
                    ss_addr_to_send[addr_len++] = name_len;
                    memcpy(ss_addr_to_send + addr_len, buf + 4 + 1, name_len +
                           2);
                    addr_len += name_len + 2;

                    if (acl || verbose) {
                        uint16_t p =
                            ntohs(*(uint16_t *)(buf + 4 + 1 + name_len));
                        memcpy(host, buf + 4 + 1, name_len);
                        host[name_len] = '\0';
                        sprintf(port, "%d", p);
                    }
                } else if (request->atyp == 4) {
                    // IP V6
                    size_t in6_addr_len = sizeof(struct in6_addr);
                    memcpy(ss_addr_to_send + addr_len, buf + 4, in6_addr_len +
                           2);
                    addr_len += in6_addr_len + 2;

                    if (acl || verbose) {
                        uint16_t p =
                            ntohs(*(uint16_t *)(buf + 4 + in6_addr_len));
                        dns_ntop(AF_INET6, (const void *)(buf + 4),
                                 host, INET6_ADDRSTRLEN);
                        sprintf(port, "%d", p);
                    }
                } else {
                    LOGE("unsupported addrtype: %d", request->atyp);
                    close_and_free_remote(EV_A_ remote);
                    close_and_free_server(EV_A_ server);
                    return;
                }

                server->stage = 5;

                r -= (3 + addr_len);
                buf += (3 + addr_len);

                if (verbose) {
                    LOGI("connect to %s:%s", host, port);
                }

                if ((acl && (request->atyp == 1 || request->atyp == 4) && acl_contains_ip(host))) {
                    if (verbose) {
                        LOGI("bypass %s:%s", host, port);
                    }
                    struct sockaddr_storage storage;
                    memset(&storage, 0, sizeof(struct sockaddr_storage));
                    if (get_sockaddr(host, port, &storage, 0) != -1) {
                        remote = create_remote(server->listener, (struct sockaddr *)&storage);
                        remote->direct = 1;
                    }
                } else {
                    remote = create_remote(server->listener, NULL);
                }

                if (remote == NULL) {
                    LOGE("invalid remote addr");
                    close_and_free_server(EV_A_ server);
                    return;
                }

                if (!remote->direct) {
                    if (auth) {
                        ss_addr_to_send[0] |= ONETIMEAUTH_FLAG;
                        ss_onetimeauth(ss_addr_to_send + addr_len, ss_addr_to_send, addr_len, server->e_ctx->evp.iv);
                        addr_len += ONETIMEAUTH_BYTES;
                    }

                    memcpy(remote->buf, ss_addr_to_send, addr_len);

                    if (r > 0) {
                        if (auth) {
                            buf = ss_gen_hash(buf, &r, &remote->counter, server->e_ctx, BUF_SIZE);
                        }
                        memcpy(remote->buf + addr_len, buf, r);
                    }
                    r += addr_len;
                } else {
                    if (r > 0) {
                        memcpy(remote->buf, buf, r);
                    }
                }

                server->remote = remote;
                remote->server = server;
            }

            // Fake reply
            struct socks5_response response;
            response.ver = SVERSION;
            response.rep = 0;
            response.rsv = 0;
            response.atyp = 1;

            memcpy(server->buf, &response, sizeof(struct socks5_response));
            memcpy(server->buf + sizeof(struct socks5_response),
                   &sock_addr.sin_addr, sizeof(sock_addr.sin_addr));
            memcpy(server->buf + sizeof(struct socks5_response) +
                   sizeof(sock_addr.sin_addr),
                   &sock_addr.sin_port, sizeof(sock_addr.sin_port));

            int reply_size = sizeof(struct socks5_response) +
                             sizeof(sock_addr.sin_addr) +
                             sizeof(sock_addr.sin_port);
            int s = send(server->fd, server->buf, reply_size, 0);
            if (s < reply_size) {
                LOGE("failed to send fake reply");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }

            if (udp_assc) {
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
                return;
            }
        }
    }
}
Ejemplo n.º 24
0
static void
recv_handler(struct ev_loop *loop, struct ev_io *watcher, int events) {
    //debug("recv_handler");

    size_t i;

    domain_t *domain = (domain_t *) watcher;
    ev_io_stop(loop, &domain->io);
    ev_timer_stop(loop, &domain->tw);


    //debug("recv_header %s -- data buffer:%p; data len: %d", domain->domain, domain->data.buffer + domain->data.len, domain->data.len);


    ssize_t len = readn(domain->io.fd, domain->data.buffer + domain->data.len, sizeof (domain->data.buffer) - domain->data.len);

    if (len <= 0) {
        if (EAGAIN == errno) { // сокет занят буфер кончился и прочее
            //err_ret("error read socket %s: ", domain->domain);
            ev_io_start(loop, &domain->io);
            ev_timer_start(loop, &domain->tw);
            return;
        } else { // жесткая ошибка
            err_ret("error read socket %s: ", domain->domain);
            free_domain(domain);
            return;
        }
    } else {

        domain->data.len += len;

        int pret = parse_response(domain);

        debug("parse_response %s:%d", domain->domain, pret);

        if (pret > 0) {

            switch (domain->http.status) {
                case 301:
                case 302:
                {

                    for (i = 0; i != domain->http.num_headers; ++i) {
                        if (NULL != memmem(domain->http.headers[i].name, domain->http.headers[i].name_len, "Location", 8)) {
                            follow_location(domain, domain->http.headers[i].value, domain->http.headers[i].value_len);
                            return;
                            //break;
                        }
                    }
                    break;
                }

                case 200:
                {
                    if (true == parse_body(&domain->data.buffer[pret], domain->data.len - pret)) {
                        success_checked(domain);
                    } else {

                        if (++domain->index_search < (sizeof (search_path) / sizeof (search_path[0]))) {
                            //ares_gethostbyname(domain->options->ares.channel, domain->domain, AF_INET, ev_ares_dns_callback, (void *) domain);
                            http_request(domain);
                            return;
                        }
                    }
                    break;
                }


            }
        } else {
            error_parse(domain);
        }
    }


    debug("-- %s %d checked", domain->domain, domain->http.status);
    free_domain(domain);
}
Ejemplo n.º 25
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;

    srand(time(NULL));

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

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

    opterr = 0;

    USE_TTY();

#ifdef ANDROID
    while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uvVA",
                            long_options, &option_index)) != -1) {
#else
    while ((c = getopt_long(argc, argv, "f:s:p:l:k:t:m:i:c:b:a:uvA",
                            long_options, &option_index)) != -1) {
#endif
        switch (c) {
        case 0:
            if (option_index == 0) {
                fast_open = 1;
            } else if (option_index == 1) {
                LOGI("initialize acl...");
                acl = !init_acl(optarg);
            }
            break;
        case 's':
            if (remote_num < MAX_REMOTE_NUM) {
                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':
            mode = TCP_AND_UDP;
            break;
        case 'v':
            verbose = 1;
            break;
        case 'A':
            auth = 1;
            break;
#ifdef ANDROID
        case 'V':
            vpn = 1;
            break;
#endif
        }
    }

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

    if (argc == 1) {
        if (conf_path == NULL) {
            conf_path = DEFAULT_CONF_PATH;
        }
    }
    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 (fast_open == 0) {
            fast_open = conf->fast_open;
        }
#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) {
                LOGI("setting NOFILE to %d", nofile);
            }
            set_nofile(nofile);
        }
#endif
    }

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

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

    if (local_addr == NULL) {
        local_addr = "127.0.0.1";
    }

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

    if (fast_open == 1) {
#ifdef TCP_FASTOPEN
        LOGI("using tcp fast open");
#else
        LOGE("tcp fast open is not supported by this environment");
#endif
    }

    if (auth) {
        LOGI("onetime authentication enabled");
    }

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

    struct ev_signal sigint_watcher;
    struct ev_signal sigterm_watcher;
    ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
    ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
    ev_signal_start(EV_DEFAULT, &sigint_watcher);
    ev_signal_start(EV_DEFAULT, &sigterm_watcher);

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

    // Setup proxy context
    struct listen_ctx listen_ctx;
    listen_ctx.remote_num = remote_num;
    listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *) * remote_num);
    for (i = 0; i < remote_num; i++) {
        char *host = remote_addr[i].host;
        char *port = remote_addr[i].port == NULL ? remote_port :
            remote_addr[i].port;
        struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage));
        memset(storage, 0, sizeof(struct sockaddr_storage));
        if (get_sockaddr(host, port, storage, 1) == -1) {
            FATAL("failed to resolve the provided hostname");
        }
        listen_ctx.remote_addr[i] = (struct sockaddr *)storage;
    }
    listen_ctx.timeout = atoi(timeout);
    listen_ctx.iface = iface;
    listen_ctx.method = m;

    struct ev_loop *loop = EV_DEFAULT;

    // 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);

    listen_ctx.fd = listenfd;

    ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
    ev_io_start(loop, &listen_ctx.io);

    // Setup UDP
    if (mode != TCP_ONLY) {
        LOGI("udprelay enabled");
        init_udprelay(local_addr, local_port, listen_ctx.remote_addr[0],
                      get_sockaddr_len(listen_ctx.remote_addr[0]), m, auth, listen_ctx.timeout, iface);
    }

    LOGI("listening at %s:%s", local_addr, local_port);

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

    // Init connections
    cork_dllist_init(&connections);

    // Enter the loop
    ev_run(loop, 0);

    if (verbose) {
        LOGI("closed gracefully");
    }

    // Clean up
    ev_io_stop(loop, &listen_ctx.io);
    free_connections(loop);

    if (mode != TCP_ONLY) {
        free_udprelay();
    }

    for (i = 0; i < remote_num; i++) {
        free(listen_ctx.remote_addr[i]);
    }
    free(listen_ctx.remote_addr);

#ifdef __MINGW32__
    winsock_cleanup();
#endif

    ev_signal_stop(EV_DEFAULT, &sigint_watcher);
    ev_signal_stop(EV_DEFAULT, &sigterm_watcher);

    return 0;
}

#else

int start_ss_local_server(profile_t profile)
{
    srand(time(NULL));

    char *remote_host = profile.remote_host;
    char *local_addr = profile.local_addr;
    char *method = profile.method;
    char *password = profile.password;
    char *log = profile.log;
    int remote_port = profile.remote_port;
    int local_port = profile.local_port;
    int timeout = profile.timeout;

    mode = profile.mode;
    fast_open = profile.fast_open;
    verbose = profile.verbose;

    char local_port_str[16];
    char remote_port_str[16];
    sprintf(local_port_str, "%d", local_port);
    sprintf(remote_port_str, "%d", remote_port);

    USE_LOGFILE(log);

    if (profile.acl != NULL) {
        acl = !init_acl(profile.acl);
    }

    if (local_addr == NULL) {
        local_addr = "127.0.0.1";
    }

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

    struct ev_signal sigint_watcher;
    struct ev_signal sigterm_watcher;
    ev_signal_init(&sigint_watcher, signal_cb, SIGINT);
    ev_signal_init(&sigterm_watcher, signal_cb, SIGTERM);
    ev_signal_start(EV_DEFAULT, &sigint_watcher);
    ev_signal_start(EV_DEFAULT, &sigterm_watcher);

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

    struct sockaddr_storage *storage = malloc(sizeof(struct sockaddr_storage));
    memset(storage, 0, sizeof(struct sockaddr_storage));
    if (get_sockaddr(remote_host, remote_port_str, storage, 1) == -1) {
        return -1;
    }

    // Setup proxy context
    struct ev_loop *loop = EV_DEFAULT;
    struct listen_ctx listen_ctx;

    listen_ctx.remote_num = 1;
    listen_ctx.remote_addr = malloc(sizeof(struct sockaddr *));
    listen_ctx.remote_addr[0] = (struct sockaddr *)storage;
    listen_ctx.timeout = timeout;
    listen_ctx.method = m;
    listen_ctx.iface = NULL;

    // Setup socket
    int listenfd;
    listenfd = create_and_bind(local_addr, local_port_str);
    if (listenfd < 0) {
        ERROR("bind()");
        return -1;
    }
    if (listen(listenfd, SOMAXCONN) == -1) {
        ERROR("listen()");
        return -1;
    }
    setnonblocking(listenfd);

    listen_ctx.fd = listenfd;

    ev_io_init(&listen_ctx.io, accept_cb, listenfd, EV_READ);
    ev_io_start(loop, &listen_ctx.io);

    // Setup UDP
    if (mode != TCP_ONLY) {
        LOGI("udprelay enabled");
        struct sockaddr *addr = (struct sockaddr *)storage;
        init_udprelay(local_addr, local_port_str, addr,
                      get_sockaddr_len(addr), m, auth, timeout, NULL);
    }

    LOGI("listening at %s:%s", local_addr, local_port_str);

    // Init connections
    cork_dllist_init(&connections);

    // Enter the loop
    ev_run(loop, 0);

    if (verbose) {
        LOGI("closed gracefully");
    }

    // Clean up
    if (mode != TCP_ONLY) {
        free_udprelay();
    }

    ev_io_stop(loop, &listen_ctx.io);
    free_connections(loop);
    close(listen_ctx.fd);

    free(listen_ctx.remote_addr);

#ifdef __MINGW32__
    winsock_cleanup();
#endif

    ev_signal_stop(EV_DEFAULT, &sigint_watcher);
    ev_signal_stop(EV_DEFAULT, &sigterm_watcher);

    // cannot reach here
    return 0;
}
Ejemplo n.º 26
0
/**
 * Initializes the networking interfaces
 * @arg config Takes the statsite_proxy server configuration
 * @arg netconf Output. The configuration for the networking stack.
 * @arg proxy Pointer to proxy for routing metrics via consistent hashing
 */
int init_networking(statsite_proxy_config *config, statsite_proxy_networking **netconf_out, proxy *proxy) {
    // Make the netconf structure
    statsite_proxy_networking *netconf = calloc(1, sizeof(struct statsite_proxy_networking));

    // Initialize
    netconf->events = NULL;
    netconf->config = config;
    netconf->proxy = proxy;
    netconf->should_run = 1;
    netconf->thread = NULL;

    /**
     * Check if we can use kqueue instead of select.
     * By default, libev will not use kqueue since it only
     * works for sockets, which is all we need.
     */
    int ev_mode = EVFLAG_AUTO;
    if (ev_supported_backends () & ~ev_recommended_backends () & EVBACKEND_KQUEUE) {
        ev_mode = EVBACKEND_KQUEUE;
    }

    if (!ev_default_loop (ev_mode)) {
        syslog(LOG_CRIT, "Failed to initialize libev!");
        free(netconf);
        return 1;
    }

    // Setup proxy connections
    int proxy_res = setup_proxy_connections(netconf);
    if (proxy_res != 0) {
    	// free proxy connections stuff
    	free(netconf);
    	return 1;
    }

    // Setup the TCP listener
    int res = setup_tcp_listener(netconf);
    if (res != 0) {
        free(netconf);
        return 1;
    }

    // Setup the UDP listener
    res = setup_udp_listener(netconf);
    if (res != 0) {
        ev_io_stop(&netconf->tcp_client);
        close(netconf->tcp_client.fd);
        free(netconf);
        return 1;
    }

    // Setup the async handler
    ev_async_init(&netconf->loop_async, handle_async_event);
    ev_async_start(&netconf->loop_async);

    // Prepare the conn handlers
    init_conn_handler(config);

    // Success!
    *netconf_out = netconf;
    return 0;
}
Ejemplo n.º 27
0
static void server_recv_cb(EV_P_ ev_io *w, int revents)
{
    struct server_ctx *server_recv_ctx = (struct server_ctx *)w;
    struct server *server = server_recv_ctx->server;
    struct remote *remote = NULL;

    int len = server->buf_len;
    char **buf = &server->buf;

    ev_timer_again(EV_A_ & server->recv_ctx->watcher);

    if (server->stage != 0) {
        remote = server->remote;
        buf = &remote->buf;
        len = 0;
    }

    ssize_t r = recv(server->fd, *buf + len, BUF_SIZE - len, 0);

    if (r == 0) {
        // connection closed
        if (verbose) {
            LOGI("server_recv close the connection");
        }
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else if (r == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // no data
            // continue to wait for recv
            return;
        } else {
            ERROR("server recv");
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    // handle incomplete header
    if (server->stage == 0) {
        r += server->buf_len;
        if (r <= enc_get_iv_len()) {
            // wait for more
            if (verbose) {
#ifdef __MINGW32__
                LOGI("imcomplete header: %u", r);
#else
                LOGI("imcomplete header: %zu", r);
#endif
            }
            server->buf_len = r;
            return;
        } else {
            server->buf_len = 0;
        }
    }

    *buf = ss_decrypt(BUF_SIZE, *buf, &r, server->d_ctx);

    if (*buf == NULL) {
        LOGE("invalid password or cipher");
        report_addr(server->fd);
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    }

    // handshake and transmit data
    if (server->stage == 5) {
        int s = send(remote->fd, remote->buf, r, 0);
        if (s == -1) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // no data, wait for send
                remote->buf_len = r;
                remote->buf_idx = 0;
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            } else {
                ERROR("server_recv_send");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
        } else if (s < r) {
            remote->buf_len = r - s;
            remote->buf_idx = s;
            ev_io_stop(EV_A_ & server_recv_ctx->io);
            ev_io_start(EV_A_ & remote->send_ctx->io);
        }
        return;

    } else if (server->stage == 0) {

        /*
         * Shadowsocks Protocol:
         *
         *    +------+----------+----------+
         *    | ATYP | DST.ADDR | DST.PORT |
         *    +------+----------+----------+
         *    |  1   | Variable |    2     |
         *    +------+----------+----------+
         */

        int offset = 1;
        int need_query = 0;
        char atyp = server->buf[0] & 0x0F;
#ifdef USE_CRYPTO_OPENSSL
        char atyp_btc = (server->buf[0] & 0x10) == 0x10 ? 1 : 0;
#endif
        char host[256] = { 0 };
        uint16_t port = 0;
        struct addrinfo info;
        struct sockaddr_storage storage;
        memset(&info, 0, sizeof(struct addrinfo));
        memset(&storage, 0, sizeof(struct sockaddr_storage));

        // get remote addr and port
        if (atyp == 1) {
            // IP V4
            struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
            size_t in_addr_len = sizeof(struct in_addr);
            addr->sin_family = AF_INET;
            if (r > in_addr_len) {
                addr->sin_addr = *(struct in_addr *)(server->buf + offset);
                dns_ntop(AF_INET, (const void *)(server->buf + offset),
                         host, INET_ADDRSTRLEN);
                offset += in_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in);
            info.ai_addr = (struct sockaddr *)addr;
        } else if (atyp == 3) {
            // Domain name
            uint8_t name_len = *(uint8_t *)(server->buf + offset);
            if (name_len < r && name_len < 255 && name_len > 0) {
                memcpy(host, server->buf + offset + 1, name_len);
                offset += name_len + 1;
            }
            struct cork_ip ip;
            if (cork_ip_init(&ip, host) != -1) {
                info.ai_socktype = SOCK_STREAM;
                info.ai_protocol = IPPROTO_TCP;
                if (ip.version == 4) {
                    struct sockaddr_in *addr = (struct sockaddr_in *)&storage;
                    dns_pton(AF_INET, host, &(addr->sin_addr));
                    addr->sin_port = *(uint16_t *)(server->buf + offset);
                    addr->sin_family = AF_INET;
                    info.ai_family = AF_INET;
                    info.ai_addrlen = sizeof(struct sockaddr_in);
                    info.ai_addr = (struct sockaddr *)addr;
                } else if (ip.version == 6) {
                    struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
                    dns_pton(AF_INET6, host, &(addr->sin6_addr));
                    addr->sin6_port = *(uint16_t *)(server->buf + offset);
                    addr->sin6_family = AF_INET6;
                    info.ai_family = AF_INET6;
                    info.ai_addrlen = sizeof(struct sockaddr_in6);
                    info.ai_addr = (struct sockaddr *)addr;
                }
            } else {
                need_query = 1;
            }
        } else if (atyp == 4) {
            // IP V6
            struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&storage;
            size_t in6_addr_len = sizeof(struct in6_addr);
            addr->sin6_family = AF_INET6;
            if (r > in6_addr_len) {
                addr->sin6_addr = *(struct in6_addr *)(server->buf + offset);
                dns_ntop(AF_INET6, (const void *)(server->buf + offset),
                         host, INET6_ADDRSTRLEN);
                offset += in6_addr_len;
            } else {
                LOGE("invalid header with addr type %d", atyp);
                report_addr(server->fd);
                close_and_free_server(EV_A_ server);
                return;
            }
            addr->sin6_port = *(uint16_t *)(server->buf + offset);
            info.ai_family = AF_INET6;
            info.ai_socktype = SOCK_STREAM;
            info.ai_protocol = IPPROTO_TCP;
            info.ai_addrlen = sizeof(struct sockaddr_in6);
            info.ai_addr = (struct sockaddr *)addr;
        }

        if (offset == 1) {
            LOGE("invalid header with addr type %d", atyp);
            report_addr(server->fd);
            close_and_free_server(EV_A_ server);
            return;
        }

        if (acl && !need_query && acl_contains_ip(host)) {
            if (verbose) {
                LOGI("Access denied to %s", host);
            }
            close_and_free_server(EV_A_ server);
            return;
        }

        port = (*(uint16_t *)(server->buf + offset));

        offset += 2;

        if (verbose) {
            LOGI("connect to: %s:%d", host, ntohs(port));
        }

#ifdef USE_CRYPTO_OPENSSL
        if (bitcoin_list != NULL) {
            if (atyp_btc == 0) {
                if (verbose) {
                    LOGE("client should carry with bitcoin information");
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            /*
             * bitcoin information:
             *    +-----------+-----------+----------+
             *    | Signature | Timestamp |  Address |
             *    +-----------+-----------+----------+
             *    |    65     |     4     |  String  |
             *    +-----------+-----------+----------+
             */
            char *signature = server->buf + offset;
            uint8_t *t = (uint8_t *)server->buf + offset + 65;
            uint32_t ts = ((uint32_t)*(t + 0) << 24) + ((uint32_t)*(t + 1) << 16)
                          + ((uint32_t)*(t + 2) << 8) + ((uint32_t)*(t + 3) << 0);
            char *address = server->buf + offset + 65 + 4;
            int64_t ts_offset = (int64_t)time(NULL) - (int64_t)ts;
            if (labs(ts_offset) > 60 * 30) {
                if (verbose) {
                    LOGE("invalid timestamp: %u, offset too large: %d",
                         ts, (int32_t)ts_offset);
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            if (!bitcoin_verify_message(address, (uint8_t *)signature, t, 4)) {
                if (verbose) {
                    LOGE("invalid signature, address: %s", address);
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            if (bitcoin_check_address(bitcoin_list, address) == 0) {
                if (verbose) {
                    LOGE("address \"%s\" is NOT in list", address);
                }
                close_and_free_server(EV_A_ server);
                return;
            }
            offset += 65 + 4 + strlen(address) + 1;

            if (verbose) {
                LOGI("bitcoin address: %s, time offset: %d",
                     address, (int32_t)ts_offset);
            }
        }
#endif

        // XXX: should handle buffer carefully
        if (r > offset) {
            server->buf_len = r - offset;
            server->buf_idx = offset;
        }

        if (!need_query) {
            struct remote *remote = connect_to_remote(&info, server);

            if (remote == NULL) {
                LOGE("connect error");
                close_and_free_server(EV_A_ server);
                return;
            } else {
                server->remote = remote;
                remote->server = server;

                // XXX: should handle buffer carefully
                if (server->buf_len > 0) {
                    memcpy(remote->buf, server->buf + server->buf_idx,
                           server->buf_len);
                    remote->buf_len = server->buf_len;
                    remote->buf_idx = 0;
                    server->buf_len = 0;
                    server->buf_idx = 0;
                }

                server->stage = 4;

                // listen to remote connected event
                ev_io_stop(EV_A_ & server_recv_ctx->io);
                ev_io_start(EV_A_ & remote->send_ctx->io);
            }
        } else {
            server->stage = 4;
            server->query = resolv_query(host, server_resolve_cb, NULL, server,
                                         port);

            ev_io_stop(EV_A_ & server_recv_ctx->io);
        }

        return;
    }
    // should not reach here
    FATAL("server context error");
}
Ejemplo n.º 28
0
void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
  uv_async_t* async;
  uv_timer_t* timer;
  uv_stream_t* stream;
  uv_process_t* process;

  handle->close_cb = close_cb;

  switch (handle->type) {
    case UV_NAMED_PIPE:
      uv_pipe_cleanup((uv_pipe_t*)handle);
      /* Fall through. */

    case UV_TTY:
    case UV_TCP:
      stream = (uv_stream_t*)handle;

      uv_read_stop(stream);
      ev_io_stop(stream->loop->ev, &stream->write_watcher);

      uv__close(stream->fd);
      stream->fd = -1;

      if (stream->accepted_fd >= 0) {
        uv__close(stream->accepted_fd);
        stream->accepted_fd = -1;
      }

      assert(!ev_is_active(&stream->read_watcher));
      assert(!ev_is_active(&stream->write_watcher));
      break;

    case UV_UDP:
      uv__udp_start_close((uv_udp_t*)handle);
      break;

    case UV_PREPARE:
      uv_prepare_stop((uv_prepare_t*) handle);
      break;

    case UV_CHECK:
      uv_check_stop((uv_check_t*) handle);
      break;

    case UV_IDLE:
      uv_idle_stop((uv_idle_t*) handle);
      break;

    case UV_ASYNC:
      async = (uv_async_t*)handle;
      ev_async_stop(async->loop->ev, &async->async_watcher);
      ev_ref(async->loop->ev);
      break;

    case UV_TIMER:
      timer = (uv_timer_t*)handle;
      if (ev_is_active(&timer->timer_watcher)) {
        ev_ref(timer->loop->ev);
      }
      ev_timer_stop(timer->loop->ev, &timer->timer_watcher);
      break;

    case UV_PROCESS:
      process = (uv_process_t*)handle;
      ev_child_stop(process->loop->ev, &process->child_watcher);
      break;

    case UV_FS_EVENT:
      uv__fs_event_destroy((uv_fs_event_t*)handle);
      break;

    default:
      assert(0);
  }

  handle->flags |= UV_CLOSING;

  /* This is used to call the on_close callback in the next loop. */
  ev_idle_start(handle->loop->ev, &handle->next_watcher);
  ev_feed_event(handle->loop->ev, &handle->next_watcher, EV_IDLE);
  assert(ev_is_pending(&handle->next_watcher));
}
Ejemplo n.º 29
0
static void remote_send_cb(EV_P_ ev_io *w, int revents)
{
    struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w;
    struct remote *remote = remote_send_ctx->remote;
    struct server *server = remote->server;

    if (server == NULL) {
        LOGE("invalid server");
        close_and_free_remote(EV_A_ remote);
        return;
    }

    if (!remote_send_ctx->connected) {

        struct sockaddr_storage addr;
        socklen_t len = sizeof addr;
        memset(&addr, 0, len);
        int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len);
        if (r == 0) {
            if (verbose) {
                LOGI("remote connected");
            }
            remote_send_ctx->connected = 1;

            if (remote->buf_len == 0) {
                server->stage = 5;
                ev_io_stop(EV_A_ & remote_send_ctx->io);
                ev_io_start(EV_A_ & server->recv_ctx->io);
                ev_io_start(EV_A_ & remote->recv_ctx->io);
                return;
            }

        } else {
            ERROR("getpeername");
            // not connected
            close_and_free_remote(EV_A_ remote);
            close_and_free_server(EV_A_ server);
            return;
        }
    }

    if (remote->buf_len == 0) {
        // close and free
        if (verbose) {
            LOGI("remote_send close the connection");
        }
        close_and_free_remote(EV_A_ remote);
        close_and_free_server(EV_A_ server);
        return;
    } else {
        // has data to send
        ssize_t s = send(remote->fd, remote->buf + remote->buf_idx,
                         remote->buf_len, 0);
        if (s == -1) {
            if (errno != EAGAIN && errno != EWOULDBLOCK) {
                ERROR("remote_send_send");
                // close and free
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
            return;
        } else if (s < remote->buf_len) {
            // partly sent, move memory, wait for the next time to send
            remote->buf_len -= s;
            remote->buf_idx += s;
            return;
        } else {
            // all sent out, wait for reading
            remote->buf_len = 0;
            remote->buf_idx = 0;
            ev_io_stop(EV_A_ & remote_send_ctx->io);
            if (server != NULL) {
                ev_io_start(EV_A_ & server->recv_ctx->io);
                if (server->stage == 4) {
                    server->stage = 5;
                    ev_io_start(EV_A_ & remote->recv_ctx->io);
                }
            } else {
                LOGE("invalid server");
                close_and_free_remote(EV_A_ remote);
                close_and_free_server(EV_A_ server);
            }
            return;
        }
    }
}
Ejemplo n.º 30
0
static void socks5_send_cb(EV_P_ ev_io *w, int revents)
{
	ctx_t *ctx = (ctx_t *)(w->data);

	UNUSED(revents);
	assert(ctx != NULL);

	ev_io_stop(EV_A_ w);

	ssize_t n = send(ctx->sock, ctx->buf, ctx->len, MSG_NOSIGNAL);
	if (n != ctx->len)
	{
		if (n < 0)
		{
			ERROR("send");
		}
		close(ctx->sock);
		free(ctx);
		return;
	}

	switch (ctx->state)
	{
	case HELLO_RCVD:
	case HELLO_ERR:
	{
		if (ctx->state == HELLO_RCVD)
		{
			ctx->state = HELLO_SENT;
			ev_io_start(EV_A_ &(ctx->w_read));
		}
		else
		{
			close(ctx->sock);
			free(ctx);
		}
		break;
	}
	case REQ_RCVD:
	case REQ_ERR:
	{
		if (ctx->state == REQ_RCVD)
		{
			(ctx->cb)(ctx->sock, ctx->host, ctx->port);
			free(ctx);
		}
		else
		{
			close(ctx->sock);
			free(ctx);
		}
		break;
	}
	default:
	{
		// 不应该来到这里
		assert(0 != 0);
		break;
	}
	}
}