From 5e9e1f0eb6646ec3fca46a3d71bcbbbd6d305919 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Sun, 24 Dec 2017 20:21:32 +0300 Subject: [PATCH 1/4] Preliminary IPv6 support. No IPv6 support in DNS redirection code. IPv6 DNS request packets would be dropped. --- goodbyedpi.c | 168 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 130 insertions(+), 38 deletions(-) diff --git a/goodbyedpi.c b/goodbyedpi.c index 54e9ec3..1281cb1 100644 --- a/goodbyedpi.c +++ b/goodbyedpi.c @@ -22,14 +22,14 @@ #define MAX_FILTERS 4 #define MAX_PACKET_SIZE 9016 -#define DIVERT_NO_LOCALNETS_DST "(" \ +#define DIVERT_NO_LOCALNETSv4_DST "(" \ "(ip.DstAddr < 127.0.0.1 or ip.DstAddr > 127.255.255.255) and " \ "(ip.DstAddr < 10.0.0.0 or ip.DstAddr > 10.255.255.255) and " \ "(ip.DstAddr < 192.168.0.0 or ip.DstAddr > 192.168.255.255) and " \ "(ip.DstAddr < 172.16.0.0 or ip.DstAddr > 172.31.255.255) and " \ "(ip.DstAddr < 169.254.0.0 or ip.DstAddr > 169.254.255.255)" \ ")" -#define DIVERT_NO_LOCALNETS_SRC "(" \ +#define DIVERT_NO_LOCALNETSv4_SRC "(" \ "(ip.SrcAddr < 127.0.0.1 or ip.SrcAddr > 127.255.255.255) and " \ "(ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255) and " \ "(ip.SrcAddr < 192.168.0.0 or ip.SrcAddr > 192.168.255.255) and " \ @@ -37,6 +37,21 @@ "(ip.SrcAddr < 169.254.0.0 or ip.SrcAddr > 169.254.255.255)" \ ")" +#define DIVERT_NO_LOCALNETSv6_DST "(" \ + "(ipv6.DstAddr > ::1) and " \ + "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr > 2002::0) and " \ + "(ipv6.DstAddr < fc00::0 or ipv6.DstAddr > fe00::0) and " \ + "(ipv6.DstAddr < fe80::0 or ipv6.DstAddr > fec0::0) and " \ + "(ipv6.DstAddr < ff00::0 or ipv6.DstAddr > ffff::0)" \ + ")" +#define DIVERT_NO_LOCALNETSv6_SRC "(" \ + "(ipv6.SrcAddr > ::1) and " \ + "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr > 2002::0) and " \ + "(ipv6.SrcAddr < fc00::0 or ipv6.SrcAddr > fe00::0) and " \ + "(ipv6.SrcAddr < fe80::0 or ipv6.SrcAddr > fec0::0) and " \ + "(ipv6.SrcAddr < ff00::0 or ipv6.SrcAddr > ffff::0)" \ + ")" + #define SET_HTTP_FRAGMENT_SIZE_OPTION(fragment_size) do { \ if (!http_fragment_size) { \ if (fragment_size <= 0 || fragment_size > 65535) { \ @@ -83,19 +98,24 @@ static struct option long_options[] = { }; static char *filter_string = NULL; -static char *filter_string_template = "(ip and tcp and " - "(inbound and ((" - "((ip.Id == 0x0001 or ip.Id == 0x0000) and tcp.SrcPort == 80 and tcp.Ack) or " - "((tcp.SrcPort == 80 or tcp.SrcPort == 443) and tcp.Ack and tcp.Syn)" - ") and " DIVERT_NO_LOCALNETS_SRC ") or " +static char *filter_string_template = "(tcp and " + "(inbound and (" + "(" + "(" + "(ip.Id >= 0x0 and ip.Id <= 0xF) and " + "tcp.SrcPort == 80 and tcp.Ack" + ") or " + "((tcp.SrcPort == 80 or tcp.SrcPort == 443) and tcp.Ack and tcp.Syn)" + ")" + " and (" DIVERT_NO_LOCALNETSv4_SRC " or " DIVERT_NO_LOCALNETSv6_SRC ")) or " "(outbound and " "(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " - DIVERT_NO_LOCALNETS_DST ")" + "(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST "))" "))"; static void add_filter_str(int proto, int port) { - const char *udp = " or (ip and udp and (udp.SrcPort == %d or udp.DstPort == %d))"; - const char *tcp = " or (ip and tcp and (tcp.SrcPort == %d or tcp.DstPort == %d))"; + const char *udp = " or (udp and (udp.SrcPort == %d or udp.DstPort == %d))"; + const char *tcp = " or (tcp and (tcp.SrcPort == %d or tcp.DstPort == %d))"; char *current_filter = filter_string; int new_filter_size = strlen(current_filter) + @@ -245,10 +265,14 @@ static PVOID find_http_method_end(const char *pkt, int http_frag, int *is_fragme } int main(int argc, char *argv[]) { - static const char *fragment_size_message = - "Fragment size should be in range [0 - 65535]\n"; + static enum packet_type_e { + unknown, + ipv4_tcp, ipv4_tcp_data, ipv4_udp_data, + ipv6_tcp, ipv6_tcp_data, ipv6_udp_data + } packet_type; int i, should_reinject, should_recalc_checksum = 0; int opt; + int packet_v4, packet_v6; HANDLE w_filter = NULL; WINDIVERT_ADDRESS addr; char packet[MAX_PACKET_SIZE]; @@ -256,6 +280,7 @@ int main(int argc, char *argv[]) { UINT packetLen; UINT packet_dataLen; PWINDIVERT_IPHDR ppIpHdr; + PWINDIVERT_IPV6HDR ppIpV6Hdr; PWINDIVERT_TCPHDR ppTcpHdr; PWINDIVERT_UDPHDR ppUdpHdr; conntrack_info_t dns_conn_info; @@ -469,18 +494,18 @@ int main(int argc, char *argv[]) { filter_num = 0; if (do_passivedpi) { - /* IPv4 filter for inbound RST packets with ID = 0 or 1 */ + /* IPv4 only filter for inbound RST packets with ID = 0 or 1 */ filters[filter_num] = init( "inbound and ip and tcp and " - "(ip.Id == 0x0001 or ip.Id == 0x0000) and " + "(ip.Id >= 0x0000 and ip.Id <= 0x000F) and " "(tcp.SrcPort == 443 or tcp.SrcPort == 80) and tcp.Rst and " - DIVERT_NO_LOCALNETS_SRC, + DIVERT_NO_LOCALNETSv4_SRC, WINDIVERT_FLAG_DROP); filter_num++; } /* - * IPv4 filter for inbound HTTP redirection packets and + * IPv4 & IPv6 filter for inbound HTTP redirection packets and * active DPI circumvention */ filters[filter_num] = init(filter_string, 0); @@ -498,13 +523,53 @@ int main(int argc, char *argv[]) { while (1) { if (WinDivertRecv(w_filter, packet, sizeof(packet), &addr, &packetLen)) { - //printf("Got %s packet, len=%d!\n", addr.Direction ? "inbound" : "outbound", - // packetLen); + debug("Got %s packet, len=%d!\n", addr.Direction ? "inbound" : "outbound", + packetLen); should_reinject = 1; should_recalc_checksum = 0; - if (WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, - NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen)) { + ppIpHdr = (PWINDIVERT_IPHDR)NULL; + ppIpV6Hdr = (PWINDIVERT_IPV6HDR)NULL; + ppTcpHdr = (PWINDIVERT_TCPHDR)NULL; + ppUdpHdr = (PWINDIVERT_UDPHDR)NULL; + packet_v4 = packet_v6 = 0; + packet_type = unknown; + + // Parse network packet and set it's type + if ((packet_v4 = WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, + NULL, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen))) + { + packet_type = ipv4_tcp_data; + } + else if ((packet_v6 = WinDivertHelperParsePacket(packet, packetLen, NULL, + &ppIpV6Hdr, NULL, NULL, &ppTcpHdr, NULL, &packet_data, &packet_dataLen))) + { + packet_type = ipv6_tcp_data; + } + else if ((packet_v4 = WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, + NULL, NULL, NULL, &ppTcpHdr, NULL, NULL, NULL))) + { + packet_type = ipv4_tcp; + } + else if ((packet_v6 = WinDivertHelperParsePacket(packet, packetLen, NULL, + &ppIpV6Hdr, NULL, NULL, &ppTcpHdr, NULL, NULL, NULL))) + { + packet_type = ipv6_tcp; + } + else if ((packet_v4 = WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, + NULL, NULL, NULL, NULL, &ppUdpHdr, &packet_data, &packet_dataLen))) + { + packet_type = ipv4_udp_data; + } + else if ((packet_v6 = WinDivertHelperParsePacket(packet, packetLen, NULL, + &ppIpV6Hdr, NULL, NULL, NULL, &ppUdpHdr, &packet_data, &packet_dataLen))) + { + packet_type = ipv6_udp_data; + } + + debug("packet_type: %d, packet_v4: %d, packet_v6: %d\n", packet_type, packet_v4, packet_v6); + + if (packet_type == ipv4_tcp_data || packet_type == ipv6_tcp_data) { //printf("Got parsed packet, len=%d!\n", packet_dataLen); /* Got a TCP packet WITH DATA */ @@ -551,12 +616,19 @@ int main(int argc, char *argv[]) { * but it's better to send it anyway since it eliminates one RTT. */ if (do_fragment_http_persistent && !http_req_fragmented && - (packet_dataLen > http_fragment_size) - ) { - ppIpHdr->Length = htons( - ntohs(ppIpHdr->Length) - - packet_dataLen + http_fragment_size - ); + (packet_dataLen > http_fragment_size)) + { + if (packet_v4) + ppIpHdr->Length = htons( + ntohs(ppIpHdr->Length) - + packet_dataLen + http_fragment_size + ); + else if (packet_v6) + ppIpV6Hdr->Length = htons( + ntohs(ppIpV6Hdr->Length) - + packet_dataLen + http_fragment_size + ); + WinDivertHelperCalcChecksums( packet, packetLen - packet_dataLen + http_fragment_size, 0 ); @@ -565,11 +637,18 @@ int main(int argc, char *argv[]) { packetLen - packet_dataLen + http_fragment_size, &addr, NULL ); + if (do_fragment_http_persistent_nowait) { - ppIpHdr->Length = htons( - ntohs(ppIpHdr->Length) - - http_fragment_size + packet_dataLen - http_fragment_size - ); + if (packet_v4) + ppIpHdr->Length = htons( + ntohs(ppIpHdr->Length) - + http_fragment_size + packet_dataLen - http_fragment_size + ); + else if (packet_v6) + ppIpV6Hdr->Length = htons( + ntohs(ppIpV6Hdr->Length) - + http_fragment_size + packet_dataLen - http_fragment_size + ); memmove(packet_data, packet_data + http_fragment_size, packet_dataLen); @@ -666,8 +745,7 @@ int main(int argc, char *argv[]) { } /* Handle TCP packet with data */ /* Else if we got TCP packet without data */ - else if (WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, - NULL, NULL, NULL, &ppTcpHdr, NULL, NULL, NULL)) { + else if (packet_type == ipv4_tcp || packet_type == ipv6_tcp) { /* If we got INBOUND SYN+ACK packet */ if (addr.Direction == WINDIVERT_DIRECTION_INBOUND && ppTcpHdr->Syn == 1 && ppTcpHdr->Ack == 1) { @@ -688,17 +766,24 @@ int main(int argc, char *argv[]) { } /* Else if we got UDP packet with data */ - else if (do_dns_redirect && WinDivertHelperParsePacket(packet, packetLen, &ppIpHdr, - NULL, NULL, NULL, NULL, &ppUdpHdr, &packet_data, &packet_dataLen)) { + else if (do_dns_redirect && + (packet_type == ipv4_udp_data || packet_type == ipv6_udp_data)) { if (addr.Direction == WINDIVERT_DIRECTION_INBOUND) { - if (dns_handle_incoming(ppIpHdr->DstAddr, ppUdpHdr->DstPort, + if ((packet_v4 && dns_handle_incoming(ppIpHdr->DstAddr, ppUdpHdr->DstPort, packet_data, packet_dataLen, &dns_conn_info)) + /*|| + (packet_v6 && dns_handle_incoming(ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, + packet_data, packet_dataLen, + &dns_conn_info))*/) { /* Changing source IP and port to the values * from DNS conntrack */ - ppIpHdr->SrcAddr = dns_conn_info.dstip; + if (packet_v4) + ppIpHdr->SrcAddr = dns_conn_info.dstip; + /*else if (packet_v6) + ppIpV6Hdr->SrcAddr = dns_conn_info.dstip;*/ ppUdpHdr->DstPort = dns_conn_info.srcport; ppUdpHdr->SrcPort = dns_conn_info.dstport; should_recalc_checksum = 1; @@ -715,13 +800,20 @@ int main(int argc, char *argv[]) { } else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND) { - if (dns_handle_outgoing(ppIpHdr->SrcAddr, ppUdpHdr->SrcPort, + if ((packet_v4 && dns_handle_outgoing(ppIpHdr->SrcAddr, ppUdpHdr->SrcPort, ppIpHdr->DstAddr, ppUdpHdr->DstPort, packet_data, packet_dataLen)) + /*|| + (packet_v6 && dns_handle_outgoing(ppIpV6Hdr->SrcAddr, ppUdpHdr->SrcPort, + ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, + packet_data, packet_dataLen))*/) { /* Changing destination IP and port to the values * from configuration */ - ppIpHdr->DstAddr = dns_addr; + if (packet_v4) + ppIpHdr->DstAddr = dns_addr; + /*else if (packet_v6) + ppIpV6Hdr->DstAddr = dns_addr;*/ ppUdpHdr->DstPort = dns_port; should_recalc_checksum = 1; } From 8e7f4ff505668b4c792248b2f1e18325b2dccf8b Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Mon, 25 Dec 2017 00:05:28 +0300 Subject: [PATCH 2/4] Properly exclude Teredo --- goodbyedpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/goodbyedpi.c b/goodbyedpi.c index 1281cb1..d7f32dc 100644 --- a/goodbyedpi.c +++ b/goodbyedpi.c @@ -39,14 +39,14 @@ #define DIVERT_NO_LOCALNETSv6_DST "(" \ "(ipv6.DstAddr > ::1) and " \ - "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr > 2002::0) and " \ + "(ipv6.DstAddr < 2001::0 or ipv6.DstAddr > 2001:1::0) and " \ "(ipv6.DstAddr < fc00::0 or ipv6.DstAddr > fe00::0) and " \ "(ipv6.DstAddr < fe80::0 or ipv6.DstAddr > fec0::0) and " \ "(ipv6.DstAddr < ff00::0 or ipv6.DstAddr > ffff::0)" \ ")" #define DIVERT_NO_LOCALNETSv6_SRC "(" \ "(ipv6.SrcAddr > ::1) and " \ - "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr > 2002::0) and " \ + "(ipv6.SrcAddr < 2001::0 or ipv6.SrcAddr > 2001:1::0) and " \ "(ipv6.SrcAddr < fc00::0 or ipv6.SrcAddr > fe00::0) and " \ "(ipv6.SrcAddr < fe80::0 or ipv6.SrcAddr > fec0::0) and " \ "(ipv6.SrcAddr < ff00::0 or ipv6.SrcAddr > ffff::0)" \ From 3d36127f5bb1621dd93701d7e5c681ff885d5754 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Fri, 16 Feb 2018 17:35:24 +0300 Subject: [PATCH 3/4] 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 { From 860f483ac33a18fcc38d3ecd562d3311c4cd01b3 Mon Sep 17 00:00:00 2001 From: ValdikSS Date: Fri, 16 Feb 2018 19:45:55 +0300 Subject: [PATCH 4/4] IPv6 DNS redirection --- goodbyedpi.c | 89 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 21 deletions(-) diff --git a/goodbyedpi.c b/goodbyedpi.c index d01fc67..95a80b9 100644 --- a/goodbyedpi.c +++ b/goodbyedpi.c @@ -9,12 +9,16 @@ #include #include #include +#include +#include #include "windivert.h" #include "goodbyedpi.h" #include "service.h" #include "dnsredir.h" #include "blackwhitelist.h" +WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr); + #define die() do { printf("Something went wrong!\n" \ "Make sure you're running this program with administrator privileges\n"); \ sleep(10); exit(EXIT_FAILURE); } while (0) @@ -92,6 +96,8 @@ static struct option long_options[] = { {"port", required_argument, 0, 'z' }, {"dns-addr", required_argument, 0, 'd' }, {"dns-port", required_argument, 0, 'g' }, + {"dnsv6-addr", required_argument, 0, '!' }, + {"dnsv6-port", required_argument, 0, '@' }, {"dns-verb", no_argument, 0, 'v' }, {"blacklist", required_argument, 0, 'b' }, {0, 0, 0, 0 } @@ -291,12 +297,14 @@ int main(int argc, char *argv[]) { do_fragment_https = 0, do_host = 0, do_host_removespace = 0, do_additional_space = 0, do_http_allports = 0, - do_host_mixedcase = 0, do_dns_redirect = 0, + do_host_mixedcase = 0, + do_dnsv4_redirect = 0, do_dnsv6_redirect = 0, do_dns_verb = 0, do_blacklist = 0; unsigned int http_fragment_size = 2; unsigned int https_fragment_size = 2; uint32_t dnsv4_addr = 0; - uint32_t dnsv6_addr[4] = {0}; + struct in6_addr dnsv6_addr = {0}; + struct in6_addr dns_temp_addr = {0}; uint16_t dnsv4_port = htons(53); uint16_t dnsv6_port = htons(53); char *host_addr, *useragent_addr, *method_addr; @@ -410,27 +418,47 @@ int main(int argc, char *argv[]) { i = 0; break; case 'd': - if (!do_dns_redirect) { - do_dns_redirect = 1; - dnsv4_addr = inet_addr(optarg); - if (!dnsv4_addr) { - printf("DNS address parameter error!\n"); + if ((inet_pton(AF_INET, optarg, dns_temp_addr.s6_addr) == 1) && + !do_dnsv4_redirect) + { + do_dnsv4_redirect = 1; + if (inet_pton(AF_INET, optarg, &dnsv4_addr) != 1) { + puts("DNS address parameter error!"); exit(EXIT_FAILURE); } add_filter_str(IPPROTO_UDP, 53); flush_dns_cache(); + break; } + puts("DNS address parameter error!"); + exit(EXIT_FAILURE); + break; + case '!': + if ((inet_pton(AF_INET6, optarg, dns_temp_addr.s6_addr) == 1) && + !do_dnsv6_redirect) + { + do_dnsv6_redirect = 1; + if (inet_pton(AF_INET6, optarg, dnsv6_addr.s6_addr) != 1) { + puts("DNS address parameter error!"); + exit(EXIT_FAILURE); + } + add_filter_str(IPPROTO_UDP, 53); + flush_dns_cache(); + break; + } + puts("DNS address parameter error!"); + exit(EXIT_FAILURE); break; case 'g': - if (!do_dns_redirect) { - printf("--dns-port should be used with --dns-addr!\n" + if (!do_dnsv4_redirect) { + puts("--dns-port should be used with --dns-addr!\n" "Make sure you use --dns-addr and pass it before " - "--dns-port\n"); + "--dns-port"); exit(EXIT_FAILURE); } dnsv4_port = atoi(optarg); if (atoi(optarg) <= 0 || atoi(optarg) > 65535) { - printf("DNS port parameter error!\n"); + puts("DNS port parameter error!"); exit(EXIT_FAILURE); } if (dnsv4_port != 53) { @@ -438,6 +466,23 @@ int main(int argc, char *argv[]) { } dnsv4_port = htons(dnsv4_port); break; + case '@': + if (!do_dnsv6_redirect) { + puts("--dnsv6-port should be used with --dnsv6-addr!\n" + "Make sure you use --dnsv6-addr and pass it before " + "--dnsv6-port"); + exit(EXIT_FAILURE); + } + dnsv6_port = atoi(optarg); + if (atoi(optarg) <= 0 || atoi(optarg) > 65535) { + puts("DNS port parameter error!"); + exit(EXIT_FAILURE); + } + if (dnsv6_port != 53) { + add_filter_str(IPPROTO_UDP, dnsv6_port); + } + dnsv6_port = htons(dnsv6_port); + break; case 'v': do_dns_verb = 1; break; @@ -480,12 +525,14 @@ int main(int argc, char *argv[]) { printf("Block passive: %d, Fragment HTTP: %d, Fragment persistent HTTP: %d, " "Fragment HTTPS: %d, " "hoSt: %d, Host no space: %d, Additional space: %d, Mix Host: %d, " - "HTTP AllPorts: %d, HTTP Persistent Nowait: %d, DNS redirect: %d\n", + "HTTP AllPorts: %d, HTTP Persistent Nowait: %d, DNS redirect: %d, " + "DNSv6 redirect: %d\n", do_passivedpi, (do_fragment_http ? http_fragment_size : 0), (do_fragment_http_persistent ? http_fragment_size : 0), (do_fragment_https ? https_fragment_size : 0), do_host, do_host_removespace, do_additional_space, do_host_mixedcase, - do_http_allports, do_fragment_http_persistent_nowait, do_dns_redirect + do_http_allports, do_fragment_http_persistent_nowait, do_dnsv4_redirect, + do_dnsv6_redirect ); if (do_fragment_http && http_fragment_size > 2) { @@ -770,17 +817,17 @@ int main(int argc, char *argv[]) { } /* Else if we got UDP packet with data */ - else if (do_dns_redirect && - (packet_type == ipv4_udp_data || packet_type == ipv6_udp_data)) { - + else if ((do_dnsv4_redirect && (packet_type == ipv4_udp_data)) || + (do_dnsv6_redirect && (packet_type == ipv6_udp_data))) + { if (addr.Direction == WINDIVERT_DIRECTION_INBOUND) { if ((packet_v4 && dns_handle_incoming(&ppIpHdr->DstAddr, ppUdpHdr->DstPort, packet_data, packet_dataLen, &dns_conn_info, 0)) - /*|| + || (packet_v6 && dns_handle_incoming(ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, packet_data, packet_dataLen, - &dns_conn_info, 1))*/) + &dns_conn_info, 1))) { /* Changing source IP and port to the values * from DNS conntrack */ @@ -807,10 +854,10 @@ int main(int argc, char *argv[]) { 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, 1))*/) + packet_data, packet_dataLen, 1))) { /* Changing destination IP and port to the values * from configuration */ @@ -819,7 +866,7 @@ int main(int argc, char *argv[]) { ppUdpHdr->DstPort = dnsv4_port; } else if (packet_v6) { - ipv6_copy_addr(ppIpV6Hdr->DstAddr, dnsv6_addr); + ipv6_copy_addr(ppIpV6Hdr->DstAddr, (uint32_t*)dnsv6_addr.s6_addr); ppUdpHdr->DstPort = dnsv6_port; } should_recalc_checksum = 1;