From fd75e6d42af895ebcb28a9676828098af0dd0b83 Mon Sep 17 00:00:00 2001 From: basil00 Date: Thu, 25 Oct 2018 10:20:46 +0800 Subject: [PATCH] Add a new SOCKET layer to WinDivert (see #156). Adds a new SOCKET layer for monitoring socket events, such as BIND, LISTEN, CONNECT, and ACCEPT. These events occur before the flow is established (and unlike the FLOW layer) it is possible to block/drop SOCKET events. Otherwise, this layer is very similar to the FLOW layer, so the PID is available and injection is not possible. This commit should be considered to be a WIP. Other changes: - New socketdump.exe sample. Prints socket events. - Improve IPv6 address parsing. - New helper functions: * WinDivertHelperFormatIPv4Address * WinDivertHelperFormatIPv6Address - Fix REFLECT bugs. - The network 5-tuple can now be accessed at the NETWORK layer. - Various cleanups. --- dll/windivert.c | 1 + dll/windivert.def | 2 + dll/windivert_helper.c | 926 +++++++++++++-------- examples/flowtrack/flowtrack.c | 49 +- examples/netdump/netdump.c | 15 +- examples/socketdump/socketdump.c | 210 +++++ examples/windivertctl/windivertctl.c | 3 + include/windivert.h | 43 +- mingw-build.sh | 4 + sys/windivert.c | 1120 ++++++++++++++++++++++++-- test/test.c | 10 +- 11 files changed, 1927 insertions(+), 456 deletions(-) create mode 100644 examples/socketdump/socketdump.c diff --git a/dll/windivert.c b/dll/windivert.c index 62208c2..32a4da4 100644 --- a/dll/windivert.c +++ b/dll/windivert.c @@ -413,6 +413,7 @@ extern HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer, case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: case WINDIVERT_LAYER_FLOW: + case WINDIVERT_LAYER_SOCKET: case WINDIVERT_LAYER_REFLECT: break; default: diff --git a/dll/windivert.def b/dll/windivert.def index a36cd4a..c9c072f 100644 --- a/dll/windivert.def +++ b/dll/windivert.def @@ -13,6 +13,8 @@ EXPORTS WinDivertHelperParsePacket WinDivertHelperParseIPv4Address WinDivertHelperParseIPv6Address + WinDivertHelperFormatIPv4Address + WinDivertHelperFormatIPv6Address WinDivertHelperCompileFilter WinDivertHelperEvalFilter WinDivertHelperFormatFilter diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index 24d7ac0..06976a6 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -126,12 +126,17 @@ typedef enum TOKEN_PROTOCOL, TOKEN_LAYER, TOKEN_FLOW, + TOKEN_SOCKET, TOKEN_NETWORK, TOKEN_NETWORK_FORWARD, TOKEN_REFLECT, TOKEN_NETWORK_PACKET, TOKEN_FLOW_ESTABLISHED, TOKEN_FLOW_DELETED, + TOKEN_SOCKET_BIND, + TOKEN_SOCKET_CONNECT, + TOKEN_SOCKET_LISTEN, + TOKEN_SOCKET_ACCEPT, TOKEN_REFLECT_ESTABLISHED, TOKEN_REFLECT_OPEN, TOKEN_REFLECT_CLOSE, @@ -158,13 +163,49 @@ typedef struct UINT pos; UINT32 val[4]; } TOKEN; -#define TOKEN_MAXLEN 32 +#define TOKEN_MAXLEN 32 typedef struct { char *name; KIND kind; -} TOKEN_NAME, *PTOKEN_NAME; + UINT8 flags; +} TOKEN_INFO, *PTOKEN_INFO; + +#define WINDIVERT_LAYER_FLAG_NETWORK (1 << WINDIVERT_LAYER_NETWORK) +#define WINDIVERT_LAYER_FLAG_NETWORK_FORWARD \ + (1 << WINDIVERT_LAYER_NETWORK_FORWARD) +#define WINDIVERT_LAYER_FLAG_FLOW (1 << WINDIVERT_LAYER_FLOW) +#define WINDIVERT_LAYER_FLAG_SOCKET (1 << WINDIVERT_LAYER_SOCKET) +#define WINDIVERT_LAYER_FLAG_REFLECT (1 << WINDIVERT_LAYER_REFLECT) + +/* + * Layer flags shorthand. + */ +#define LNMFSR (WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_NETWORK_FORWARD | \ + WINDIVERT_LAYER_FLAG_FLOW | \ + WINDIVERT_LAYER_FLAG_SOCKET | \ + WINDIVERT_LAYER_FLAG_REFLECT) +#define LNMFS_ (WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_NETWORK_FORWARD | \ + WINDIVERT_LAYER_FLAG_FLOW | \ + WINDIVERT_LAYER_FLAG_SOCKET) +#define LN_F__ (WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_FLOW) +#define LN_FS_ (WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_FLOW | \ + WINDIVERT_LAYER_FLAG_SOCKET) +#define L__FSR (WINDIVERT_LAYER_FLAG_FLOW | \ + WINDIVERT_LAYER_FLAG_SOCKET | \ + WINDIVERT_LAYER_FLAG_REFLECT) +#define LNM___ (WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_NETWORK_FORWARD) +#define L__F__ WINDIVERT_LAYER_FLAG_FLOW +#define L___S_ WINDIVERT_LAYER_FLAG_SOCKET +#define L____R WINDIVERT_LAYER_FLAG_REFLECT + + /* * Filter expressions. @@ -280,11 +321,11 @@ static UINT8 WinDivertSkipExtHeaders(UINT8 proto, UINT8 **header, UINT *len) /* * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. */ -extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen, +static BOOL WinDivertHelperParsePacket_2(PVOID pPacket, UINT packetLen, PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr, PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr, - PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, PVOID *ppData, - UINT *pDataLen) + PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, UINT8 *pProto, + PVOID *ppData, UINT *pDataLen) { PWINDIVERT_IPHDR ip_header = NULL; PWINDIVERT_IPV6HDR ipv6_header = NULL; @@ -293,7 +334,7 @@ extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen, PWINDIVERT_TCPHDR tcp_header = NULL; PWINDIVERT_UDPHDR udp_header = NULL; UINT16 header_len; - UINT8 trans_proto; + UINT8 trans_proto = 0; PVOID data = NULL; UINT data_len = 0; BOOL success; @@ -431,6 +472,10 @@ WinDivertHelperParsePacketExit: *ppUdpHdr = udp_header; success = success && (udp_header != NULL); } + if (pProto != NULL) + { + *pProto = trans_proto; + } if (ppData != NULL) { *ppData = data; @@ -443,6 +488,20 @@ WinDivertHelperParsePacketExit: return success; } +/* + * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. + */ +extern BOOL WinDivertHelperParsePacket(PVOID pPacket, UINT packetLen, + PWINDIVERT_IPHDR *ppIpHdr, PWINDIVERT_IPV6HDR *ppIpv6Hdr, + PWINDIVERT_ICMPHDR *ppIcmpHdr, PWINDIVERT_ICMPV6HDR *ppIcmpv6Hdr, + PWINDIVERT_TCPHDR *ppTcpHdr, PWINDIVERT_UDPHDR *ppUdpHdr, PVOID *ppData, + UINT *pDataLen) +{ + return WinDivertHelperParsePacket_2(pPacket, packetLen, ppIpHdr, + ppIpv6Hdr, ppIcmpHdr, ppIcmpv6Hdr, ppTcpHdr, ppUdpHdr, NULL, + ppData, pDataLen); +} + /* * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. */ @@ -461,8 +520,8 @@ extern UINT WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen, UINT payload_len, checksum_len; UINT count = 0; - WinDivertHelperParsePacket(pPacket, packetLen, &ip_header, &ipv6_header, - &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, + WinDivertHelperParsePacket_2(pPacket, packetLen, &ip_header, &ipv6_header, + &icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL, NULL, &payload_len); if (ip_header != NULL && !(flags & WINDIVERT_HELPER_NO_IP_CHECKSUM)) @@ -675,15 +734,15 @@ extern BOOL WinDivertHelperParseIPv4Address(const char *str, UINT32 *addr_ptr) */ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr) { - UINT16 laddr[8]; - UINT16 raddr[8]; - BOOL left = TRUE; + UINT16 laddr[8] = {0}; + UINT16 raddr[8] = {0}; + UINT32 addr[4]; + BOOL left = TRUE, ipv4 = FALSE; + UINT32 ipv4_addr; UINT i, j, k, l, part; char part_str[5]; - memset(laddr, 0, sizeof(laddr)); - memset(raddr, 0, sizeof(raddr)); - + j = 0; if (*str == ':') { str++; @@ -694,9 +753,13 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr) } left = FALSE; str++; + if (*str == '\0') + { + goto WinDivertHelperParseIPv6AddressSuccess; + } } - for (i = 0, j = 0, k = 0; k < 8; k++) + for (i = 0, k = 0; k < 8; k++) { if (*str == ':') { @@ -707,6 +770,18 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr) } left = FALSE; str++; + if (*str == '\0') + { + break; + } + } + + if (i < 6 && WinDivertHelperParseIPv4Address(str, &ipv4_addr)) + { + // Tail is IPv4 address: + ipv4 = TRUE; + j += 2; + goto WinDivertHelperParseIPv6AddressSuccess; } for (l = 0; l < 4 && WinDivertIsXDigit(*str); l++) { @@ -735,11 +810,7 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr) } if (*str == '\0') { - if (!left) - { - break; - } - if (k == 7) + if (!left || k == 7) { break; } @@ -748,44 +819,55 @@ extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr) } str++; } - if (*str != '\0') - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (addr_ptr == NULL) + +WinDivertHelperParseIPv6AddressSuccess: + + if (!ipv4 && addr_ptr == NULL) { return TRUE; } - for (i = 0; i < 4; i++) { k = 2 * i + j; l = k + 1; k = (k >= 8? k - 8: k); l = (l >= 8? l - 8: l); - addr_ptr[3 - i] = + addr[3 - i] = (UINT32)laddr[2 * i + 1] | (UINT32)laddr[2 * i] << 16 | (UINT32)raddr[l] | (UINT32)raddr[k] << 16; } + if (ipv4) + { + // Validate IPv4 address + if (addr[3] != 0 || addr[2] != 0 || addr[0] != 0 || + (addr[1] != 0x0000FFFF && addr[1] != 0)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + addr[0] = ipv4_addr; + } + if (addr_ptr != NULL) + { + memcpy(addr_ptr, addr, sizeof(addr)); + } return TRUE; } /* * Lookup a token. */ -static PTOKEN_NAME WinDivertTokenLookup(PTOKEN_NAME token_names, - size_t token_names_len, const char *name) +static PTOKEN_INFO WinDivertTokenLookup(PTOKEN_INFO token_info, + size_t token_info_len, const char *name) { - int lo = 0, hi = (int)token_names_len-1, mid; + int lo = 0, hi = (int)token_info_len-1, mid; int cmp; while (hi >= lo) { mid = (lo + hi) / 2; - cmp = WinDivertStrCmp(token_names[mid].name, name); + cmp = WinDivertStrCmp(token_info[mid].name, name); if (cmp < 0) { lo = mid+1; @@ -796,191 +878,12 @@ static PTOKEN_NAME WinDivertTokenLookup(PTOKEN_NAME token_names, } else { - return &token_names[mid]; + return &token_info[mid]; } } return NULL; } -/* - * Validate token for layer. - */ -static BOOL WinDivertCheckTokenKindForLayer(WINDIVERT_LAYER layer, KIND kind) -{ - switch (layer) - { - case WINDIVERT_LAYER_NETWORK: - case WINDIVERT_LAYER_NETWORK_FORWARD: - switch (kind) - { - case TOKEN_INBOUND: - case TOKEN_OUTBOUND: - return (layer != WINDIVERT_LAYER_NETWORK_FORWARD); - case TOKEN_PROCESS_ID: - case TOKEN_LOCAL_ADDR: - case TOKEN_REMOTE_ADDR: - case TOKEN_LOCAL_PORT: - case TOKEN_REMOTE_PORT: - case TOKEN_PROTOCOL: - case TOKEN_LAYER: - case TOKEN_FLOW: - case TOKEN_NETWORK: - case TOKEN_NETWORK_FORWARD: - case TOKEN_REFLECT: - case TOKEN_FLOW_ESTABLISHED: - case TOKEN_FLOW_DELETED: - case TOKEN_REFLECT_ESTABLISHED: - case TOKEN_REFLECT_OPEN: - case TOKEN_REFLECT_CLOSE: - return FALSE; - default: - return TRUE; - } - case WINDIVERT_LAYER_FLOW: - switch (kind) - { - case TOKEN_ICMP_BODY: - case TOKEN_ICMP_CHECKSUM: - case TOKEN_ICMP_CODE: - case TOKEN_ICMP_TYPE: - case TOKEN_ICMPV6_BODY: - case TOKEN_ICMPV6_CHECKSUM: - case TOKEN_ICMPV6_CODE: - case TOKEN_ICMPV6_TYPE: - case TOKEN_IP_CHECKSUM: - case TOKEN_IP_DF: - case TOKEN_IP_DST_ADDR: - case TOKEN_IP_FRAG_OFF: - case TOKEN_IP_HDR_LENGTH: - case TOKEN_IP_ID: - case TOKEN_IP_LENGTH: - case TOKEN_IP_MF: - case TOKEN_IP_PROTOCOL: - case TOKEN_IP_SRC_ADDR: - case TOKEN_IP_TOS: - case TOKEN_IP_TTL: - case TOKEN_IPV6_DST_ADDR: - case TOKEN_IPV6_FLOW_LABEL: - case TOKEN_IPV6_HOP_LIMIT: - case TOKEN_IPV6_LENGTH: - case TOKEN_IPV6_NEXT_HDR: - case TOKEN_IPV6_SRC_ADDR: - case TOKEN_IPV6_TRAFFIC_CLASS: - case TOKEN_TCP_ACK: - case TOKEN_TCP_ACK_NUM: - case TOKEN_TCP_CHECKSUM: - case TOKEN_TCP_DST_PORT: - case TOKEN_TCP_FIN: - case TOKEN_TCP_HDR_LENGTH: - case TOKEN_TCP_PAYLOAD_LENGTH: - case TOKEN_TCP_PSH: - case TOKEN_TCP_RST: - case TOKEN_TCP_SEQ_NUM: - case TOKEN_TCP_SRC_PORT: - case TOKEN_TCP_SYN: - case TOKEN_TCP_URG: - case TOKEN_TCP_URG_PTR: - case TOKEN_TCP_WINDOW: - case TOKEN_UDP_CHECKSUM: - case TOKEN_UDP_DST_PORT: - case TOKEN_UDP_LENGTH: - case TOKEN_UDP_PAYLOAD_LENGTH: - case TOKEN_UDP_SRC_PORT: - case TOKEN_IF_IDX: - case TOKEN_SUB_IF_IDX: - case TOKEN_IMPOSTOR: - case TOKEN_LAYER: - case TOKEN_FLOW: - case TOKEN_NETWORK: - case TOKEN_NETWORK_FORWARD: - case TOKEN_REFLECT: - case TOKEN_NETWORK_PACKET: - case TOKEN_REFLECT_ESTABLISHED: - case TOKEN_REFLECT_OPEN: - case TOKEN_REFLECT_CLOSE: - return FALSE; - default: - return TRUE; - } - case WINDIVERT_LAYER_REFLECT: - switch (kind) - { - case TOKEN_ICMP_BODY: - case TOKEN_ICMP_CHECKSUM: - case TOKEN_ICMP_CODE: - case TOKEN_ICMP_TYPE: - case TOKEN_ICMPV6_BODY: - case TOKEN_ICMPV6_CHECKSUM: - case TOKEN_ICMPV6_CODE: - case TOKEN_ICMPV6_TYPE: - case TOKEN_IP_CHECKSUM: - case TOKEN_IP_DF: - case TOKEN_IP_DST_ADDR: - case TOKEN_IP_FRAG_OFF: - case TOKEN_IP_HDR_LENGTH: - case TOKEN_IP_ID: - case TOKEN_IP_LENGTH: - case TOKEN_IP_MF: - case TOKEN_IP_PROTOCOL: - case TOKEN_IP_SRC_ADDR: - case TOKEN_IP_TOS: - case TOKEN_IP_TTL: - case TOKEN_IPV6_DST_ADDR: - case TOKEN_IPV6_FLOW_LABEL: - case TOKEN_IPV6_HOP_LIMIT: - case TOKEN_IPV6_LENGTH: - case TOKEN_IPV6_NEXT_HDR: - case TOKEN_IPV6_SRC_ADDR: - case TOKEN_IPV6_TRAFFIC_CLASS: - case TOKEN_TCP_ACK: - case TOKEN_TCP_ACK_NUM: - case TOKEN_TCP_CHECKSUM: - case TOKEN_TCP_DST_PORT: - case TOKEN_TCP_FIN: - case TOKEN_TCP_HDR_LENGTH: - case TOKEN_TCP_PAYLOAD_LENGTH: - case TOKEN_TCP_PSH: - case TOKEN_TCP_RST: - case TOKEN_TCP_SEQ_NUM: - case TOKEN_TCP_SRC_PORT: - case TOKEN_TCP_SYN: - case TOKEN_TCP_URG: - case TOKEN_TCP_URG_PTR: - case TOKEN_TCP_WINDOW: - case TOKEN_UDP_CHECKSUM: - case TOKEN_UDP_DST_PORT: - case TOKEN_UDP_LENGTH: - case TOKEN_UDP_PAYLOAD_LENGTH: - case TOKEN_UDP_SRC_PORT: - case TOKEN_IP: - case TOKEN_IPV6: - case TOKEN_ICMP: - case TOKEN_ICMPV6: - case TOKEN_TCP: - case TOKEN_UDP: - case TOKEN_LOOPBACK: - case TOKEN_IF_IDX: - case TOKEN_SUB_IF_IDX: - case TOKEN_IMPOSTOR: - case TOKEN_INBOUND: - case TOKEN_OUTBOUND: - case TOKEN_LOCAL_ADDR: - case TOKEN_REMOTE_ADDR: - case TOKEN_LOCAL_PORT: - case TOKEN_REMOTE_PORT: - case TOKEN_PROTOCOL: - case TOKEN_NETWORK_PACKET: - case TOKEN_FLOW_ESTABLISHED: - case TOKEN_FLOW_DELETED: - return FALSE; - default: - return TRUE; - } - default: - return FALSE; - } -} - /* * Expand a "macro" value. */ @@ -997,6 +900,9 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val) case TOKEN_FLOW: *val = WINDIVERT_LAYER_FLOW; return TRUE; + case TOKEN_SOCKET: + *val = WINDIVERT_LAYER_SOCKET; + return TRUE; case TOKEN_REFLECT: *val = WINDIVERT_LAYER_REFLECT; return TRUE; @@ -1009,6 +915,18 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val) case TOKEN_FLOW_DELETED: *val = WINDIVERT_EVENT_FLOW_DELETED; return TRUE; + case TOKEN_SOCKET_BIND: + *val = WINDIVERT_EVENT_SOCKET_BIND; + return TRUE; + case TOKEN_SOCKET_CONNECT: + *val = WINDIVERT_EVENT_SOCKET_CONNECT; + return TRUE; + case TOKEN_SOCKET_LISTEN: + *val = WINDIVERT_EVENT_SOCKET_LISTEN; + return TRUE; + case TOKEN_SOCKET_ACCEPT: + *val = WINDIVERT_EVENT_SOCKET_ACCEPT; + return TRUE; case TOKEN_REFLECT_ESTABLISHED: *val = WINDIVERT_EVENT_REFLECT_ESTABLISHED; return TRUE; @@ -1029,93 +947,98 @@ static BOOL WinDivertExpandMacro(KIND kind, UINT32 *val) static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, TOKEN *tokens, UINT tokensmax) { - static const TOKEN_NAME token_names[] = + static const TOKEN_INFO token_info[] = { - {"FLOW", TOKEN_FLOW}, - {"FLOW_DELETED", TOKEN_FLOW_DELETED}, - {"FLOW_ESTABLISHED", TOKEN_FLOW_ESTABLISHED}, - {"NETWORK", TOKEN_NETWORK}, - {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD}, - {"NETWORK_PACKET", TOKEN_NETWORK_PACKET}, - {"REFLECT", TOKEN_REFLECT}, - {"REFLECT_CLOSE", TOKEN_REFLECT_CLOSE}, - {"REFLECT_ESTABLISHED", TOKEN_REFLECT_ESTABLISHED}, - {"REFLECT_OPEN", TOKEN_REFLECT_OPEN}, - {"and", TOKEN_AND}, - {"event", TOKEN_EVENT}, - {"false", TOKEN_FALSE}, - {"icmp", TOKEN_ICMP}, - {"icmp.Body", TOKEN_ICMP_BODY}, - {"icmp.Checksum", TOKEN_ICMP_CHECKSUM}, - {"icmp.Code", TOKEN_ICMP_CODE}, - {"icmp.Type", TOKEN_ICMP_TYPE}, - {"icmpv6", TOKEN_ICMPV6}, - {"icmpv6.Body", TOKEN_ICMPV6_BODY}, - {"icmpv6.Checksum", TOKEN_ICMPV6_CHECKSUM}, - {"icmpv6.Code", TOKEN_ICMPV6_CODE}, - {"icmpv6.Type", TOKEN_ICMPV6_TYPE}, - {"ifIdx", TOKEN_IF_IDX}, - {"impostor", TOKEN_IMPOSTOR}, - {"inbound", TOKEN_INBOUND}, - {"ip", TOKEN_IP}, - {"ip.Checksum", TOKEN_IP_CHECKSUM}, - {"ip.DF", TOKEN_IP_DF}, - {"ip.DstAddr", TOKEN_IP_DST_ADDR}, - {"ip.FragOff", TOKEN_IP_FRAG_OFF}, - {"ip.HdrLength", TOKEN_IP_HDR_LENGTH}, - {"ip.Id", TOKEN_IP_ID}, - {"ip.Length", TOKEN_IP_LENGTH}, - {"ip.MF", TOKEN_IP_MF}, - {"ip.Protocol", TOKEN_IP_PROTOCOL}, - {"ip.SrcAddr", TOKEN_IP_SRC_ADDR}, - {"ip.TOS", TOKEN_IP_TOS}, - {"ip.TTL", TOKEN_IP_TTL}, - {"ipv6", TOKEN_IPV6}, - {"ipv6.DstAddr", TOKEN_IPV6_DST_ADDR}, - {"ipv6.FlowLabel", TOKEN_IPV6_FLOW_LABEL}, - {"ipv6.HopLimit", TOKEN_IPV6_HOP_LIMIT}, - {"ipv6.Length", TOKEN_IPV6_LENGTH}, - {"ipv6.NextHdr", TOKEN_IPV6_NEXT_HDR}, - {"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR}, - {"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS}, - {"layer", TOKEN_LAYER}, - {"localAddr", TOKEN_LOCAL_ADDR}, - {"localPort", TOKEN_LOCAL_PORT}, - {"loopback", TOKEN_LOOPBACK}, - {"not", TOKEN_NOT}, - {"or", TOKEN_OR}, - {"outbound", TOKEN_OUTBOUND}, - {"processId", TOKEN_PROCESS_ID}, - {"protocol", TOKEN_PROTOCOL}, - {"remoteAddr", TOKEN_REMOTE_ADDR}, - {"remotePort", TOKEN_REMOTE_PORT}, - {"subIfIdx", TOKEN_SUB_IF_IDX}, - {"tcp", TOKEN_TCP}, - {"tcp.Ack", TOKEN_TCP_ACK}, - {"tcp.AckNum", TOKEN_TCP_ACK_NUM}, - {"tcp.Checksum", TOKEN_TCP_CHECKSUM}, - {"tcp.DstPort", TOKEN_TCP_DST_PORT}, - {"tcp.Fin", TOKEN_TCP_FIN}, - {"tcp.HdrLength", TOKEN_TCP_HDR_LENGTH}, - {"tcp.PayloadLength", TOKEN_TCP_PAYLOAD_LENGTH}, - {"tcp.Psh", TOKEN_TCP_PSH}, - {"tcp.Rst", TOKEN_TCP_RST}, - {"tcp.SeqNum", TOKEN_TCP_SEQ_NUM}, - {"tcp.SrcPort", TOKEN_TCP_SRC_PORT}, - {"tcp.Syn", TOKEN_TCP_SYN}, - {"tcp.Urg", TOKEN_TCP_URG}, - {"tcp.UrgPtr", TOKEN_TCP_URG_PTR}, - {"tcp.Window", TOKEN_TCP_WINDOW}, - {"true", TOKEN_TRUE}, - {"udp", TOKEN_UDP}, - {"udp.Checksum", TOKEN_UDP_CHECKSUM}, - {"udp.DstPort", TOKEN_UDP_DST_PORT}, - {"udp.Length", TOKEN_UDP_LENGTH}, - {"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH}, - {"udp.SrcPort", TOKEN_UDP_SRC_PORT}, - {"zero", TOKEN_ZERO}, + {"FLOW", TOKEN_FLOW, L____R}, + {"FLOW_DELETED", TOKEN_FLOW_DELETED, L__F__}, + {"FLOW_ESTABLISHED", TOKEN_FLOW_ESTABLISHED, L__F__}, + {"NETWORK", TOKEN_NETWORK, L____R}, + {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD, L____R}, + {"NETWORK_PACKET", TOKEN_NETWORK_PACKET, LNM___}, + {"REFLECT", TOKEN_REFLECT, L____R}, + {"REFLECT_CLOSE", TOKEN_REFLECT_CLOSE, L____R}, + {"REFLECT_ESTABLISHED", TOKEN_REFLECT_ESTABLISHED, L____R}, + {"REFLECT_OPEN", TOKEN_REFLECT_OPEN, L____R}, + {"SOCKET", TOKEN_SOCKET, L____R}, + {"SOCKET_ACCEPT", TOKEN_SOCKET_ACCEPT, L___S_}, + {"SOCKET_BIND", TOKEN_SOCKET_BIND, L___S_}, + {"SOCKET_CONNECT", TOKEN_SOCKET_CONNECT, L___S_}, + {"SOCKET_LISTEN", TOKEN_SOCKET_LISTEN, L___S_}, + {"and", TOKEN_AND, LNMFSR}, + {"event", TOKEN_EVENT, LNMFSR}, + {"false", TOKEN_FALSE, LNMFSR}, + {"icmp", TOKEN_ICMP, LNMFS_}, + {"icmp.Body", TOKEN_ICMP_BODY, LNM___}, + {"icmp.Checksum", TOKEN_ICMP_CHECKSUM, LNM___}, + {"icmp.Code", TOKEN_ICMP_CODE, LNM___}, + {"icmp.Type", TOKEN_ICMP_TYPE, LNM___}, + {"icmpv6", TOKEN_ICMPV6, LNMFS_}, + {"icmpv6.Body", TOKEN_ICMPV6_BODY, LNM___}, + {"icmpv6.Checksum", TOKEN_ICMPV6_CHECKSUM, LNM___}, + {"icmpv6.Code", TOKEN_ICMPV6_CODE, LNM___}, + {"icmpv6.Type", TOKEN_ICMPV6_TYPE, LNM___}, + {"ifIdx", TOKEN_IF_IDX, LNM___}, + {"impostor", TOKEN_IMPOSTOR, LNM___}, + {"inbound", TOKEN_INBOUND, LN_F__}, + {"ip", TOKEN_IP, LNMFS_}, + {"ip.Checksum", TOKEN_IP_CHECKSUM, LNM___}, + {"ip.DF", TOKEN_IP_DF, LNM___}, + {"ip.DstAddr", TOKEN_IP_DST_ADDR, LNM___}, + {"ip.FragOff", TOKEN_IP_FRAG_OFF, LNM___}, + {"ip.HdrLength", TOKEN_IP_HDR_LENGTH, LNM___}, + {"ip.Id", TOKEN_IP_ID, LNM___}, + {"ip.Length", TOKEN_IP_LENGTH, LNM___}, + {"ip.MF", TOKEN_IP_MF, LNM___}, + {"ip.Protocol", TOKEN_IP_PROTOCOL, LNM___}, + {"ip.SrcAddr", TOKEN_IP_SRC_ADDR, LNM___}, + {"ip.TOS", TOKEN_IP_TOS, LNM___}, + {"ip.TTL", TOKEN_IP_TTL, LNM___}, + {"ipv6", TOKEN_IPV6, LNMFS_}, + {"ipv6.DstAddr", TOKEN_IPV6_DST_ADDR, LNM___}, + {"ipv6.FlowLabel", TOKEN_IPV6_FLOW_LABEL, LNM___}, + {"ipv6.HopLimit", TOKEN_IPV6_HOP_LIMIT, LNM___}, + {"ipv6.Length", TOKEN_IPV6_LENGTH, LNM___}, + {"ipv6.NextHdr", TOKEN_IPV6_NEXT_HDR, LNM___}, + {"ipv6.SrcAddr", TOKEN_IPV6_SRC_ADDR, LNM___}, + {"ipv6.TrafficClass", TOKEN_IPV6_TRAFFIC_CLASS, LNM___}, + {"layer", TOKEN_LAYER, L____R}, + {"localAddr", TOKEN_LOCAL_ADDR, LN_FS_}, + {"localPort", TOKEN_LOCAL_PORT, LN_FS_}, + {"loopback", TOKEN_LOOPBACK, LN_FS_}, + {"not", TOKEN_NOT, LNMFSR}, + {"or", TOKEN_OR, LNMFSR}, + {"outbound", TOKEN_OUTBOUND, LN_F__}, + {"processId", TOKEN_PROCESS_ID, L__FSR}, + {"protocol", TOKEN_PROTOCOL, LN_FS_}, + {"remoteAddr", TOKEN_REMOTE_ADDR, LN_FS_}, + {"remotePort", TOKEN_REMOTE_PORT, LN_FS_}, + {"subIfIdx", TOKEN_SUB_IF_IDX, LNM___}, + {"tcp", TOKEN_TCP, LNMFS_}, + {"tcp.Ack", TOKEN_TCP_ACK, LNM___}, + {"tcp.AckNum", TOKEN_TCP_ACK_NUM, LNM___}, + {"tcp.Checksum", TOKEN_TCP_CHECKSUM, LNM___}, + {"tcp.DstPort", TOKEN_TCP_DST_PORT, LNM___}, + {"tcp.Fin", TOKEN_TCP_FIN, LNM___}, + {"tcp.HdrLength", TOKEN_TCP_HDR_LENGTH, LNM___}, + {"tcp.PayloadLength", TOKEN_TCP_PAYLOAD_LENGTH, LNM___}, + {"tcp.Psh", TOKEN_TCP_PSH, LNM___}, + {"tcp.Rst", TOKEN_TCP_RST, LNM___}, + {"tcp.SeqNum", TOKEN_TCP_SEQ_NUM, LNM___}, + {"tcp.SrcPort", TOKEN_TCP_SRC_PORT, LNM___}, + {"tcp.Syn", TOKEN_TCP_SYN, LNM___}, + {"tcp.Urg", TOKEN_TCP_URG, LNM___}, + {"tcp.UrgPtr", TOKEN_TCP_URG_PTR, LNM___}, + {"tcp.Window", TOKEN_TCP_WINDOW, LNM___}, + {"true", TOKEN_TRUE, LNMFSR}, + {"udp", TOKEN_UDP, LNMFS_}, + {"udp.Checksum", TOKEN_UDP_CHECKSUM, LNM___}, + {"udp.DstPort", TOKEN_UDP_DST_PORT, LNM___}, + {"udp.Length", TOKEN_UDP_LENGTH, LNM___}, + {"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH, LNM___}, + {"udp.SrcPort", TOKEN_UDP_SRC_PORT, LNM___}, + {"zero", TOKEN_ZERO, LNMFSR}, }; - TOKEN_NAME *result; + TOKEN_INFO *result; char c; char token[TOKEN_MAXLEN]; UINT i = 0, j; @@ -1240,11 +1163,11 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, } // Check for symbol: - result = WinDivertTokenLookup((PTOKEN_NAME)token_names, - sizeof(token_names) / sizeof(TOKEN_NAME), token); + result = WinDivertTokenLookup((PTOKEN_INFO)token_info, + sizeof(token_info) / sizeof(TOKEN_INFO), token); if (result != NULL) { - if (!WinDivertCheckTokenKindForLayer(layer, result->kind)) + if ((result->flags & (1 << layer)) == 0) { return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER, i-j); } @@ -2618,6 +2541,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, PWINDIVERT_ICMPV6HDR icmpv6hdr = NULL; PWINDIVERT_TCPHDR tcphdr = NULL; PWINDIVERT_UDPHDR udphdr = NULL; + UINT8 protocol = 0; UINT payload_len; UINT32 val[4]; BOOL pass; @@ -2639,8 +2563,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - WinDivertHelperParsePacket(packet, packet_len, &iphdr, &ipv6hdr, - &icmphdr, &icmpv6hdr, &tcphdr, &udphdr, NULL, &payload_len); + WinDivertHelperParsePacket_2(packet, packet_len, &iphdr, &ipv6hdr, + &icmphdr, &icmpv6hdr, &tcphdr, &udphdr, &protocol, NULL, + &payload_len); if ((addr->IPv6 && ipv6hdr == NULL) || (!addr->IPv6 && iphdr == NULL)) { @@ -2649,6 +2574,7 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, } break; case WINDIVERT_LAYER_FLOW: + case WINDIVERT_LAYER_SOCKET: if (packet != NULL) { SetLastError(ERROR_INVALID_PARAMETER); @@ -2689,6 +2615,47 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, pass = TRUE; switch (object[pc].field) { + case WINDIVERT_FILTER_FIELD_ZERO: + case WINDIVERT_FILTER_FIELD_EVENT: + pass = TRUE; + break; + case WINDIVERT_FILTER_FIELD_INBOUND: + case WINDIVERT_FILTER_FIELD_OUTBOUND: + pass = (addr->Layer != WINDIVERT_LAYER_NETWORK_FORWARD && + addr->Layer != WINDIVERT_LAYER_REFLECT); + break; + case WINDIVERT_FILTER_FIELD_LOOPBACK: + case WINDIVERT_FILTER_FIELD_IMPOSTOR: + case WINDIVERT_FILTER_FIELD_IP: + case WINDIVERT_FILTER_FIELD_IPV6: + case WINDIVERT_FILTER_FIELD_ICMP: + case WINDIVERT_FILTER_FIELD_ICMPV6: + case WINDIVERT_FILTER_FIELD_TCP: + case WINDIVERT_FILTER_FIELD_UDP: + pass = (addr->Layer != WINDIVERT_LAYER_REFLECT); + break; + case WINDIVERT_FILTER_FIELD_IFIDX: + case WINDIVERT_FILTER_FIELD_SUBIFIDX: + pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || + addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); + break; + case WINDIVERT_FILTER_FIELD_LOCALADDR: + case WINDIVERT_FILTER_FIELD_REMOTEADDR: + case WINDIVERT_FILTER_FIELD_LOCALPORT: + case WINDIVERT_FILTER_FIELD_REMOTEPORT: + case WINDIVERT_FILTER_FIELD_PROTOCOL: + pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || + addr->Layer == WINDIVERT_LAYER_FLOW || + addr->Layer == WINDIVERT_LAYER_SOCKET); + break; + case WINDIVERT_FILTER_FIELD_PROCESSID: + pass = (addr->Layer == WINDIVERT_LAYER_FLOW || + addr->Layer == WINDIVERT_LAYER_SOCKET || + addr->Layer == WINDIVERT_LAYER_REFLECT); + break; + case WINDIVERT_FILTER_FIELD_LAYER: + pass = (addr->Layer == WINDIVERT_LAYER_REFLECT); + break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: case WINDIVERT_FILTER_FIELD_IP_TOS: case WINDIVERT_FILTER_FIELD_IP_LENGTH: @@ -2701,7 +2668,9 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_IP_CHECKSUM: case WINDIVERT_FILTER_FIELD_IP_SRCADDR: case WINDIVERT_FILTER_FIELD_IP_DSTADDR: - pass = (iphdr != NULL); + pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || + addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); + pass = pass && (iphdr != NULL); break; case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS: case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL: @@ -2710,19 +2679,25 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT: case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR: case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR: - pass = (ipv6hdr != NULL); + pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || + addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); + pass = pass && (ipv6hdr != NULL); break; case WINDIVERT_FILTER_FIELD_ICMP_TYPE: case WINDIVERT_FILTER_FIELD_ICMP_CODE: case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM: case WINDIVERT_FILTER_FIELD_ICMP_BODY: - pass = (icmphdr != NULL); + pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || + addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); + pass = pass && (icmphdr != NULL); break; case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE: case WINDIVERT_FILTER_FIELD_ICMPV6_CODE: case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM: case WINDIVERT_FILTER_FIELD_ICMPV6_BODY: - pass = (icmpv6hdr != NULL); + pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || + addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); + pass = pass && (icmpv6hdr != NULL); break; case WINDIVERT_FILTER_FIELD_TCP_SRCPORT: case WINDIVERT_FILTER_FIELD_TCP_DSTPORT: @@ -2739,35 +2714,22 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM: case WINDIVERT_FILTER_FIELD_TCP_URGPTR: case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH: - pass = (tcphdr != NULL); + pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || + addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); + pass = pass && (tcphdr != NULL); break; case WINDIVERT_FILTER_FIELD_UDP_SRCPORT: case WINDIVERT_FILTER_FIELD_UDP_DSTPORT: case WINDIVERT_FILTER_FIELD_UDP_LENGTH: case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM: case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH: - pass = (udphdr != NULL); - break; - case WINDIVERT_FILTER_FIELD_INBOUND: - case WINDIVERT_FILTER_FIELD_OUTBOUND: - pass = (addr->Layer != WINDIVERT_LAYER_NETWORK_FORWARD); - break; - case WINDIVERT_FILTER_FIELD_IFIDX: - case WINDIVERT_FILTER_FIELD_SUBIFIDX: pass = (addr->Layer == WINDIVERT_LAYER_NETWORK || addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD); - break; - case WINDIVERT_FILTER_FIELD_PROCESSID: - case WINDIVERT_FILTER_FIELD_LOCALADDR: - case WINDIVERT_FILTER_FIELD_REMOTEADDR: - case WINDIVERT_FILTER_FIELD_LOCALPORT: - case WINDIVERT_FILTER_FIELD_REMOTEPORT: - case WINDIVERT_FILTER_FIELD_PROTOCOL: - pass = (addr->Layer == WINDIVERT_LAYER_FLOW); + pass = pass && (udphdr != NULL); break; default: - pass = TRUE; - break; + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; } if (!pass) { @@ -2808,20 +2770,80 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, val[0] = addr->IPv6; break; case WINDIVERT_FILTER_FIELD_ICMP: - val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW? - addr->Flow.Protocol == IPPROTO_ICMP: icmphdr != NULL); + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + val[0] = (UINT32)(icmphdr != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = (UINT32)(!addr->IPv6 && + addr->Socket.Protocol == IPPROTO_ICMP); + break; + case WINDIVERT_LAYER_FLOW: + val[0] = (UINT32)(!addr->IPv6 && + addr->Flow.Protocol == IPPROTO_ICMP); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_ICMPV6: - val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW? - addr->Flow.Protocol == IPPROTO_ICMPV6: icmpv6hdr != NULL); + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + val[0] = (UINT32)(icmpv6hdr != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = (UINT32)(addr->IPv6 && + addr->Socket.Protocol == IPPROTO_ICMPV6); + break; + case WINDIVERT_LAYER_FLOW: + val[0] = (UINT32)(addr->IPv6 && + addr->Flow.Protocol == IPPROTO_ICMPV6); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_TCP: - val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW? - addr->Flow.Protocol == IPPROTO_TCP: tcphdr != NULL); + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + val[0] = (UINT32)(tcphdr != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = (UINT32)(addr->Socket.Protocol == IPPROTO_TCP); + break; + case WINDIVERT_LAYER_FLOW: + val[0] = (UINT32)(addr->Flow.Protocol == IPPROTO_TCP); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_UDP: - val[0] = (addr->Layer == WINDIVERT_LAYER_FLOW? - addr->Flow.Protocol == IPPROTO_UDP: udphdr != NULL); + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + val[0] = (UINT32)(udphdr != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = (UINT32)(addr->Socket.Protocol == IPPROTO_UDP); + break; + case WINDIVERT_LAYER_FLOW: + val[0] = (UINT32)(addr->Flow.Protocol == IPPROTO_UDP); + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: val[0] = iphdr->HdrLength; @@ -2972,29 +2994,183 @@ extern BOOL WinDivertHelperEvalFilter(const char *filter, PVOID packet, case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH: val[0] = payload_len; break; - case WINDIVERT_FILTER_FIELD_PROCESSID: - val[0] = addr->Flow.ProcessId; - break; case WINDIVERT_FILTER_FIELD_LOCALADDR: - val[0] = addr->Flow.LocalAddr[0]; - val[1] = addr->Flow.LocalAddr[1]; - val[2] = addr->Flow.LocalAddr[2]; - val[3] = addr->Flow.LocalAddr[3]; + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + if (!addr->IPv6) + { + val[1] = 0x0000FFFF; + val[0] = ntohl((addr->Outbound? iphdr->SrcAddr: + iphdr->DstAddr)); + } + else if (addr->Outbound) + { + val[3] = ntohl(ipv6hdr->SrcAddr[0]); + val[2] = ntohl(ipv6hdr->SrcAddr[1]); + val[1] = ntohl(ipv6hdr->SrcAddr[2]); + val[0] = ntohl(ipv6hdr->SrcAddr[3]); + } + else + { + val[3] = ntohl(ipv6hdr->DstAddr[0]); + val[2] = ntohl(ipv6hdr->DstAddr[1]); + val[1] = ntohl(ipv6hdr->DstAddr[2]); + val[0] = ntohl(ipv6hdr->DstAddr[3]); + } + break; + case WINDIVERT_LAYER_FLOW: + val[0] = addr->Flow.LocalAddr[0]; + val[1] = addr->Flow.LocalAddr[1]; + val[2] = addr->Flow.LocalAddr[2]; + val[3] = addr->Flow.LocalAddr[3]; + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = addr->Socket.LocalAddr[0]; + val[1] = addr->Socket.LocalAddr[1]; + val[2] = addr->Socket.LocalAddr[2]; + val[3] = addr->Socket.LocalAddr[3]; + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_REMOTEADDR: - val[0] = addr->Flow.RemoteAddr[0]; - val[1] = addr->Flow.RemoteAddr[1]; - val[2] = addr->Flow.RemoteAddr[2]; - val[3] = addr->Flow.RemoteAddr[3]; + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + if (!addr->IPv6) + { + val[1] = 0x0000FFFF; + val[0] = ntohl((!addr->Outbound? iphdr->SrcAddr: + iphdr->DstAddr)); + } + else if (!addr->Outbound) + { + val[3] = ntohl(ipv6hdr->SrcAddr[0]); + val[2] = ntohl(ipv6hdr->SrcAddr[1]); + val[1] = ntohl(ipv6hdr->SrcAddr[2]); + val[0] = ntohl(ipv6hdr->SrcAddr[3]); + } + else + { + val[3] = ntohl(ipv6hdr->DstAddr[0]); + val[2] = ntohl(ipv6hdr->DstAddr[1]); + val[1] = ntohl(ipv6hdr->DstAddr[2]); + val[0] = ntohl(ipv6hdr->DstAddr[3]); + } + break; + case WINDIVERT_LAYER_FLOW: + val[0] = addr->Flow.RemoteAddr[0]; + val[1] = addr->Flow.RemoteAddr[1]; + val[2] = addr->Flow.RemoteAddr[2]; + val[3] = addr->Flow.RemoteAddr[3]; + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = addr->Socket.RemoteAddr[0]; + val[1] = addr->Socket.RemoteAddr[1]; + val[2] = addr->Socket.RemoteAddr[2]; + val[3] = addr->Socket.RemoteAddr[3]; + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_LOCALPORT: - val[0] = addr->Flow.LocalPort; + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + if (tcphdr != NULL) + { + val[0] = ntohs((addr->Outbound? tcphdr->SrcPort: + tcphdr->DstPort)); + } + else if (udphdr != NULL) + { + val[0] = ntohs((addr->Outbound? udphdr->SrcPort: + udphdr->DstPort)); + } + else + { + val[0] = 0; + } + break; + case WINDIVERT_LAYER_FLOW: + val[0] = addr->Flow.LocalPort; + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = addr->Socket.LocalPort; + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_REMOTEPORT: - val[0] = addr->Flow.RemotePort; + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + if (tcphdr != NULL) + { + val[0] = ntohs((!addr->Outbound? tcphdr->SrcPort: + tcphdr->DstPort)); + } + else if (udphdr != NULL) + { + val[0] = ntohs((!addr->Outbound? udphdr->SrcPort: + udphdr->DstPort)); + } + else + { + val[0] = 0; + } + break; + case WINDIVERT_LAYER_FLOW: + val[0] = addr->Flow.RemotePort; + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = addr->Socket.RemotePort; + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; case WINDIVERT_FILTER_FIELD_PROTOCOL: - val[0] = addr->Flow.Protocol; + switch (addr->Layer) + { + case WINDIVERT_LAYER_NETWORK: + val[0] = protocol; + break; + case WINDIVERT_LAYER_FLOW: + val[0] = addr->Flow.Protocol; + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = addr->Socket.Protocol; + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + break; + case WINDIVERT_FILTER_FIELD_PROCESSID: + switch (addr->Layer) + { + case WINDIVERT_LAYER_FLOW: + val[0] = addr->Flow.ProcessId; + break; + case WINDIVERT_LAYER_SOCKET: + val[0] = addr->Socket.ProcessId; + break; + case WINDIVERT_LAYER_REFLECT: + val[0] = addr->Reflect.ProcessId; + break; + default: + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } break; default: SetLastError(ERROR_INVALID_PARAMETER); @@ -3736,6 +3912,48 @@ static void WinDivertFormatIPv6Addr(PWINDIVERT_STREAM stream, } } +/* + * Format an IPv4 address. + */ +extern BOOL WinDivertHelperFormatIPv4Address(UINT32 addr, char *buffer, + UINT bufLen) +{ + WINDIVERT_STREAM stream; + stream.data = buffer; + stream.pos = 0; + stream.max = bufLen; + stream.overflow = FALSE; + WinDivertFormatIPv4Addr(&stream, addr); + WinDivertPutNul(&stream); + if (stream.overflow) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + return TRUE; +} + +/* + * Format an IPv6 address. + */ +extern BOOL WinDivertHelperFormatIPv6Address(const UINT32 *addr, char *buffer, + UINT bufLen) +{ + WINDIVERT_STREAM stream; + stream.data = buffer; + stream.pos = 0; + stream.max = bufLen; + stream.overflow = FALSE; + WinDivertFormatIPv6Addr(&stream, addr); + WinDivertPutNul(&stream); + if (stream.overflow) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + return TRUE; +} + /* * Format a test expression. */ @@ -3840,6 +4058,8 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr) WinDivertPutString(stream, "NETWORK_FORWARD"); break; case WINDIVERT_LAYER_FLOW: WinDivertPutString(stream, "FLOW"); break; + case WINDIVERT_LAYER_SOCKET: + WinDivertPutString(stream, "SOCKET"); break; case WINDIVERT_LAYER_REFLECT: WinDivertPutString(stream, "REFLECT"); break; default: @@ -3856,6 +4076,14 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr) WinDivertPutString(stream, "FLOW_ESTABLISHED"); break; case WINDIVERT_EVENT_FLOW_DELETED: WinDivertPutString(stream, "FLOW_DELETED"); break; + case WINDIVERT_EVENT_SOCKET_BIND: + WinDivertPutString(stream, "SOCKET_BIND"); break; + case WINDIVERT_EVENT_SOCKET_CONNECT: + WinDivertPutString(stream, "SOCKET_CONNECT"); break; + case WINDIVERT_EVENT_SOCKET_LISTEN: + WinDivertPutString(stream, "SOCKET_LISTEN"); break; + case WINDIVERT_EVENT_SOCKET_ACCEPT: + WinDivertPutString(stream, "SOCKET_ACCEPT"); break; case WINDIVERT_EVENT_REFLECT_ESTABLISHED: WinDivertPutString(stream, "REFLECT_ESTABLISHED"); break; case WINDIVERT_EVENT_REFLECT_OPEN: @@ -4175,7 +4403,7 @@ BOOL WinDivertHelperFormatFilter(const char *filter, WINDIVERT_LAYER layer, stream.max = buflen; stream.overflow = FALSE; WinDivertFormatExpr(&stream, expr, /*top_level=*/TRUE, /*and=*/FALSE); - WinDivertPutChar(&stream, '\0'); + WinDivertPutNul(&stream); // Clean-up: HeapDestroy(pool); diff --git a/examples/flowtrack/flowtrack.c b/examples/flowtrack/flowtrack.c index 83a1774..c0e935e 100644 --- a/examples/flowtrack/flowtrack.c +++ b/examples/flowtrack/flowtrack.c @@ -1,5 +1,5 @@ /* - * streamdump.c + * flowtrack.c * (C) 2018, all rights reserved, * * This file is part of WinDivert. @@ -47,7 +47,8 @@ #include "windivert.h" -#define MAX_FLOWS 256 +#define MAX_FLOWS 256 +#define INET6_ADDRSTRLEN 45 /* * Flow tracking. @@ -61,39 +62,6 @@ typedef struct FLOW static HANDLE lock; static PFLOW flows = NULL; -/* - * Print an IP address. - */ -static void print_address(const UINT32 *addr) -{ - if (addr[3] == 0 && addr[2] == 0 && addr[1] == 0x0000FFFF) - { - // IPv4 address: - UINT32 a, b, c, d; - a = (addr[0] >> 24) & 0xFF; - b = (addr[0] >> 16) & 0xFF; - c = (addr[0] >> 8) & 0xFF; - d = (addr[0] >> 0) & 0xFF; - printf("%u.%u.%u.%u", a, b, c, d); - } - else - { - // IPv6 address: - int i; - for (i = 3; i >= 0; i--) - { - UINT32 a, b; - a = (addr[i] >> 16) & 0xFFFF; - b = (addr[i] >> 0) & 0xFFFF; - printf("%x:%x", a, b); - if (i != 0) - { - putchar(':'); - } - } - } -} - /* * Draw flows to console in a delayed loop. * @@ -105,6 +73,7 @@ static DWORD draw(LPVOID arg) HANDLE process, console = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO screen; char path[MAX_PATH+1]; + char addr_str[INET6_ADDRSTRLEN+1]; char *filename; const char header[] = "PID PROGRAM PROT FLOW"; DWORD rows, columns, written, fill_len, path_len, i; @@ -216,11 +185,13 @@ static DWORD draw(LPVOID arg) } SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); - print_address(addr->Flow.LocalAddr); - printf(":%u %s ", addr->Flow.LocalPort, + WinDivertHelperFormatIPv6Address(addr->Flow.LocalAddr, addr_str, + sizeof(addr_str)); + printf("%s:%u %s ", addr_str, addr->Flow.LocalPort, (addr->Outbound? "---->": "<----")); - print_address(addr->Flow.RemoteAddr); - printf(":%u", addr->Flow.RemotePort); + WinDivertHelperFormatIPv6Address(addr->Flow.RemoteAddr, addr_str, + sizeof(addr_str)); + printf("%s:%u", addr_str, addr->Flow.RemotePort); fflush(stdout); } for (; i < rows-1; i++) diff --git a/examples/netdump/netdump.c b/examples/netdump/netdump.c index 1785c93..c07f2ef 100644 --- a/examples/netdump/netdump.c +++ b/examples/netdump/netdump.c @@ -49,7 +49,8 @@ #include "windivert.h" -#define MAXBUF 0xFFFF +#define MAXBUF 0xFFFF +#define INET6_ADDRSTRLEN 45 /* * Entry. @@ -68,6 +69,7 @@ int __cdecl main(int argc, char **argv) PWINDIVERT_ICMPV6HDR icmpv6_header; PWINDIVERT_TCPHDR tcp_header; PWINDIVERT_UDPHDR udp_header; + char src_str[INET6_ADDRSTRLEN+1], dst_str[INET6_ADDRSTRLEN+1]; const char *err_str; LARGE_INTEGER base, freq; double time_passed; @@ -166,16 +168,19 @@ int __cdecl main(int argc, char **argv) FOREGROUND_GREEN | FOREGROUND_RED); printf("IPv4 [Version=%u HdrLength=%u TOS=%u Length=%u Id=0x%.4X " "Reserved=%u DF=%u MF=%u FragOff=%u TTL=%u Protocol=%u " - "Checksum=0x%.4X SrcAddr=%u.%u.%u.%u DstAddr=%u.%u.%u.%u]\n", + "Checksum=0x%.4X SrcAddr=%s DstAddr=%s]\n", ip_header->Version, ip_header->HdrLength, ntohs(ip_header->TOS), ntohs(ip_header->Length), ntohs(ip_header->Id), WINDIVERT_IPHDR_GET_RESERVED(ip_header), WINDIVERT_IPHDR_GET_DF(ip_header), WINDIVERT_IPHDR_GET_MF(ip_header), ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)), ip_header->TTL, - ip_header->Protocol, ntohs(ip_header->Checksum), - src_addr[0], src_addr[1], src_addr[2], src_addr[3], - dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3]); + ip_header->Protocol, ntohs(ip_header->Checksum)); + WinDivertHelperFormatIPv4Address(ntohl(ip_header->SrcAddr), + src_str, sizeof(src_str)); + WinDivertHelperFormatIPv4Address(ntohl(ip_header->DstAddr), + dst_str, sizeof(dst_str)); + } if (ipv6_header != NULL) { diff --git a/examples/socketdump/socketdump.c b/examples/socketdump/socketdump.c new file mode 100644 index 0000000..705b73a --- /dev/null +++ b/examples/socketdump/socketdump.c @@ -0,0 +1,210 @@ +/* + * socketdump.c + * (C) 2018, all rights reserved, + * + * This file is part of WinDivert. + * + * WinDivert is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * WinDivert is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * DESCRIPTION: + * + * usage: socketdump.exe [filter] + */ + +#include +#include +#include +#include +#include +#include + +#include "windivert.h" + +#define INET6_ADDRSTRLEN 45 + +/* + * Entry. + */ +int __cdecl main(int argc, char **argv) +{ + HANDLE handle, process, console; + INT16 priority = 1121; // Arbitrary. + const char *filter = "true", *err_str; + char path[MAX_PATH+1]; + char local_str[INET6_ADDRSTRLEN+1], remote_str[INET6_ADDRSTRLEN+1]; + char *filename; + DWORD path_len; + UINT packet_len; + WINDIVERT_ADDRESS addr; + + switch (argc) + { + case 1: + break; + case 2: + filter = argv[1]; + break; + default: + fprintf(stderr, "usage: %s [filter]\n"); + exit(EXIT_FAILURE); + } + + // Open WinDivert SOCKET handle: + handle = WinDivertOpen(filter, WINDIVERT_LAYER_SOCKET, priority, + WINDIVERT_FLAG_SNIFF | WINDIVERT_FLAG_RECV_ONLY); + if (handle == INVALID_HANDLE_VALUE) + { + if (GetLastError() == ERROR_INVALID_PARAMETER && + !WinDivertHelperCompileFilter(filter, WINDIVERT_LAYER_SOCKET, + NULL, 0, &err_str, NULL)) + { + fprintf(stderr, "error: invalid filter \"%s\"\n", err_str); + exit(EXIT_FAILURE); + } + fprintf(stderr, "error: failed to open the WinDivert device (%d)\n", + GetLastError()); + return EXIT_FAILURE; + } + + // Main loop: + console = GetStdHandle(STD_OUTPUT_HANDLE); + while (TRUE) + { + if (!WinDivertRecv(handle, NULL, 0, &addr, &packet_len)) + { + fprintf(stderr, "failed to read packet (%d)\n", GetLastError()); + continue; + } + + SetConsoleTextAttribute(console, FOREGROUND_GREEN); + switch (addr.Event) + { + case WINDIVERT_EVENT_SOCKET_BIND: + printf("BIND"); + break; + case WINDIVERT_EVENT_SOCKET_LISTEN: + printf("LISTEN"); + break; + case WINDIVERT_EVENT_SOCKET_CONNECT: + printf("CONNECT"); + break; + case WINDIVERT_EVENT_SOCKET_ACCEPT: + printf("ACCEPT"); + break; + default: + printf("???"); + break; + } + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE); + + printf(" pid="); + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN); + printf("%u", addr.Socket.ProcessId); + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE); + + printf(" program="); + process = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, + addr.Socket.ProcessId); + path_len = 0; + if (process != NULL) + { + path_len = GetProcessImageFileName(process, path, sizeof(path)); + CloseHandle(process); + } + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN); + if (path_len != 0) + { + filename = PathFindFileName(path); + printf("%s", filename); + } + else if (addr.Socket.ProcessId == 4) + { + printf("Windows"); + } + else + { + printf("???"); + } + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE); + + printf(" protocol="); + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN); + switch (addr.Socket.Protocol) + { + case IPPROTO_TCP: + printf("TCP"); + break; + case IPPROTO_UDP: + printf("UDP"); + break; + case IPPROTO_ICMP: + printf("ICMP"); + break; + case IPPROTO_ICMPV6: + printf("ICMPV6"); + break; + default: + printf("%u", addr.Socket.Protocol); + break; + } + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE); + + WinDivertHelperFormatIPv6Address(addr.Socket.LocalAddr, local_str, + sizeof(local_str)); + if (addr.Socket.LocalPort != 0 || strcmp(local_str, "::") != 0) + { + printf(" local="); + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN); + printf("[%s]:%u", local_str, addr.Socket.LocalPort); + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE); + } + + WinDivertHelperFormatIPv6Address(addr.Socket.RemoteAddr, remote_str, + sizeof(remote_str)); + if (addr.Socket.RemotePort != 0 || strcmp(remote_str, "::") != 0) + { + printf(" remote="); + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN); + printf("[%s]:%u", remote_str, addr.Socket.RemotePort); + SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE); + } + + putchar('\n'); + } + + return 0; +} + diff --git a/examples/windivertctl/windivertctl.c b/examples/windivertctl/windivertctl.c index 7be5d34..5e503dd 100644 --- a/examples/windivertctl/windivertctl.c +++ b/examples/windivertctl/windivertctl.c @@ -315,6 +315,9 @@ usage: case WINDIVERT_LAYER_FLOW: fputs("FLOW", stdout); break; + case WINDIVERT_LAYER_SOCKET: + fputs("SOCKET", stdout); + break; case WINDIVERT_LAYER_REFLECT: fputs("REFLECT", stdout); break; diff --git a/include/windivert.h b/include/windivert.h index 68c2131..aa35f40 100644 --- a/include/windivert.h +++ b/include/windivert.h @@ -77,7 +77,8 @@ typedef enum WINDIVERT_LAYER_NETWORK = 0, /* Network layer. */ WINDIVERT_LAYER_NETWORK_FORWARD = 1,/* Network layer (forwarded packets) */ WINDIVERT_LAYER_FLOW = 2, /* Flow layer. */ - WINDIVERT_LAYER_REFLECT = 3, /* Reflect layer. */ + WINDIVERT_LAYER_SOCKET = 3, /* Socket layer. */ + WINDIVERT_LAYER_REFLECT = 4, /* Reflect layer. */ } WINDIVERT_LAYER, *PWINDIVERT_LAYER; /* @@ -102,6 +103,19 @@ typedef struct UINT8 Protocol; /* Protocol. */ } WINDIVERT_FLOW_DATA, *PWINDIVERT_FLOW_DATA; +/* + * WinDivert SOCKET layer data. + */ +typedef struct +{ + UINT32 ProcessId; /* Process ID. */ + UINT32 LocalAddr[4]; /* Local address. */ + UINT32 RemoteAddr[4]; /* Remote address. */ + UINT16 LocalPort; /* Local port. */ + UINT16 RemotePort; /* Remote port. */ + UINT8 Protocol; /* Protocol. */ +} WINDIVERT_SOCKET_DATA, *PWINDIVERT_SOCKET_DATA; + /* * WinDivert REFLECTION layer data. */ @@ -135,6 +149,7 @@ typedef struct { WINDIVERT_NETWORK_DATA Network; /* Network layer data. */ WINDIVERT_FLOW_DATA Flow; /* Flow layer data. */ + WINDIVERT_SOCKET_DATA Socket; /* Socket layer data. */ WINDIVERT_REFLECT_DATA Reflect; /* Reflect layer data. */ }; } WINDIVERT_ADDRESS, *PWINDIVERT_ADDRESS; @@ -148,10 +163,14 @@ typedef enum WINDIVERT_EVENT_FLOW_ESTABLISHED = 1, /* Flow established. */ WINDIVERT_EVENT_FLOW_DELETED = 2, /* Flow deleted. */ - WINDIVERT_EVENT_REFLECT_ESTABLISHED = 3, + WINDIVERT_EVENT_SOCKET_BIND = 3, /* Socket bind. */ + WINDIVERT_EVENT_SOCKET_CONNECT = 4, /* Socket connect. */ + WINDIVERT_EVENT_SOCKET_LISTEN = 5, /* Socket listen. */ + WINDIVERT_EVENT_SOCKET_ACCEPT = 6, /* Socket accept. */ + WINDIVERT_EVENT_REFLECT_ESTABLISHED = 7, /* Previously open WinDivert handle. */ - WINDIVERT_EVENT_REFLECT_OPEN = 4, /* Open new WinDivert handle. */ - WINDIVERT_EVENT_REFLECT_CLOSE = 5, /* Close existing WinDivert handle. */ + WINDIVERT_EVENT_REFLECT_OPEN = 8, /* Open new WinDivert handle. */ + WINDIVERT_EVENT_REFLECT_CLOSE = 9, /* Close existing WinDivert handle. */ } WINDIVERT_EVENT, *PWINDIVERT_EVENT; /* @@ -434,6 +453,22 @@ extern WINDIVERTEXPORT BOOL WinDivertHelperParseIPv6Address( __in const char *addrStr, __out_opt UINT32 *pAddr); +/* + * Format an IPv4 address. + */ +extern WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv4Address( + __in UINT32 addr, + __out char *buffer, + __in UINT bufLen); + +/* + * Format an IPv6 address. + */ +extern WINDIVERTEXPORT BOOL WinDivertHelperFormatIPv6Address( + __in const UINT32 *pAddr, + __out char *buffer, + __in UINT bufLen); + /* * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. */ diff --git a/mingw-build.sh b/mingw-build.sh index 29a550e..e0acd54 100644 --- a/mingw-build.sh +++ b/mingw-build.sh @@ -105,6 +105,10 @@ do $CC -s -O2 -Iinclude/ examples/windivertctl/windivertctl.c \ -o "install/MINGW/$CPU/windivertctl.exe" -lWinDivert -lws2_32 \ -lpsapi -lshlwapi -L"install/MINGW/$CPU/" + echo "\tcopy install/MINGW/$CPU/socketdump.exe..." + $CC -s -O2 -Iinclude/ examples/socketdump/socketdump.c \ + -o "install/MINGW/$CPU/socketdump.exe" -lWinDivert -lws2_32 \ + -lpsapi -lshlwapi -L"install/MINGW/$CPU/" echo "\tcopy install/MINGW/$CPU/WinDivert$BITS.sys..." cp install/WDDK/$CPU/WinDivert$BITS.sys install/MINGW/$CPU else diff --git a/sys/windivert.c b/sys/windivert.c index d174986..e6cb0f9 100644 --- a/sys/windivert.c +++ b/sys/windivert.c @@ -107,13 +107,14 @@ struct reflect_context_s LONGLONG timestamp; // Open timestamp. WINDIVERT_REFLECT_DATA data; // Reflect data. BOOL inserted; // Entry inserted? + BOOL open; // Seen OPEN event? }; /* * WinDivert context information. */ #define WINDIVERT_CONTEXT_SIZE (sizeof(struct context_s)) -#define WINDIVERT_CONTEXT_MAXLAYERS 4 +#define WINDIVERT_CONTEXT_MAXLAYERS 8 #define WINDIVERT_CONTEXT_MAXWORKERS 1 typedef enum { @@ -412,11 +413,54 @@ static void windivert_flow_established_v6_classify( IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, const FWPS_FILTER0 *filter, IN UINT64 flow_context, OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_resource_assignment_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_resource_assignment_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_auth_connect_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_auth_connect_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_auth_listen_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_auth_listen_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_auth_recv_accept_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); +static void windivert_auth_recv_accept_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result); static void windivert_flow_established_classify(context_t context, IN UINT64 flow_id, IN PWINDIVERT_FLOW_DATA flow_data, IN BOOL ipv4, IN BOOL outbound, IN BOOL loopback, OUT FWPS_CLASSIFY_OUT0 *result); static void windivert_flow_delete_notify(UINT16 layer_id, UINT32 callout_id, UINT64 flow_context); +static void windivert_socket_classify(context_t context, + PWINDIVERT_SOCKET_DATA socket_data, WINDIVERT_EVENT event, BOOL ipv4, + BOOL outbound, BOOL loopback, FWPS_CLASSIFY_OUT0 *result); static void windivert_network_classify(context_t context, IN PWINDIVERT_NETWORK_DATA network_data, IN BOOL ipv4, IN BOOL outbound, IN BOOL loopback, IN UINT advance, IN OUT void *data, @@ -431,6 +475,12 @@ static void windivert_reinject_packet(packet_t packet); static void windivert_free_packet(packet_t packet); static BOOL windivert_decrement_ttl(PVOID data, BOOL ipv4, BOOL checksum); static int windivert_big_num_compare(const UINT32 *a, const UINT32 *b); +static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, + 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 *payload_len_ptr); static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, PVOID layer_data, WINDIVERT_EVENT event, BOOL ipv4, BOOL outbound, BOOL loopback, BOOL impostor, PWINDIVERT_FILTER filter); @@ -449,29 +499,53 @@ static void windivert_reflect_worker(IN WDFWORKITEM item); * WinDivert sublayer GUIDs */ DEFINE_GUID(WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID, - 0x09C273C5, 0x0FB1, 0x4453, - 0x95, 0xDF, 0x7E, 0x1C, 0x28, 0x78, 0xED, 0xDF); + 0x82A99281, 0x0389, 0x4DE2, + 0xAE, 0x2D, 0xA4, 0x51, 0x59, 0x16, 0x26, 0x06); DEFINE_GUID(WINDIVERT_SUBLAYER_OUTBOUND_IPV4_GUID, - 0x11C342F5, 0x4276, 0x494F, - 0xBB, 0x30, 0x84, 0x55, 0x78, 0x6C, 0x67, 0x30); + 0xB0BB07C6, 0x3B3B, 0x41FE, + 0x83, 0x8B, 0xD8, 0x37, 0xDD, 0xB8, 0x75, 0x41); DEFINE_GUID(WINDIVERT_SUBLAYER_INBOUND_IPV6_GUID, - 0x2E5F6801, 0xE721, 0x4A0D, - 0x8D, 0x48, 0xC8, 0x1D, 0x4F, 0x25, 0x45, 0x93); + 0xD7674846, 0x3AB5, 0x4E93, + 0x82, 0xD0, 0x2F, 0xCC, 0x03, 0xA2, 0x88, 0x7A); DEFINE_GUID(WINDIVERT_SUBLAYER_OUTBOUND_IPV6_GUID, - 0xB6511564, 0xD5E6, 0x44C8, - 0x9C, 0x73, 0xBB, 0x22, 0x15, 0x39, 0xEB, 0x8A); + 0x6672F761, 0xA0F2, 0x4578, + 0x92, 0x50, 0x09, 0x03, 0x0D, 0x4E, 0x8C, 0x46); DEFINE_GUID(WINDIVERT_SUBLAYER_FORWARD_IPV4_GUID, - 0xEC5C40E3, 0xE508, 0x408B, - 0xB9, 0x86, 0x58, 0xDE, 0xC7, 0x5F, 0x86, 0xE4); + 0x4622DCC6, 0xBD71, 0x48ED, + 0x9D, 0x1A, 0x72, 0xC9, 0x0D, 0xEB, 0xA1, 0x74); DEFINE_GUID(WINDIVERT_SUBLAYER_FORWARD_IPV6_GUID, - 0xE70D0973, 0x935F, 0x4790, - 0x8E, 0x64, 0xF7, 0xF7, 0x36, 0x27, 0xA5, 0x8F); + 0x7E5B39EC, 0xB54C, 0x41B3, + 0xA7, 0x99, 0x47, 0x5E, 0x57, 0x41, 0xA4, 0x33); DEFINE_GUID(WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID, - 0x168A6CF7, 0x6080, 0x4905, - 0xAA, 0x72, 0x03, 0x74, 0x67, 0xCD, 0x4F, 0x19); + 0x53D6C270, 0xEB79, 0x44CD, + 0x83, 0xCD, 0x14, 0x34, 0xE6, 0x13, 0x91, 0x68); DEFINE_GUID(WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID, - 0x9EAAEB28, 0xC1BB, 0x41F5, - 0x9F, 0x27, 0x18, 0xD4, 0xDF, 0xE1, 0x31, 0xEE); + 0x44B0CDED, 0xAA11, 0x4704, + 0x92, 0xA7, 0x99, 0xD2, 0xB7, 0x59, 0x7A, 0x68); +DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID, + 0x736848B6, 0xBE0D, 0x4A8D, + 0xA0, 0xC2, 0xE2, 0x02, 0xDC, 0x29, 0x32, 0xBC); +DEFINE_GUID(WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID, + 0xF3458E58, 0xD123, 0x439B, + 0xB6, 0x40, 0x74, 0x3C, 0xC7, 0x53, 0x9E, 0x36); +DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID, + 0x2F97411F, 0x6350, 0x450A, + 0xBF, 0x45, 0x4C, 0x0B, 0xC1, 0xDB, 0x3F, 0x7E); +DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID, + 0x7BAFEEEB, 0x84F0, 0x4BB0, + 0x91, 0x1F, 0x7E, 0x62, 0x2D, 0x73, 0x24, 0x2C); +DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID, + 0x49F2A9AD, 0x805E, 0x4328, + 0xBB, 0xDA, 0x92, 0x57, 0xB5, 0x18, 0x3A, 0x40); +DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID, + 0xC1BB250E, 0xDE07, 0x41AB, + 0x82, 0xEE, 0xAD, 0x7B, 0xFF, 0x13, 0xCE, 0x35); +DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID, + 0x7A012579, 0xC75A, 0x4D29, + 0xB7, 0x47, 0x04, 0xAD, 0x3C, 0x7B, 0x32, 0x69); +DEFINE_GUID(WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID, + 0x1C51DD53, 0x6BA4, 0x4149, + 0x89, 0x97, 0x1C, 0xD4, 0x8B, 0x51, 0x1B, 0x7D); /* * WinDivert supported layers. @@ -572,6 +646,136 @@ static struct layer_s layer_forward_network_ipv6_0 = }; static layer_t layer_forward_network_ipv6 = &layer_forward_network_ipv6_0; +static struct layer_s layer_resource_assignment_ipv4_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv4", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv4", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv4", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)", + {0}, + {0}, + windivert_resource_assignment_v4_classify, + NULL, + 0 +}; +static layer_t layer_resource_assignment_ipv4 = + &layer_resource_assignment_ipv4_0; + +static struct layer_s layer_resource_assignment_ipv6_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerResourceAssignmentIPv6", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutResourceAssignmentIPv6", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_FilterResourceAssignmentIPv6", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)", + {0}, + {0}, + windivert_resource_assignment_v6_classify, + NULL, + 0 +}; +static layer_t layer_resource_assignment_ipv6 = + &layer_resource_assignment_ipv6_0; + +static struct layer_s layer_auth_connect_ipv4_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv4", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv4", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv4", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)", + {0}, + {0}, + windivert_auth_connect_v4_classify, + NULL, + 0 +}; +static layer_t layer_auth_connect_ipv4 = &layer_auth_connect_ipv4_0; + +static struct layer_s layer_auth_connect_ipv6_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthConnectIPv6", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthConnectIPv6", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_FilterAuthConnectIPv6", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)", + {0}, + {0}, + windivert_auth_connect_v6_classify, + NULL, + 0 +}; +static layer_t layer_auth_connect_ipv6 = &layer_auth_connect_ipv6_0; + +static struct layer_s layer_auth_listen_ipv4_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv4", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv4", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv4", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)", + {0}, + {0}, + windivert_auth_listen_v4_classify, + NULL, + 0 +}; +static layer_t layer_auth_listen_ipv4 = &layer_auth_listen_ipv4_0; + +static struct layer_s layer_auth_listen_ipv6_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthListenIPv6", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthListenIPv6", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_FilterAuthListenIPv6", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)", + {0}, + {0}, + windivert_auth_listen_v6_classify, + NULL, + 0 +}; +static layer_t layer_auth_listen_ipv6 = &layer_auth_listen_ipv6_0; + +static struct layer_s layer_auth_recv_accept_ipv4_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv4", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv4", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv4)", + L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv4", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv4)", + {0}, + {0}, + windivert_auth_recv_accept_v4_classify, + NULL, + 0 +}; +static layer_t layer_auth_recv_accept_ipv4 = &layer_auth_recv_accept_ipv4_0; + +static struct layer_s layer_auth_recv_accept_ipv6_0 = +{ + L"" WINDIVERT_DEVICE_NAME L"_SubLayerAuthRecvAcceptIPv6", + L"" WINDIVERT_DEVICE_NAME L" sublayer flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_CalloutAuthRecvAcceptIPv6", + L"" WINDIVERT_DEVICE_NAME L" callout flow established (IPv6)", + L"" WINDIVERT_DEVICE_NAME L"_FilterAuthRecvAcceptIPv6", + L"" WINDIVERT_DEVICE_NAME L" filter flow established (IPv6)", + {0}, + {0}, + windivert_auth_recv_accept_v6_classify, + NULL, + 0 +}; +static layer_t layer_auth_recv_accept_ipv6 = &layer_auth_recv_accept_ipv6_0; + static struct layer_s layer_flow_established_ipv4_0 = { L"" WINDIVERT_DEVICE_NAME L"_SubLayerFlowEstablishedIPv4", @@ -677,6 +881,18 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj, FWPM_LAYER_ALE_FLOW_ESTABLISHED_V4; layer_flow_established_ipv6->layer_guid = FWPM_LAYER_ALE_FLOW_ESTABLISHED_V6; + layer_resource_assignment_ipv4->layer_guid = + FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V4; + layer_resource_assignment_ipv6->layer_guid = + FWPM_LAYER_ALE_RESOURCE_ASSIGNMENT_V6; + layer_auth_connect_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V4; + layer_auth_connect_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_CONNECT_V6; + layer_auth_listen_ipv4->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V4; + layer_auth_listen_ipv6->layer_guid = FWPM_LAYER_ALE_AUTH_LISTEN_V6; + layer_auth_recv_accept_ipv4->layer_guid = + FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V4; + layer_auth_recv_accept_ipv6->layer_guid = + FWPM_LAYER_ALE_AUTH_RECV_ACCEPT_V6; layer_inbound_network_ipv4->sublayer_guid = WINDIVERT_SUBLAYER_INBOUND_IPV4_GUID; layer_outbound_network_ipv4->sublayer_guid = @@ -693,6 +909,22 @@ extern NTSTATUS DriverEntry(IN PDRIVER_OBJECT driver_obj, WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV4_GUID; layer_flow_established_ipv6->sublayer_guid = WINDIVERT_SUBLAYER_FLOW_ESTABLISHED_IPV6_GUID; + layer_resource_assignment_ipv4->sublayer_guid = + WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV4_GUID; + layer_resource_assignment_ipv6->sublayer_guid = + WINDIVERT_SUBLAYER_RESOURCE_ASSIGNMENT_IPV6_GUID; + layer_auth_connect_ipv4->sublayer_guid = + WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV4_GUID; + layer_auth_connect_ipv6->sublayer_guid = + WINDIVERT_SUBLAYER_AUTH_CONNECT_IPV6_GUID; + layer_auth_listen_ipv4->sublayer_guid = + WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV4_GUID; + layer_auth_listen_ipv6->sublayer_guid = + WINDIVERT_SUBLAYER_AUTH_LISTEN_IPV6_GUID; + layer_auth_recv_accept_ipv4->sublayer_guid = + WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV4_GUID; + layer_auth_recv_accept_ipv6->sublayer_guid = + WINDIVERT_SUBLAYER_AUTH_RECV_ACCEPT_IPV6_GUID; // Configure ourself as a non-PnP driver: WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK); @@ -873,6 +1105,46 @@ driver_entry_sublayer_error: { goto driver_entry_sublayer_error; } + status = windivert_install_sublayer(layer_resource_assignment_ipv4); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } + status = windivert_install_sublayer(layer_resource_assignment_ipv6); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } + status = windivert_install_sublayer(layer_auth_connect_ipv4); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } + status = windivert_install_sublayer(layer_auth_connect_ipv6); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } + status = windivert_install_sublayer(layer_auth_listen_ipv4); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } + status = windivert_install_sublayer(layer_auth_listen_ipv6); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } + status = windivert_install_sublayer(layer_auth_recv_accept_ipv4); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } + status = windivert_install_sublayer(layer_auth_recv_accept_ipv6); + if (!NT_SUCCESS(status)) + { + goto driver_entry_sublayer_error; + } status = FwpmTransactionCommit0(engine_handle); if (!NT_SUCCESS(status)) { @@ -954,6 +1226,22 @@ static void windivert_driver_unload(void) &layer_flow_established_ipv4->sublayer_guid); FwpmSubLayerDeleteByKey0(engine_handle, &layer_flow_established_ipv6->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_resource_assignment_ipv4->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_resource_assignment_ipv6->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_auth_connect_ipv4->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_auth_connect_ipv6->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_auth_listen_ipv4->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_auth_listen_ipv6->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_auth_recv_accept_ipv4->sublayer_guid); + FwpmSubLayerDeleteByKey0(engine_handle, + &layer_auth_recv_accept_ipv6->sublayer_guid); status = FwpmTransactionCommit0(engine_handle); if (!NT_SUCCESS(status)) { @@ -1170,6 +1458,23 @@ static NTSTATUS windivert_install_callouts(context_t context, UINT8 layer, } break; + case WINDIVERT_LAYER_SOCKET: + if (ipv4) + { + layers[i++] = layer_resource_assignment_ipv4; + layers[i++] = layer_auth_connect_ipv4; + layers[i++] = layer_auth_listen_ipv4; + layers[i++] = layer_auth_recv_accept_ipv4; + } + if (ipv6) + { + layers[i++] = layer_resource_assignment_ipv6; + layers[i++] = layer_auth_connect_ipv6; + layers[i++] = layer_auth_listen_ipv6; + layers[i++] = layer_auth_recv_accept_ipv6; + } + break; + case WINDIVERT_LAYER_REFLECT: break; @@ -1436,6 +1741,9 @@ extern VOID windivert_cleanup(IN WDFFILEOBJECT object) DEBUG("CLEANUP: cleaning up WinDivert context (context=%p)", context); + windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_CLOSE); + timestamp = KeQueryPerformanceCounter(NULL).QuadPart; + KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle); if (context->state != WINDIVERT_CONTEXT_STATE_OPENING && context->state != WINDIVERT_CONTEXT_STATE_OPEN) @@ -1450,10 +1758,6 @@ windivert_cleanup_error: sniff_mode = ((context->flags & WINDIVERT_FLAG_SNIFF) != 0); forward = (context->layer == WINDIVERT_LAYER_NETWORK_FORWARD); priority = context->priority; - KeReleaseInStackQueuedSpinLock(&lock_handle); - windivert_reflect_event(context, WINDIVERT_EVENT_REFLECT_CLOSE); - timestamp = KeQueryPerformanceCounter(NULL).QuadPart; - KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle); while (!IsListEmpty(&context->flow_set)) { entry = RemoveHeadList(&context->flow_set); @@ -1671,6 +1975,7 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request) break; case WINDIVERT_LAYER_FLOW: + case WINDIVERT_LAYER_SOCKET: status = STATUS_SUCCESS; dst_len = 0; @@ -1712,6 +2017,11 @@ static void windivert_read_service_request(packet_t packet, WDFREQUEST request) sizeof(WINDIVERT_FLOW_DATA)); break; + case WINDIVERT_LAYER_SOCKET: + RtlCopyMemory(&addr->Socket, layer_data, + sizeof(WINDIVERT_SOCKET_DATA)); + break; + case WINDIVERT_LAYER_REFLECT: RtlCopyMemory(&addr->Reflect, layer_data, sizeof(WINDIVERT_REFLECT_DATA)); @@ -1832,6 +2142,7 @@ static NTSTATUS windivert_write(context_t context, WDFREQUEST request, switch (layer) { case WINDIVERT_LAYER_FLOW: + case WINDIVERT_LAYER_SOCKET: case WINDIVERT_LAYER_REFLECT: status = STATUS_INVALID_PARAMETER; DEBUG_ERROR("failed to inject at layer", status); @@ -2289,6 +2600,13 @@ windivert_ioctl_bad_start_state: } break; + case WINDIVERT_LAYER_SOCKET: + if ((flags & WINDIVERT_FLAG_RECV_ONLY) == 0) + { + goto windivert_ioctl_bad_start_state; + } + break; + default: break; } @@ -2317,6 +2635,7 @@ windivert_ioctl_bad_start_state: case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: case WINDIVERT_LAYER_FLOW: + case WINDIVERT_LAYER_SOCKET: case WINDIVERT_LAYER_REFLECT: break; default: @@ -2953,6 +3272,7 @@ static void windivert_flow_established_v6_classify( FWPS_FIELD_ALE_FLOW_ESTABLISHED_V6_IP_LOCAL_ADDRESS] .value.byteArray16->byteArray16[i]; } + addr = (UINT8 *)&flow_data.RemoteAddr; for (i = sizeof(flow_data.RemoteAddr)-1; i >= 0; i--) { addr[sizeof(flow_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[ @@ -3159,6 +3479,415 @@ windivert_flow_delete_notify_exit: } } +/* + * WinDivert classify resource assignment IPv4 function. + */ +static void windivert_resource_assignment_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + FWP_VALUE0 value; + BOOL loopback; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + value = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_ADDRESS].value; + if (value.type == FWP_UINT32) + { + socket_data.LocalAddr[0] = value.uint32; + socket_data.LocalAddr[1] = 0x0000FFFF; + } + else + { + socket_data.LocalAddr[0] = 0; + socket_data.LocalAddr[1] = 0; + } + socket_data.LocalAddr[2] = 0; + socket_data.LocalAddr[3] = 0; + socket_data.RemoteAddr[0] = 0; + socket_data.RemoteAddr[1] = 0; + socket_data.RemoteAddr[2] = 0; + socket_data.RemoteAddr[3] = 0; + value = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_LOCAL_PORT].value; + socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0); + socket_data.RemotePort = 0; + socket_data.Protocol = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_IP_PROTOCOL].value.uint8; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V4_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_BIND, /*ipv4=*/TRUE, + /*outbound=*/FALSE, loopback, result); +} + +/* + * WinDivert classify resource assignment IPv6 function. + */ +static void windivert_resource_assignment_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + FWP_VALUE0 value; + BOOL loopback; + UINT8 *addr; + INT i; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + addr = (UINT8 *)&socket_data.LocalAddr; + value = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_ADDRESS].value; + if (value.type == FWP_BYTE_ARRAY16_TYPE) + { + for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--) + { + addr[sizeof(socket_data.LocalAddr)-i-1] = + value.byteArray16->byteArray16[i]; + } + } + else + { + socket_data.LocalAddr[0] = 0; + socket_data.LocalAddr[1] = 0; + socket_data.LocalAddr[2] = 0; + socket_data.LocalAddr[3] = 0; + } + socket_data.RemoteAddr[0] = 0; + socket_data.RemoteAddr[1] = 0; + socket_data.RemoteAddr[2] = 0; + socket_data.RemoteAddr[3] = 0; + value = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_LOCAL_PORT].value; + socket_data.LocalPort = (value.type == FWP_UINT16? value.uint16: 0); + socket_data.RemotePort = 0; + socket_data.Protocol = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_IP_PROTOCOL].value.uint8; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_RESOURCE_ASSIGNMENT_V6_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_BIND, /*ipv4=*/FALSE, + /*outbound=*/FALSE, loopback, result); +} + +/* + * WinDivert classify auth connect IPv4 function. + */ +static void windivert_auth_connect_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + BOOL loopback; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + socket_data.LocalAddr[0] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS].value.uint32; + socket_data.LocalAddr[1] = 0x0000FFFF; + socket_data.LocalAddr[2] = 0; + socket_data.LocalAddr[3] = 0; + socket_data.RemoteAddr[0] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS].value.uint32; + socket_data.RemoteAddr[1] = 0x0000FFFF; + socket_data.RemoteAddr[2] = 0; + socket_data.RemoteAddr[3] = 0; + socket_data.LocalPort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16; + socket_data.RemotePort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16; + socket_data.Protocol = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_CONNECT, /*ipv4=*/TRUE, + /*outbound=*/TRUE, loopback, result); +} + +/* + * WinDivert classify auth connect IPv6 function. + */ +static void windivert_auth_connect_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + BOOL loopback; + UINT8 *addr; + INT i; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + addr = (UINT8 *)&socket_data.LocalAddr; + for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--) + { + addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_LOCAL_ADDRESS] + .value.byteArray16->byteArray16[i]; + } + addr = (UINT8 *)&socket_data.RemoteAddr; + for (i = sizeof(socket_data.RemoteAddr)-1; i >= 0; i--) + { + addr[sizeof(socket_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V6_IP_REMOTE_ADDRESS] + .value.byteArray16->byteArray16[i]; + } + socket_data.LocalPort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_PORT].value.uint16; + socket_data.RemotePort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_PORT].value.uint16; + socket_data.Protocol = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_PROTOCOL].value.uint8; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_CONNECT_V4_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_CONNECT, /*ipv4=*/FALSE, + /*outbound=*/TRUE, loopback, result); +} + +/* + * WinDivert classify auth listen IPv4 function. + */ +static void windivert_auth_listen_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + BOOL loopback; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + socket_data.LocalAddr[0] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_ADDRESS].value.uint32; + socket_data.LocalAddr[1] = 0x0000FFFF; + socket_data.LocalAddr[2] = 0; + socket_data.LocalAddr[3] = 0; + socket_data.RemoteAddr[0] = 0; + socket_data.RemoteAddr[1] = 0; + socket_data.RemoteAddr[2] = 0; + socket_data.RemoteAddr[3] = 0; + socket_data.LocalPort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_LISTEN_V4_IP_LOCAL_PORT].value.uint16; + socket_data.RemotePort = 0; + socket_data.Protocol = IPPROTO_TCP; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_LISTEN_V4_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_LISTEN, /*ipv4=*/TRUE, + /*outbound=*/FALSE, loopback, result); +} + +/* + * WinDivert classify auth listen IPv6 function. + */ +static void windivert_auth_listen_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + BOOL loopback; + UINT8 *addr; + INT i; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + addr = (UINT8 *)&socket_data.LocalAddr; + for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--) + { + addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_ADDRESS] + .value.byteArray16->byteArray16[i]; + } + socket_data.RemoteAddr[0] = 0; + socket_data.RemoteAddr[1] = 0; + socket_data.RemoteAddr[2] = 0; + socket_data.RemoteAddr[3] = 0; + socket_data.LocalPort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_LISTEN_V6_IP_LOCAL_PORT].value.uint16; + socket_data.RemotePort = 0; + socket_data.Protocol = IPPROTO_TCP; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_LISTEN_V6_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_LISTEN, /*ipv4=*/FALSE, + /*outbound=*/FALSE, loopback, result); +} + +/* + * WinDivert classify auth recv accept IPv4 function. + */ +static void windivert_auth_recv_accept_v4_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + BOOL loopback; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + socket_data.LocalAddr[0] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS].value.uint32; + socket_data.LocalAddr[1] = 0x0000FFFF; + socket_data.LocalAddr[2] = 0; + socket_data.LocalAddr[3] = 0; + socket_data.RemoteAddr[0] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS].value.uint32; + socket_data.RemoteAddr[1] = 0x0000FFFF; + socket_data.RemoteAddr[2] = 0; + socket_data.RemoteAddr[3] = 0; + socket_data.LocalPort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16; + socket_data.RemotePort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16; + socket_data.Protocol = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_ACCEPT, /*ipv4=*/TRUE, + /*outbound=*/FALSE, loopback, result); +} + +/* + * WinDivert classify auth recv accept IPv6 function. + */ +static void windivert_auth_recv_accept_v6_classify( + IN const FWPS_INCOMING_VALUES0 *fixed_vals, + IN const FWPS_INCOMING_METADATA_VALUES0 *meta_vals, IN OUT void *data, + const FWPS_FILTER0 *filter, IN UINT64 flow_context, + OUT FWPS_CLASSIFY_OUT0 *result) +{ + WINDIVERT_SOCKET_DATA socket_data; + BOOL loopback; + UINT8 *addr; + INT i; + + socket_data.ProcessId = (UINT32)meta_vals->processId; + addr = (UINT8 *)&socket_data.LocalAddr; + for (i = sizeof(socket_data.LocalAddr)-1; i >= 0; i--) + { + addr[sizeof(socket_data.LocalAddr)-i-1] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_LOCAL_ADDRESS] + .value.byteArray16->byteArray16[i]; + } + addr = (UINT8 *)&socket_data.RemoteAddr; + for (i = sizeof(socket_data.RemoteAddr)-1; i >= 0; i--) + { + addr[sizeof(socket_data.RemoteAddr)-i-1] = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V6_IP_REMOTE_ADDRESS] + .value.byteArray16->byteArray16[i]; + } + socket_data.LocalPort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_PORT].value.uint16; + socket_data.RemotePort = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_PORT].value.uint16; + socket_data.Protocol = fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_PROTOCOL].value.uint8; + + loopback = ((fixed_vals->incomingValue[ + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_FLAGS].value.uint32 & + FWP_CONDITION_FLAG_IS_LOOPBACK) != 0); + + windivert_socket_classify((context_t)filter->context, + &socket_data, /*event=*/WINDIVERT_EVENT_SOCKET_ACCEPT, /*ipv4=*/FALSE, + /*outbound=*/FALSE, loopback, result); +} + +/* + * WinDivert socket classify function. + */ +static void windivert_socket_classify(context_t context, + PWINDIVERT_SOCKET_DATA socket_data, WINDIVERT_EVENT event, BOOL ipv4, + BOOL outbound, BOOL loopback, FWPS_CLASSIFY_OUT0 *result) +{ + KLOCK_QUEUE_HANDLE lock_handle; + UINT64 flags; + BOOL match, ok; + WDFOBJECT object; + PWINDIVERT_FILTER filter; + LONGLONG timestamp; + NTSTATUS status; + + // Basic checks: + if (!(result->rights & FWPS_RIGHT_ACTION_WRITE)) + { + return; + } + + // Get the timestamp. + timestamp = KeQueryPerformanceCounter(NULL).QuadPart; + + result->actionType = FWP_ACTION_CONTINUE; + + KeAcquireInStackQueuedSpinLock(&context->lock, &lock_handle); + if (context->state != WINDIVERT_CONTEXT_STATE_OPEN) + { + KeReleaseInStackQueuedSpinLock(&lock_handle); + return; + } + filter = context->filter; + flags = context->flags; + object = (WDFOBJECT)context->object; + WdfObjectReference(object); + KeReleaseInStackQueuedSpinLock(&lock_handle); + + match = windivert_filter(/*buffer=*/NULL, /*layer=*/WINDIVERT_LAYER_SOCKET, + (PVOID)socket_data, event, ipv4, outbound, loopback, + /*impostor=*/FALSE, filter); + if (match) + { + ok = windivert_queue_work(context, /*packet=*/NULL, /*packet_len=*/0, + /*buffers=*/NULL, /*layer=*/WINDIVERT_LAYER_SOCKET, + (PVOID)socket_data, event, flags, /*priority=*/0, ipv4, outbound, + loopback, /*impostor=*/FALSE, /*final=*/FALSE, match, timestamp); + if (!ok) + { + WdfObjectDereference(object); + return; + } + } + + WdfObjectDereference(object); + if ((flags & WINDIVERT_FLAG_SNIFF) == 0) + { + result->actionType = FWP_ACTION_BLOCK; + result->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB; + result->rights &= ~FWPS_RIGHT_ACTION_WRITE; + } +} + /* * WinDivert work item routine for out-of-band filtering. */ @@ -3211,6 +3940,7 @@ static BOOL windivert_queue_work(context_t context, PVOID packet, NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO checksums; PWINDIVERT_NETWORK_DATA network_data; PWINDIVERT_FLOW_DATA flow_data; + PWINDIVERT_SOCKET_DATA socket_data; PWINDIVERT_REFLECT_DATA reflect_data; BOOL pseudo_ip_checksum, pseudo_tcp_checksum, pseudo_udp_checksum; @@ -3288,6 +4018,21 @@ static BOOL windivert_queue_work(context_t context, PVOID packet, pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum = FALSE; break; + + case WINDIVERT_LAYER_SOCKET: + socket_data = (PWINDIVERT_SOCKET_DATA)layer_data; + work = (packet_t)windivert_malloc( + WINDIVERT_PACKET_SIZE(WINDIVERT_SOCKET_DATA, 0), FALSE); + if (work == NULL) + { + return TRUE; + } + work->packet_len = 0; + data = WINDIVERT_LAYER_DATA_PTR(work); + RtlCopyMemory(data, socket_data, sizeof(WINDIVERT_SOCKET_DATA)); + pseudo_ip_checksum = pseudo_tcp_checksum = pseudo_udp_checksum = + FALSE; + break; case WINDIVERT_LAYER_REFLECT: reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data; @@ -3600,7 +4345,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, PWINDIVERT_ICMPHDR *icmp_header_ptr, PWINDIVERT_ICMPV6HDR *icmpv6_header_ptr, PWINDIVERT_TCPHDR *tcp_header_ptr, PWINDIVERT_UDPHDR *udp_header_ptr, - UINT *payload_len_ptr) + UINT8 *proto_ptr, UINT *payload_len_ptr) { UINT tot_len, ip_header_len; PWINDIVERT_IPHDR ip_header = NULL; @@ -3767,6 +4512,7 @@ static BOOL windivert_parse_headers(PNET_BUFFER buffer, BOOL ipv4, *icmpv6_header_ptr = icmpv6_header; *tcp_header_ptr = tcp_header; *udp_header_ptr = udp_header; + *proto_ptr = proto; *payload_len_ptr = payload_len; return TRUE; @@ -3785,10 +4531,12 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, PWINDIVERT_ICMPV6HDR icmpv6_header = NULL; PWINDIVERT_TCPHDR tcp_header = NULL; PWINDIVERT_UDPHDR udp_header = NULL; + UINT8 protocol = 0; UINT payload_len = 0; UINT16 ip, ttl; PWINDIVERT_NETWORK_DATA network_data = NULL; PWINDIVERT_FLOW_DATA flow_data = NULL; + PWINDIVERT_SOCKET_DATA socket_data = NULL; PWINDIVERT_REFLECT_DATA reflect_data = NULL; NTSTATUS status; @@ -3798,7 +4546,7 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_LAYER_NETWORK_FORWARD: if (!windivert_parse_headers(buffer, ipv4, &ip_header, &ipv6_header, &icmp_header, &icmpv6_header, &tcp_header, &udp_header, - &payload_len)) + &protocol, &payload_len)) { return FALSE; } @@ -3807,6 +4555,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_LAYER_FLOW: flow_data = (PWINDIVERT_FLOW_DATA)layer_data; break; + case WINDIVERT_LAYER_SOCKET: + socket_data = (PWINDIVERT_SOCKET_DATA)layer_data; + break; case WINDIVERT_LAYER_REFLECT: reflect_data = (PWINDIVERT_REFLECT_DATA)layer_data; break; @@ -3836,6 +4587,9 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, break; case WINDIVERT_FILTER_FIELD_INBOUND: case WINDIVERT_FILTER_FIELD_OUTBOUND: + result = (layer != WINDIVERT_LAYER_NETWORK_FORWARD && + layer != WINDIVERT_LAYER_REFLECT); + break; case WINDIVERT_FILTER_FIELD_LOOPBACK: case WINDIVERT_FILTER_FIELD_IMPOSTOR: case WINDIVERT_FILTER_FIELD_IP: @@ -3850,25 +4604,23 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, case WINDIVERT_FILTER_FIELD_SUBIFIDX: result = (layer == WINDIVERT_LAYER_NETWORK || layer == WINDIVERT_LAYER_NETWORK_FORWARD); - result = result && (network_data != NULL); break; case WINDIVERT_FILTER_FIELD_LOCALADDR: case WINDIVERT_FILTER_FIELD_REMOTEADDR: case WINDIVERT_FILTER_FIELD_LOCALPORT: case WINDIVERT_FILTER_FIELD_REMOTEPORT: case WINDIVERT_FILTER_FIELD_PROTOCOL: - result = (layer == WINDIVERT_LAYER_FLOW); - result = result && (flow_data != NULL); + result = (layer == WINDIVERT_LAYER_NETWORK || + layer == WINDIVERT_LAYER_FLOW || + layer == WINDIVERT_LAYER_SOCKET); break; case WINDIVERT_FILTER_FIELD_PROCESSID: - result = ((layer == WINDIVERT_LAYER_FLOW && - flow_data != NULL) || - (layer == WINDIVERT_LAYER_REFLECT && - reflect_data != NULL)); + result = (layer == WINDIVERT_LAYER_FLOW || + layer == WINDIVERT_LAYER_SOCKET || + layer == WINDIVERT_LAYER_REFLECT); break; case WINDIVERT_FILTER_FIELD_LAYER: result = (layer == WINDIVERT_LAYER_REFLECT); - result = result && (reflect_data != NULL); break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: case WINDIVERT_FILTER_FIELD_IP_TOS: @@ -3981,24 +4733,88 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = (UINT32)!ipv4; break; case WINDIVERT_FILTER_FIELD_ICMP: - field[0] = (UINT32)(flow_data != NULL? - flow_data->Protocol == IPPROTO_ICMP: - icmp_header != NULL); + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + field[0] = (UINT32)(icmp_header != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = (UINT32)(ipv4 && + socket_data->Protocol == IPPROTO_ICMP); + break; + case WINDIVERT_LAYER_FLOW: + field[0] = (UINT32)(ipv4 && + flow_data->Protocol == IPPROTO_ICMP); + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_ICMPV6: - field[0] = (UINT32)(flow_data != NULL? - flow_data->Protocol == IPPROTO_ICMPV6: - icmpv6_header != NULL); + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + field[0] = (UINT32)(icmpv6_header != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = (UINT32)(!ipv4 && + socket_data->Protocol == IPPROTO_ICMPV6); + break; + case WINDIVERT_LAYER_FLOW: + field[0] = (UINT32)(!ipv4 && + flow_data->Protocol == IPPROTO_ICMPV6); + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_TCP: - field[0] = (UINT32)(flow_data != NULL? - flow_data->Protocol == IPPROTO_TCP: - tcp_header != NULL); + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + field[0] = (UINT32)(tcp_header != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = + (UINT32)(socket_data->Protocol == IPPROTO_TCP); + break; + case WINDIVERT_LAYER_FLOW: + field[0] = + (UINT32)(flow_data->Protocol == IPPROTO_TCP); + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_UDP: - field[0] = (UINT32)(flow_data != NULL? - flow_data->Protocol == IPPROTO_UDP: - udp_header != NULL); + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + field[0] = (UINT32)(udp_header != NULL); + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = + (UINT32)(socket_data->Protocol == IPPROTO_UDP); + break; + case WINDIVERT_LAYER_FLOW: + field[0] = + (UINT32)(flow_data->Protocol == IPPROTO_UDP); + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: field[0] = (UINT32)ip_header->HdrLength; @@ -4164,30 +4980,209 @@ static BOOL windivert_filter(PNET_BUFFER buffer, WINDIVERT_LAYER layer, field[0] = (UINT32)payload_len; break; case WINDIVERT_FILTER_FIELD_LOCALADDR: - field[0] = flow_data->LocalAddr[0]; - field[1] = flow_data->LocalAddr[1]; - field[2] = flow_data->LocalAddr[2]; - field[3] = flow_data->LocalAddr[3]; + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + if (ipv4) + { + field[1] = 0x0000FFFF; + field[0] = (UINT32)RtlUlongByteSwap( + (outbound? ip_header->SrcAddr: + ip_header->DstAddr)); + } + else if (outbound) + { + field[3] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[0]); + field[2] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[1]); + field[1] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[2]); + field[0] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[3]); + } + else + { + field[3] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[0]); + field[2] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[1]); + field[1] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[2]); + field[0] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[3]); + } + break; + case WINDIVERT_LAYER_FLOW: + field[0] = flow_data->LocalAddr[0]; + field[1] = flow_data->LocalAddr[1]; + field[2] = flow_data->LocalAddr[2]; + field[3] = flow_data->LocalAddr[3]; + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = socket_data->LocalAddr[0]; + field[1] = socket_data->LocalAddr[1]; + field[2] = socket_data->LocalAddr[2]; + field[3] = socket_data->LocalAddr[3]; + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_REMOTEADDR: - field[0] = flow_data->RemoteAddr[0]; - field[1] = flow_data->RemoteAddr[1]; - field[2] = flow_data->RemoteAddr[2]; - field[3] = flow_data->RemoteAddr[3]; + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + if (ipv4) + { + field[1] = 0x0000FFFF; + field[0] = (UINT32)RtlUlongByteSwap( + (!outbound? ip_header->SrcAddr: + ip_header->DstAddr)); + } + else if (!outbound) + { + field[3] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[0]); + field[2] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[1]); + field[1] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[2]); + field[0] = (UINT32)RtlUlongByteSwap( + ipv6_header->SrcAddr[3]); + } + else + { + field[3] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[0]); + field[2] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[1]); + field[1] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[2]); + field[0] = (UINT32)RtlUlongByteSwap( + ipv6_header->DstAddr[3]); + } + break; + case WINDIVERT_LAYER_FLOW: + field[0] = flow_data->RemoteAddr[0]; + field[1] = flow_data->RemoteAddr[1]; + field[2] = flow_data->RemoteAddr[2]; + field[3] = flow_data->RemoteAddr[3]; + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = socket_data->RemoteAddr[0]; + field[1] = socket_data->RemoteAddr[1]; + field[2] = socket_data->RemoteAddr[2]; + field[3] = socket_data->RemoteAddr[3]; + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_LOCALPORT: - field[0] = (UINT32)flow_data->LocalPort; + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + if (tcp_header != NULL) + { + field[0] = (UINT32)RtlUshortByteSwap( + (outbound? tcp_header->SrcPort: + tcp_header->DstPort)); + } + else if (udp_header != NULL) + { + field[0] = (UINT32)RtlUshortByteSwap( + (outbound? udp_header->SrcPort: + udp_header->DstPort)); + } + else + { + field[0] = 0; + } + break; + case WINDIVERT_LAYER_FLOW: + field[0] = (UINT32)flow_data->LocalPort; + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = (UINT32)socket_data->LocalPort; + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_REMOTEPORT: - field[0] = (UINT32)flow_data->RemotePort; + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + if (tcp_header != NULL) + { + field[0] = (UINT32)RtlUshortByteSwap( + (!outbound? tcp_header->SrcPort: + tcp_header->DstPort)); + } + else if (udp_header != NULL) + { + field[0] = (UINT32)RtlUshortByteSwap( + (!outbound? udp_header->SrcPort: + udp_header->DstPort)); + } + else + { + field[0] = 0; + } + break; + case WINDIVERT_LAYER_FLOW: + field[0] = (UINT32)flow_data->RemotePort; + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = (UINT32)socket_data->RemotePort; + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_PROTOCOL: - field[0] = (UINT32)flow_data->Protocol; + switch (layer) + { + case WINDIVERT_LAYER_NETWORK: + field[0] = (UINT32)protocol; + break; + case WINDIVERT_LAYER_FLOW: + field[0] = (UINT32)flow_data->Protocol; + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = (UINT32)socket_data->Protocol; + break; + default: + error = TRUE; + result = FALSE; + break; + } break; case WINDIVERT_FILTER_FIELD_PROCESSID: - field[0] = (flow_data != NULL? - flow_data->ProcessId: - reflect_data->ProcessId); + switch (layer) + { + case WINDIVERT_LAYER_FLOW: + field[0] = flow_data->ProcessId; + break; + case WINDIVERT_LAYER_SOCKET: + field[0] = socket_data->ProcessId; + break; + case WINDIVERT_LAYER_REFLECT: + field[0] = reflect_data->ProcessId; + break; + default: + error = TRUE; + result = FALSE; + } break; case WINDIVERT_FILTER_FIELD_LAYER: field[0] = reflect_data->Layer; @@ -4520,15 +5515,24 @@ static void windivert_reflect_event(context_t context, WINDIVERT_EVENT event) // To be released on WINDIVERT_EVENT_REFLECT_CLOSE. This ensures the // context object remains valid until the close event has been handled. WdfObjectReference(object); + context->reflect.open = TRUE; } KeReleaseInStackQueuedSpinLock(&lock_handle); + if (!context->reflect.open) + { + // Ignore CLOSE with no matching OPEN: + return; + } // Queue the event: reflect_event = (reflect_event_t)windivert_malloc( sizeof(struct reflect_event_s), FALSE); if (reflect_event == NULL) { - WdfObjectDereference(object); + if (event == WINDIVERT_EVENT_REFLECT_CLOSE && context->reflect.open) + { + WdfObjectDereference(object); + } return; } reflect_event->context = context; diff --git a/test/test.c b/test/test.c index f6511fc..fa30a02 100644 --- a/test/test.c +++ b/test/test.c @@ -257,6 +257,8 @@ static struct test tests[] = &pkt_dns_request, TRUE}, {"ip.SrcAddr < 10.0.0.0 or ip.SrcAddr > 10.255.255.255", &pkt_dns_request, FALSE}, + {"ip.DstAddr == ::ffff:8.8.4.4", &pkt_dns_request, TRUE}, + {"ip.DstAddr == ::0:ffff:8.8.4.4", &pkt_dns_request, TRUE}, {"udp.PayloadLength == 29", &pkt_dns_request, TRUE}, {"ipv6", &pkt_ipv6_tcp_syn, TRUE}, {"ip", &pkt_ipv6_tcp_syn, FALSE}, @@ -284,8 +286,10 @@ static struct test tests[] = {"false", &pkt_ipv6_exthdrs_udp, FALSE}, {"udp", &pkt_ipv6_exthdrs_udp, TRUE}, {"tcp", &pkt_ipv6_exthdrs_udp, FALSE}, + {"ipv6.SrcAddr == ::", &pkt_ipv6_exthdrs_udp, FALSE}, {"ipv6.SrcAddr == ::1", &pkt_ipv6_exthdrs_udp, TRUE}, {"ipv6.SrcAddr == ::2", &pkt_ipv6_exthdrs_udp, FALSE}, + {"ipv6.SrcAddr == ::8.8.4.4", &pkt_ipv6_exthdrs_udp, FALSE}, {"ipv6.SrcAddr < abcd::1", &pkt_ipv6_exthdrs_udp, TRUE}, {"ipv6.SrcAddr <= abcd::1", &pkt_ipv6_exthdrs_udp, TRUE}, {"ipv6.SrcAddr != abcd::1", &pkt_ipv6_exthdrs_udp, TRUE}, @@ -332,7 +336,7 @@ int main(void) Sleep(100); // Run tests: - size_t num_tests = sizeof(tests) / sizeof(struct test); + size_t num_tests = sizeof(tests) / sizeof(struct test), passed_tests = 0; for (i = 0; i < num_tests; i++) { char *filter = tests[i].filter; @@ -352,6 +356,7 @@ int main(void) { SetConsoleTextAttribute(console, FOREGROUND_GREEN); printf("PASSED"); + passed_tests++; } else { @@ -376,6 +381,9 @@ int main(void) WinDivertClose(upper_handle); WinDivertClose(lower_handle); + printf("\npassed = %.2f%%\n", + ((double)passed_tests / (double)num_tests) * 100.0); + return 0; }