コード例 #1
0
ファイル: local.c プロジェクト: MYJN/shadowsocks-libev
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;
    buffer_t *buf;

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

    ssize_t r;

    r = recv(server->fd, 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 < 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;
        }
    }

    buf->len = r;

    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) {
                ss_gen_hash(remote->buf, &remote->counter, server->e_ctx);
            }

            // insert shadowsocks header
            if (!remote->direct) {
                // SSR beg
                if (server->protocol_plugin) {
                    obfs_class *protocol_plugin = server->protocol_plugin;
                    if (protocol_plugin->client_pre_encrypt) {
                        remote->buf->len = protocol_plugin->client_pre_encrypt(server->protocol, &remote->buf->array, remote->buf->len, &remote->buf->capacity);
                    }
                }
                int err = ss_encrypt(remote->buf, server->e_ctx);

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

                if (server->obfs_plugin) {
                    obfs_class *obfs_plugin = server->obfs_plugin;
                    if (obfs_plugin->client_encode) {
                        remote->buf->len = obfs_plugin->client_encode(server->obfs, &remote->buf->array, remote->buf->len, &remote->buf->capacity);
                    }
                }
                // SSR end
#ifdef ANDROID
                tx += r;
#endif
            }

            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;

                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
#ifdef __APPLE__
                    ((struct sockaddr_in*)&(remote->addr))->sin_len = sizeof(struct sockaddr_in);
                    sa_endpoints_t endpoints;
                    bzero((char*)&endpoints, sizeof(endpoints));
                    endpoints.sae_dstaddr = (struct sockaddr*)&(remote->addr);
                    endpoints.sae_dstaddrlen = remote->addr_len;

                    int s = connectx(remote->fd, &endpoints, SAE_ASSOCID_ANY,
                            CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
                            NULL, 0, NULL, NULL);
                    if (s == 0) {
                        s = send(remote->fd, remote->buf->array, remote->buf->len, 0);
                    }
#else
                    int s = sendto(remote->fd, remote->buf->array, remote->buf->len, MSG_FASTOPEN,
                                   (struct sockaddr *)&(remote->addr), remote->addr_len);
