From d0d06ea84074106e96a12d194b0ad496c9243e71 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Fri, 8 Feb 2019 11:59:56 +0100 Subject: [PATCH] Move project here to ease dev with Gnome Builder --- main.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++ meson.build | 2 + 2 files changed, 267 insertions(+) create mode 100644 main.c create mode 100644 meson.build diff --git a/main.c b/main.c new file mode 100644 index 0000000..9ec03b0 --- /dev/null +++ b/main.c @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int create_tcp_client(char* host, char* service) { + int err, sock; + struct addrinfo conf; + struct addrinfo *result, *cursor; + + memset(&conf, 0, sizeof(struct addrinfo)); + conf.ai_family = AF_UNSPEC; + conf.ai_socktype = SOCK_STREAM; + conf.ai_flags = 0; + conf.ai_protocol = 0; + + err = getaddrinfo(host, service, &conf, &result); + if (err != 0) { + fprintf(stderr, "Error with getaddrinfo()\n"); + exit(EXIT_FAILURE); + } + + for (cursor = result; cursor != NULL; cursor = cursor->ai_next) { + sock = socket(cursor->ai_family, cursor->ai_socktype, cursor->ai_protocol); + if (sock == -1) continue; + if (connect(sock, cursor->ai_addr, cursor->ai_addrlen) != -1) break; + close(sock); + } + + if (cursor == NULL) { + fprintf(stderr, "No connect worked\n"); + exit(EXIT_FAILURE); + } + + freeaddrinfo(result); + + return sock; +} + +int read_entity(int fd, void* entity, int size) { + int remaining = size; + int total_read = 0; + + while (remaining > 0) { + int nread = read(fd, ((char*)entity)+total_read, remaining); + if (nread == -1) { + return nread; + } + remaining -= nread; + total_read += nread; + } + return total_read; +} + +struct client_handshake { + uint8_t ver; + uint8_t nmethods; + uint8_t methods[255]; +}; + +struct server_handshake { + uint8_t ver; + uint8_t method; +}; + +void socks5_handshake(int sock) { + struct client_handshake ch = {0x05, 0x01, 0x00}; + + int size = sizeof(uint8_t) * (2 + ch.nmethods); + if (size != write(sock, &ch, size)) { + fprintf(stderr, "partial/failed write\n"); + exit(EXIT_FAILURE); + } + + struct server_handshake sh = {0}; + int err = read_entity(sock, &sh, sizeof(struct server_handshake)); + if (err == -1) { + perror("read"); + exit(EXIT_FAILURE); + } + + printf("[server_handshake] ver=%d, method=%d\n", sh.ver, sh.method); +} + +enum cmd { + CMD_CONNECT = 0x01, + CMD_BIND = 0x02, + CMD_UDP_ASSOCIATE = 0x03 +}; + +enum atyp { + ATYP_IPV4 = 0x01, + ATYP_DOMAINNAME = 0x03, + ATYP_IPV6 = 0x04 +}; + +struct client_request { + uint8_t ver; + uint8_t cmd; + uint8_t rsv; + uint8_t atyp; + uint8_t dst_addr_len; + char* dst_addr; + uint16_t port; +}; + +union socks5_addr { + struct { + uint8_t len; + char* str; + } dns; + uint8_t ipv4[4]; + uint8_t ipv6[16]; +}; + +struct server_reply { + uint8_t ver; + uint8_t rep; + uint8_t rsv; + uint8_t atyp; + union socks5_addr bind_addr; + uint16_t port; +}; + +void fill_buffer(size_t* written, char* dest, void *src, size_t n) { + memcpy(dest+*written, src, n); + *written += n; +} + +void socks5_reply(int sock) { + struct server_reply sr = {0}; + read_entity(sock, &sr, sizeof(uint8_t) * 4); + switch(sr.atyp) { + case ATYP_IPV4: + if (read_entity(sock, sr.bind_addr.ipv4, sizeof(uint8_t) * 4) == -1) + goto read_error; + break; + case ATYP_DOMAINNAME: + if (read_entity(sock, &sr.bind_addr.dns.len, sizeof(uint8_t) * 4) == -1) + goto read_error; + if (read_entity(sock, sr.bind_addr.dns.str, sizeof(char) * sr.bind_addr.dns.len) == -1) + goto read_error; + break; + case ATYP_IPV6: + if (read_entity(sock, sr.bind_addr.ipv6, sizeof(uint8_t) * 16) == -1) + goto read_error; + break; + default: + fprintf(stderr, "unsupported ATYP in server reply\n"); + exit(EXIT_FAILURE); + } + read_entity(sock, &sr.port, sizeof(uint16_t)); + + printf("[server_reply] ver=%d, rep=%d, atyp=%d, port=%d\n", sr.ver, sr.rep, sr.atyp, sr.port); + + return; + +read_error: + fprintf(stderr, "unsupported ATYP in server reply\n"); + exit(EXIT_FAILURE); +} + +void socks5_connect_dns(int sock, char* addr, uint16_t port) { + char buffer[262]; + size_t domainLength = strlen(addr); + if (domainLength > 255) { + fprintf(stderr, "domain is too long\n"); + exit(EXIT_FAILURE); + } + struct client_request cr = { 0x05, CMD_CONNECT, 0x00, ATYP_DOMAINNAME, (uint8_t)domainLength, addr, htons(port) }; + size_t written = 0; + fill_buffer(&written, buffer, &cr, 5*sizeof(uint8_t)); + fill_buffer(&written, buffer, cr.dst_addr, cr.dst_addr_len*sizeof(char)); + fill_buffer(&written, buffer, &cr.port, sizeof(uint16_t)); + + if (written != write(sock, buffer, written)) { + fprintf(stderr, "partial/failed write\n"); + exit(EXIT_FAILURE); + } +} + +struct onion_services { + size_t filled; + size_t size; + char** list; +}; + +void tor_os_create(struct onion_services os, size_t size) { + os.size = size; + os.filled = 0; + os.list = malloc(size); + if (os.list == NULL) { + fprintf(stderr, "unable to allocate memory\n"); + exit(EXIT_FAILURE); + } +} + +char* tor_os_append(struct onion_services os) { + if (os.filled == os.size) { + return NULL; + } + char* cur = os.list[os.filled]; + os.filled++; + return cur; +} + +void tor_os_read (struct onion_services os) { + FILE* fd = fopen("onion_services.txt", O_RDONLY); + if (fd < 0) { + return; + } + + ssize_t read; + size_t len = 0; + int n = 0; + while (1) { + char* dst = tor_os_append(os); + if (dst == NULL) break; + if (getline(&os.list[n],&len,fd) == -1) break; + } + fclose(fd); +} + +void tor_os_free(struct onion_services os) { + for (int i = 0; i < os.filled; i++) { + free(os.list[i]); + } + free(os.list); +} + +int main(int argc, char** argv) { + printf("UDP <-> TCP proxy\n"); + int sock; + + if (argc < 3) { + fprintf(stderr, "Insufficient arguments\n"); + exit(EXIT_FAILURE); + } + + sock = create_tcp_client(argv[1], argv[2]); + socks5_handshake(sock); + socks5_connect_dns(sock, "monip.org", 80); + socks5_reply(sock); + + char* req = "GET / HTTP/1.0\r\nHost: monip.org\r\n\r\n"; + size_t req_len = strlen(req); + if (req_len != write(sock, req, req_len)) { + fprintf(stderr, "partial/failed write\n"); + exit(EXIT_FAILURE); + } + char page[256]; + size_t nread = 0; + while ((nread = read(sock, page, sizeof(char) * 255)) > 0) { + //printf("%s\n", nread); + fwrite(page, nread, 1, stdout); + } + + close(sock); + exit(EXIT_SUCCESS); +} diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..4c5e4ae --- /dev/null +++ b/meson.build @@ -0,0 +1,2 @@ +project('tor_latency', 'c') +executable('proxy', 'main.c') \ No newline at end of file