diff --git a/CHANGELOG b/CHANGELOG index cfc0a92..d20eeeb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -93,3 +93,10 @@ WinDivert 1.4.0-rc - Internally queued packets are now reinjected on WinDivertClose(). - WinDivertRecv() will eventually fail with ERROR_HOST_UNREACHABLE if a packet loops indefinitely between WinDivert and another driver. + - WINDIVERT_ADDRESS now includes a Timestamp field that indicates when + the packet was first captured by WinDivert. The timestamp uses the + same clock as QueryPerformanceCounter(). + - WINDIVERT_ADDRESS now includes a Loopback field that indicates whether + the packet is a loopback packet or not. + - The filter language has been extended to include a loopback field that + matches loopback packets. diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index ded1a9d..44d8b45 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -98,6 +98,7 @@ typedef enum TOKEN_OUTBOUND, TOKEN_IF_IDX, TOKEN_SUB_IF_IDX, + TOKEN_LOOPBACK, TOKEN_OPEN, TOKEN_CLOSE, TOKEN_EQ, @@ -824,6 +825,7 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, {"ipv6.NextHdr", TOKEN_IPV6_NEXT_HDR}, {"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR}, {"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS}, + {"loopback", TOKEN_LOOPBACK}, {"not", TOKEN_NOT}, {"or", TOKEN_OR}, {"outbound", TOKEN_OUTBOUND}, @@ -1132,7 +1134,8 @@ static PEXPR WinDivertMakeVar(PPOOL pool, KIND kind) {{{0}}, TOKEN_INBOUND}, {{{0}}, TOKEN_OUTBOUND}, {{{0}}, TOKEN_IF_IDX}, - {{{0}}, TOKEN_SUB_IF_IDX} + {{{0}}, TOKEN_SUB_IF_IDX}, + {{{0}}, TOKEN_LOOPBACK} }; // Binary search: @@ -1252,6 +1255,7 @@ static PEXPR WinDivertParseTest(PPOOL pool, TOKEN *toks, UINT *i) case TOKEN_INBOUND: case TOKEN_IF_IDX: case TOKEN_SUB_IF_IDX: + case TOKEN_LOOPBACK: case TOKEN_IP: case TOKEN_IPV6: case TOKEN_ICMP: @@ -1719,6 +1723,9 @@ static void WinDivertEmitTest(PEXPR test, UINT16 offset, case TOKEN_SUB_IF_IDX: object->field = WINDIVERT_FILTER_FIELD_SUBIFIDX; break; + case TOKEN_LOOPBACK: + object->field = WINDIVERT_FILTER_FIELD_LOOPBACK; + break; case TOKEN_IP: object->field = WINDIVERT_FILTER_FIELD_IP; break; @@ -2243,6 +2250,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, case WINDIVERT_FILTER_FIELD_SUBIFIDX: val[0] = addr->SubIfIdx; break; + case WINDIVERT_FILTER_FIELD_LOOPBACK: + val[0] = addr->Loopback; + break; case WINDIVERT_FILTER_FIELD_IP: val[0] = (iphdr != NULL); break; diff --git a/doc/windivert.html b/doc/windivert.html index 2eb2bee..18e6023 100644 --- a/doc/windivert.html +++ b/doc/windivert.html @@ -311,9 +311,11 @@ library.
 typedef struct
 {
+    INT64  Timestamp;
     UINT32 IfIdx;
     UINT32 SubIfIdx;
-    UINT8  Direction;
+    UINT8  Direction:1;
+    UINT8  Loopback:1;
 } WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
 
@@ -321,6 +323,11 @@ typedef struct

Fields

