static void listener_event_func(int _fd, unsigned ev, void* _l) { alistener* listener = reinterpret_cast<alistener*>(_l); asocket *s; if (ev & FDE_READ) { sockaddr_storage ss; sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss); socklen_t alen; int fd; alen = sizeof(ss); fd = adb_socket_accept(_fd, addrp, &alen); if (fd < 0) { return; } s = create_local_socket(fd); if (s) { s->transport = listener->transport; connect_to_remote(s, listener->connect_to.c_str()); return; } adb_close(fd); } }
void client_accept_cb(uv_stream_t *server, int status) { struct client_context *client = new_client(); struct remote_context *remote = new_remote(idle_timeout); client->remote = remote; remote->client = client; uv_timer_init(server->loop, remote->timer); uv_tcp_init(server->loop, &client->handle.tcp); uv_tcp_init(server->loop, &remote->handle.tcp); int rc = uv_accept(server, &client->handle.stream); if (rc == 0) { int namelen = sizeof client->addr; uv_tcp_getpeername(&client->handle.tcp, &client->addr, &namelen); reset_timer(remote); // start timer connect_to_remote(remote); } else { logger_log(LOG_ERR, "accept error: %s", uv_strerror(rc)); close_client(client); close_remote(remote); } }
void listener_event_func(int _fd, unsigned ev, void* _l) { alistener* listener = reinterpret_cast<alistener*>(_l); asocket *s; if (ev & FDE_READ) { struct sockaddr addr; socklen_t alen; int fd; alen = sizeof(addr); fd = adb_socket_accept(_fd, &addr, &alen); if (fd < 0) { return; } s = create_local_socket(fd); if (s) { s->transport = listener->transport; connect_to_remote(s, listener->connect_to); return; } adb_close(fd); } }
static void listener_event_func(int _fd, unsigned ev, void *_l) { alistener *l = _l; asocket *s; if(ev & FDE_READ) { struct sockaddr addr; socklen_t alen; int fd; alen = sizeof(addr); fd = adb_socket_accept(_fd, &addr, &alen); if(fd < 0) return; s = create_local_socket(fd); if(s) { s->transport = l->transport; connect_to_remote(s, l->connect_to); return; } D("listener_event_func adb_close \n"); XLOGD("listener_event_func adb_close \n"); adb_close(fd); } }
static void server_resolve_cb(struct sockaddr *addr, void *data) { struct server *server = (struct server *)data; struct ev_loop *loop = server->listen_ctx->loop; server->query = NULL; if (verbose) { LOGI("udns resolved"); } if (addr == NULL) { LOGE("unable to resolve"); close_and_free_server(EV_A_ server); } else { struct addrinfo info; memset(&info, 0, sizeof(struct addrinfo)); info.ai_socktype = SOCK_STREAM; info.ai_protocol = IPPROTO_TCP; info.ai_addr = addr; if (addr->sa_family == AF_INET) { info.ai_family = AF_INET; info.ai_addrlen = sizeof(struct sockaddr_in); } else if (addr->sa_family == AF_INET6) { info.ai_family = AF_INET6; info.ai_addrlen = sizeof(struct sockaddr_in6); } struct remote *remote = connect_to_remote(&info, server); if (remote == NULL) { LOGE("connect error"); close_and_free_server(EV_A_ server); } 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; } // listen to remote connected event ev_io_start(EV_A_ & remote->send_ctx->io); } } }
static void resolve_cb(struct sockaddr *addr, void *data) { struct remote_context *remote = data; if (addr == NULL) { logger_log(LOG_ERR, "resolve %s failed: %s", remote->client->target_addr, resolver_lasterror(remote->host_query)); remote->stage = XSTAGE_TERMINATE; close_client(remote->client); close_remote(remote); } else { if (verbose) { logger_log(LOG_INFO, "connect to %s", remote->client->target_addr); } remote->addr = *addr; connect_to_remote(remote); } }
static void listener_event_func(int _fd, unsigned ev, void* _l) { alistener* listener = reinterpret_cast<alistener*>(_l); asocket *s; if (ev & FDE_READ) { int fd = adb_socket_accept(_fd, nullptr, nullptr); if (fd < 0) { return; } s = create_local_socket(fd); if (s) { s->transport = listener->transport; connect_to_remote(s, listener->connect_to.c_str()); return; } adb_close(fd); } }
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 = 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; } // 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) { remote->buf_idx = 0; remote->buf_len = r; if (!fast_open || remote->direct) { // connecting, wait until connected connect(remote->fd, remote->addr_info->ai_addr, remote->addr_info->ai_addrlen); // 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, remote->addr_info->ai_addr, remote->addr_info->ai_addrlen); 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 (udprelay && request->cmd == 3) { udp_assc = 1; socklen_t addr_len = sizeof(sock_addr); getsockname(server->fd, (struct sockaddr *)&sock_addr, &addr_len); if (verbose) { LOGD("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 *ss_addr_to_send = malloc(BUF_SIZE); ssize_t addr_len = 0; ss_addr_to_send[addr_len++] = request->atyp; char host[256], port[16]; // 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)); inet_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)); inet_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) { LOGD("connect to %s:%s", host, port); } if ((acl && request->atyp == 1 && acl_contains_ip(host)) || (acl && request->atyp == 3 && acl_contains_domain(host))) { remote = connect_to_remote(server->listener, host, port); remote->direct = 1; if (verbose) { LOGD("bypass %s:%s", host, port); } } else { remote = connect_to_remote(server->listener, NULL, NULL); } if (remote == NULL) { LOGE("invalid remote addr."); close_and_free_server(EV_A_ server); return; } if (!remote->direct) { memcpy(remote->buf, ss_addr_to_send, addr_len); if (r > 0) { 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; } } } }
static int smart_socket_enqueue(asocket* s, apacket* p) { unsigned len; #if ADB_HOST char* service = nullptr; char* serial = nullptr; TransportId transport_id = 0; TransportType type = kTransportAny; #endif D("SS(%d): enqueue %zu", s->id, p->len); if (s->pkt_first == 0) { s->pkt_first = p; s->pkt_last = p; } else { if ((s->pkt_first->len + p->len) > s->get_max_payload()) { D("SS(%d): overflow", s->id); put_apacket(p); goto fail; } memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len); s->pkt_first->len += p->len; put_apacket(p); p = s->pkt_first; } /* don't bother if we can't decode the length */ if (p->len < 4) { return 0; } len = unhex(p->data, 4); if ((len < 1) || (len > MAX_PAYLOAD)) { D("SS(%d): bad size (%d)", s->id, len); goto fail; } D("SS(%d): len is %d", s->id, len); /* can't do anything until we have the full header */ if ((len + 4) > p->len) { D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - p->len); return 0; } p->data[len + 4] = 0; D("SS(%d): '%s'", s->id, (char*)(p->data + 4)); #if ADB_HOST service = (char*)p->data + 4; if (!strncmp(service, "host-serial:", strlen("host-serial:"))) { char* serial_end; service += strlen("host-serial:"); // serial number should follow "host:" and could be a host:port string. serial_end = internal::skip_host_serial(service); if (serial_end) { *serial_end = 0; // terminate string serial = service; service = serial_end + 1; } } else if (!strncmp(service, "host-transport-id:", strlen("host-transport-id:"))) { service += strlen("host-transport-id:"); transport_id = strtoll(service, &service, 10); if (*service != ':') { return -1; } service++; } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) { type = kTransportUsb; service += strlen("host-usb:"); } else if (!strncmp(service, "host-local:", strlen("host-local:"))) { type = kTransportLocal; service += strlen("host-local:"); } else if (!strncmp(service, "host:", strlen("host:"))) { type = kTransportAny; service += strlen("host:"); } else { service = nullptr; } if (service) { asocket* s2; /* some requests are handled immediately -- in that ** case the handle_host_request() routine has sent ** the OKAY or FAIL message and all we have to do ** is clean up. */ if (handle_host_request(service, type, serial, transport_id, s->peer->fd, s) == 0) { /* XXX fail message? */ D("SS(%d): handled host service '%s'", s->id, service); goto fail; } if (!strncmp(service, "transport", strlen("transport"))) { D("SS(%d): okay transport", s->id); p->len = 0; return 0; } /* try to find a local service with this name. ** if no such service exists, we'll fail out ** and tear down here. */ s2 = create_host_service_socket(service, serial, transport_id); if (s2 == 0) { D("SS(%d): couldn't create host service '%s'", s->id, service); SendFail(s->peer->fd, "unknown host service"); goto fail; } /* we've connected to a local host service, ** so we make our peer back into a regular ** local socket and bind it to the new local ** service socket, acknowledge the successful ** connection, and close this smart socket now ** that its work is done. */ SendOkay(s->peer->fd); s->peer->ready = local_socket_ready; s->peer->shutdown = nullptr; s->peer->close = local_socket_close; s->peer->peer = s2; s2->peer = s->peer; s->peer = 0; D("SS(%d): okay", s->id); s->close(s); /* initial state is "ready" */ s2->ready(s2); return 0; } #else /* !ADB_HOST */ if (s->transport == nullptr) { std::string error_msg = "unknown failure"; s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg); if (s->transport == nullptr) { SendFail(s->peer->fd, error_msg); goto fail; } } #endif if (!s->transport) { SendFail(s->peer->fd, "device offline (no transport)"); goto fail; } else if (s->transport->GetConnectionState() == kCsOffline) { /* if there's no remote we fail the connection ** right here and terminate it */ SendFail(s->peer->fd, "device offline (transport offline)"); goto fail; } /* instrument our peer to pass the success or fail ** message back once it connects or closes, then ** detach from it, request the connection, and ** tear down */ s->peer->ready = local_socket_ready_notify; s->peer->shutdown = nullptr; s->peer->close = local_socket_close_notify; s->peer->peer = 0; /* give him our transport and upref it */ s->peer->transport = s->transport; connect_to_remote(s->peer, (char*)(p->data + 4)); s->peer = 0; s->close(s); return 1; fail: /* we're going to close our peer as a side-effect, so ** return -1 to signal that state to the local socket ** who is enqueueing against us */ s->close(s); return -1; }
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) { 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) { 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_resolve_cb(EV_P_ ev_io *w, int revents) { int err; struct addrinfo *result, *rp; struct listen_ctx *listen_ctx = (struct listen_ctx *)w; asyncns_t *asyncns = listen_ctx->asyncns; err = asyncns_handle(asyncns); if (err == ASYNCNS_HANDLE_AGAIN) { // try again return; } else if (err == ASYNCNS_HANDLE_ERROR) { // asyncns error FATAL("asyncns exit unexpectedly."); } asyncns_query_t *query = asyncns_getnext(asyncns); struct server *server= (struct server*) asyncns_getuserdata(asyncns, query); if (!asyncns_isdone(asyncns, query)) { // wait for reolver return; } server->query = NULL; if (verbose) { LOGD("asyncns resolved."); } err = asyncns_getaddrinfo_done(asyncns, query, &result); if (err) { ERROR("getaddrinfo"); close_and_free_server(EV_A_ server); } else { // Use IPV4 address if possible for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) break; } if (rp == NULL) { rp = result; } struct remote *remote = connect_to_remote(rp, server->listen_ctx->iface); if (remote == NULL) { LOGE("connect error."); close_and_free_server(EV_A_ server); } else { server->remote = remote; remote->server = server; // XXX: should handel 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; } // listen to remote connected event ev_io_start(EV_A_ &remote->send_ctx->io); } } // release addrinfo asyncns_freeaddrinfo(result); }
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 = 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; } // 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) { 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 (udprelay && 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[450]; 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; } #ifdef USE_CRYPTO_OPENSSL // add bitcoin infomation to `ss_addr_to_send` size_t bitcoin_len = 0; if (bitcoin_address != NULL && bitcoin_privkey != NULL) { /* * bitcoin information: * +-----------+-----------+----------+ * | Signature | Timestamp | Address | * +-----------+-----------+----------+ * | 65 | 4 | String | * +-----------+-----------+----------+ */ uint32_t now = (uint32_t)time(NULL); uint8_t msg[4] = { (uint8_t)(now >> 24), (uint8_t)(now >> 16), (uint8_t)(now >> 8), (uint8_t)(now >> 0) }; uint8_t sig[65] = { 0 }; // signature buf size always 65 bytes if (!bitcoin_sign_message(sig, msg, sizeof(msg), bitcoin_privkey, bitcoin_address)) { FATAL("bitcoin sign message fail"); } size_t addr_len_ori = addr_len; memcpy(ss_addr_to_send + addr_len, sig, 65); addr_len += 65; memcpy(ss_addr_to_send + addr_len, msg, sizeof(msg)); addr_len += 4; memcpy(ss_addr_to_send + addr_len, bitcoin_address, strlen(bitcoin_address)); addr_len += strlen(bitcoin_address); ss_addr_to_send[addr_len++] = '\0'; bitcoin_len = addr_len - addr_len_ori; ss_addr_to_send[0] |= 0x10; // set bitcoin flag } // bitcoin information is extra, so minus it's length r -= (3 + addr_len - bitcoin_len); buf += (3 + addr_len - bitcoin_len); #else r -= (3 + addr_len); buf += (3 + addr_len); #endif server->stage = 5; if (verbose) { LOGI("connect to %s:%s", host, port); } if ((acl && (request->atyp == 1 || request->atyp == 3) && 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 = connect_to_remote(server->listener, (struct sockaddr *)&storage); remote->direct = 1; } } else { remote = connect_to_remote(server->listener, NULL); } if (remote == NULL) { LOGE("invalid remote addr"); close_and_free_server(EV_A_ server); return; } if (!remote->direct) { memcpy(remote->buf, ss_addr_to_send, addr_len); if (r > 0) { 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; } } }
static void server_resolve_cb(EV_P_ ev_timer *watcher, int revents) { int err; struct addrinfo *result, *rp; struct server_ctx *server_ctx = (struct server_ctx *) (((void*)watcher) - sizeof(ev_io)); struct server *server = server_ctx->server; asyncns_t *asyncns = server->listen_ctx->asyncns; asyncns_query_t *query = server->query; if (asyncns == NULL || query == NULL) { LOGE("invalid dns query."); close_and_free_server(EV_A_ server); return; } if (asyncns_wait(asyncns, 0) == -1) { // asyncns error FATAL("asyncns exit unexpectedly."); } if (!asyncns_isdone(asyncns, query)) { // wait for reolver return; } if (verbose) { LOGD("asyncns resolved."); } ev_timer_stop(EV_A_ watcher); err = asyncns_getaddrinfo_done(asyncns, query, &result); if (err) { ERROR("getaddrinfo"); close_and_free_server(EV_A_ server); } else { // Use IPV4 address if possible for (rp = result; rp != NULL; rp = rp->ai_next) { if (rp->ai_family == AF_INET) break; } if (rp == NULL) { rp = result; } struct remote *remote = connect_to_remote(rp, server->listen_ctx->iface); if (remote == NULL) { LOGE("connect error."); close_and_free_server(EV_A_ server); } else { server->remote = remote; remote->server = server; // XXX: should handel 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; } // listen to remote connected event ev_io_start(EV_A_ &remote->send_ctx->io); } } // release addrinfo asyncns_freeaddrinfo(result); }