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); }
int main(int argc, char const *argv[]) { LOGI(WELCOME_MESSAGE); make_tables((unsigned char *)PASSWORD, encrypt_table, decrypt_table); LOGI("Encrypt and decrypt table generated"); int n; uv_loop_t *loop = uv_default_loop(); uv_tcp_t listener; struct sockaddr_in addr = uv_ip4_addr(SERVER_LISTEN, SERVER_PORT); n = uv_tcp_init(loop, &listener); if (n) SHOW_UV_ERROR_AND_EXIT(loop); n = uv_tcp_bind(&listener, addr); if (n) SHOW_UV_ERROR_AND_EXIT(loop); n = uv_listen((uv_stream_t*)(void *)&listener, 5, connect_cb); if (n) SHOW_UV_ERROR_AND_EXIT(loop); LOGI("Listening on " SERVER_LISTEN ":" TOSTR(SERVER_PORT)); return uv_run(loop); }
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 } }
int main(int argc, char *argv[]) { char **newargv = uv_setup_args(argc, argv); char *server_listen = SERVER_LISTEN; int server_port = SERVER_PORT; uint8_t *password = (uint8_t *)PASSWORD; uint8_t crypt_method = CRYPTO_METHOD; char *pid_path = PID_FILE; char opt; while((opt = getopt(argc, newargv, "l:p:k:f:m:")) != -1) { // not portable to windows switch(opt) { case 'l': server_listen = optarg; break; case 'p': server_port = atoi(optarg); break; case 'k': password = (uint8_t *)optarg; break; case 'f': pid_path = optarg; break; case 'm': if (!strcmp("rc4", optarg)) crypt_method = METHOD_RC4; else if (!strcmp("shadow", optarg)) crypt_method = METHOD_SHADOWCRYPT; break; default: fprintf(stderr, USAGE, newargv[0]); abort(); } } FILE *pid_file = fopen(pid_path, "wb"); if (!pid_file) FATAL("fopen failed, %s", strerror(errno)); fprintf(pid_file, "%d", getpid()); fclose(pid_file); char *process_title = malloc(PROCESS_TITLE_LENGTH); // we do not like waste memory if (!process_title) FATAL("malloc() failed!"); snprintf(process_title, PROCESS_TITLE_LENGTH, PROCESS_TITLE, server_port); uv_set_process_title(process_title); free(process_title); LOGI(WELCOME_MESSAGE); if (crypt_method == METHOD_SHADOWCRYPT) LOGI("Using shadowcrypt crypto"); else if (crypt_method == METHOD_RC4) LOGI("Using RC4 crypto"); else FATAL("Crypto unknown!"); make_encryptor(NULL, &crypto, crypt_method, password); LOGI("Crypto ready"); int n; uv_loop_t *loop = uv_default_loop(); uv_tcp_t listener; struct sockaddr_in6 addr = uv_ip6_addr(server_listen, server_port); n = uv_tcp_init(loop, &listener); if (n) SHOW_UV_ERROR_AND_EXIT(loop); n = uv_tcp_bind6(&listener, addr); if (n) SHOW_UV_ERROR_AND_EXIT(loop); n = uv_listen((uv_stream_t*)(void *)&listener, 5, connect_cb); if (n) SHOW_UV_ERROR_AND_EXIT(loop); LOGI("Listening on %s:%d", server_listen, server_port); #ifndef NDEBUG setup_signal_handler(loop); #endif /* !NDEBUG */ return uv_run(loop); }
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; }
int main(int argc, char *argv[]) { char *server_listen = SERVER_LISTEN; int server_port = SERVER_PORT; uint8_t *password = (uint8_t *)PASSWORD; char *pid_path = PID_FILE; char opt; while((opt = getopt(argc, argv, "l:p:k:f:")) != -1) { // not portable to windows switch(opt) { case 'l': server_listen = optarg; break; case 'p': server_port = atoi(optarg); break; case 'k': password = malloc(strlen(optarg + 1)); strcpy((char *)password, optarg); break; case 'f': pid_path = optarg; break; default: fprintf(stderr, USAGE, argv[0]); abort(); } } FILE *pid_file = fopen(pid_path, "wb"); if (!pid_file) FATAL("fopen failed, %s", strerror(errno)); fprintf(pid_file, "%d", getpid()); fclose(pid_file); char *process_title = malloc(PROCESS_TITLE_LENGTH); // we do not like waste memory if (!process_title) FATAL("malloc() failed!"); snprintf(process_title, PROCESS_TITLE_LENGTH, PROCESS_TITLE, server_port); uv_setup_args(argc, argv); uv_set_process_title(process_title); free(process_title); LOGI(WELCOME_MESSAGE); make_tables(password, encrypt_table, decrypt_table); LOGI("Encrypt and decrypt table generated"); int n; uv_loop_t *loop = uv_default_loop(); uv_tcp_t listener; struct sockaddr_in addr = uv_ip4_addr(server_listen, server_port); n = uv_tcp_init(loop, &listener); if (n) SHOW_UV_ERROR_AND_EXIT(loop); n = uv_tcp_bind(&listener, addr); if (n) SHOW_UV_ERROR_AND_EXIT(loop); n = uv_listen((uv_stream_t*)(void *)&listener, 5, connect_cb); if (n) SHOW_UV_ERROR_AND_EXIT(loop); LOGI("Listening on %s:%d", server_listen, server_port); #ifndef NDEBUG setup_signal_handler(loop); #endif /* !NDEBUG */ return uv_run(loop); }