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; }