diff --git a/src/evt_core.c b/src/evt_core.c index ffe547a..edd2b7a 100644 --- a/src/evt_core.c +++ b/src/evt_core.c @@ -64,6 +64,30 @@ void evt_core_add_cat(struct evt_core_ctx* ctx, struct evt_core_cat* cat) { g_hash_table_insert (ctx->catlist, dyn->name, dyn); } +void evt_core_mv_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, struct evt_core_cat* to_cat) { + // 1. Update old category + for (int i = 0; i < fdinfo->cat->socklist->len; i++) { + if (g_array_index(fdinfo->cat->socklist, struct evt_core_fdinfo*, i) == fdinfo) { + g_array_remove_index(fdinfo->cat->socklist, i); + } + } + + // 2. Set new cat for fdinfo + fdinfo->cat = to_cat; + + // 3. Update new category + g_array_append_val (fdinfo->cat->socklist, fdinfo); +} + +void evt_core_mv_fd2(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, char* to_cat) { + struct evt_core_cat* cat = evt_core_get_from_cat (ctx, to_cat); + if (cat == NULL) { + fprintf(stderr, "Category %s does not exist\n", to_cat); + exit(EXIT_FAILURE); + } + evt_core_mv_fd (ctx, fdinfo, cat); +} + void evt_core_add_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* user_data) { // 1. Fetch fd category struct evt_core_cat* cat = g_hash_table_lookup(ctx->catlist, user_data->cat->name); diff --git a/src/evt_core.h b/src/evt_core.h index 2f6d96a..6aaf4cc 100644 --- a/src/evt_core.h +++ b/src/evt_core.h @@ -45,6 +45,8 @@ struct evt_core_fdinfo { void evt_core_init(struct evt_core_ctx* ctx); void evt_core_add_cat(struct evt_core_ctx* ctx, struct evt_core_cat* cat); +void evt_core_mv_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, struct evt_core_cat* to_cat); +void evt_core_mv_fd2(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo, char* to_cat); void evt_core_add_fd(struct evt_core_ctx* ctx, struct evt_core_fdinfo* user_data); struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd); void evt_core_free(struct evt_core_ctx* ctx); diff --git a/src/socks5.c b/src/socks5.c index 24d407e..6d36599 100644 --- a/src/socks5.c +++ b/src/socks5.c @@ -4,8 +4,14 @@ struct socks5_ctx { struct client_handshake ch; struct server_handshake sh; struct client_request cr; - char cr_buffer[262]; struct server_reply sr; + uint64_t ch_cursor; + uint64_t sh_cursor; + uint64_t cr_cursor; + uint64_t sr_cursor; + char cr_buffer[262]; + size_t ch_size; + size_t cr_size; }; void socks5_free_ctx(void* elem) { @@ -14,9 +20,26 @@ void socks5_free_ctx(void* elem) { } void create_socks5_dns_client(struct evt_core_ctx* ctx, char* proxy_host, char* proxy_port, char* addr, uint16_t port) { - int sock = create_tcp_client (proxy_host, proxy_port); struct evt_core_fdinfo fdinfo; struct evt_core_cat cat; + struct socks5_ctx* s5ctx; + char url[1024]; + + // 0. Compute domain length and enforce an upper bound on its size + size_t domainLength = strlen(addr); + if (domainLength > 255) { + fprintf(stderr, "domain is too long\n"); + exit(EXIT_FAILURE); + } + + // 1. Open connection + int sock = create_tcp_client (proxy_host, proxy_port); + if (sock < 0) { + fprintf(stderr, "Unable to connect to proxy %s:%s\n", proxy_host, proxy_port); + exit(EXIT_FAILURE); + } + + // 2. Create fdinfo fdinfo.cat = &cat; fdinfo.cat->name = "socks5-send-handshake"; fdinfo.fd = sock; @@ -25,35 +48,57 @@ void create_socks5_dns_client(struct evt_core_ctx* ctx, char* proxy_host, char* perror("malloc failed"); exit(EXIT_FAILURE); } + memset(fdinfo.other, 0, sizeof(struct socks5_ctx)); fdinfo.free_other = socks5_free_ctx; + sprintf(url, "socks5:send-hs:%s:%d", addr, port); + fdinfo.url = strdup(url); + + // 3. Fill socks5_ctx structures + s5ctx = fdinfo.other; + + // 3.1 Client handshake to send + s5ctx->ch.ver = VER_SOCKS5; + s5ctx->ch.nmethods = 0x01; + s5ctx->ch.methods[0] = METHOD_NOAUTH; + s5ctx->ch_size = sizeof(uint8_t) * (2 + s5ctx->ch.nmethods); + + // 3.2 Client request to send + s5ctx->cr.ver = VER_SOCKS5; + s5ctx->cr.cmd = CMD_CONNECT; + s5ctx->cr.rsv = 0x00; + s5ctx->cr.atyp = ATYP_DOMAINNAME; + s5ctx->cr.dst_addr_len = domainLength; + s5ctx->cr.dst_addr = addr; + s5ctx->cr.port = htons(port); + + // 3.3 Generate client request buffer + s5ctx->cr_size = 0; + fill_buffer(&s5ctx->cr_size, s5ctx->cr_buffer, &s5ctx->cr, 5*sizeof(uint8_t)); + fill_buffer(&s5ctx->cr_size, s5ctx->cr_buffer, s5ctx->cr.dst_addr, s5ctx->cr.dst_addr_len*sizeof(char)); + fill_buffer(&s5ctx->cr_size, s5ctx->cr_buffer, &s5ctx->cr.port, sizeof(uint16_t)); + evt_core_add_fd (ctx, &fdinfo); } -int socks5_handshake_syn(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) { - struct client_handshake ch = { - .ver = 0x05, - .nmethods = 0x01, - .methods = {0x00} - }; +int on_socks5_send_handshake(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) { + struct socks5_ctx* s5ctx = fdinfo->other; - fdinfo-> - - int size = sizeof(uint8_t) * (2 + ch.nmethods); - if (size != write(sock, &ch, size)) { - perror("write failed on tcp socket in socks5"); - return -1; - } + size_t written = write(fdinfo->fd, &s5ctx->ch + s5ctx->ch_cursor, s5ctx->ch_size - s5ctx->ch_cursor); + if (written == -1 && errno == EAGAIN) return 1; + if (written < 0) { + perror("write failed on tcp socket in socks5"); + evt_core_mv_fd2(ctx, fdinfo, "socks5-failed"); return 0; + } + s5ctx->ch_cursor += written; + if (s5ctx->ch_cursor < s5ctx->ch_size) return 0; + + evt_core_mv_fd2(ctx, fdinfo, "socks5-recv-handshake"); + return 0; } -int socks5_handshake_ack(int sock) { - struct client_handshake ch = { - .ver = 0x05, - .nmethods = 0x01, - .methods = {0x00} - }; - struct server_handshake sh = {0}; - int err = read_entity(sock, &sh, sizeof(struct server_handshake)); +int on_socks5_recv_handshake(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) { + if (err == -1) { perror("sock5 handshake failed read"); return -1; diff --git a/src/socks5.h b/src/socks5.h index a606e3e..a5f8b9a 100644 --- a/src/socks5.h +++ b/src/socks5.h @@ -28,6 +28,17 @@ enum atyp { ATYP_IPV6 = 0x04 }; +enum ver { + VER_SOCKS5 = 0x05 +}; + +enum methods { + METHOD_NOAUTH = 0x00, + METHOD_GSSAPI = 0x01, + METHOD_USERPASS = 0x02, + METHOD_NOACCEPT = 0xff +}; + union socks5_addr { struct { uint8_t len;