From 8319d782d1b53228731e6b24c7f5573a2bb177dd Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Fri, 8 Feb 2019 14:28:39 +0100 Subject: [PATCH] Migrate to cmake --- CMakeLists.txt | 18 ++++ main.c | 265 ---------------------------------------------- meson.build | 2 - src/donar-proxy.c | 47 ++++++++ src/net_tools.c | 56 ++++++++++ src/net_tools.h | 10 ++ src/socks5.c | 72 +++++++++++++ src/socks5.h | 68 ++++++++++++ src/tor_os.c | 44 ++++++++ src/tor_os.h | 15 +++ 10 files changed, 330 insertions(+), 267 deletions(-) create mode 100644 CMakeLists.txt delete mode 100644 main.c delete mode 100644 meson.build create mode 100644 src/donar-proxy.c create mode 100644 src/net_tools.c create mode 100644 src/net_tools.h create mode 100644 src/socks5.c create mode 100644 src/socks5.h create mode 100644 src/tor_os.c create mode 100644 src/tor_os.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..1a672df --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 2.6) +project(donar) + + +list(APPEND CSOURCES + src/net_tools.h + src/net_tools.c + src/socks5.h + src/socks5.c + src/tor_os.h + src/tor_os.c +) + +add_executable(donar-proxy ${CSOURCES} src/donar-proxy.c) + +install(TARGETS donar-proxy + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib) \ No newline at end of file diff --git a/main.c b/main.c deleted file mode 100644 index 9ec03b0..0000000 --- a/main.c +++ /dev/null @@ -1,265 +0,0 @@ -#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 deleted file mode 100644 index 4c5e4ae..0000000 --- a/meson.build +++ /dev/null @@ -1,2 +0,0 @@ -project('tor_latency', 'c') -executable('proxy', 'main.c') \ No newline at end of file diff --git a/src/donar-proxy.c b/src/donar-proxy.c new file mode 100644 index 0000000..fcb819c --- /dev/null +++ b/src/donar-proxy.c @@ -0,0 +1,47 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "socks5.h" +#include "tor_os.h" + +int main(int argc, char** argv) { + printf("~ Donar ~\n"); + int sock; + + struct tor_os_str tos; + tor_os_create (&tos, 10); + tor_os_read (&tos, "onion_services.txt"); + tor_os_free (&tos); + + 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/src/net_tools.c b/src/net_tools.c new file mode 100644 index 0000000..2c2fef1 --- /dev/null +++ b/src/net_tools.c @@ -0,0 +1,56 @@ +#include "net_tools.h" + +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; +} + +void fill_buffer(size_t* written, char* dest, void *src, size_t n) { + memcpy(dest+*written, src, n); + *written += n; +} + diff --git a/src/net_tools.h b/src/net_tools.h new file mode 100644 index 0000000..d1a9bf0 --- /dev/null +++ b/src/net_tools.h @@ -0,0 +1,10 @@ +#include +#include +#include +#include +#include +#include + +int create_tcp_client(char* host, char* service); +int read_entity(int fd, void* entity, int size); +void fill_buffer(size_t* written, char* dest, void *src, size_t n); diff --git a/src/socks5.c b/src/socks5.c new file mode 100644 index 0000000..03167ba --- /dev/null +++ b/src/socks5.c @@ -0,0 +1,72 @@ +#include "socks5.h" + +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); +} + +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); + } +} diff --git a/src/socks5.h b/src/socks5.h new file mode 100644 index 0000000..f879125 --- /dev/null +++ b/src/socks5.h @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include +#include +#include "net_tools.h" + +enum cmd { + CMD_CONNECT = 0x01, + CMD_BIND = 0x02, + CMD_UDP_ASSOCIATE = 0x03 +}; + +enum atyp { + ATYP_IPV4 = 0x01, + ATYP_DOMAINNAME = 0x03, + ATYP_IPV6 = 0x04 +}; + +union socks5_addr { + struct { + uint8_t len; + char* str; + } dns; + uint8_t ipv4[4]; + uint8_t ipv6[16]; +}; + +/* + * RFC 1928 Messages + * https://tools.ietf.org/html/rfc1928 + */ + +struct client_handshake { + uint8_t ver; + uint8_t nmethods; + uint8_t methods[255]; +}; + +struct server_handshake { + uint8_t ver; + uint8_t method; +}; + +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; +}; + +struct server_reply { + uint8_t ver; + uint8_t rep; + uint8_t rsv; + uint8_t atyp; + union socks5_addr bind_addr; + uint16_t port; +}; + +void socks5_handshake(int sock); +void socks5_connect_dns(int sock, char* addr, uint16_t port); +void socks5_reply(int sock); diff --git a/src/tor_os.c b/src/tor_os.c new file mode 100644 index 0000000..8014fbc --- /dev/null +++ b/src/tor_os.c @@ -0,0 +1,44 @@ +#include "tor_os.h" + +void tor_os_create(struct tor_os_str* os, size_t size) { + os->size = size; + os->filled = 0; + os->list = malloc(size * sizeof(char*)); + if (os->list == NULL) { + fprintf(stderr, "unable to allocate memory\n"); + exit(EXIT_FAILURE); + } +} + +char* tor_os_append(struct tor_os_str* os) { + if (os->filled == os->size) { + return NULL; + } + char* cur = os->list[os->filled]; + os->filled++; + return cur; +} + +void tor_os_read (struct tor_os_str* os, char* file) { + FILE* fd = NULL; + fd = fopen(file, "r"); + if (fd == NULL) { + return; + } + 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 tor_os_str* os) { + for (int i = 0; i < os->filled; i++) { + free(os->list[i]); + } + free(os->list); +} + diff --git a/src/tor_os.h b/src/tor_os.h new file mode 100644 index 0000000..26ad5e8 --- /dev/null +++ b/src/tor_os.h @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +struct tor_os_str { + size_t filled; + size_t size; + char** list; +}; + +void tor_os_create(struct tor_os_str* os, size_t size); +char* tor_os_append(struct tor_os_str* os); +void tor_os_read (struct tor_os_str* os, char* file); +void tor_os_free(struct tor_os_str* os);