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) { 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 = 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 == 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) { 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 == 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)); } // 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"); }
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; } } } }
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"); }
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"); }
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) { LOGD("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) { LOGD("imcomplete header: %zu", r); } 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"); 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 = 0; char atyp = server->buf[offset++]; char host[256] = {0}; char port[64] = {0}; // get remote addr and port if (atyp == 1) { // IP V4 size_t in_addr_len = sizeof(struct in_addr); if (r > in_addr_len) { inet_ntop(AF_INET, (const void *)(server->buf + offset), host, INET_ADDRSTRLEN); offset += in_addr_len; } } 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; } } else if (atyp == 4) { // IP V6 size_t in6_addr_len = sizeof(struct in6_addr); if (r > in6_addr_len) { inet_ntop(AF_INET6, (const void*)(server->buf + offset), host, INET6_ADDRSTRLEN); offset += in6_addr_len; } } if (offset == 1) { LOGE("invalid header with addr type %d", atyp); close_and_free_server(EV_A_ server); return; } sprintf(port, "%d", ntohs(*(uint16_t *)(server->buf + offset))); offset += 2; if (verbose) { LOGD("connect to: %s:%s", host, port); } struct addrinfo hints; asyncns_query_t *query; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; query = asyncns_getaddrinfo(server->listen_ctx->asyncns, host, port, &hints); if (query == NULL) { ERROR("asyncns_getaddrinfo"); close_and_free_server(EV_A_ server); return; } asyncns_setuserdata(server->listen_ctx->asyncns, query, server); // XXX: should handle buffer carefully if (r > offset) { server->buf_len = r - offset; server->buf_idx = offset; } server->stage = 4; server->query = query; ev_io_stop(EV_A_ &server_recv_ctx->io); return; } // should not reach here FATAL("server context error."); }