From 3d36127f5bb1621dd93701d7e5c681ff885d5754 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Fri, 16 Feb 2018 17:35:24 +0300 Subject: [PATCH] Handle IPv6 packets and prepare for IPv6 DNS redirection --- dnsredir.c | 98 +++++++++++++++++++++++++++++++++++++--------------- dnsredir.h | 33 +++++++++++++----- goodbyedpi.c | 81 +++++++++++++++++++++++-------------------- 3 files changed, 140 insertions(+), 72 deletions(-) diff --git a/dnsredir.c b/dnsredir.c index 40199aa..90c0c92 100644 --- a/dnsredir.c +++ b/dnsredir.c @@ -17,8 +17,8 @@ #include "dnsredir.h" #include "uthash.h" -// IPv6 incompatible! -#define UDP_CONNRECORD_KEY_LEN 6 +/* key ('4' for IPv4 or '6' for IPv6 + srcip[16] + srcport[2]) */ +#define UDP_CONNRECORD_KEY_LEN 19 #define DNS_CLEANUP_INTERVAL_SEC 30 @@ -32,10 +32,10 @@ #define uthash_strlen(s) UDP_CONNRECORD_KEY_LEN typedef struct udp_connrecord { - /* key (srcip[4] + srcport[2]) */ + /* key ('4' for IPv4 or '6' for IPv6 + srcip[16] + srcport[2]) */ char key[UDP_CONNRECORD_KEY_LEN]; time_t time; /* time when this record was added */ - uint32_t dstip; + uint32_t dstip[4]; uint16_t dstport; UT_hash_handle hh; /* makes this structure hashable */ } udp_connrecord_t; @@ -59,26 +59,60 @@ void flush_dns_cache() { FreeLibrary(dnsapi); } -inline static void construct_key(const uint32_t srcip, const uint16_t srcport, char *key) { +inline static void fill_key_data(char *key, const uint8_t is_ipv6, const uint32_t srcip[4], + const uint16_t srcport) +{ + if (is_ipv6) { + *(uint8_t*)(key) = '6'; + ipv6_copy_addr((uint32_t*)(key + sizeof(uint8_t)), srcip); + } + else { + *(uint8_t*)(key) = '4'; + ipv4_copy_addr((uint32_t*)(key + sizeof(uint8_t)), srcip); + } + + *(uint16_t*)(key + sizeof(uint8_t) + sizeof(uint32_t) * 4) = srcport; +} + +inline static void fill_data_from_key(uint8_t *is_ipv6, uint32_t srcip[4], uint16_t *srcport, + const char *key) +{ + if (key[0] == '6') { + *is_ipv6 = 1; + ipv6_copy_addr(srcip, (uint32_t*)(key + sizeof(uint8_t))); + } + else { + *is_ipv6 = 0; + ipv4_copy_addr(srcip, (uint32_t*)(key + sizeof(uint8_t))); + } + *srcport = *(uint16_t*)(key + sizeof(uint8_t) + sizeof(uint32_t) * 4); +} + +inline static void construct_key(const uint32_t srcip[4], const uint16_t srcport, + char *key, int is_ipv6) +{ debug("Construct key enter\n"); if (key) { debug("Constructing key\n"); - - *(uint32_t*)(key) = srcip; - *(uint16_t*)(key + sizeof(srcip)) = srcport; + fill_key_data(key, is_ipv6, srcip, srcport); } debug("Construct key end\n"); } -inline static void deconstruct_key(const char *key, udp_connrecord_t *connrecord, - conntrack_info_t *conn_info) { +inline static void deconstruct_key(const char *key, const udp_connrecord_t *connrecord, + conntrack_info_t *conn_info) +{ debug("Deconstruct key enter\n"); if (key && conn_info) { debug("Deconstructing key\n"); + fill_data_from_key(&conn_info->is_ipv6, conn_info->srcip, + &conn_info->srcport, key); + + if (conn_info->is_ipv6) + ipv6_copy_addr(conn_info->dstip, connrecord->dstip); + else + ipv4_copy_addr(conn_info->dstip, connrecord->dstip); - conn_info->srcip = *(uint32_t*)(key); - conn_info->srcport = *(uint16_t*)(key + sizeof(conn_info->srcip)); - conn_info->dstip = connrecord->dstip; conn_info->dstport = connrecord->dstport; } debug("Deconstruct key end\n"); @@ -99,17 +133,26 @@ static int check_get_udp_conntrack_key(const char *key, udp_connrecord_t **connr return FALSE; } -static int add_udp_conntrack(const uint32_t srcip, const uint16_t srcport, - const uint32_t dstip, const uint16_t dstport) { +static int add_udp_conntrack(const uint32_t srcip[4], const uint16_t srcport, + const uint32_t dstip[4], const uint16_t dstport, + const int is_ipv6 + ) +{ if (!(srcip && srcport && dstip && dstport)) return FALSE; udp_connrecord_t *tmp_connrecord = malloc(sizeof(udp_connrecord_t)); - construct_key(srcip, srcport, tmp_connrecord->key); + construct_key(srcip, srcport, tmp_connrecord->key, is_ipv6); if (!check_get_udp_conntrack_key(tmp_connrecord->key, NULL)) { tmp_connrecord->time = time(NULL); - tmp_connrecord->dstip = dstip; + + if (is_ipv6) { + ipv6_copy_addr(tmp_connrecord->dstip, dstip); + } + else { + ipv4_copy_addr(tmp_connrecord->dstip, dstip); + } tmp_connrecord->dstport = dstport; HASH_ADD_STR(conntrack, key, tmp_connrecord); debug("Added UDP conntrack\n"); @@ -120,7 +163,7 @@ static int add_udp_conntrack(const uint32_t srcip, const uint16_t srcport, return FALSE; } -void dns_cleanup() { +static void dns_cleanup() { udp_connrecord_t *tmp_connrecord, *tmp_connrecord2 = NULL; if (last_cleanup == 0) { @@ -154,10 +197,11 @@ int dns_is_dns_packet(const char *packet_data, const UINT packet_dataLen, const return FALSE; } -int dns_handle_outgoing(const uint32_t srcip, const uint16_t srcport, - const uint32_t dstip, const uint16_t dstport, - const char *packet_data, const UINT packet_dataLen) { - +int dns_handle_outgoing(const uint32_t srcip[4], const uint16_t srcport, + const uint32_t dstip[4], const uint16_t dstport, + const char *packet_data, const UINT packet_dataLen, + const uint8_t is_ipv6) +{ if (packet_dataLen < 16) return FALSE; @@ -166,16 +210,16 @@ int dns_handle_outgoing(const uint32_t srcip, const uint16_t srcport, if (dns_is_dns_packet(packet_data, packet_dataLen, 1)) { /* Looks like DNS request */ debug("trying to add srcport = %hu, dstport = %hu\n", ntohs(srcport), ntohs(dstport)); - return add_udp_conntrack(srcip, srcport, dstip, dstport); + return add_udp_conntrack(srcip, srcport, dstip, dstport, is_ipv6); } debug("____dns_handle_outgoing FALSE: srcport = %hu, dstport = %hu\n", ntohs(srcport), ntohs(dstport)); return FALSE; } -int dns_handle_incoming(const uint32_t srcip, const uint16_t srcport, +int dns_handle_incoming(const uint32_t srcip[4], const uint16_t srcport, const char *packet_data, const UINT packet_dataLen, - conntrack_info_t *conn_info) { - + conntrack_info_t *conn_info, const uint8_t is_ipv6) +{ char key[UDP_CONNRECORD_KEY_LEN]; udp_connrecord_t *tmp_connrecord = NULL; @@ -186,7 +230,7 @@ int dns_handle_incoming(const uint32_t srcip, const uint16_t srcport, if (dns_is_dns_packet(packet_data, packet_dataLen, 0)) { /* Looks like DNS response */ - construct_key(srcip, srcport, key); + construct_key(srcip, srcport, key, is_ipv6); if (check_get_udp_conntrack_key(key, &tmp_connrecord) && tmp_connrecord) { /* Connection exists in conntrack, moving on */ deconstruct_key(key, tmp_connrecord, conn_info); diff --git a/dnsredir.h b/dnsredir.h index 7f0b8d8..106c6fb 100644 --- a/dnsredir.h +++ b/dnsredir.h @@ -1,19 +1,36 @@ #include typedef struct conntrack_info { - uint32_t srcip; + uint8_t is_ipv6; + uint32_t srcip[4]; uint16_t srcport; - uint32_t dstip; + uint32_t dstip[4]; uint16_t dstport; } conntrack_info_t; -int dns_handle_incoming(const uint32_t srcip, const uint16_t srcport, - const char *packet_data, const UINT packet_dataLen, - conntrack_info_t *conn_info); +inline static void ipv4_copy_addr(uint32_t dst[4], const uint32_t src[4]) { + dst[0] = src[0]; + dst[1] = 0; + dst[2] = 0; + dst[3] = 0; +} -int dns_handle_outgoing(const uint32_t srcip, const uint16_t srcport, - const uint32_t dstip, const uint16_t dstport, - const char *packet_data, const UINT packet_dataLen); +inline static void ipv6_copy_addr(uint32_t dst[4], const uint32_t src[4]) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; +} + +int dns_handle_incoming(const uint32_t srcip[4], const uint16_t srcport, + const char *packet_data, const UINT packet_dataLen, + conntrack_info_t *conn_info, const uint8_t is_ipv6); + +int dns_handle_outgoing(const uint32_t srcip[4], const uint16_t srcport, + const uint32_t dstip[4], const uint16_t dstport, + const char *packet_data, const UINT packet_dataLen, + const uint8_t is_ipv6 + ); void flush_dns_cache(); int dns_is_dns_packet(const char *packet_data, const UINT packet_dataLen, const int outgoing); diff --git a/goodbyedpi.c b/goodbyedpi.c index d7f32dc..d01fc67 100644 --- a/goodbyedpi.c +++ b/goodbyedpi.c @@ -89,12 +89,12 @@ static const char *http_methods[] = { }; static struct option long_options[] = { - {"port", required_argument, 0, 'z' }, - {"dns-addr", required_argument, 0, 'd' }, - {"dns-port", required_argument, 0, 'g' }, - {"dns-verb", no_argument, 0, 'v' }, - {"blacklist", required_argument, 0, 'b' }, - {0, 0, 0, 0 } + {"port", required_argument, 0, 'z' }, + {"dns-addr", required_argument, 0, 'd' }, + {"dns-port", required_argument, 0, 'g' }, + {"dns-verb", no_argument, 0, 'v' }, + {"blacklist", required_argument, 0, 'b' }, + {0, 0, 0, 0 } }; static char *filter_string = NULL; @@ -295,8 +295,10 @@ int main(int argc, char *argv[]) { do_dns_verb = 0, do_blacklist = 0; unsigned int http_fragment_size = 2; unsigned int https_fragment_size = 2; - uint32_t dns_addr = 0; - uint16_t dns_port = htons(53); + uint32_t dnsv4_addr = 0; + uint32_t dnsv6_addr[4] = {0}; + uint16_t dnsv4_port = htons(53); + uint16_t dnsv6_port = htons(53); char *host_addr, *useragent_addr, *method_addr; int host_len, useragent_len; int http_req_fragmented; @@ -410,8 +412,8 @@ int main(int argc, char *argv[]) { case 'd': if (!do_dns_redirect) { do_dns_redirect = 1; - dns_addr = inet_addr(optarg); - if (!dns_addr) { + dnsv4_addr = inet_addr(optarg); + if (!dnsv4_addr) { printf("DNS address parameter error!\n"); exit(EXIT_FAILURE); } @@ -426,15 +428,15 @@ int main(int argc, char *argv[]) { "--dns-port\n"); exit(EXIT_FAILURE); } - dns_port = atoi(optarg); + dnsv4_port = atoi(optarg); if (atoi(optarg) <= 0 || atoi(optarg) > 65535) { printf("DNS port parameter error!\n"); exit(EXIT_FAILURE); } - if (dns_port != 53) { - add_filter_str(IPPROTO_UDP, dns_port); + if (dnsv4_port != 53) { + add_filter_str(IPPROTO_UDP, dnsv4_port); } - dns_port = htons(dns_port); + dnsv4_port = htons(dnsv4_port); break; case 'v': do_dns_verb = 1; @@ -447,7 +449,7 @@ int main(int argc, char *argv[]) { } break; default: - printf("Usage: goodbyedpi.exe [OPTION...]\n" + puts("Usage: goodbyedpi.exe [OPTION...]\n" " -p block passive DPI\n" " -r replace Host with hoSt\n" " -s remove space between host header and its value\n" @@ -458,17 +460,19 @@ int main(int argc, char *argv[]) { " -n do not wait for first segment ACK when -k is enabled\n" " -e [value] set HTTPS fragmentation to value\n" " -w try to find and parse HTTP traffic on all processed ports (not only on port 80)\n" - " --port [value] additional TCP port to perform fragmentation on (and HTTP tricks with -w)\n" - " --dns-addr [value] redirect UDP DNS requests to the supplied IP address (experimental)\n" - " --dns-port [value] redirect UDP DNS requests to the supplied port (53 by default)\n" - " --dns-verb print verbose DNS redirection messages\n" - " --blacklist [txtfile] perform HTTP tricks only to host names and subdomains from\n" - " supplied text file. This option can be supplied multiple times.\n" + " --port [value] additional TCP port to perform fragmentation on (and HTTP tricks with -w)\n" + " --dns-addr [value] redirect UDPv4 DNS requests to the supplied IPv4 address (experimental)\n" + " --dns-port [value] redirect UDPv4 DNS requests to the supplied port (53 by default)\n" + " --dnsv6-addr [value] redirect UDPv6 DNS requests to the supplied IPv6 address (experimental)\n" + " --dnsv6-port [value] redirect UDPv6 DNS requests to the supplied port (53 by default)\n" + " --dns-verb print verbose DNS redirection messages\n" + " --blacklist [txtfile] perform HTTP tricks only to host names and subdomains from\n" + " supplied text file. This option can be supplied multiple times.\n" "\n" " -1 -p -r -s -f 2 -k 2 -n -e 2 (most compatible mode, default)\n" " -2 -p -r -s -f 2 -k 2 -n -e 40 (better speed for HTTPS yet still compatible)\n" " -3 -p -r -s -e 40 (better speed for HTTP and HTTPS)\n" - " -4 -p -r -s (best speed)\n"); + " -4 -p -r -s (best speed)"); exit(EXIT_FAILURE); } } @@ -770,20 +774,20 @@ int main(int argc, char *argv[]) { (packet_type == ipv4_udp_data || packet_type == ipv6_udp_data)) { if (addr.Direction == WINDIVERT_DIRECTION_INBOUND) { - if ((packet_v4 && dns_handle_incoming(ppIpHdr->DstAddr, ppUdpHdr->DstPort, + if ((packet_v4 && dns_handle_incoming(&ppIpHdr->DstAddr, ppUdpHdr->DstPort, packet_data, packet_dataLen, - &dns_conn_info)) + &dns_conn_info, 0)) /*|| (packet_v6 && dns_handle_incoming(ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, packet_data, packet_dataLen, - &dns_conn_info))*/) + &dns_conn_info, 1))*/) { /* Changing source IP and port to the values * from DNS conntrack */ if (packet_v4) - ppIpHdr->SrcAddr = dns_conn_info.dstip; - /*else if (packet_v6) - ppIpV6Hdr->SrcAddr = dns_conn_info.dstip;*/ + ppIpHdr->SrcAddr = dns_conn_info.dstip[0]; + else if (packet_v6) + ipv6_copy_addr(ppIpV6Hdr->SrcAddr, dns_conn_info.dstip); ppUdpHdr->DstPort = dns_conn_info.srcport; ppUdpHdr->SrcPort = dns_conn_info.dstport; should_recalc_checksum = 1; @@ -800,21 +804,24 @@ int main(int argc, char *argv[]) { } else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND) { - if ((packet_v4 && dns_handle_outgoing(ppIpHdr->SrcAddr, ppUdpHdr->SrcPort, - ppIpHdr->DstAddr, ppUdpHdr->DstPort, - packet_data, packet_dataLen)) + if ((packet_v4 && dns_handle_outgoing(&ppIpHdr->SrcAddr, ppUdpHdr->SrcPort, + &ppIpHdr->DstAddr, ppUdpHdr->DstPort, + packet_data, packet_dataLen, 0)) /*|| (packet_v6 && dns_handle_outgoing(ppIpV6Hdr->SrcAddr, ppUdpHdr->SrcPort, ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, - packet_data, packet_dataLen))*/) + packet_data, packet_dataLen, 1))*/) { /* Changing destination IP and port to the values * from configuration */ - if (packet_v4) - ppIpHdr->DstAddr = dns_addr; - /*else if (packet_v6) - ppIpV6Hdr->DstAddr = dns_addr;*/ - ppUdpHdr->DstPort = dns_port; + if (packet_v4) { + ppIpHdr->DstAddr = dnsv4_addr; + ppUdpHdr->DstPort = dnsv4_port; + } + else if (packet_v6) { + ipv6_copy_addr(ppIpV6Hdr->DstAddr, dnsv6_addr); + ppUdpHdr->DstPort = dnsv6_port; + } should_recalc_checksum = 1; } else {