diff --git a/dnsredir.c b/dnsredir.c index 8b175df..27adc8c 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 fdbc93c..85cb677 100644 --- a/goodbyedpi.c +++ b/goodbyedpi.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "windivert.h" #include "goodbyedpi.h" #include "repl_str.h" @@ -16,19 +18,22 @@ #include "dnsredir.h" #include "blackwhitelist.h" +// My mingw installation does not load inet_pton definition for some reason +WINSOCK_API_LINKAGE INT WSAAPI inet_pton(INT Family, LPCSTR pStringBuf, PVOID pAddr); + #define die() do { sleep(20); exit(EXIT_FAILURE); } while (0) #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 " \ @@ -36,22 +41,43 @@ "(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 > 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 > 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)" \ + ")" + /* #IPID# is a template to find&replace */ #define IPID_TEMPLATE "#IPID#" -#define FILTER_STRING_TEMPLATE "(ip and tcp and " \ - "(inbound and ((" \ - "(((ip.Id <= 0xF and ip.Id >= 0x0) " IPID_TEMPLATE \ - ") 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 " \ +#define FILTER_STRING_TEMPLATE \ + "(tcp and " \ + "(inbound and (" \ + "(" \ + "(" \ + "((ip.Id >= 0x0 and ip.Id <= 0xF) " IPID_TEMPLATE \ + ") 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 ")" \ + "(tcp.DstPort == 80 or tcp.DstPort == 443) and tcp.Ack and " \ + "(" DIVERT_NO_LOCALNETSv4_DST " or " DIVERT_NO_LOCALNETSv6_DST "))" \ "))" #define FILTER_PASSIVE_STRING_TEMPLATE "inbound and ip and tcp and " \ "((ip.Id <= 0xF and ip.Id >= 0x0) " IPID_TEMPLATE ") and " \ "(tcp.SrcPort == 443 or tcp.SrcPort == 80) and tcp.Rst and " \ - DIVERT_NO_LOCALNETS_SRC + DIVERT_NO_LOCALNETSv4_SRC #define SET_HTTP_FRAGMENT_SIZE_OPTION(fragment_size) do { \ if (!http_fragment_size) { \ @@ -90,21 +116,23 @@ 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' }, - {"ip-id", required_argument, 0, 'i' }, - {0, 0, 0, 0 } + {"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' }, + {"ip-id", required_argument, 0, 'i' }, + {0, 0, 0, 0 } }; static char *filter_string = NULL; static char *filter_passive_string = NULL; 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) + @@ -294,8 +322,14 @@ static PVOID find_http_method_end(const char *pkt, int http_frag, int *is_fragme } int main(int argc, char *argv[]) { + 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]; @@ -303,6 +337,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; @@ -313,12 +348,16 @@ 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 dns_addr = 0; - uint16_t dns_port = htons(53); + uint32_t dnsv4_addr = 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; int host_len, useragent_len; int http_req_fragmented; @@ -449,33 +488,70 @@ int main(int argc, char *argv[]) { i = 0; break; case 'd': - if (!do_dns_redirect) { - do_dns_redirect = 1; - dns_addr = inet_addr(optarg); - if (!dns_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); } - dns_port = atoi(optarg); + 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 (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 '@': + 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; @@ -488,7 +564,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" @@ -499,19 +575,20 @@ 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" - " --ip-id [value] handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID).\n" - " This option can be supplied multiple times.\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" + " --ip-id [value] handle additional IP ID (decimal, drop redirects and TCP RSTs with this ID).\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); } } @@ -519,12 +596,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) { @@ -538,7 +617,7 @@ int main(int argc, char *argv[]) { filter_num = 0; if (do_passivedpi) { - /* IPv4 filter for inbound RST packets with ID [0x0; 0xF] */ + /* IPv4 only filter for inbound RST packets with ID [0x0; 0xF] */ filters[filter_num] = init( filter_passive_string, WINDIVERT_FLAG_DROP); @@ -548,7 +627,7 @@ int main(int argc, char *argv[]) { } /* - * 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); @@ -566,13 +645,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 */ @@ -619,12 +738,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 ); @@ -633,11 +759,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); @@ -734,8 +867,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) { @@ -756,17 +888,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_dnsv4_redirect && (packet_type == ipv4_udp_data)) || + (do_dnsv6_redirect && (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)) + &dns_conn_info, 0)) + || + (packet_v6 && dns_handle_incoming(ppIpV6Hdr->DstAddr, ppUdpHdr->DstPort, + packet_data, packet_dataLen, + &dns_conn_info, 1))) { /* 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[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; @@ -783,14 +922,24 @@ int main(int argc, char *argv[]) { } else if (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND) { - if (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, 1))) { /* Changing destination IP and port to the values * from configuration */ - ppIpHdr->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, (uint32_t*)dnsv6_addr.s6_addr); + ppUdpHdr->DstPort = dnsv6_port; + } should_recalc_checksum = 1; } else {