#include "donar_client.h" void load_onion_services(struct donar_client_ctx* ctx, char* onion_file, int ports_count) { tor_os_create (&(ctx->tos), onion_file, NULL, ports_count); tor_os_read (&(ctx->tos)); } void init_tcp_client(struct donar_client_ctx* ctx, int i) { struct evt_core_cat cat = {0}; struct evt_core_fdinfo fdinfo = {0}; char url_buf[255]; int err; ctx->ports[i] = 7500 + i; cat.name = "configure-socks5"; fdinfo.cat = &cat; fdinfo.url = url_buf; while (1) { fdinfo.fd = create_tcp_client("127.0.0.1", "9050"); if (fdinfo.fd < 0) goto failed_socks5; ctx->client_sock[i].fd = fdinfo.fd; ctx->client_sock[i].state = SOCKS5_STATE_NEW; sprintf(url_buf, "socks5:dist:%d", i); evt_core_add_fd (&(ctx->evts), &fdinfo); //@FIXME: We suppose that we will be able to do the whole write at once which is wrong err = socks5_handshake_syn(fdinfo.fd); if (err) goto failed_socks5; break; failed_socks5: fprintf(stderr, "Failed connection for socket %d/%d. Sleeping 2 seconds...\n",i+1, CLIENT_PORT_SIZE); close(fdinfo.fd); sleep(2); } } int configure_tcp_clients(struct evt_core_ctx* ctx, struct evt_core_fdinfo* fdinfo) { int err, pos; struct donar_client_ctx* app_ctx = (struct donar_client_ctx*) fdinfo->cat->app_ctx; pos = -1; for (int i = 0; i < CLIENT_PORT_SIZE; i++) { if (app_ctx->client_sock[i].fd == fdinfo->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 (fdinfo->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(fdinfo->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 (fdinfo->fd); if (err == -SOCKS5_REP_GENERAL_FAILURE || err == -SOCKS5_REP_TTLEXP || err == -SOCKS5_REP_HOSTUNREACH) { fprintf(stderr, "%s is not ready, received %s\n", fdinfo->url, socks5_rep(-err)); goto on_socks5_err; } else if (err < 0) { fprintf(stderr, "An other error occured on %s\n", fdinfo->url); exit(EXIT_FAILURE); } app_ctx->client_sock[pos].state = SOCKS5_STATE_RDY; int sock1, sock2; sock1 = dup(fdinfo->fd); sock2 = dup(fdinfo->fd); if (sock1 < 0 || sock2 < 0) { exit(EXIT_FAILURE); } void* fdcat = evt_core_rm_fd (ctx, fdinfo->fd); if (fdcat == NULL) { exit(EXIT_FAILURE); } struct evt_core_fdinfo fdinfo = {0}; struct evt_core_cat cat = {0}; char url[1024]; fdinfo.cat = &cat; fdinfo.url = url; fdinfo.cat->name = "tcp-write"; fdinfo.fd = sock1; sprintf(fdinfo.url, "tcp:write:127.0.0.1:%d", app_ctx->ports[pos]); evt_core_add_fd (ctx, &fdinfo); fdinfo.cat->name = "tcp-read"; fdinfo.fd = sock2; sprintf(fdinfo.url, "tcp:read:127.0.0.1:%d", app_ctx->ports[pos]); evt_core_add_fd (ctx, &fdinfo); 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 1; 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, fdinfo->fd); sleep(2); init_tcp_client (app_ctx, pos); return 1; } void donar_client(struct donar_client_ctx* ctx, struct algo_skel* algo, char* onion_file, GPtrArray* exposed_ports, GPtrArray* remote_ports) { evt_core_init (&(ctx->evts)); struct evt_core_cat init_socks5 = { .app_ctx = ctx, .free_app_ctx = NULL, .cb = configure_tcp_clients, .err_cb = NULL, .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)); evt_core_add_cat (&(ctx->evts), &(algo->on_udp_write)); evt_core_add_cat (&(ctx->evts), &(algo->on_tcp_write)); printf("--- Categories created\n"); load_onion_services (ctx, onion_file, CLIENT_PORT_SIZE); printf("--- Onion services loaded\n"); for (int i = 0; i < CLIENT_PORT_SIZE; i++) { init_tcp_client(ctx, i); } printf("--- TCP Clients Connected\n"); g_ptr_array_foreach (remote_ports, (void(*)(void*, void*))init_udp_remote, &(ctx->evts)); printf("--- Remote ports are binded locally\n"); g_ptr_array_foreach (exposed_ports, (void(*)(void*, void*))init_udp_exposed, &(ctx->evts)); printf("--- Local UDP services are exposed\n"); evt_core_loop(&(ctx->evts)); tor_os_free (&(ctx->tos)); }