#endif
                    if (s == -1) {
                        if (errno == EINPROGRESS) {
                            // in progress, wait until connected
                            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("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 <= remote->buf->len) {
                        remote->buf->len -= 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->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("server_recv_cb_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;
                }
            }

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

            int off = (buf->array[1] & 0xff) + 2;
            if (buf->array[0] == 0x05 && off < buf->len) {
                memmove(buf->array, buf->array + off, buf->len - off);
                buf->len -= off;
                continue;
            }

            return;
        } else if (server->stage == 1) {
            struct socks5_request *request = (struct socks5_request *)buf->array;

            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];

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

                abuf->array[abuf->len++] = request->atyp;

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

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

                    if (acl || verbose) {
                        uint16_t p =
                            ntohs(*(uint16_t *)(buf->array + 4 + 1 + name_len));
                        memcpy(host, buf->array + 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(abuf->array + abuf->len, buf->array + 4, in6_addr_len + 2);
                    abuf->len += in6_addr_len + 2;

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

                server->stage = 5;

                buf->len -= (3 + abuf->len);
                if (buf->len > 0) {
                    memmove(buf->array, buf->array + 3 + abuf->len, buf->len);
                }

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

                if ((acl && (request->atyp == 1 || request->atyp == 4) && acl_match_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) {
                    bfree(abuf);
                    LOGE("invalid remote addr");
                    close_and_free_server(EV_A_ server);
                    return;
                }

                // SSR beg
                if (server->listener->list_obfs_global[remote->remote_index] == NULL && server->obfs_plugin) {
                    server->listener->list_obfs_global[remote->remote_index] = server->obfs_plugin->init_data();
                }
                if (server->listener->list_protocol_global[remote->remote_index] == NULL && server->protocol_plugin) {
                    server->listener->list_protocol_global[remote->remote_index] = server->protocol_plugin->init_data();
                }

                server_info _server_info;
                memset(&_server_info, 0, sizeof(server_info));
                strcpy(_server_info.host, inet_ntoa(((struct sockaddr_in*)&remote->addr)->sin_addr));
                _server_info.port = ((struct sockaddr_in*)&remote->addr)->sin_port;
                _server_info.port = _server_info.port >> 8 | _server_info.port << 8;
                _server_info.param = server->listener->obfs_param;
                _server_info.g_data = server->listener->list_obfs_global[remote->remote_index];
                _server_info.head_len = get_head_size(ss_addr_to_send.array, 320, 30);
                _server_info.iv = server->e_ctx->evp.iv;
                _server_info.iv_len = enc_get_iv_len();
                _server_info.key = enc_get_key();
                _server_info.key_len = enc_get_key_len();
                _server_info.tcp_mss = 1440;

                if (server->obfs_plugin)
                    server->obfs_plugin->set_server_info(server->obfs, &_server_info);

                _server_info.param = NULL;
                _server_info.g_data = server->listener->list_protocol_global[remote->remote_index];

                if (server->protocol_plugin)
                    server->protocol_plugin->set_server_info(server->protocol, &_server_info);
                // SSR end

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

                    brealloc(remote->buf, buf->len + abuf->len, BUF_SIZE);
                    memcpy(remote->buf->array, abuf->array, abuf->len);
                    remote->buf->len = buf->len + abuf->len;

                    if (buf->len > 0) {
                        if (auth) {
                            ss_gen_hash(buf, &remote->counter, server->e_ctx);
                        }
                        memcpy(remote->buf->array + abuf->len, buf->array, buf->len);
                    }
                } else {
                    if (buf->len > 0) {
                        memcpy(remote->buf->array, buf->array, buf->len);
                        remote->buf->len = buf->len;
                    }
                }

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

                bfree(abuf);
            }

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

            memcpy(server->buf->array, &response, sizeof(struct socks5_response));
            memcpy(server->buf->array + sizeof(struct socks5_response),
                   &sock_addr.sin_addr, sizeof(sock_addr.sin_addr));
            memcpy(server->buf->array + 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->array, 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;
            }
        }
    }
}
コード例 #2
0
ファイル: udprelay.c プロジェクト: CalixHu/shadowsocksr-libev
int
init_udprelay(const char *server_host, const char *server_port,
#ifdef MODULE_LOCAL
              const struct sockaddr *remote_addr, const int remote_addr_len,
              const ss_addr_t tunnel_addr,
#endif
              int mtu, int timeout, const char *iface,
              cipher_env_t* cipher_env, const char *protocol, const char *protocol_param)
{
    // Initialize ev loop
    struct ev_loop *loop = EV_DEFAULT;

    // Initialize MTU
    if (mtu > 0) {
        packet_size = mtu - 1 - 28 - 2 - 64;
        buf_size    = packet_size * 2;
    }

    // Initialize cache
    struct cache *conn_cache;
    cache_create(&conn_cache, MAX_UDP_CONN_NUM, free_cb);

    // ////////////////////////////////////////////////
    // Setup server context

    // Bind to port
    int serverfd = create_server_socket(server_host, server_port);
    if (serverfd < 0) {
        FATAL("[udp] bind() error");
    }
    setnonblocking(serverfd);

    server_ctx_t *server_ctx = new_server_ctx(serverfd);

    server_ctx->cipher_env = cipher_env;
#ifdef MODULE_REMOTE
    server_ctx->loop = loop;
#endif
    server_ctx->timeout    = max(timeout, MIN_UDP_TIMEOUT);
    server_ctx->iface      = iface;
    server_ctx->conn_cache = conn_cache;
#ifdef MODULE_LOCAL
    server_ctx->remote_addr     = remote_addr;
    server_ctx->remote_addr_len = remote_addr_len;
    //SSR beg
    server_ctx->protocol_plugin = new_obfs_class((char *)protocol);
    if (server_ctx->protocol_plugin) {
        server_ctx->protocol = server_ctx->protocol_plugin->new_obfs();
        server_ctx->protocol_global = server_ctx->protocol_plugin->init_data();
    }

    server_info _server_info;
    memset(&_server_info, 0, sizeof(server_info));
    strcpy(_server_info.host, server_host);
    _server_info.port = atoi(server_port);
    _server_info.g_data = server_ctx->protocol_global;
    _server_info.param = (char *)protocol_param;
    _server_info.key = enc_get_key(cipher_env);
    _server_info.key_len = enc_get_key_len(cipher_env);

    if (server_ctx->protocol_plugin)
        server_ctx->protocol_plugin->set_server_info(server_ctx->protocol, &_server_info);
    //SSR end
    server_ctx->tunnel_addr = tunnel_addr;
#endif

    ev_io_start(loop, &server_ctx->io);

    server_ctx_list[server_num++] = server_ctx;

    return 0;
}