diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index fa50e86..c6e0862 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -128,6 +128,7 @@ typedef enum TOKEN_FALSE, TOKEN_INBOUND, TOKEN_OUTBOUND, + TOKEN_FRAGMENT, TOKEN_IF_IDX, TOKEN_SUB_IF_IDX, TOKEN_LOOPBACK, @@ -679,6 +680,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, {"endpointId", TOKEN_ENDPOINT_ID, L__FS_}, {"event", TOKEN_EVENT, LNMFSR}, {"false", TOKEN_FALSE, LNMFSR}, + {"fragment", TOKEN_FRAGMENT, LNM___}, {"icmp", TOKEN_ICMP, LNMFS_}, {"icmp.Body", TOKEN_ICMP_BODY, LNM___}, {"icmp.Checksum", TOKEN_ICMP_CHECKSUM, LNM___}, @@ -1058,6 +1060,7 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error) {{{0}}, TOKEN_FALSE}, {{{0}}, TOKEN_INBOUND}, {{{0}}, TOKEN_OUTBOUND}, + {{{0}}, TOKEN_FRAGMENT}, {{{0}}, TOKEN_IF_IDX}, {{{0}}, TOKEN_SUB_IF_IDX}, {{{0}}, TOKEN_LOOPBACK}, @@ -1209,6 +1212,7 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error) case TOKEN_FALSE: case TOKEN_OUTBOUND: case TOKEN_INBOUND: + case TOKEN_FRAGMENT: case TOKEN_IF_IDX: case TOKEN_SUB_IF_IDX: case TOKEN_LOOPBACK: @@ -1543,6 +1547,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) break; case TOKEN_INBOUND: case TOKEN_OUTBOUND: + case TOKEN_FRAGMENT: case TOKEN_IP: case TOKEN_IPV6: case TOKEN_ICMP: @@ -1875,6 +1880,9 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, case TOKEN_INBOUND: object->field = WINDIVERT_FILTER_FIELD_INBOUND; break; + case TOKEN_FRAGMENT: + object->field = WINDIVERT_FILTER_FIELD_FRAGMENT; + break; case TOKEN_IF_IDX: object->field = WINDIVERT_FILTER_FIELD_IFIDX; break; @@ -2619,16 +2627,16 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, PWINDIVERT_ICMPV6HDR icmpv6hdr = NULL; PWINDIVERT_TCPHDR tcphdr = NULL; PWINDIVERT_UDPHDR udphdr = NULL; + WINDIVERT_PACKET info; UINT8 protocol = 0; UINT header_len = 0, payload_len = 0; UINT64 random64 = 0; - BOOL neg; UINT32 val[4]; ULARGE_INTEGER val64; UINT8 data8; UINT16 data16; UINT32 data32; - BOOL pass, big; + BOOL pass, big, neg, fragment = FALSE; int cmp; HANDLE pool; WINDIVERT_FILTER *object; @@ -2648,14 +2656,21 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (!WinDivertHelperParsePacket((PVOID)packet, packet_len, - &iphdr, &ipv6hdr, &protocol, &icmphdr, &icmpv6hdr, - &tcphdr, &udphdr, NULL, &payload_len, NULL, NULL)) + if (!WinDivertHelperParsePacketEx((PVOID)packet, packet_len, &info)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - header_len = packet_len - payload_len; + protocol = info.Protocol; + iphdr = info.IPHeader; + ipv6hdr = info.IPv6Header; + icmphdr = info.ICMPHeader; + icmpv6hdr = info.ICMPv6Header; + tcphdr = info.TCPHeader; + udphdr = info.UDPHeader; + payload_len = info.PayloadLength; + header_len = info.HeaderLength; + fragment = info.Fragment; if ((addr->IPv6 && ipv6hdr == NULL) || (!addr->IPv6 && iphdr == NULL)) { @@ -2759,6 +2774,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, case WINDIVERT_FILTER_FIELD_PACKET16: case WINDIVERT_FILTER_FIELD_PACKET32: case WINDIVERT_FILTER_FIELD_LENGTH: + case WINDIVERT_FILTER_FIELD_FRAGMENT: pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); break; @@ -2954,6 +2970,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, case WINDIVERT_FILTER_FIELD_OUTBOUND: val[0] = addr->Outbound; break; + case WINDIVERT_FILTER_FIELD_FRAGMENT: + val[0] = (UINT32)fragment; + break; case WINDIVERT_FILTER_FIELD_IFIDX: val[0] = addr->Network.IfIdx; break; @@ -3836,6 +3855,8 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test) kind = TOKEN_INBOUND; break; case WINDIVERT_FILTER_FIELD_OUTBOUND: kind = TOKEN_OUTBOUND; break; + case WINDIVERT_FILTER_FIELD_FRAGMENT: + kind = TOKEN_FRAGMENT; break; case WINDIVERT_FILTER_FIELD_IFIDX: kind = TOKEN_IF_IDX; break; case WINDIVERT_FILTER_FIELD_SUBIFIDX: @@ -4490,6 +4511,7 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, case TOKEN_ZERO: case TOKEN_INBOUND: case TOKEN_OUTBOUND: + case TOKEN_FRAGMENT: case TOKEN_IP: case TOKEN_IPV6: case TOKEN_ICMP: @@ -4787,6 +4809,8 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr, WinDivertPutString(stream, "inbound"); return; case TOKEN_OUTBOUND: WinDivertPutString(stream, "outbound"); return; + case TOKEN_FRAGMENT: + WinDivertPutString(stream, "fragment"); return; case TOKEN_IF_IDX: WinDivertPutString(stream, "ifIdx"); return; case TOKEN_SUB_IF_IDX: diff --git a/doc/windivert.html b/doc/windivert.html index 64e71e0..5b28903 100644 --- a/doc/windivert.html +++ b/doc/windivert.html @@ -2751,6 +2751,7 @@ The possible fields are: subIfIdx✔✔Sub-interface index loopback✔✔✔Is loopback packet? impostor✔✔Is impostor packet? +fragment✔✔Is IP fragment packet? endpointId✔✔Endpoint ID parentEndpointId✔✔Parent endpoint ID processId✔✔✔Process ID diff --git a/include/windivert_device.h b/include/windivert_device.h index 0022318..325944e 100644 --- a/include/windivert_device.h +++ b/include/windivert_device.h @@ -149,8 +149,9 @@ #define WINDIVERT_FILTER_FIELD_RANDOM8 82 #define WINDIVERT_FILTER_FIELD_RANDOM16 83 #define WINDIVERT_FILTER_FIELD_RANDOM32 84 +#define WINDIVERT_FILTER_FIELD_FRAGMENT 85 #define WINDIVERT_FILTER_FIELD_MAX \ - WINDIVERT_FILTER_FIELD_RANDOM32 + WINDIVERT_FILTER_FIELD_FRAGMENT #define WINDIVERT_FILTER_TEST_EQ 0 #define WINDIVERT_FILTER_TEST_NEQ 1 diff --git a/sys/windivert.c b/sys/windivert.c index 4bc61f4..d3d54a2 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -472,7 +472,7 @@ static BOOL windivert_copy_data(PNET_BUFFER buffer, PVOID data, UINT size); static BOOL windivert_lookup_data(PNET_BUFFER buffer, UINT offset, INT idx, PVOID data, UINT size); static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, - BOOL frag_mode, PWINDIVERT_IPHDR *ip_header_ptr, + BOOL *fragment_ptr, PWINDIVERT_IPHDR *ip_header_ptr, PWINDIVERT_IPV6HDR *ipv6_header_ptr, PWINDIVERT_ICMPHDR *icmp_header_ptr, PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr, PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr, UINT8 *proto_ptr, UINT *header_len_ptr, @@ -5286,7 +5286,7 @@ static BOOL windivert_lookup_data(PNET_BUFFER buffer, UINT offset, INT idx, * Parse packet headers. */ static __forceinline BOOL windivert_parse_headers(PNET_BUFFER buffer, - BOOL ipv4, BOOL frag_mode, PWINDIVERT_IPHDR *ip_header_ptr, + BOOL ipv4, BOOL *fragment_ptr, PWINDIVERT_IPHDR *ip_header_ptr, PWINDIVERT_IPV6HDR *ipv6_header_ptr, PWINDIVERT_ICMPHDR *icmp_header_ptr, PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr, PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr, UINT8 *proto_ptr, UINT *header_len_ptr, @@ -5300,6 +5300,7 @@ static __forceinline BOOL windivert_parse_headers(PNET_BUFFER buffer, PWINDIVERT_TCPHDR tcp_header = NULL; PWINDIVERT_UDPHDR udp_header = NULL; PWINDIVERT_IPV6FRAGHDR frag_header; + BOOL fragment = FALSE; UINT8 protocol = 0; UINT16 frag_off = 0; UINT header_len = 0; @@ -5344,12 +5345,7 @@ static __forceinline BOOL windivert_parse_headers(PNET_BUFFER buffer, return FALSE; } frag_off = RtlUshortByteSwap(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)); - if (!frag_mode && - (WINDIVERT_IPHDR_GET_MF(ip_header) != 0 || frag_off != 0)) - { - DEBUG("FILTER: REJECT (fragment)"); - return FALSE; - } + fragment = (frag_off != 0 || WINDIVERT_IPHDR_GET_MF(ip_header) != 0); protocol = ip_header->Protocol; NdisAdvanceNetBufferDataStart(buffer, ip_header_len, FALSE, NULL); } @@ -5381,7 +5377,6 @@ static __forceinline BOOL windivert_parse_headers(PNET_BUFFER buffer, NdisAdvanceNetBufferDataStart(buffer, ip_header_len, FALSE, NULL); // Skip extension headers: - frag_header = NULL; while (frag_off == 0) { UINT8 *ext_header = NULL; @@ -5390,26 +5385,15 @@ static __forceinline BOOL windivert_parse_headers(PNET_BUFFER buffer, switch (protocol) { case IPPROTO_FRAGMENT: - if (frag_header != NULL) - { - is_ext_header = FALSE; - break; - } frag_header = (PWINDIVERT_IPV6FRAGHDR) NdisGetDataBuffer(buffer, 8, NULL, 1, 0); ext_header = (UINT8 *)frag_header; - if (frag_header == NULL) + if (fragment || frag_header == NULL) { is_ext_header = FALSE; break; } - if (!frag_mode) - { - DEBUG("FILTER: REJECT (fragment)"); - NdisRetreatNetBufferDataStart(buffer, ip_header_len, - 0, NULL); - return FALSE; - } + fragment = TRUE; frag_off = RtlUshortByteSwap( WINDIVERT_IPV6FRAGHDR_GET_FRAGOFF(frag_header)); ext_header_len = 8; @@ -5525,6 +5509,7 @@ static __forceinline BOOL windivert_parse_headers(PNET_BUFFER buffer, return FALSE; } + *fragment_ptr = fragment; *ip_header_ptr = ip_header; *ipv6_header_ptr = ipv6_header; *icmp_header_ptr = icmp_header; @@ -5556,6 +5541,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, UINT header_len = 0, payload_len = 0; UINT64 random64 = 0; UINT16 ip, ttl; + BOOL fragment = FALSE; PWINDIVERT_DATA_NETWORK network_data = NULL; PWINDIVERT_DATA_FLOW flow_data = NULL; PWINDIVERT_DATA_SOCKET socket_data = NULL; @@ -5568,12 +5554,16 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, { case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: - if (!windivert_parse_headers(buffer, ipv4, frag_mode, &ip_header, + if (!windivert_parse_headers(buffer, ipv4, &fragment, &ip_header, &ipv6_header, &icmp_header, &icmpv6_header, &tcp_header, &udp_header, &protocol, &header_len, &payload_len)) { return FALSE; } + if (fragment && !frag_mode) + { + return FALSE; + } network_data = (PWINDIVERT_DATA_NETWORK)layer_data; break; case WINDIVERT_LAYER_FLOW: @@ -5642,6 +5632,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_FILTER_FIELD_PACKET16: case WINDIVERT_FILTER_FIELD_PACKET32: case WINDIVERT_FILTER_FIELD_LENGTH: + case WINDIVERT_FILTER_FIELD_FRAGMENT: result = (layer == WINDIVERT_LAYER_NETWORK || layer == WINDIVERT_LAYER_NETWORK_FORWARD); break; @@ -5829,6 +5820,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_FILTER_FIELD_OUTBOUND: field[0] = (UINT32)outbound; break; + case WINDIVERT_FILTER_FIELD_FRAGMENT: + field[0] = (UINT32)fragment; + break; case WINDIVERT_FILTER_FIELD_IFIDX: field[0] = network_data->IfIdx; break; @@ -6499,6 +6493,7 @@ static const WINDIVERT_FILTER *windivert_filter_compile( case WINDIVERT_FILTER_FIELD_ZERO: case WINDIVERT_FILTER_FIELD_INBOUND: case WINDIVERT_FILTER_FIELD_OUTBOUND: + case WINDIVERT_FILTER_FIELD_FRAGMENT: case WINDIVERT_FILTER_FIELD_IP: case WINDIVERT_FILTER_FIELD_IPV6: case WINDIVERT_FILTER_FIELD_ICMP: diff --git a/test/test.c b/test/test.c index 946b3c0..92f5aaa 100644 --- a/test/test.c +++ b/test/test.c @@ -192,6 +192,7 @@ static const struct test tests[] = &pkt_echo_request, TRUE}, {"(tcp? tcp.DstPort == 80: true) and (udp? udp.DstPort == 80: true)", &pkt_echo_request, TRUE}, + {"fragment", &pkt_echo_request, FALSE}, {"ip and ip and ip and ip and ip and " // Max filter length: "ip and ip and ip and ip and ip and " "ip and ip and ip and ip and ip and " @@ -752,6 +753,7 @@ static const struct test tests[] = {"ip and !loopback and (outbound? tcp.DstPort == 80 or" " tcp.DstPort == 443 or udp.DstPort == 53 :" " icmp.Type == 11 and icmp.Code == 0)", &pkt_ipv6_echo_reply, FALSE}, + {"fragment", &pkt_ipv6_echo_reply, FALSE}, {"random8 < 128", &pkt_ipv6_echo_reply, TRUE}, {"(random8 < 128? random16 < 0x8000: random32 < 0x80000000)", &pkt_ipv6_echo_reply, TRUE}, @@ -884,6 +886,7 @@ static const struct test tests[] = &pkt_ipv6_exthdrs_udp, FALSE}, {"localAddr == ::1 and remoteAddr == 1 and localPort == 4660 and " "remotePort == 43690 and protocol == 17", &pkt_ipv6_exthdrs_udp, TRUE}, + {"fragment", &pkt_ipv4_fragment_0, TRUE}, {"ip.MF or ip.FragOff != 0", &pkt_ipv4_fragment_0, TRUE}, {"icmp", &pkt_ipv4_fragment_0, TRUE}, {"icmp.Body != 123 || icmp.Body == 123", &pkt_ipv4_fragment_0, TRUE}, @@ -893,6 +896,7 @@ static const struct test tests[] = "ip.TTL == 64 and ip.Protocol == 1 and ip.SrcAddr == 0xFFFF0A000001 and " "ip.DstAddr == 0xFFFF08080808 and icmp.Type == 8 and icmp.Code == 0 and " "icmp.Body == 0x0D560001", &pkt_ipv4_fragment_0, TRUE}, + {"fragment", &pkt_ipv4_fragment_1, TRUE}, {"ip.MF or ip.FragOff != 0", &pkt_ipv4_fragment_1, TRUE}, {"icmp", &pkt_ipv4_fragment_1, FALSE}, {"icmp.Body != 123 || icmp.Body == 123", &pkt_ipv4_fragment_1, FALSE}, @@ -901,6 +905,7 @@ static const struct test tests[] = "ip.Id == 0x1234 and ip.FragOff == 1 and ip.MF == 0 and ip.DF == 0 and " "ip.TTL == 64 and ip.Protocol == 1 and ip.SrcAddr == 0xFFFF0A000001 and " "ip.DstAddr == 0xFFFF08080808", &pkt_ipv4_fragment_1, TRUE}, + {"fragment", &pkt_ipv6_fragment_0, TRUE}, {"icmpv6", &pkt_ipv6_fragment_0, TRUE}, {"length == 104 || ipv6.Length == 64", &pkt_ipv6_fragment_0, FALSE}, {"ipv6.TrafficClass == 0x00000000 and ipv6.FlowLabel == 0x0000 and " @@ -908,6 +913,7 @@ static const struct test tests[] = "ipv6.SrcAddr == 0:0:0:0:0:0:0:1 and ipv6.DstAddr == 0:0:0:0:0:0:0:1 and " "icmpv6.Type == 129 and icmpv6.Code == 0 and icmpv6.Body == 0x10720003", &pkt_ipv6_fragment_0, TRUE}, + {"fragment", &pkt_ipv6_fragment_1, TRUE}, {"icmpv6", &pkt_ipv6_fragment_1, FALSE}, {"length == 104 || ipv6.Length == 64", &pkt_ipv6_fragment_1, FALSE}, {"ipv6.TrafficClass == 0x00000000 and ipv6.FlowLabel == 0x0000 and "