+
  • Loopback: Set to 1 for loopback packets, 0 +otherwise
  • Remarks
    @@ -1508,6 +1517,7 @@ The possible fields are: inboundIs inbound? (only valid for WINDIVERT_LAYER_NETWORK) ifIdxInterface index subIfIdxSub-interface index +loopbackIs loopback packet? ipIs IPv4? ipv6Is IPv6? icmpIs ICMP? @@ -1535,10 +1545,10 @@ contain a TCP header.

    1. -Divert all outbound web traffic: +Divert all outbound (non-local) web traffic:
       HANDLE handle = WinDivertOpen(
      -        "outbound and "
      +        "outbound and !loopback and "
               "(tcp.DstPort == 80 or udp.DstPort == 53)",
               0, 0, 0
           );
      @@ -1555,17 +1565,6 @@ HANDLE handle = WinDivertOpen(
       
    2. -Divert only (inbound) local traffic: -
      -HANDLE handle = WinDivertOpen(
      -        "inbound and ("
      -        "(ip.DstAddr >= 127.0.0.1 and ip.DstAddr <= 127.255.255.255) or"
      -        "ipv6.DstAddr == ::1)",
      -        0, 0, 0
      -    );
      -
      -
    3. -
    4. Divert all traffic:
       HANDLE handle = WinDivertOpen("true", 0, 0, 0);
      diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c
      index 6db3a5b..e06dd55 100644
      --- a/examples/netdump/netdump.c
      +++ b/examples/netdump/netdump.c
      @@ -1,6 +1,6 @@
       /*
        * netdump.c
      - * (C) 2016, all rights reserved,
      + * (C) 2017, all rights reserved,
        *
        * This program is free software: you can redistribute it and/or modify
        * it under the terms of the GNU Lesser General Public License as published by
      @@ -53,6 +53,8 @@ int __cdecl main(int argc, char **argv)
           PWINDIVERT_TCPHDR tcp_header;
           PWINDIVERT_UDPHDR udp_header;
           const char *err_str;
      +    LARGE_INTEGER base, freq;
      +    double time_passed;
       
           // Check arguments.
           switch (argc)
      @@ -107,6 +109,10 @@ int __cdecl main(int argc, char **argv)
               exit(EXIT_FAILURE);
           }
       
      +    // Set up timing:
      +    QueryPerformanceFrequency(&freq);
      +    QueryPerformanceCounter(&base);
      +
           // Main loop:
           while (TRUE)
           {
      @@ -134,8 +140,13 @@ int __cdecl main(int argc, char **argv)
               // Dump packet info: 
               putchar('\n');
               SetConsoleTextAttribute(console, FOREGROUND_RED);
      -        printf("Packet [Direction=%u IfIdx=%u SubIfIdx=%u]\n",
      -            addr.Direction, addr.IfIdx, addr.SubIfIdx);
      +        time_passed = (double)(addr.Timestamp - base.QuadPart) /
      +            (double)freq.QuadPart;
      +        printf("Packet [Timestamp=%.8g, Direction=%s IfIdx=%u SubIfIdx=%u "
      +            "Loopback=%u]\n",
      +            time_passed, (addr.Direction == WINDIVERT_DIRECTION_OUTBOUND?
      +                "outbound": "inbound"), addr.IfIdx, addr.SubIfIdx,
      +                addr.Loopback);
               if (ip_header != NULL)
               {
                   UINT8 *src_addr = (UINT8 *)&ip_header->SrcAddr;
      diff --git a/examples/webfilter/webfilter.c b/examples/webfilter/webfilter.c
      index 829d935..89e5b19 100644
      --- a/examples/webfilter/webfilter.c
      +++ b/examples/webfilter/webfilter.c
      @@ -1,6 +1,6 @@
       /*
        * webfilter.c
      - * (C) 2016, all rights reserved,
      + * (C) 2017, all rights reserved,
        *
        * This program is free software: you can redistribute it and/or modify
        * it under the terms of the GNU Lesser General Public License as published by
      @@ -160,6 +160,7 @@ int __cdecl main(int argc, char **argv)
           // Open the Divert device:
           handle = WinDivertOpen(
                   "outbound && "              // Outbound traffic only
      +            "!loopback && "             // No loopback traffic
                   "ip && "                    // Only IPv4 supported
                   "tcp.DstPort == 80 && "     // HTTP (port 80) only
                   "tcp.PayloadLength > 0",    // TCP data packets only
      diff --git a/include/windivert.h b/include/windivert.h
      index 543a591..fe173f8 100644
      --- a/include/windivert.h
      +++ b/include/windivert.h
      @@ -1,6 +1,6 @@
       /*
        * windivert.h
      - * (C) 2016, all rights reserved,
      + * (C) 2017, all rights reserved,
        *
        * This program is free software: you can redistribute it and/or modify
        * it under the terms of the GNU Lesser General Public License as published by
      @@ -57,9 +57,12 @@ extern "C" {
        */
       typedef struct
       {
      +    INT64  Timestamp;                   /* Packet's timestamp. */
           UINT32 IfIdx;                       /* Packet's interface index. */
           UINT32 SubIfIdx;                    /* Packet's sub-interface index. */
      -    UINT8  Direction;                   /* Packet's direction. */
      +    UINT8  Direction:1;                 /* Packet's direction. */
      +    UINT8  Loopback:1;                  /* Packet is loopback? */
      +    UINT8  Reserved:6;
       } WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS;
       
       #define WINDIVERT_DIRECTION_OUTBOUND    0
      diff --git a/include/windivert_device.h b/include/windivert_device.h
      index 3892326..d84e145 100644
      --- a/include/windivert_device.h
      +++ b/include/windivert_device.h
      @@ -104,8 +104,9 @@
       #define WINDIVERT_FILTER_FIELD_UDP_LENGTH           55
       #define WINDIVERT_FILTER_FIELD_UDP_CHECKSUM         56
       #define WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH    57
      +#define WINDIVERT_FILTER_FIELD_LOOPBACK             58
       #define WINDIVERT_FILTER_FIELD_MAX                  \
      -    WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH
      +    WINDIVERT_FILTER_FIELD_LOOPBACK
       
       #define WINDIVERT_FILTER_TEST_EQ                    0
       #define WINDIVERT_FILTER_TEST_NEQ                   1
      diff --git a/sys/windivert.c b/sys/windivert.c
      index 14c2f12..904faee 100644
      --- a/sys/windivert.c
      +++ b/sys/windivert.c
      @@ -186,7 +186,7 @@ typedef struct layer_s *layer_t;
        */
       struct req_context_s
       {
      -    struct windivert_addr_s *addr;          // Pointer to address structure.
      +    PWINDIVERT_ADDRESS addr;                // Pointer to address structure.
       };
       typedef struct req_context_s req_context_s;
       typedef struct req_context_s *req_context_t;
      @@ -202,8 +202,9 @@ struct work_s
           PNET_BUFFER_LIST buffers;               // Packet list.
           PNET_BUFFER buffer;                     // First matching packet.
           UINT advance;                           // Bytes to retreat/advance.
      -    BOOL is_ipv4;                           // Is IPv4?
      -    BOOL hop;                               // Decrement TTL?
      +    BOOL is_ipv4:1;                         // Is IPv4?
      +    BOOL hop:1;                             // Decrement TTL?
      +    BOOL loopback:1;                        // Is loopback?
           UINT8 checksums;                        // Which checksums are valid.
           UINT8 direction;                        // Packet direction.
           UINT32 if_idx;                          // Interface index.
      @@ -226,8 +227,9 @@ struct packet_s
           LIST_ENTRY entry;                       // Entry for queue.
           UINT8 checksums;                        // Which checksums are valid.
           UINT8 direction;                        // Packet direction.
      -    BOOL is_ipv4;                           // Is IPv4?
      -    BOOL hop;                               // Decrement TTL?
      +    BOOL is_ipv4:1;                         // Is IPv4?
      +    BOOL hop:1;                             // Decrement TTL?
      +    BOOL loopback:1;                        // Is loopback?
           UINT32 if_idx;                          // Interface index.
           UINT32 sub_if_idx;                      // Sub-interface index.
           LONGLONG timestamp;                     // Packet timestamp.
      @@ -236,6 +238,7 @@ struct packet_s
       };
       typedef struct packet_s *packet_t;
       
      +#if 0
       /*
        * WinDivert address definition.
        */
      @@ -246,6 +249,7 @@ struct windivert_addr_s
           UINT8  Direction;
       };
       typedef struct windivert_addr_s *windivert_addr_t;
      +#endif
       
       /*
        * Header definitions.
      @@ -382,7 +386,7 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object);
       extern VOID windivert_close(IN WDFFILEOBJECT object);
       extern VOID windivert_destroy(IN WDFOBJECT object);
       extern NTSTATUS windivert_write(context_t context, WDFREQUEST request,
      -    windivert_addr_t addr);
      +    PWINDIVERT_ADDRESS addr);
       extern void NTAPI windivert_inject_complete(VOID *context,
           NET_BUFFER_LIST *packets, BOOLEAN dispatch_level);
       static NTSTATUS windivert_notify_callout(IN FWPS_CALLOUT_NOTIFY_TYPE type,
      @@ -423,7 +427,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
           IN UINT64 flow_context, OUT FWPS_CLASSIFY_OUT0 *result);
       static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
           UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4, BOOL hop,
      -    UINT8 checksums, LONGLONG timestamp);
      +    BOOL loopback, UINT8 checksums, LONGLONG timestamp);
       static BOOL windivert_reinject_packet(BOOL sniff_mode, BOOL foward,
           UINT8 direction, BOOL isipv4, UINT32 if_idx, UINT32 sub_if_idx,
           UINT32 priority, PNET_BUFFER_LIST buffers, PNET_BUFFER buffer,
      @@ -436,8 +440,8 @@ static void windivert_free_packet(packet_t packet);
       static UINT8 windivert_skip_headers(UINT8 proto, UINT8 **header, size_t *len);
       static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b);
       static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
      -    UINT32 sub_if_idx, BOOL outbound, BOOL isipv4, BOOL hop, UINT8 checksums,
      -    filter_t filter);
      +    UINT32 sub_if_idx, BOOL outbound, BOOL isipv4, BOOL hop, BOOL loopback,
      +    UINT8 checksums, filter_t filter);
       static NTSTATUS windivert_finalize_packet(void *header, size_t len,
           BOOL hop, UINT8 checksums);
       static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
      @@ -1481,14 +1485,15 @@ static NTSTATUS windivert_read(context_t context, WDFREQUEST request)
        */
       static void windivert_read_service_request(packet_t packet,
           PNET_BUFFER buffer, UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx,
      -    BOOL hop, UINT8 checksums, WDFREQUEST request)
      +    BOOL hop, BOOL loopback, LONGLONG timestamp, UINT8 checksums,
      +    WDFREQUEST request)
       {
           PMDL dst_mdl;
           PVOID dst, src;
           ULONG dst_len, src_len;
           NTSTATUS status;
           req_context_t req_context;
      -    windivert_addr_t addr;
      +    PWINDIVERT_ADDRESS addr;
       
           DEBUG("SERVICE: servicing read request (request=%p)", request);
               
      @@ -1534,9 +1539,12 @@ static void windivert_read_service_request(packet_t packet,
           addr = req_context->addr;
           if (addr != NULL)
           {
      +        addr->Timestamp = (INT64)timestamp;
               addr->IfIdx = if_idx;
               addr->SubIfIdx = sub_if_idx;
               addr->Direction = direction;
      +        addr->Loopback = (loopback? 1: 0);
      +        addr->Reserved = 0;
           }
       
           // Zero the IP/TCP/UDP checksums and/or decrement the TTL (if required).
      @@ -1569,7 +1577,7 @@ static void windivert_read_service(context_t context)
           NTSTATUS status;
           packet_t packet;
           req_context_t req_context;
      -    windivert_addr_t addr;
      +    PWINDIVERT_ADDRESS addr;
       
           timestamp = KeQueryPerformanceCounter(NULL).QuadPart;
           KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle);
      @@ -1596,9 +1604,10 @@ static void windivert_read_service(context_t context)
       
               if (!timeout)
               {
      -            windivert_read_service_request(packet, NULL,
      -                packet->direction, packet->if_idx, packet->sub_if_idx,
      -                packet->hop, packet->checksums, request);
      +            windivert_read_service_request(packet, NULL, packet->direction,
      +                packet->if_idx, packet->sub_if_idx, packet->hop,
      +                packet->loopback, packet->timestamp, packet->checksums,
      +                request);
               }
       
               windivert_free_packet(packet);
      @@ -1612,7 +1621,7 @@ static void windivert_read_service(context_t context)
        * WinDivert write routine.
        */
       static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
      -    windivert_addr_t addr)
      +    PWINDIVERT_ADDRESS addr)
       {
           KLOCK_QUEUE_HANDLE lock_handle;
           PMDL mdl = NULL, mdl_copy = NULL;
      @@ -1626,6 +1635,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request,
           UINT64 flags;
           HANDLE handle, compl_handle;
           PNET_BUFFER_LIST buffers = NULL;
      +    NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums_info;
           NTSTATUS status = STATUS_SUCCESS;
       
           DEBUG("WRITE: writing/injecting a packet (context=%p, request=%p)",
      @@ -1819,7 +1829,7 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
           size_t inbuflen;
           WDF_REQUEST_PARAMETERS params;
           WDFMEMORY memobj;
      -    windivert_addr_t addr = NULL;
      +    PWINDIVERT_ADDRESS addr = NULL;
           windivert_ioctl_t ioctl;
           WDF_OBJECT_ATTRIBUTES attributes;
           req_context_t req_context = NULL;
      @@ -1876,13 +1886,13 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
                       goto windivert_caller_context_error;
                   }
                   status = WdfRequestProbeAndLockUserBufferForWrite(request,
      -                (PVOID)ioctl->arg, sizeof(struct windivert_addr_s), &memobj);
      +                (PVOID)ioctl->arg, sizeof(WINDIVERT_ADDRESS), &memobj);
                   if (!NT_SUCCESS(status))
                   {
                       DEBUG_ERROR("invalid arg pointer for RECV ioctl", status);
                       goto windivert_caller_context_error;
                   }
      -            addr = (windivert_addr_t)WdfMemoryGetBuffer(memobj, NULL);
      +            addr = (PWINDIVERT_ADDRESS)WdfMemoryGetBuffer(memobj, NULL);
                   break;
       
               case IOCTL_WINDIVERT_SEND:
      @@ -1893,13 +1903,13 @@ VOID windivert_caller_context(IN WDFDEVICE device, IN WDFREQUEST request)
                       goto windivert_caller_context_error;
                   }
                   status = WdfRequestProbeAndLockUserBufferForRead(request,
      -                (PVOID)ioctl->arg, sizeof(struct windivert_addr_s), &memobj);
      +                (PVOID)ioctl->arg, sizeof(WINDIVERT_ADDRESS), &memobj);
                   if (!NT_SUCCESS(status))
                   {
                       DEBUG_ERROR("invalid arg pointer for SEND ioctl", status);
                       goto windivert_caller_context_error;
                   }
      -            addr = (windivert_addr_t)WdfMemoryGetBuffer(memobj, NULL);
      +            addr = (PWINDIVERT_ADDRESS)WdfMemoryGetBuffer(memobj, NULL);
                   break;
       
               case IOCTL_WINDIVERT_START_FILTER:
      @@ -1947,7 +1957,7 @@ extern VOID windivert_ioctl(IN WDFQUEUE queue, IN WDFREQUEST request,
           UINT8 layer;
           UINT32 priority;
           UINT64 flags;
      -    windivert_addr_t addr;
      +    PWINDIVERT_ADDRESS addr;
           req_context_t req_context;
           NTSTATUS status = STATUS_SUCCESS;
           context_t context =
      @@ -2495,7 +2505,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
           do
           {
               BOOL match = windivert_filter(buffer_fst, if_idx, sub_if_idx, outbound,
      -            isipv4, hop, checksums, filter);
      +            isipv4, hop, loopback, checksums, filter);
               if (match)
               {
                   break;
      @@ -2530,6 +2540,7 @@ static void windivert_classify_callout(context_t context, IN UINT8 direction,
           work->advance = advance;
           work->is_ipv4 = isipv4;
           work->hop = hop;
      +    work->loopback = loopback;
           work->checksums = checksums;
           work->direction = direction;
           work->if_idx = if_idx;
      @@ -2653,7 +2664,7 @@ VOID windivert_worker(IN WDFWORKITEM item)
               // Queue the first matching packet.
               ok = windivert_queue_packet(context, buffer_itr, work->direction,
                   work->if_idx, work->sub_if_idx, work->is_ipv4, work->hop,
      -            work->checksums, work->timestamp);
      +            work->loopback, work->checksums, work->timestamp);
               if (!ok)
               {
                   goto windivert_worker_complete;
      @@ -2666,12 +2677,12 @@ VOID windivert_worker(IN WDFWORKITEM item)
               {
                   match = windivert_filter(buffer_itr, work->if_idx,
                       work->sub_if_idx, outbound, work->is_ipv4, work->hop,
      -                work->checksums, filter);
      +                work->loopback, work->checksums, filter);
                   if (match)
                   {
                       ok = windivert_queue_packet(context, buffer_itr,
                           work->direction, work->if_idx, work->sub_if_idx,
      -                    work->is_ipv4, work->hop, work->checksums,
      +                    work->is_ipv4, work->hop, work->loopback, work->checksums,
                           work->timestamp);
                   }
                   else
      @@ -2705,7 +2716,7 @@ windivert_worker_complete:
        */
       static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
           UINT8 direction, UINT32 if_idx, UINT32 sub_if_idx, BOOL is_ipv4, BOOL hop,
      -    UINT8 checksums, LONGLONG timestamp0)
      +    BOOL loopback, UINT8 checksums, LONGLONG timestamp0)
       {
           KLOCK_QUEUE_HANDLE lock_handle;
           PVOID data;
      @@ -2751,7 +2762,7 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
           {
               // FAST PATH: Service an I/O request without queueing the packet.
               windivert_read_service_request(NULL, buffer, direction, if_idx,
      -            sub_if_idx, hop, checksums, request);
      +            sub_if_idx, hop, loopback, timestamp0, checksums, request);
               return TRUE;
           }
       
      @@ -2780,6 +2791,7 @@ static BOOL windivert_queue_packet(context_t context, PNET_BUFFER buffer,
           }
           packet->is_ipv4 = is_ipv4;
           packet->hop = hop;
      +    packet->loopback = loopback;
           packet->checksums = checksums;
           packet->direction = direction;
           packet->if_idx = if_idx;
      @@ -3237,8 +3249,8 @@ static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b)
        * Checks if the given packet is of interest.
        */
       static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
      -    UINT32 sub_if_idx, BOOL outbound, BOOL isipv4, BOOL hop, UINT8 checksums,
      -    filter_t filter)
      +    UINT32 sub_if_idx, BOOL outbound, BOOL isipv4, BOOL hop, BOOL loopback,
      +    UINT8 checksums, filter_t filter)
       {
           size_t tot_len, ip_header_len;
           struct iphdr *ip_header = NULL;
      @@ -3447,6 +3459,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, UINT32 if_idx,
                       case WINDIVERT_FILTER_FIELD_SUBIFIDX:
                           field[0] = (UINT32)sub_if_idx;
                           break;
      +                case WINDIVERT_FILTER_FIELD_LOOPBACK:
      +                    field[0] = (UINT32)loopback;
      +                    break;
                       case WINDIVERT_FILTER_FIELD_IP:
                           field[0] = (UINT32)(ip_header != NULL);
                           break;
      @@ -4008,6 +4023,7 @@ static filter_t windivert_filter_compile(windivert_ioctl_filter_t ioctl_filter,
                   case WINDIVERT_FILTER_FIELD_OUTBOUND:
                   case WINDIVERT_FILTER_FIELD_IFIDX:
                   case WINDIVERT_FILTER_FIELD_SUBIFIDX:
      +            case WINDIVERT_FILTER_FIELD_LOOPBACK:
                   case WINDIVERT_FILTER_FIELD_IP:
                   case WINDIVERT_FILTER_FIELD_IPV6:
                   case WINDIVERT_FILTER_FIELD_ICMP: