diff --git a/src/donar_client.c b/src/donar_client.c index 30ccbb6..eb50fa0 100644 --- a/src/donar_client.c +++ b/src/donar_client.c @@ -5,35 +5,22 @@ void load_onion_services(struct donar_client_ctx* ctx, char* onion_file, int por tor_os_read (&(ctx->tos)); } -void init_tcp_clients(struct donar_client_ctx* ctx) { - for (uint16_t i = 0; i < CLIENT_PORT_SIZE ; i++) { - ctx->ports[i] = 7500 + i; - } - int sock1, sock2, err; - char target_host[255]; +void init_tcp_client(struct donar_client_ctx* ctx, int i) { - for (int i = 0; i < CLIENT_PORT_SIZE; ) { + ctx->ports[i] = 7500 + i; + int sock1, err; + + while (1) { sock1 = create_tcp_client("127.0.0.1", "9050"); - err = socks5_handshake(sock1); - if (err < 0) goto failed_socks5; - if (strlen(ctx->tos.keys[i].pub) > 254) { - fprintf(stderr, "Domain name is too long\n"); - exit(EXIT_FAILURE); - } - sprintf(target_host, "%s.onion", ctx->tos.keys[i].pub); - err = socks5_connect_dns(sock1, target_host, ctx->ports[i]); - if (err < 0) goto failed_socks5; - err = socks5_reply(sock1); if (err < 0) goto failed_socks5; + ctx->client_sock[i].fd = sock1; + ctx->client_sock[i].state = SOCKS5_STATE_NEW; + evt_core_add_fd (&(ctx->evts), "configure-socks5", sock1); + //@FIXME: We suppose that we will be able to do the whole write at once which is wrong too + err = socks5_handshake_syn(sock1); + if (err) goto failed_socks5; - sock2 = dup(sock1); - if (sock2 < 0) goto failed_socks5; - evt_core_add_fd (&(ctx->evts), "tcp-read", sock1); - evt_core_add_fd (&(ctx->evts), "tcp-write", sock2); - printf("Socket %d/%d %s:%d has been added to the pool\n", i+1, CLIENT_PORT_SIZE, target_host, ctx->ports[i]); - - i++; - continue; + break; failed_socks5: fprintf(stderr, "Failed connection for socket %d/%d. Sleeping 2 seconds...\n",i+1, CLIENT_PORT_SIZE); close(sock1); @@ -41,6 +28,66 @@ failed_socks5: } } +void configure_tcp_clients(struct evt_core_ctx* ctx, struct evt_core_cat* cat, int fd) { + int err, pos; + struct donar_client_ctx* app_ctx = (struct donar_client_ctx*) cat->app_ctx; + + pos = -1; + for (int i = 0; i < CLIENT_PORT_SIZE; i++) { + if (app_ctx->client_sock[i].fd == fd) { + pos = i; + } + } + + char target_host[255]; + if (strlen(app_ctx->tos.keys[pos].pub) > 254) { + fprintf(stderr, "Domain name is too long\n"); + exit(EXIT_FAILURE); + } + sprintf(target_host, "%s.onion", app_ctx->tos.keys[pos].pub); + + switch (app_ctx->client_sock[pos].state) { + case SOCKS5_STATE_NEW: + //@FIXME: We suppose that we will be able to do the whole read at once which is wrong + err = socks5_handshake_ack (fd); + if (err < 0) goto on_socks5_err; + //@FIXME: We suppose that we will be able to do the whole write at once which is wrong too + err = socks5_connect_dns(fd, target_host, app_ctx->ports[pos]); + if (err < 0) goto on_socks5_err; + app_ctx->client_sock[pos].state = SOCKS5_STATE_ACK; + printf("Socket %d/%d %s:%d is connecting...\n", pos+1, CLIENT_PORT_SIZE, target_host, app_ctx->ports[pos]); + break; + case SOCKS5_STATE_ACK: + //@FIXME: We suppose that we will be able to do the whole read at once which is wrong too + err = socks5_reply (fd); + if (err < 0) goto on_socks5_err; + app_ctx->client_sock[pos].state = SOCKS5_STATE_RDY; + int sock1, sock2; + sock1 = dup(fd); + sock2 = dup(fd); + if (sock1 < 0 || sock2 < 0) goto on_socks5_err; + void* fdcat = evt_core_rm_fd (ctx, fd); + if (fdcat == NULL) goto on_socks5_err; + evt_core_add_fd (ctx, "tcp-write", sock1); + evt_core_add_fd (ctx, "tcp-read", sock2); + printf("Socket %d/%d %s:%d has been added to the pool!\n", pos+1, CLIENT_PORT_SIZE, target_host, app_ctx->ports[pos]); + break; + case SOCKS5_STATE_RDY: + goto on_socks5_err; + break; + case SOCKS5_STATE_ERR: + goto on_socks5_err; + break; + } + + return; +on_socks5_err: + perror("An error occured while connecting to an Onion Service"); + app_ctx->client_sock[pos].state = SOCKS5_STATE_ERR; + evt_core_rm_fd (ctx, fd); + init_tcp_client (app_ctx, pos); +} + void init_udp_server(struct donar_client_ctx* ctx, char* port) { int sock1, sock2; sock1 = create_udp_server(port); @@ -58,6 +105,15 @@ socket_failed: void donar_client(struct donar_client_ctx* ctx, struct algo_skel* algo, char* onion_file, char* port) { evt_core_init (&(ctx->evts)); + struct evt_core_cat init_socks5 = { + .app_ctx = ctx, + .free_app_ctx = NULL, + .cb = configure_tcp_clients, + .name = "configure-socks5", + .flags = EPOLLIN | EPOLLET, + .socklist = NULL + }; + evt_core_add_cat (&(ctx->evts), &init_socks5); evt_core_add_cat (&(ctx->evts), &(algo->on_tcp_co)); evt_core_add_cat (&(ctx->evts), &(algo->on_udp_read)); evt_core_add_cat (&(ctx->evts), &(algo->on_tcp_read)); @@ -68,7 +124,9 @@ void donar_client(struct donar_client_ctx* ctx, struct algo_skel* algo, char* on load_onion_services (ctx, onion_file, CLIENT_PORT_SIZE); printf("--- Onion services loaded\n"); - init_tcp_clients(ctx); + for (int i = 0; i < CLIENT_PORT_SIZE; i++) { + init_tcp_client(ctx, i); + } printf("--- TCP Clients Connected\n"); init_udp_server (ctx, port); diff --git a/src/donar_client.h b/src/donar_client.h index 7b80881..356104f 100644 --- a/src/donar_client.h +++ b/src/donar_client.h @@ -11,6 +11,10 @@ struct donar_client_ctx { struct tor_os_str tos; struct evt_core_ctx evts; uint16_t ports[CLIENT_PORT_SIZE]; + struct { + int fd; + enum socks5_state state; + } client_sock[CLIENT_PORT_SIZE]; }; void donar_client(struct donar_client_ctx* ctx, struct algo_skel* as, char* onion_file, char* port); diff --git a/src/evt_core.c b/src/evt_core.c index 469fc37..daf7fc7 100644 --- a/src/evt_core.c +++ b/src/evt_core.c @@ -84,6 +84,19 @@ void evt_core_add_fd(struct evt_core_ctx* ctx, char* name, int fd) { add_fd_to_epoll(ctx->epollfd, fd, cat->flags); } +struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd) { + struct evt_core_cat* cat = g_hash_table_lookup (ctx->socklist, &fd); + if (cat == NULL) return NULL; + + g_hash_table_remove(ctx->socklist, &fd); + for (int i = 0; i < cat->socklist->len; i++) { + if (g_array_index(cat->socklist, int, i) == fd) { + g_array_remove_index(cat->socklist, i); + } + } + return cat; +} + void evt_core_free(struct evt_core_ctx* ctx) { g_hash_table_destroy(ctx->socklist); g_hash_table_destroy(ctx->catlist); @@ -109,19 +122,13 @@ void evt_core_loop(struct evt_core_ctx* ctx) { if (evt & EPOLLRDHUP) fprintf(stderr, "Epoll Read Hup Event. "); if (evt & EPOLLHUP) fprintf(stderr, "Epoll Hup Event. "); if (evt & EPOLLERR) fprintf(stderr, "Epoll Err Event. "); - fprintf (stderr, "Epoll error or stream closed for fd=%d. Updating our data structures...\n", err_fd); - struct evt_core_cat* cat = g_hash_table_lookup (ctx->socklist, &err_fd); + + cat = evt_core_rm_fd (ctx, err_fd); if (cat != NULL) { - fprintf(stderr, "The fd was belonging to category %s, clearing it.\n", cat->name); - g_hash_table_remove(ctx->socklist, &err_fd); - for (int i = 0; i < cat->socklist->len; i++) { - if (g_array_index(cat->socklist, int, i) == err_fd) { - g_array_remove_index(cat->socklist, i); - } - } + fprintf(stderr, "Clearing fd=%d on cat=%s\n", err_fd, cat->name); } else { fprintf(stderr, "The file descriptor is not registered in a category, this is probably a logic error\n"); - close (events[n].data.fd); + close (err_fd); } continue; } diff --git a/src/evt_core.h b/src/evt_core.h index 63e34a2..3e97e96 100644 --- a/src/evt_core.h +++ b/src/evt_core.h @@ -34,5 +34,6 @@ struct evt_core_ctx { 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_add_fd(struct evt_core_ctx* ctx, char* name, int fd); +struct evt_core_cat* evt_core_rm_fd(struct evt_core_ctx* ctx, int fd); void evt_core_free(struct evt_core_ctx* ctx); void evt_core_loop(struct evt_core_ctx* ctx); diff --git a/src/socks5.c b/src/socks5.c index c825dd1..925b1f8 100644 --- a/src/socks5.c +++ b/src/socks5.c @@ -1,6 +1,7 @@ #include "socks5.h" -int socks5_handshake(int sock) { +int socks5_handshake_syn(int sock) { + //@TODO: Refactor the client handshake management struct client_handshake ch = { .ver = 0x05, .nmethods = 0x01, @@ -9,10 +10,19 @@ int socks5_handshake(int sock) { int size = sizeof(uint8_t) * (2 + ch.nmethods); if (size != write(sock, &ch, size)) { - fprintf(stderr, "partial/failed write\n"); + perror("write failed on tcp socket in socks5"); return -1; } + return 0; +} +int socks5_handshake_ack(int sock) { + //@TODO: Refactor the client handshake management + 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)); if (err == -1) { @@ -82,4 +92,5 @@ int socks5_connect_dns(int sock, char* addr, uint16_t port) { fprintf(stderr, "partial/failed write\n"); return -1; } + return 0; } diff --git a/src/socks5.h b/src/socks5.h index 4cd6380..c56acb6 100644 --- a/src/socks5.h +++ b/src/socks5.h @@ -8,6 +8,13 @@ #include #include "net_tools.h" +enum socks5_state { + SOCKS5_STATE_NEW, + SOCKS5_STATE_ACK, + SOCKS5_STATE_RDY, + SOCKS5_STATE_ERR +}; + enum cmd { CMD_CONNECT = 0x01, CMD_BIND = 0x02, @@ -76,6 +83,7 @@ struct server_reply { uint16_t port; }; -int socks5_handshake(int sock); +int socks5_handshake_syn(int sock); +int socks5_handshake_ack(int sock); int socks5_connect_dns(int sock, char* addr, uint16_t port); int socks5_reply(int sock);