static void client_handshake_domain_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) { server_ctx *ctx = (server_ctx *)resolver->data; if (status) { if (uv_last_error(ctx->client.loop).code == UV_ENOENT) { LOGI("Resolve error, NXDOMAIN"); } else { SHOW_UV_ERROR(ctx->client.loop); } HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->client, handshake_client_close_cb); uv_freeaddrinfo(res); free(resolver); return; } ctx->remote_ip = ((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr; int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, client_handshake_alloc_cb, client_handshake_read_cb); if (n) { HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->client, handshake_client_close_cb); SHOW_UV_ERROR(ctx->client.loop); } uv_freeaddrinfo(res); free(resolver); }
static void connect_to_remote_cb(uv_connect_t* req, int status) { server_ctx *ctx = (server_ctx *)req->data; free(req); if (status) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); return; } LOGI("Connected to remote server"); uv_buf_t buf; buf.base = (char *)ctx->handshake_buffer; buf.len = HANDSHAKE_BUFFER_SIZE; shadow_encrypt((unsigned char *)buf.base, encrypt_table, ctx->buffer_len); client_established_read_cb((uv_stream_t *)(void *)&ctx->client, ctx->buffer_len, buf); // Deal with ramaining data, only once ctx->handshake_buffer = NULL; ctx->buffer_len = 0; int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, established_alloc_cb, client_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); return; } n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); return; } }
static void connect_to_remote_cb(uv_connect_t* req, int status) { server_ctx *ctx = (server_ctx *)req->data; if (status) { if (uv_last_error(req->handle->loop).code != UV_ECANCELED) { SHOW_UV_ERROR(ctx->client.loop); uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); free(ctx->handshake_buffer); free(req); } return; } free(req); LOGCONN(&ctx->remote, "Connected to %s"); uv_buf_t buf; buf.base = (char *)ctx->handshake_buffer; buf.len = HANDSHAKE_BUFFER_SIZE; if (!ctx->buffer_len) { free(ctx->handshake_buffer); } else { uv_write_t *wreq = (uv_write_t *)malloc(sizeof(uv_write_t)); if (!wreq) { uv_close((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); FATAL("malloc() failed!"); } wreq->data = buf.base; buf.len = ctx->buffer_len; int n = uv_write(wreq, (uv_stream_t *)(void *)&ctx->remote, &buf, 1, after_write_cb); if (n) { LOGE("Write to remote failed!"); free(wreq); uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } } ctx->handshake_buffer = NULL; ctx->buffer_len = 0; int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, established_alloc_cb, client_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); uv_close((uv_handle_t*)(void *)&ctx->client, client_established_close_cb); return; } n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); uv_close((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } }
static void connect_cb(uv_stream_t* listener, int status) { int n; if (status) { SHOW_UV_ERROR(listener->loop); return; } server_ctx *ctx = calloc(1, sizeof(server_ctx)); ctx->client.data = ctx; ctx->remote.data = ctx; ctx->handshake_buffer = calloc(1, HANDSHAKE_BUFFER_SIZE); if (!ctx || !ctx->handshake_buffer) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_tcp_init(listener->loop, &ctx->client); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_accept(listener, (uv_stream_t *)(void *)&ctx->client); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_tcp_nodelay(&ctx->client, 1); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_read_start((uv_stream_t *)(void *)&ctx->client, client_handshake_alloc_cb, client_handshake_read_cb); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); }
static void after_write_cb(uv_write_t* req, int status) { server_ctx *ctx = (server_ctx *)req->handle->data; if (status) { if (uv_last_error(req->handle->loop).code != UV_ECANCELED) { if ((uv_tcp_t *)req->handle == &ctx->client) { HANDLE_CLOSE((uv_handle_t *)req->handle, client_established_close_cb); } else { HANDLE_CLOSE((uv_handle_t *)req->handle, remote_established_close_cb); } } free(req->data); // Free buffer free(req); return; } if ((uv_tcp_t *)req->handle == &ctx->client && !uv_is_closing((uv_handle_t *)(void *)&ctx->remote)) { if (ctx->buffer_len <= MAX_PENDING_PER_CONN) { int n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); free(req->data); // Free buffer free(req); return; } } ctx->buffer_len--; } free(req->data); // Free buffer free(req); }
static void connect_to_remote_cb(uv_connect_t* req, int status) { server_ctx *ctx = (server_ctx *)req->data; if (status) { if (uv_last_error(req->handle->loop).code != UV_ECANCELED) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); free(ctx->handshake_buffer); free(req); } return; } free(req); LOGCONN(&ctx->remote, "Connected to %s"); uv_buf_t buf; buf.base = (char *)ctx->handshake_buffer; buf.len = HANDSHAKE_BUFFER_SIZE; shadow_encrypt((uint8_t *)buf.base, encrypt_table, ctx->buffer_len); client_established_read_cb((uv_stream_t *)(void *)&ctx->client, ctx->buffer_len, buf); // Deal with ramaining data, only once ctx->handshake_buffer = NULL; ctx->buffer_len = 0; if (uv_is_closing((uv_handle_t *)(void *)&ctx->remote) || uv_is_closing((uv_handle_t *)(void *)&ctx->client)) { LOGE("Connection failed, remote or client already closed"); return; } int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, established_alloc_cb, client_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } n = uv_read_start((uv_stream_t *)(void *)&ctx->remote, established_alloc_cb, remote_established_read_cb); if (n) { SHOW_UV_ERROR(ctx->client.loop); HANDLE_CLOSE((uv_handle_t*)(void *)&ctx->remote, remote_established_close_cb); return; } }
static void client_handshake_domain_resolved(uv_getaddrinfo_t *resolver, int status, struct addrinfo *res) { server_ctx *ctx = (server_ctx *)resolver->data; if (status) { if (uv_last_error(ctx->client.loop).code == UV_ENOENT) { LOGI("Resolve error, NXDOMAIN"); } else { SHOW_UV_ERROR(ctx->client.loop); } uv_close((uv_handle_t*)(void *)&ctx->client, handshake_client_close_cb); uv_freeaddrinfo(res); free(resolver); return; } if (res->ai_family == AF_INET) { // IPv4 memcpy(ctx->remote_ip, &((struct sockaddr_in*)(res->ai_addr))->sin_addr.s_addr, 4); ctx->remote_ip_type = ADDRTYPE_IPV4; } else if (res->ai_family == AF_INET6) { memcpy(ctx->remote_ip, &((struct sockaddr_in6*)(res->ai_addr))->sin6_addr.s6_addr, 16); ctx->remote_ip_type = ADDRTYPE_IPV6; } else { FATAL("dns resolve failed!"); } if (do_handshake((uv_stream_t *)(void *)&ctx->client) == 1) { int n = uv_read_start((uv_stream_t *)(void *)&ctx->client, client_handshake_alloc_cb, client_handshake_read_cb); if (n) { uv_close((uv_handle_t*)(void *)&ctx->client, handshake_client_close_cb); SHOW_UV_ERROR(ctx->client.loop); } } uv_freeaddrinfo(res); free(resolver); }
static void connect_cb(uv_stream_t* listener, int status) { int n; if (status) { SHOW_UV_ERROR(listener->loop); return; } server_ctx *ctx = calloc(1, sizeof(server_ctx)); ctx->handshake_buffer = calloc(1, HANDSHAKE_BUFFER_SIZE); if (!ctx || !ctx->handshake_buffer) FATAL("malloc() failed!"); ctx->client.data = ctx; ctx->remote.data = ctx; make_encryptor(&crypto, &ctx->encoder, 0, NULL); n = uv_tcp_init(listener->loop, &ctx->client); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_accept(listener, (uv_stream_t *)(void *)&ctx->client); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); n = uv_tcp_nodelay(&ctx->client, 1); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); #ifdef KEEPALIVE_TIMEOUT n = uv_tcp_keepalive(&ctx->client, 1, KEEPALIVE_TIMEOUT); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); #endif /* KEEPALIVE_TIMEOUT */ n = uv_read_start((uv_stream_t *)(void *)&ctx->client, client_handshake_alloc_cb, client_handshake_read_cb); if (n) SHOW_UV_ERROR_AND_EXIT(listener->loop); LOGCONN(&ctx->client, "Accepted connection from %s"); }
static void client_handshake_read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { int n; server_ctx *ctx = (server_ctx *)stream->data; if (nread < 0) { if (buf.len) // If buf is set, we need to free it free(buf.base); HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); // Then close the connection return; } else if (!nread) { free(buf.base); return; } memcpy(ctx->handshake_buffer + ctx->buffer_len, buf.base, buf.len); shadow_decrypt(ctx->handshake_buffer + ctx->buffer_len, decrypt_table, buf.len); ctx->buffer_len += nread; if (!ctx->handshake_buffer) { FATAL("Should no call this anmore"); } free(buf.base); if (!ctx->remote_ip) { if (ctx->buffer_len < 2) // Not interpretable return; uint8_t addrtype = ctx->handshake_buffer[0]; if (addrtype == ADDRTYPE_IPV4) { if (ctx->buffer_len < 5) return; ctx->remote_ip = *((uint32_t *)(ctx->handshake_buffer + 1)); SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 5, HANDSHAKE_BUFFER_SIZE); ctx->buffer_len -= 5; // TODO: Print out } else if (addrtype == ADDRTYPE_DOMAIN) { uint8_t domain_len = ctx->handshake_buffer[1]; if (!domain_len) { // Domain length is zero LOGE("Domain length is zero"); HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); return; } if (ctx->buffer_len < domain_len + 2) return; char domain[domain_len+1]; domain[domain_len] = 0; memcpy(domain, ctx->handshake_buffer+2, domain_len); struct addrinfo hints; hints.ai_family = AF_INET; // IPv4 Only hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = 0; uv_getaddrinfo_t *resolver = (uv_getaddrinfo_t *)malloc(sizeof(uv_getaddrinfo_t)); if (!resolver) { HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); FATAL("malloc() failed!"); } resolver->data = ctx; // We need to locate back the stream LOGI("Domain is: %s", domain); n = uv_getaddrinfo(stream->loop, resolver, client_handshake_domain_resolved, domain, NULL, &hints); if (n) { SHOW_UV_ERROR(stream->loop); HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); free(resolver); return; } SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 2+domain_len, HANDSHAKE_BUFFER_SIZE); ctx->buffer_len -= 2 + domain_len; uv_read_stop(stream); // Pause the reading process, wait for resolve result return; } else { // Unsupported addrtype LOGI("addrtype unknown, closing"); HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); return; } } // !ctx->remote_ip if (!ctx->remote_port) { if (ctx->buffer_len < 2) // Not interpretable return; ctx->remote_port = *((uint16_t *)ctx->handshake_buffer); if (!ctx->remote_port) { LOGE("Remote port is zero"); HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); return; } SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 2, HANDSHAKE_BUFFER_SIZE); ctx->buffer_len -= 2; // Try connect now n = uv_tcp_init(stream->loop, &ctx->remote); if (n) SHOW_UV_ERROR_AND_EXIT(stream->loop); uv_connect_t *req = (uv_connect_t *)malloc(sizeof(uv_connect_t)); if (!req) { HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); FATAL("malloc() failed!"); } req->data = ctx; struct sockaddr_in remote_addr; memset(&remote_addr, 0, sizeof(remote_addr)); remote_addr.sin_family = AF_INET; remote_addr.sin_addr.s_addr = ctx->remote_ip; remote_addr.sin_port = ctx->remote_port; n = uv_tcp_connect(req, &ctx->remote, remote_addr, connect_to_remote_cb); if (n) { SHOW_UV_ERROR(stream->loop); HANDLE_CLOSE((uv_handle_t*)stream, handshake_client_close_cb); free(req); return; } uv_read_stop(stream); // We are done handshake } }
static int do_handshake(uv_stream_t *stream) { server_ctx *ctx = (server_ctx *)stream->data; int n; if (!ctx->remote_ip_type) { if (ctx->buffer_len < 2) // Not interpretable return 1; uint8_t addrtype = ctx->handshake_buffer[0]; if (addrtype == ADDRTYPE_IPV4) { if (ctx->buffer_len < 5) return 1; memcpy(ctx->remote_ip, ctx->handshake_buffer + 1, 4); ctx->remote_ip_type = ADDRTYPE_IPV4; SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 5, HANDSHAKE_BUFFER_SIZE); ctx->buffer_len -= 5; // TODO: Print out } else if (addrtype == ADDRTYPE_DOMAIN) { uint8_t domain_len = ctx->handshake_buffer[1]; if (!domain_len) { // Domain length is zero LOGE("Domain length is zero"); uv_close((uv_handle_t*)stream, handshake_client_close_cb); return -1; } if (ctx->buffer_len < domain_len + 2) return 1; char domain[domain_len+1]; domain[domain_len] = 0; memcpy(domain, ctx->handshake_buffer+2, domain_len); uv_getaddrinfo_t *resolver = (uv_getaddrinfo_t *)malloc(sizeof(uv_getaddrinfo_t)); if (!resolver) { uv_close((uv_handle_t*)stream, handshake_client_close_cb); FATAL("malloc() failed!"); } resolver->data = ctx; // We need to locate back the stream LOGI("Domain is: %s", domain); n = uv_getaddrinfo(stream->loop, resolver, client_handshake_domain_resolved, domain, NULL, NULL); if (n) { SHOW_UV_ERROR(stream->loop); uv_close((uv_handle_t*)stream, handshake_client_close_cb); free(resolver); return -1; } SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 2+domain_len, HANDSHAKE_BUFFER_SIZE); ctx->buffer_len -= 2 + domain_len; uv_read_stop(stream); // Pause the reading process, wait for resolve result return 1; } else { // Unsupported addrtype LOGI("addrtype unknown, closing"); uv_close((uv_handle_t*)stream, handshake_client_close_cb); return -1; } } // !ctx->remote_ip if (!ctx->remote_port) { if (ctx->buffer_len < 2) // Not interpretable return 1; ctx->remote_port = *((uint16_t *)ctx->handshake_buffer); if (!ctx->remote_port) { LOGE("Remote port is zero"); uv_close((uv_handle_t*)stream, handshake_client_close_cb); return -1; } SHIFT_BYTE_ARRAY_TO_LEFT(ctx->handshake_buffer, 2, HANDSHAKE_BUFFER_SIZE); ctx->buffer_len -= 2; // Try connect now n = uv_tcp_init(stream->loop, &ctx->remote); if (n) SHOW_UV_ERROR_AND_EXIT(stream->loop); uv_connect_t *req = (uv_connect_t *)malloc(sizeof(uv_connect_t)); if (!req) { uv_close((uv_handle_t*)stream, handshake_client_close_cb); FATAL("malloc() failed!"); } req->data = ctx; if (ctx->remote_ip_type == ADDRTYPE_IPV4) { struct sockaddr_in remote; memset(&remote, 0, sizeof(remote)); remote.sin_family = AF_INET; memcpy(&remote.sin_addr.s_addr, ctx->remote_ip, 4); remote.sin_port = ctx->remote_port; n = uv_tcp_connect(req, &ctx->remote, remote, connect_to_remote_cb); } else if (ctx->remote_ip_type == ADDRTYPE_IPV6) { struct sockaddr_in6 remote; memset(&remote, 0, sizeof(remote)); remote.sin6_family = AF_INET6; memcpy(&remote.sin6_addr.s6_addr, ctx->remote_ip, 16); remote.sin6_port = ctx->remote_port; n = uv_tcp_connect6(req, &ctx->remote, remote, connect_to_remote_cb); } else { FATAL("addrtype unknown!"); } if (n) { SHOW_UV_ERROR(stream->loop); uv_close((uv_handle_t*)stream, handshake_client_close_cb); free(req); return -1; } } uv_read_stop(stream); return 0; }