static void ss_forward_pkt(redudp_client *client, struct sockaddr * destaddr, void *data, size_t pktlen) { ss_client *ssclient = (void*)(client + 1); ss_instance * ss = (ss_instance *)(client->instance+1); struct sockaddr_in * relayaddr = &client->instance->config.relayaddr; struct msghdr msg; struct iovec io[1]; ssize_t outgoing; int rc; ss_header_ipv4 header; size_t len = 0; size_t fwdlen = 0; void * buff = client->instance->shared_buff; /* build and send header */ // TODO: Better implementation and IPv6 Support header.addr_type = ss_addrtype_ipv4; header.addr = ((struct sockaddr_in *)destaddr)->sin_addr.s_addr; header.port = ((struct sockaddr_in *)destaddr)->sin_port; if (enc_ctx_init(&ss->info, &ss->e_ctx, 1)) { redudp_log_error(client, LOG_ERR, "Shadowsocks UDP failed to initialize encryption context."); return; } rc = ss_encrypt(&ss->e_ctx, (char *)&header, sizeof(header), buff, &len); if (rc) { if (len + pktlen < MAX_UDP_PACKET_SIZE) rc = ss_encrypt(&ss->e_ctx, (char *)data, pktlen, buff+len, &fwdlen); else rc = 0; } enc_ctx_free(&ss->e_ctx); if (!rc) { redudp_log_error(client, LOG_DEBUG, "Can't encrypt packet, dropping it"); return; } fwdlen += len; memset(&msg, 0, sizeof(msg)); msg.msg_name = relayaddr; msg.msg_namelen = sizeof(*relayaddr); msg.msg_iov = io; msg.msg_iovlen = SIZEOF_ARRAY(io); io[0].iov_base = buff; io[0].iov_len = fwdlen; outgoing = sendmsg(event_get_fd(&ssclient->udprelay), &msg, 0); if (outgoing == -1) { redudp_log_errno(client, LOG_DEBUG, "sendmsg: Can't forward packet, dropping it"); return; } else if (outgoing != fwdlen) { redudp_log_error(client, LOG_DEBUG, "sendmsg: I was sending %zd bytes, but only %zd were sent.", fwdlen, outgoing); return; } }
static void encrypt_mem(redsocks_client * client, char * data, size_t len, struct bufferevent * to, int decrypt) { ss_client *sclient = (void*)(client + 1); struct evbuffer_iovec vec; struct evbuffer * buf_out = bufferevent_get_output(to); size_t required; int rc; if (!len || !data) return; if (decrypt) required = ss_calc_buffer_size(&sclient->d_ctx, len); else required = ss_calc_buffer_size(&sclient->e_ctx, len); if (required && evbuffer_reserve_space(buf_out, required, &vec, 1) == 1) { if (decrypt) rc = ss_decrypt(&sclient->d_ctx, data, len, vec.iov_base, &vec.iov_len); else rc = ss_encrypt(&sclient->e_ctx, data, len, vec.iov_base, &vec.iov_len); if (!rc) vec.iov_len = 0; evbuffer_commit_space(buf_out, &vec, 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 = server->remote; ssize_t r = recv(server->fd, remote->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"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } 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; } 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); return; } else { ERROR("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; } }
// ssize_t size = 0; // char *buffer = as_char_array(env, array, &size); // decrypted = ss_decrypt(BUFF_SIZE, buffer, &size, temp_d_ctx); // if(decrypted == NULL) { // return NULL; // } // return as_byte_array(env, decrypted, size); // } JNIEXPORT jint JNICALL Java_me_smartproxy_crypto_CryptoUtils_encrypt(JNIEnv *env, jclass thiz, jobject array, jint jsize, jlong id) { ssize_t size = (ssize_t) jsize; jbyte *bytes = (jbyte *) env->GetDirectBufferAddress(array); buffer_t *buffer = (buffer_t *) ss_malloc(sizeof(buffer_t)); balloc(buffer, BUFF_SIZE); memcpy(buffer->array, bytes, size); buffer->len = size; enc_connection *connection = enc_ctx_map[id]; ss_encrypt(buffer, connection->text_e_ctx, BUFF_SIZE); size = buffer->len; memcpy(bytes, buffer->array, buffer->len); bfree(buffer); return size; }
static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; if (!remote_send_ctx->connected) { struct sockaddr_storage addr; socklen_t len = sizeof addr; int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_stop(EV_A_ & server->recv_ctx->io); ev_timer_stop(EV_A_ & remote_send_ctx->watcher); ev_timer_start(EV_A_ & remote->recv_ctx->watcher); // send destaddr buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, BUF_SIZE); if (server->hostname_len > 0) { // HTTP/SNI uint16_t port; if (AF_INET6 == server->destaddr.ss_family) { // IPv6 port = (((struct sockaddr_in6 *)&(server->destaddr))->sin6_port); } else { // IPv4 port = (((struct sockaddr_in *)&(server->destaddr))->sin_port); } abuf->array[abuf->len++] = 3; // Type 3 is hostname abuf->array[abuf->len++] = server->hostname_len; memcpy(abuf->array + abuf->len, server->hostname, server->hostname_len); abuf->len += server->hostname_len; memcpy(abuf->array + abuf->len, &port, 2); } else if (AF_INET6 == server->destaddr.ss_family) { // IPv6 abuf->array[abuf->len++] = 4; // Type 4 is IPv6 address size_t in6_addr_len = sizeof(struct in6_addr); memcpy(abuf->array + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr), in6_addr_len); abuf->len += in6_addr_len; memcpy(abuf->array + abuf->len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port), 2); } else { // IPv4 abuf->array[abuf->len++] = 1; // Type 1 is IPv4 address size_t in_addr_len = sizeof(struct in_addr); memcpy(abuf->array + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len); abuf->len += in_addr_len; memcpy(abuf->array + abuf->len, &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2); } abuf->len += 2; if (auth) { abuf->array[0] |= ONETIMEAUTH_FLAG; ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE); } brealloc(remote->buf, remote->buf->len + abuf->len, BUF_SIZE); memmove(remote->buf->array + abuf->len, remote->buf->array, remote->buf->len); memcpy(remote->buf->array, abuf->array, abuf->len); remote->buf->len += abuf->len; bfree(abuf); int err = ss_encrypt(remote->buf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } ev_io_start(EV_A_ & remote->recv_ctx->io); } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf->array + remote->buf->idx, remote->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } }
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; ssize_t r = recv(server->fd, remote->buf->array + remote->buf->len, BUF_SIZE - remote->buf->len, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("server recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } remote->buf->len += r; if (verbose) { uint16_t port = 0; char ipstr[INET6_ADDRSTRLEN]; memset(&ipstr, 0, INET6_ADDRSTRLEN); if (AF_INET == server->destaddr.ss_family) { struct sockaddr_in *sa = (struct sockaddr_in *)&(server->destaddr); dns_ntop(AF_INET, &(sa->sin_addr), ipstr, INET_ADDRSTRLEN); port = ntohs(sa->sin_port); } else { // TODO: The code below need to be test in IPv6 envirment, which I // don't have. struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(server->destaddr); dns_ntop(AF_INET6, &(sa->sin6_addr), ipstr, INET6_ADDRSTRLEN); port = ntohs(sa->sin6_port); } LOGI("redir to %s:%d, len=%zd, recv=%zd", ipstr, port, remote->buf->len, r); } if (auth) { ss_gen_hash(remote->buf, &remote->counter, server->e_ctx, BUF_SIZE); } if (!remote->send_ctx->connected) { // SNI int ret = 0; uint16_t port = 0; if (AF_INET6 == server->destaddr.ss_family) { // IPv6 port = ntohs(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port); } else { // IPv4 port = ntohs(((struct sockaddr_in *)&(server->destaddr))->sin_port); } if (port == http_protocol->default_port) ret = http_protocol->parse_packet(remote->buf->array, remote->buf->len, &server->hostname); else if (port == tls_protocol->default_port) ret = tls_protocol->parse_packet(remote->buf->array, remote->buf->len, &server->hostname); if (ret > 0) { server->hostname_len = ret; } ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } int err = ss_encrypt(remote->buf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, remote->buf->array, remote->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < remote->buf->len) { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { remote->buf->idx = 0; remote->buf->len = 0; } }
static void server_recv_cb(EV_P_ ev_io *w, int revents) { server_ctx_t *server_recv_ctx = (server_ctx_t *)w; server_t *server = server_recv_ctx->server; remote_t *remote = server->remote; ssize_t r = recv(server->fd, remote->buf->array, BUF_SIZE, 0); if (r == 0) { // connection closed close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else if (r < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data // continue to wait for recv return; } else { ERROR("server recv"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } remote->buf->len = r; if (auth) { ss_gen_hash(remote->buf, &remote->counter, server->e_ctx, BUF_SIZE); } if (!remote->send_ctx->connected) { ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } int err = ss_encrypt(remote->buf, server->e_ctx, BUF_SIZE); if (err) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, remote->buf->array, remote->buf->len, 0); if (s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // no data, wait for send remote->buf->idx = 0; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } else { ERROR("send"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else if (s < remote->buf->len) { remote->buf->len -= s; remote->buf->idx = s; ev_io_stop(EV_A_ & server_recv_ctx->io); ev_io_start(EV_A_ & remote->send_ctx->io); return; } }
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 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; if (remote == NULL) { close_and_free_server(EV_A_ server); return; } ssize_t r = recv(server->fd, remote->buf, BUF_SIZE, 0); if (r == 0) { // connection closed remote->buf_len = 0; remote->buf_idx = 0; close_and_free_server(EV_A_ server); if (remote != NULL) { ev_io_start(EV_A_ &remote->send_ctx->io); } return; } else if(r < 0) { 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; } } // local socks5 server if (server->stage == 5) { 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; } 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); return; } else { ERROR("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; } } 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 *)remote->buf; struct sockaddr_in sock_addr; memset(&sock_addr, 0, sizeof(sock_addr)); if (udprelay && request->cmd == 3) { 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; // 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, remote->buf + 4, in_addr_len + 2); addr_len += in_addr_len + 2; if (verbose) { char host[INET_ADDRSTRLEN]; uint16_t port = ntohs(*(uint16_t *)(remote->buf + 4 + in_addr_len)); inet_ntop(AF_INET, (const void *)(remote->buf + 4), host, INET_ADDRSTRLEN); LOGD("connect to %s:%d", host, port); } } else if (request->atyp == 3) { // Domain name uint8_t name_len = *(uint8_t *)(remote->buf + 4); ss_addr_to_send[addr_len++] = name_len; memcpy(ss_addr_to_send + addr_len, remote->buf + 4 + 1, name_len + 2); addr_len += name_len + 2; if (verbose) { char host[256]; uint16_t port = ntohs(*(uint16_t *)(remote->buf + 4 + 1 + name_len)); memcpy(host, remote->buf + 4 + 1, name_len); host[name_len] = '\0'; LOGD("connect to %s:%d", host, port); } } else if (request->atyp == 4) { // IP V6 size_t in6_addr_len = sizeof(struct in6_addr); memcpy(ss_addr_to_send + addr_len, remote->buf + 4, in6_addr_len + 2); addr_len += in6_addr_len + 2; if (verbose) { char host[INET6_ADDRSTRLEN]; uint16_t port = ntohs(*(uint16_t *)(remote->buf + 4 + in6_addr_len)); inet_ntop(AF_INET6, (const void *)(remote->buf + 4), host, INET6_ADDRSTRLEN); LOGD("connect to %s:%d", host, port); } } else { LOGE("unsupported addrtype: %d", request->atyp); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } ss_addr_to_send = ss_encrypt(BUF_SIZE, ss_addr_to_send, &addr_len, server->e_ctx); if (ss_addr_to_send == NULL) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, ss_addr_to_send, addr_len, 0); free(ss_addr_to_send); if (s < addr_len) { LOGE("failed to send remote addr."); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } server->stage = 5; ev_io_start(EV_A_ &remote->recv_ctx->io); } // 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 (request->cmd == 3) { close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } }
static void remote_send_cb(EV_P_ ev_io *w, int revents) { struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; struct remote *remote = remote_send_ctx->remote; struct server *server = remote->server; if (!remote_send_ctx->connected) { struct sockaddr_storage addr; socklen_t len = sizeof addr; int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_timer_stop(EV_A_ & remote_send_ctx->watcher); char *ss_addr_to_send = malloc(BUF_SIZE); ssize_t addr_len = 0; ss_addr_t *sa = &server->destaddr; struct cork_ip ip; if (cork_ip_init(&ip, sa->host) != -1) { if (ip.version == 4) { // send as IPv4 struct in_addr host; int host_len = sizeof(struct in_addr); if (dns_pton(AF_INET, sa->host, &host) == -1) { FATAL("IP parser error"); } ss_addr_to_send[addr_len++] = 1; memcpy(ss_addr_to_send + addr_len, &host, host_len); addr_len += host_len; } else if (ip.version == 6) { // send as IPv6 struct in6_addr host; int host_len = sizeof(struct in6_addr); if (dns_pton(AF_INET6, sa->host, &host) == -1) { FATAL("IP parser error"); } ss_addr_to_send[addr_len++] = 4; memcpy(ss_addr_to_send + addr_len, &host, host_len); addr_len += host_len; } else { FATAL("IP parser error"); } } else { // send as domain int host_len = strlen(sa->host); ss_addr_to_send[addr_len++] = 3; ss_addr_to_send[addr_len++] = host_len; memcpy(ss_addr_to_send + addr_len, sa->host, host_len); addr_len += host_len; } uint16_t port = htons(atoi(sa->port)); memcpy(ss_addr_to_send + addr_len, &port, 2); addr_len += 2; ss_addr_to_send = ss_encrypt(BUF_SIZE, ss_addr_to_send, &addr_len, server->e_ctx); if (ss_addr_to_send == NULL) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, ss_addr_to_send, addr_len, 0); free(ss_addr_to_send); if (s < addr_len) { LOGE("failed to send addr"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } ev_io_start(EV_A_ & remote->recv_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); return; } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else { if (remote->buf_len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf + remote->buf_idx, remote->buf_len, 0); if (s < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf_len) { // partly sent, move memory, wait for the next time to send remote->buf_len -= s; remote->buf_idx += s; return; } else { // all sent out, wait for reading remote->buf_len = 0; remote->buf_idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } } }
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 remote_send_cb(EV_P_ ev_io *w, int revents) { struct remote_ctx *remote_send_ctx = (struct remote_ctx *)w; struct remote *remote = remote_send_ctx->remote; struct server *server = remote->server; if (!remote_send_ctx->connected) { struct sockaddr_storage addr; socklen_t len = sizeof addr; int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_timer_stop(EV_A_ & remote_send_ctx->watcher); // send destaddr char *ss_addr_to_send = malloc(BUF_SIZE); ssize_t addr_len = 0; if (AF_INET6 == server->destaddr.ss_family) { // IPv6 ss_addr_to_send[addr_len++] = 4; //Type 4 is IPv6 address size_t in_addr_len = sizeof(struct in6_addr); memcpy(ss_addr_to_send + addr_len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_addr), in_addr_len); addr_len += in_addr_len; memcpy(ss_addr_to_send + addr_len, &(((struct sockaddr_in6 *)&(server->destaddr))->sin6_port), 2); } else { //IPv4 ss_addr_to_send[addr_len++] = 1; //Type 1 is IPv4 address size_t in_addr_len = sizeof(struct in_addr); memcpy(ss_addr_to_send + addr_len, &((struct sockaddr_in *)&(server->destaddr))->sin_addr, in_addr_len); addr_len += in_addr_len; memcpy(ss_addr_to_send + addr_len, &((struct sockaddr_in *)&(server->destaddr))->sin_port, 2); } addr_len += 2; ss_addr_to_send = ss_encrypt(BUF_SIZE, ss_addr_to_send, &addr_len, server->e_ctx); if (ss_addr_to_send == NULL) { LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, ss_addr_to_send, addr_len, 0); free(ss_addr_to_send); if (s < addr_len) { LOGE("failed to send remote addr."); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } ev_io_start(EV_A_ & server->recv_ctx->io); ev_io_start(EV_A_ & remote->recv_ctx->io); return; } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else { if (remote->buf_len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf + remote->buf_idx, remote->buf_len, 0); if (s < 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf_len) { // partly sent, move memory, wait for the next time to send remote->buf_len -= s; remote->buf_idx += s; return; } else { // all sent out, wait for reading remote->buf_len = 0; remote->buf_idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); if (server != NULL) { ev_io_start(EV_A_ & server->recv_ctx->io); } else { close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } } } }
static void remote_send_cb(EV_P_ ev_io *w, int revents) { remote_ctx_t *remote_send_ctx = (remote_ctx_t *)w; remote_t *remote = remote_send_ctx->remote; server_t *server = remote->server; if (!remote_send_ctx->connected) { struct sockaddr_storage addr; socklen_t len = sizeof addr; int r = getpeername(remote->fd, (struct sockaddr *)&addr, &len); if (r == 0) { remote_send_ctx->connected = 1; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_timer_stop(EV_A_ & remote_send_ctx->watcher); buffer_t ss_addr_to_send; buffer_t *abuf = &ss_addr_to_send; balloc(abuf, BUF_SIZE); ss_addr_t *sa = &server->destaddr; struct cork_ip ip; if (cork_ip_init(&ip, sa->host) != -1) { if (ip.version == 4) { // send as IPv4 struct in_addr host; int host_len = sizeof(struct in_addr); if (dns_pton(AF_INET, sa->host, &host) == -1) { FATAL("IP parser error"); } abuf->array[abuf->len++] = 1; memcpy(abuf->array + abuf->len, &host, host_len); abuf->len += host_len; } else if (ip.version == 6) { // send as IPv6 struct in6_addr host; int host_len = sizeof(struct in6_addr); if (dns_pton(AF_INET6, sa->host, &host) == -1) { FATAL("IP parser error"); } abuf->array[abuf->len++] = 4; memcpy(abuf->array + abuf->len, &host, host_len); abuf->len += host_len; } else { FATAL("IP parser error"); } } else { // send as domain int host_len = strlen(sa->host); abuf->array[abuf->len++] = 3; abuf->array[abuf->len++] = host_len; memcpy(abuf->array + abuf->len, sa->host, host_len); abuf->len += host_len; } uint16_t port = htons(atoi(sa->port)); memcpy(abuf->array + abuf->len, &port, 2); abuf->len += 2; if (auth) { abuf->array[0] |= ONETIMEAUTH_FLAG; ss_onetimeauth(abuf, server->e_ctx->evp.iv, BUF_SIZE); } int err = ss_encrypt(abuf, server->e_ctx, BUF_SIZE); if (err) { bfree(abuf); LOGE("invalid password or cipher"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } int s = send(remote->fd, abuf->array, abuf->len, 0); bfree(abuf); if (s < abuf->len) { LOGE("failed to send addr"); close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } ev_io_start(EV_A_ & remote->recv_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); return; } else { ERROR("getpeername"); // not connected close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } } else { if (remote->buf->len == 0) { // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); return; } else { // has data to send ssize_t s = send(remote->fd, remote->buf->array + remote->buf->idx, remote->buf->len, 0); if (s == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { ERROR("send"); // close and free close_and_free_remote(EV_A_ remote); close_and_free_server(EV_A_ server); } return; } else if (s < remote->buf->len) { // partly sent, move memory, wait for the next time to send remote->buf->len -= s; remote->buf->idx += s; return; } else { // all sent out, wait for reading remote->buf->len = 0; remote->buf->idx = 0; ev_io_stop(EV_A_ & remote_send_ctx->io); ev_io_start(EV_A_ & server->recv_ctx->io); } } } }
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; } } }