diff --git a/dll/windivert.c b/dll/windivert.c index f0ec577..dc2a092 100644 --- a/dll/windivert.c +++ b/dll/windivert.c @@ -479,6 +479,7 @@ HANDLE WinDivertOpen(const char *filter, WINDIVERT_LAYER layer, INT16 priority, // Parameter checking: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: case WINDIVERT_LAYER_FLOW: diff --git a/dll/windivert.def b/dll/windivert.def index 2c2ecc7..054df2b 100644 --- a/dll/windivert.def +++ b/dll/windivert.def @@ -13,8 +13,10 @@ EXPORTS WinDivertHelperDecrementTTL WinDivertHelperHashPacket WinDivertHelperParsePacket + WinDivertHelperParseMACAddress WinDivertHelperParseIPv4Address WinDivertHelperParseIPv6Address + WinDivertHelperFormatMACAddress WinDivertHelperFormatIPv4Address WinDivertHelperFormatIPv6Address WinDivertHelperCompileFilter @@ -26,6 +28,8 @@ EXPORTS WinDivertHelperHtonl WinDivertHelperNtohll WinDivertHelperHtonll + WinDivertHelperNtohMACAddress + WinDivertHelperHtonMACAddress WinDivertHelperNtohIPv6Address WinDivertHelperHtonIPv6Address WinDivertHelperNtohIpv6Address diff --git a/dll/windivert_hash.c b/dll/windivert_hash.c index 460b35f..3e12636 100644 --- a/dll/windivert_hash.c +++ b/dll/windivert_hash.c @@ -105,8 +105,8 @@ static UINT64 WinDivertXXH64Avalanche(UINT64 h64) * WinDivert packet hash function. */ static UINT64 WinDivertHashPacket(UINT64 seed, - const WINDIVERT_IPHDR *ip_header, const WINDIVERT_IPV6HDR *ipv6_header, - const WINDIVERT_ICMPHDR *icmp_header, + const WINDIVERT_ETHHDR *eth_header, const WINDIVERT_IPHDR *ip_header, + const WINDIVERT_IPV6HDR *ipv6_header, const WINDIVERT_ICMPHDR *icmp_header, const WINDIVERT_ICMPV6HDR *icmpv6_header, const WINDIVERT_TCPHDR *tcp_header, const WINDIVERT_UDPHDR *udp_header) { diff --git a/dll/windivert_helper.c b/dll/windivert_helper.c index 076f961..a725f2e 100644 --- a/dll/windivert_helper.c +++ b/dll/windivert_helper.c @@ -143,11 +143,16 @@ typedef enum TOKEN_PARENT_ENDPOINT_ID, TOKEN_LAYER, TOKEN_PRIORITY, - TOKEN_FLOW, - TOKEN_SOCKET, - TOKEN_NETWORK, - TOKEN_NETWORK_FORWARD, - TOKEN_REFLECT, + TOKEN_ETH_DST_ADDR, + TOKEN_ETH_SRC_ADDR, + TOKEN_ETH_TYPE, + TOKEN_LAYER_FLOW, + TOKEN_LAYER_SOCKET, + TOKEN_LAYER_NETWORK, + TOKEN_LAYER_NETWORK_FORWARD, + TOKEN_LAYER_REFLECT, + TOKEN_LAYER_ETHERNET, + TOKEN_EVENT_FRAME, TOKEN_EVENT_PACKET, TOKEN_EVENT_ESTABLISHED, TOKEN_EVENT_DELETED, @@ -260,10 +265,58 @@ static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length, static int WinDivertCompare128(BOOL neg_a, const UINT32 *a, BOOL neg_b, const UINT32 *b, BOOL big); static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream, - PWINDIVERT_FILTER filter, UINT *length); + WINDIVERT_LAYER layer, PWINDIVERT_FILTER filter, UINT *length); static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr, WINDIVERT_LAYER layer, BOOL top_level, BOOL and); +/* + * Parse a MAC address. + */ +extern BOOL WinDivertHelperParseMACAddress(const char *str, UINT8 *addr_ptr) +{ + UINT i, j; + UINT8 part; + char c; + + for (i = 0; i < 6; i++) + { + part = 0; + for (j = 0; j < 2; j++) + { + c = *str++; + part <<= 4; + if (c >= '0' && c <= '9') + { + part += (UINT8)(c - '0'); + } + else if (c >= 'a' && c <= 'f') + { + part += (UINT8)(c - 'a') + 10; + } + else if (c >= 'A' && c <= 'F') + { + part += (UINT8)(c - 'A') + 10; + } + else + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + } + if ((i != 5? *str != ':': *str != '\0')) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + str++; + if (addr_ptr != NULL) + { + addr_ptr[5-i] = part; + } + } + return TRUE; +} + /* * Parse an IPv4 address. */ @@ -463,14 +516,14 @@ static PTOKEN_INFO WinDivertTokenLookup(PTOKEN_INFO token_info, * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. */ BOOL WinDivertHelperParsePacket(const VOID *pPacket, UINT packetLen, + WINDIVERT_LAYER layer, PWINDIVERT_ETHHDR *ppEthHeader, PWINDIVERT_IPHDR *ppIPHeader, PWINDIVERT_IPV6HDR *ppIPv6Header, UINT8 *pProtocol, PWINDIVERT_ICMPHDR *ppICMPHeader, PWINDIVERT_ICMPV6HDR *ppICMPv6Header, PWINDIVERT_TCPHDR *ppTCPHeader, - PWINDIVERT_UDPHDR *ppUDPHeader, PVOID *ppData, UINT *pDataLen, - PVOID *ppNext, UINT *pNextLen) + PWINDIVERT_UDPHDR *ppUDPHeader, PVOID *ppData, UINT *pDataLen) { WINDIVERT_PACKET info; - if (!WinDivertHelperParsePacketEx(pPacket, packetLen, &info)) + if (!WinDivertHelperParsePacketEx(pPacket, packetLen, layer, &info)) { return FALSE; } @@ -483,6 +536,10 @@ BOOL WinDivertHelperParsePacket(const VOID *pPacket, UINT packetLen, { *pProtocol = info.Protocol; } + if (ppEthHeader != NULL) + { + *ppEthHeader = info.EthHeader; + } if (ppIPHeader != NULL) { *ppIPHeader = info.IPHeader; @@ -515,16 +572,6 @@ BOOL WinDivertHelperParsePacket(const VOID *pPacket, UINT packetLen, { *pDataLen = info.PayloadLength; } - if (ppNext != NULL) - { - *ppNext = (info.Extended? (PVOID)((UINT8 *)pPacket + - (info.HeaderLength + info.PayloadLength)): NULL); - } - if (pNextLen != NULL) - { - *pNextLen = (info.Extended? - packetLen - (info.HeaderLength + info.PayloadLength): 0); - } return TRUE; } @@ -536,21 +583,27 @@ static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer, UINT32 *val) { switch (kind) { - case TOKEN_NETWORK: + case TOKEN_LAYER_ETHERNET: + *val = WINDIVERT_LAYER_ETHERNET; + return TRUE; + case TOKEN_LAYER_NETWORK: *val = WINDIVERT_LAYER_NETWORK; return TRUE; - case TOKEN_NETWORK_FORWARD: + case TOKEN_LAYER_NETWORK_FORWARD: *val = WINDIVERT_LAYER_NETWORK_FORWARD; return TRUE; - case TOKEN_FLOW: + case TOKEN_LAYER_FLOW: *val = WINDIVERT_LAYER_FLOW; return TRUE; - case TOKEN_SOCKET: + case TOKEN_LAYER_SOCKET: *val = WINDIVERT_LAYER_SOCKET; return TRUE; - case TOKEN_REFLECT: + case TOKEN_LAYER_REFLECT: *val = WINDIVERT_LAYER_REFLECT; return TRUE; + case TOKEN_EVENT_FRAME: + *val = WINDIVERT_EVENT_ETHERNET_FRAME; + return (layer == WINDIVERT_LAYER_ETHERNET); case TOKEN_EVENT_PACKET: *val = WINDIVERT_EVENT_NETWORK_PACKET; return (layer == WINDIVERT_LAYER_NETWORK || @@ -619,121 +672,128 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, { static const TOKEN_INFO token_info[] = { - {"ACCEPT", TOKEN_EVENT_ACCEPT }, - {"BIND", TOKEN_EVENT_BIND }, - {"CLOSE", TOKEN_EVENT_CLOSE }, - {"CONNECT", TOKEN_EVENT_CONNECT }, - {"DELETED", TOKEN_EVENT_DELETED }, - {"ESTABLISHED", TOKEN_EVENT_ESTABLISHED }, - {"FALSE", TOKEN_MACRO_FALSE }, - {"FLOW", TOKEN_FLOW }, - {"ICMP", TOKEN_MACRO_ICMP }, - {"ICMPV6", TOKEN_MACRO_ICMPV6 }, - {"LISTEN", TOKEN_EVENT_LISTEN }, - {"NETWORK", TOKEN_NETWORK }, - {"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD }, - {"OPEN", TOKEN_EVENT_OPEN }, - {"PACKET", TOKEN_EVENT_PACKET }, - {"REFLECT", TOKEN_REFLECT }, - {"SOCKET", TOKEN_SOCKET }, - {"TCP", TOKEN_MACRO_TCP }, - {"TRUE", TOKEN_MACRO_TRUE }, - {"UDP", TOKEN_MACRO_UDP }, - {"and", TOKEN_AND }, - {"endpointId", TOKEN_ENDPOINT_ID }, - {"event", TOKEN_EVENT }, - {"false", TOKEN_FALSE }, - {"fragment", TOKEN_FRAGMENT }, - {"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 }, - {"length", TOKEN_LENGTH }, - {"localAddr", TOKEN_LOCAL_ADDR }, - {"localPort", TOKEN_LOCAL_PORT }, - {"loopback", TOKEN_LOOPBACK }, - {"not", TOKEN_NOT }, - {"or", TOKEN_OR }, - {"outbound", TOKEN_OUTBOUND }, - {"packet", TOKEN_PACKET }, - {"packet16", TOKEN_PACKET16 }, - {"packet32", TOKEN_PACKET32 }, - {"parentEndpointId", TOKEN_PARENT_ENDPOINT_ID}, - {"priority", TOKEN_PRIORITY }, - {"processId", TOKEN_PROCESS_ID }, - {"protocol", TOKEN_PROTOCOL }, - {"random16", TOKEN_RANDOM16 }, - {"random32", TOKEN_RANDOM32 }, - {"random8", TOKEN_RANDOM8 }, - {"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.Payload", TOKEN_TCP_PAYLOAD }, - {"tcp.Payload16", TOKEN_TCP_PAYLOAD16 }, - {"tcp.Payload32", TOKEN_TCP_PAYLOAD32 }, - {"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 }, - {"timestamp", TOKEN_TIMESTAMP }, - {"true", TOKEN_TRUE }, - {"udp", TOKEN_UDP }, - {"udp.Checksum", TOKEN_UDP_CHECKSUM }, - {"udp.DstPort", TOKEN_UDP_DST_PORT }, - {"udp.Length", TOKEN_UDP_LENGTH }, - {"udp.Payload", TOKEN_UDP_PAYLOAD }, - {"udp.Payload16", TOKEN_UDP_PAYLOAD16 }, - {"udp.Payload32", TOKEN_UDP_PAYLOAD32 }, - {"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH}, - {"udp.SrcPort", TOKEN_UDP_SRC_PORT }, - {"zero", TOKEN_ZERO }, + {"ACCEPT", TOKEN_EVENT_ACCEPT }, + {"BIND", TOKEN_EVENT_BIND }, + {"CLOSE", TOKEN_EVENT_CLOSE }, + {"CONNECT", TOKEN_EVENT_CONNECT }, + {"DELETED", TOKEN_EVENT_DELETED }, + {"ESTABLISHED", TOKEN_EVENT_ESTABLISHED }, + {"ETHERNET", TOKEN_LAYER_ETHERNET }, + {"FALSE", TOKEN_MACRO_FALSE }, + {"FRAME", TOKEN_EVENT_FRAME }, + {"FLOW", TOKEN_LAYER_FLOW }, + {"ICMP", TOKEN_MACRO_ICMP }, + {"ICMPV6", TOKEN_MACRO_ICMPV6 }, + {"LISTEN", TOKEN_EVENT_LISTEN }, + {"NETWORK", TOKEN_LAYER_NETWORK }, + {"NETWORK_FORWARD", TOKEN_LAYER_NETWORK_FORWARD}, + {"OPEN", TOKEN_EVENT_OPEN }, + {"PACKET", TOKEN_EVENT_PACKET }, + {"REFLECT", TOKEN_LAYER_REFLECT }, + {"SOCKET", TOKEN_LAYER_SOCKET }, + {"TCP", TOKEN_MACRO_TCP }, + {"TRUE", TOKEN_MACRO_TRUE }, + {"UDP", TOKEN_MACRO_UDP }, + {"and", TOKEN_AND }, + {"b", TOKEN_BYTES }, + {"endpointId", TOKEN_ENDPOINT_ID }, + {"eth.DstAddr", TOKEN_ETH_DST_ADDR }, + {"eth.SrcAddr", TOKEN_ETH_SRC_ADDR }, + {"eth.Type", TOKEN_ETH_TYPE }, + {"event", TOKEN_EVENT }, + {"false", TOKEN_FALSE }, + {"fragment", TOKEN_FRAGMENT }, + {"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 }, + {"length", TOKEN_LENGTH }, + {"localAddr", TOKEN_LOCAL_ADDR }, + {"localPort", TOKEN_LOCAL_PORT }, + {"loopback", TOKEN_LOOPBACK }, + {"not", TOKEN_NOT }, + {"or", TOKEN_OR }, + {"outbound", TOKEN_OUTBOUND }, + {"packet", TOKEN_PACKET }, + {"packet16", TOKEN_PACKET16 }, + {"packet32", TOKEN_PACKET32 }, + {"parentEndpointId", TOKEN_PARENT_ENDPOINT_ID }, + {"priority", TOKEN_PRIORITY }, + {"processId", TOKEN_PROCESS_ID }, + {"protocol", TOKEN_PROTOCOL }, + {"random16", TOKEN_RANDOM16 }, + {"random32", TOKEN_RANDOM32 }, + {"random8", TOKEN_RANDOM8 }, + {"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.Payload", TOKEN_TCP_PAYLOAD }, + {"tcp.Payload16", TOKEN_TCP_PAYLOAD16 }, + {"tcp.Payload32", TOKEN_TCP_PAYLOAD32 }, + {"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 }, + {"timestamp", TOKEN_TIMESTAMP }, + {"true", TOKEN_TRUE }, + {"udp", TOKEN_UDP }, + {"udp.Checksum", TOKEN_UDP_CHECKSUM }, + {"udp.DstPort", TOKEN_UDP_DST_PORT }, + {"udp.Length", TOKEN_UDP_LENGTH }, + {"udp.Payload", TOKEN_UDP_PAYLOAD }, + {"udp.Payload16", TOKEN_UDP_PAYLOAD16 }, + {"udp.Payload32", TOKEN_UDP_PAYLOAD32 }, + {"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH }, + {"udp.SrcPort", TOKEN_UDP_SRC_PORT }, + {"zero", TOKEN_ZERO }, }; TOKEN_INFO *result; char c; char token[TOKEN_MAXLEN]; + UINT8 eth_addr[6]; UINT32 field; UINT i = 0, j; UINT tp = 0; @@ -890,13 +950,6 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, continue; } - // Check for 'b': - if (token[0] == 'b' && token[1] == '\0') - { - tokens[tp].kind = TOKEN_BYTES; - continue; - } - // Check for base 10 number: if (WinDivertAToI(token, &end, num, sizeof(num)/sizeof(num[0]))) { @@ -928,6 +981,22 @@ static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer, continue; } + // Check for MAC address: + if (WinDivertHelperParseMACAddress(token, eth_addr)) + { + tokens[tp].val[0] = + (UINT32)eth_addr[0] | + ((UINT32)eth_addr[1] << 8) | + ((UINT32)eth_addr[2] << 16) | + ((UINT32)eth_addr[3] << 24); + tokens[tp].val[1] = + (UINT32)eth_addr[4] | + ((UINT32)eth_addr[5] << 8); + tokens[tp].kind = TOKEN_NUMBER; + tp++; + continue; + } + // Check for IPv4 address: if (WinDivertHelperParseIPv4Address(token, tokens[tp].val)) { @@ -1042,6 +1111,9 @@ static PEXPR WinDivertMakeVar(KIND kind, PERROR error) {{{0}}, TOKEN_PARENT_ENDPOINT_ID}, {{{0}}, TOKEN_LAYER}, {{{0}}, TOKEN_PRIORITY}, + {{{0}}, TOKEN_ETH_DST_ADDR}, + {{{0}}, TOKEN_ETH_SRC_ADDR}, + {{{0}}, TOKEN_ETH_TYPE}, }; // Binary search: @@ -1200,6 +1272,9 @@ static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error) case TOKEN_PARENT_ENDPOINT_ID: case TOKEN_LENGTH: case TOKEN_LAYER: + case TOKEN_ETH_DST_ADDR: + case TOKEN_ETH_SRC_ADDR: + case TOKEN_ETH_TYPE: case TOKEN_IP_HDR_LENGTH: case TOKEN_IP_TOS: case TOKEN_IP_LENGTH: @@ -1554,6 +1629,7 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) case TOKEN_IP_FRAG_OFF: lb[0] = 0; ub[0] = 0x1FFF; break; + case TOKEN_ETH_TYPE: case TOKEN_IP_TOS: case TOKEN_IP_LENGTH: case TOKEN_IP_ID: @@ -1607,6 +1683,12 @@ static BOOL WinDivertEvalTest(PEXPR test, BOOL *res) ub[1] = 0x7FFFFFFF; neg_lb = TRUE; break; + case TOKEN_ETH_DST_ADDR: + case TOKEN_ETH_SRC_ADDR: + lb[0] = lb[1] = 0; + ub[0] = 0xFFFFFFFF; + ub[1] = 0xFFFF; + break; case TOKEN_ENDPOINT_ID: case TOKEN_PARENT_ENDPOINT_ID: lb[0] = lb[1] = 0; @@ -1831,6 +1913,12 @@ static UINT32 WinDivertKindToField(KIND kind) return WINDIVERT_FILTER_FIELD_TCP; case TOKEN_UDP: return WINDIVERT_FILTER_FIELD_UDP; + case TOKEN_ETH_DST_ADDR: + return WINDIVERT_FILTER_FIELD_ETH_DST_ADDR; + case TOKEN_ETH_SRC_ADDR: + return WINDIVERT_FILTER_FIELD_ETH_SRC_ADDR; + case TOKEN_ETH_TYPE: + return WINDIVERT_FILTER_FIELD_ETH_TYPE; case TOKEN_IP_HDR_LENGTH: return WINDIVERT_FILTER_FIELD_IP_HDRLENGTH; case TOKEN_IP_TOS: @@ -2054,7 +2142,8 @@ static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer, return 0; } - if (layer == WINDIVERT_LAYER_NETWORK || + if (layer == WINDIVERT_LAYER_ETHERNET || + layer == WINDIVERT_LAYER_NETWORK || layer == WINDIVERT_LAYER_NETWORK_FORWARD) { // Inbound? @@ -2078,7 +2167,8 @@ static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer, flags |= (result? WINDIVERT_FILTER_FLAG_OUTBOUND: 0); } - if (layer != WINDIVERT_LAYER_REFLECT) + if (layer != WINDIVERT_LAYER_ETHERNET && + layer != WINDIVERT_LAYER_REFLECT) { // IPv4? result = WinDivertCondExecFilter(filter, length, @@ -2258,7 +2348,7 @@ static ERROR WinDivertCompileFilter(const char *filter, HANDLE pool, stream.max = UINT_MAX; stream.overflow = FALSE; - if (!WinDivertDeserializeFilter(&stream, object, obj_len)) + if (!WinDivertDeserializeFilter(&stream, layer, object, obj_len)) { SetLastError(ERROR_INVALID_PARAMETER); return MAKE_ERROR(WINDIVERT_ERROR_BAD_OBJECT, 0); @@ -2434,17 +2524,19 @@ static BOOL WinDivertGetData(const VOID *packet, UINT packet_len, INT min, * Evaluate the given filter with the given packet as input. */ BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, - UINT packet_len, const WINDIVERT_ADDRESS *addr) + UINT packet_len, WINDIVERT_LAYER layer, const WINDIVERT_ADDRESS *addr) { ERROR err; DWORD error; WINDIVERT_PACKET info; + PWINDIVERT_ETHHDR eth_header = NULL; PWINDIVERT_IPHDR ip_header = NULL; PWINDIVERT_IPV6HDR ipv6_header = NULL; PWINDIVERT_ICMPHDR icmp_header = NULL; PWINDIVERT_ICMPV6HDR icmpv6_header = NULL; PWINDIVERT_TCPHDR tcp_header = NULL; PWINDIVERT_UDPHDR udp_header = NULL; + const WINDIVERT_DATA_ETHERNET *ethernet_data = NULL; const WINDIVERT_DATA_NETWORK *network_data = NULL; const WINDIVERT_DATA_FLOW *flow_data = NULL; const WINDIVERT_DATA_SOCKET *socket_data = NULL; @@ -2462,8 +2554,9 @@ BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - switch (addr->Layer) + switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: if (packet == NULL) @@ -2471,12 +2564,14 @@ BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - if (!WinDivertHelperParsePacketEx((PVOID)packet, packet_len, &info)) + if (!WinDivertHelperParsePacketEx((PVOID)packet, packet_len, + layer, &info)) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } protocol = info.Protocol; + eth_header = info.EthHeader; ip_header = info.IPHeader; ipv6_header = info.IPv6Header; icmp_header = info.ICMPHeader; @@ -2507,8 +2602,11 @@ BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, SetLastError(ERROR_INVALID_PARAMETER); return FALSE; } - switch (addr->Layer) + switch (layer) { + case WINDIVERT_LAYER_ETHERNET: + ethernet_data = &addr->Ethernet; + break; case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: network_data = &addr->Network; @@ -2539,7 +2637,7 @@ BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, { goto WinDivertHelperEvalFilterError; } - err = WinDivertCompileFilter(filter, pool, addr->Layer, object, &obj_len); + err = WinDivertCompileFilter(filter, pool, layer, object, &obj_len); if (IS_ERROR(err)) { SetLastError(ERROR_INVALID_PARAMETER); @@ -2548,7 +2646,7 @@ BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, result = WinDivertExecuteFilter( object, - addr->Layer, + layer, addr->Timestamp, addr->Event, (addr->IPv6 != 0? FALSE: TRUE), @@ -2556,10 +2654,12 @@ BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet, (addr->Loopback != 0? TRUE: FALSE), (addr->Impostor != 0? TRUE: FALSE), fragment, + ethernet_data, network_data, flow_data, socket_data, reflect_data, + eth_header, ip_header, ipv6_header, icmp_header, @@ -2720,7 +2820,7 @@ static BOOL WinDivertDeserializeLabel(PWINDIVERT_STREAM stream, UINT16 *label) * Deserialize a test. */ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream, - PWINDIVERT_FILTER filter) + WINDIVERT_LAYER layer, PWINDIVERT_FILTER filter) { UINT32 val; UINT16 success, failure; @@ -2732,7 +2832,7 @@ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream, } if (!WinDivertDeserializeNumber(stream, 2, &val) || - val > WINDIVERT_FILTER_FIELD_MAX) + !WinDivertValidateField(layer, val)) { return FALSE; } @@ -2773,6 +2873,8 @@ static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream, case WINDIVERT_FILTER_FIELD_ENDPOINTID: case WINDIVERT_FILTER_FIELD_PARENTENDPOINTID: case WINDIVERT_FILTER_FIELD_TIMESTAMP: + case WINDIVERT_FILTER_FIELD_ETH_DST_ADDR: + case WINDIVERT_FILTER_FIELD_ETH_SRC_ADDR: if (!WinDivertDeserializeNumber(stream, 7, &filter->arg[1])) { return FALSE; @@ -2854,7 +2956,7 @@ static BOOL WinDivertDeserializeFilterHeader(PWINDIVERT_STREAM stream, * Deserialize a filter. */ static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream, - PWINDIVERT_FILTER filter, UINT *length) + WINDIVERT_LAYER layer, PWINDIVERT_FILTER filter, UINT *length) { UINT i; @@ -2865,7 +2967,7 @@ static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream, for (i = 0; i < *length; i++) { - if (!WinDivertDeserializeTest(stream, filter + i)) + if (!WinDivertDeserializeTest(stream, layer, filter + i)) { return FALSE; } @@ -2967,6 +3069,12 @@ static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test) kind = TOKEN_UDP; break; case WINDIVERT_FILTER_FIELD_ICMPV6: kind = TOKEN_ICMPV6; break; + case WINDIVERT_FILTER_FIELD_ETH_DST_ADDR: + kind = TOKEN_ETH_DST_ADDR; break; + case WINDIVERT_FILTER_FIELD_ETH_SRC_ADDR: + kind = TOKEN_ETH_SRC_ADDR; break; + case WINDIVERT_FILTER_FIELD_ETH_TYPE: + kind = TOKEN_ETH_TYPE; break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: kind = TOKEN_IP_HDR_LENGTH; break; case WINDIVERT_FILTER_FIELD_IP_TOS: @@ -3482,6 +3590,36 @@ static void WinDivertFormatHexNumber(PWINDIVERT_STREAM stream, } } +/* + * Format a MAC address. + */ +static void WinDivertFormatMacAddr(PWINDIVERT_STREAM stream, const UINT8 *addr) +{ + UINT8 part, dig; + INT i, j; + + for (i = 0; i < 6; i++) + { + part = addr[5-i]; + for (j = 0; j < 2; j++) + { + dig = (j == 0? part >> 4: part & 0xF); + if (dig <= 9) + { + WinDivertPutChar(stream, '0' + dig); + } + else + { + WinDivertPutChar(stream, 'a' + (dig - 10)); + } + } + if (i != 5) + { + WinDivertPutChar(stream, ':'); + } + } +} + /* * Format an IPv4 address. */ @@ -3548,6 +3686,27 @@ static void WinDivertFormatIPv6Addr(PWINDIVERT_STREAM stream, } } +/* + * Format a MAC address. + */ +extern BOOL WinDivertHelperFormatMACAddress(const UINT8 *addr, char *buffer, + UINT bufLen) +{ + WINDIVERT_STREAM stream; + stream.data = buffer; + stream.pos = 0; + stream.max = bufLen; + stream.overflow = FALSE; + WinDivertFormatMacAddr(&stream, addr); + WinDivertPutNul(&stream); + if (stream.overflow) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + return TRUE; +} + /* * Format an IPv4 address. */ @@ -3596,8 +3755,8 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, WINDIVERT_LAYER layer) { PEXPR field = expr->arg[0], val = expr->arg[1]; - BOOL is_ipv4_addr = FALSE, is_ipv6_addr = FALSE, is_layer = FALSE, - is_event = FALSE, is_hex = FALSE; + BOOL is_eth_addr = FALSE, is_ipv4_addr = FALSE, is_ipv6_addr = FALSE, + is_layer = FALSE, is_event = FALSE, is_hex = FALSE; switch (field->kind) { @@ -3642,8 +3801,20 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, break; } break; + case TOKEN_ETH_SRC_ADDR: + case TOKEN_ETH_DST_ADDR: + if (val->val[2] != 0 || val->val[3] != 0 || val->val[1] > 0xFFFF) + { + break; + } + is_eth_addr = TRUE; + break; case TOKEN_IP_SRC_ADDR: case TOKEN_IP_DST_ADDR: + if (val->val[2] != 0 || val->val[3] != 0 || val->val[1] != 0xFFFF) + { + break; + } is_ipv4_addr = TRUE; break; case TOKEN_IPV6_SRC_ADDR: @@ -3673,6 +3844,7 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, case TOKEN_UDP_PAYLOAD32: case TOKEN_ICMP_CHECKSUM: case TOKEN_ICMPV6_CHECKSUM: + case TOKEN_ETH_TYPE: is_hex = TRUE; break; default: @@ -3700,7 +3872,18 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, { WinDivertPutChar(stream, '-'); } - if (is_ipv4_addr) + if (is_eth_addr) + { + UINT8 eth_addr[6]; + eth_addr[0] = (UINT8)val->val[0]; + eth_addr[1] = (UINT8)(val->val[0] >> 8); + eth_addr[2] = (UINT8)(val->val[0] >> 16); + eth_addr[3] = (UINT8)(val->val[0] >> 24); + eth_addr[4] = (UINT8)val->val[1]; + eth_addr[5] = (UINT8)(val->val[1] >> 8); + WinDivertFormatMacAddr(stream, eth_addr); + } + else if (is_ipv4_addr) { WinDivertFormatIPv4Addr(stream, val->val[0]); } @@ -3712,6 +3895,8 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, { switch (val->val[0]) { + case WINDIVERT_LAYER_ETHERNET: + WinDivertPutString(stream, "ETHERNET"); break; case WINDIVERT_LAYER_NETWORK: WinDivertPutString(stream, "NETWORK"); break; case WINDIVERT_LAYER_NETWORK_FORWARD: @@ -3730,6 +3915,16 @@ static void WinDivertFormatTestExpr(PWINDIVERT_STREAM stream, PEXPR expr, { switch (layer) { + case WINDIVERT_LAYER_ETHERNET: + if (val->val[0] == WINDIVERT_EVENT_ETHERNET_FRAME) + { + WinDivertPutString(stream, "FRAME"); + } + else + { + WinDivertFormatDecNumber32(stream, val->val[0]); + } + break; case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: if (val->val[0] == WINDIVERT_EVENT_NETWORK_PACKET) @@ -3920,6 +4115,12 @@ static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr, WinDivertPutString(stream, "udp"); return; case TOKEN_ICMPV6: WinDivertPutString(stream, "icmpv6"); return; + case TOKEN_ETH_DST_ADDR: + WinDivertPutString(stream, "eth.DstAddr"); return; + case TOKEN_ETH_SRC_ADDR: + WinDivertPutString(stream, "eth.SrcAddr"); return; + case TOKEN_ETH_TYPE: + WinDivertPutString(stream, "eth.Type"); return; case TOKEN_IP_HDR_LENGTH: WinDivertPutString(stream, "ip.HdrLength"); return; case TOKEN_IP_TOS: @@ -4171,8 +4372,9 @@ WinDivertHelperFormatFilterError: * WinDivert packet hash function. */ UINT64 WinDivertHelperHashPacket(const VOID *pPacket, UINT packetLen, - UINT64 seed) + WINDIVERT_LAYER layer, UINT64 seed) { + PWINDIVERT_ETHHDR eth_header = NULL; PWINDIVERT_IPHDR ip_header = NULL; PWINDIVERT_IPV6HDR ipv6_header = NULL; PWINDIVERT_ICMPHDR icmp_header = NULL; @@ -4180,14 +4382,14 @@ UINT64 WinDivertHelperHashPacket(const VOID *pPacket, UINT packetLen, PWINDIVERT_TCPHDR tcp_header = NULL; PWINDIVERT_UDPHDR udp_header = NULL; - if (!WinDivertHelperParsePacket((PVOID)pPacket, packetLen, &ip_header, - &ipv6_header, NULL, &icmp_header, &icmpv6_header, &tcp_header, - &udp_header, NULL, NULL, NULL, NULL)) + if (!WinDivertHelperParsePacket((PVOID)pPacket, packetLen, layer, + ð_header, &ip_header, &ipv6_header, NULL, &icmp_header, + &icmpv6_header, &tcp_header, &udp_header, NULL, NULL)) { return 0; } - return WinDivertHashPacket(seed, ip_header, ipv6_header, icmp_header, - icmpv6_header, tcp_header, udp_header); + return WinDivertHashPacket(seed, eth_header, ip_header, ipv6_header, + icmp_header, icmpv6_header, tcp_header, udp_header); } /* @@ -4217,6 +4419,26 @@ UINT64 WinDivertHelperHtonll(UINT64 x) { return BYTESWAP64(x); } +static void WinDivertByteSwap48(const UINT8 *inAddr, UINT8 *outAddr) +{ + UINT8 tmp[6], i; // tmp[] allows overlapping inAddr/outAddr + for (i = 0; i < 6; i++) + { + tmp[5-i] = inAddr[i]; + } + for (i = 0; i < 6; i++) + { + outAddr[i] = tmp[i]; + } +} +extern void WinDivertHelperNtohMACAddress(const UINT8 *inAddr, UINT8 *outAddr) +{ + WinDivertByteSwap48(inAddr, outAddr); +} +extern void WinDivertHelperHtonMACAddress(const UINT8 *inAddr, UINT8 *outAddr) +{ + WinDivertByteSwap48(inAddr, outAddr); +} static void WinDivertByteSwap128(const UINT *inAddr, UINT *outAddr) { UINT32 tmp[4], i; // tmp[] allows overlapping inAddr/outAddr diff --git a/dll/windivert_shared.c b/dll/windivert_shared.c index 6c6a68c..88f16b0 100644 --- a/dll/windivert_shared.c +++ b/dll/windivert_shared.c @@ -45,6 +45,13 @@ #define BYTESWAP32(x) \ ((((x) >> 24) & 0x000000FFu) | (((x) >> 8) & 0x0000FF00u) | \ (((x) << 8) & 0x00FF0000u) | (((x) << 24) & 0xFF000000u)) +#define BYTESWAP48(x) \ + ((((x) >> 40) & 0x0000000000FF0000ull) | \ + (((x) >> 24) & 0x00000000FF000000ull) | \ + (((x) >> 8) & 0x000000FF00000000ull) | \ + (((x) << 8) & 0x0000FF0000000000ull) | \ + (((x) << 24) & 0x00FF000000000000ull) | \ + (((x) << 40) & 0xFF00000000000000ull)) #define BYTESWAP64(x) \ ((((x) >> 56) & 0x00000000000000FFull) | \ (((x) >> 40) & 0x000000000000FF00ull) | \ @@ -58,6 +65,11 @@ #define htons(x) BYTESWAP16(x) #define ntohl(x) BYTESWAP32(x) #define htonl(x) BYTESWAP32(x) +#define ntohl48(x) BYTESWAP48(x) +#define htonl48(x) BYTESWAP48(x) + +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_IPV6 0x86DD /* * Layer flags shorthand. @@ -68,32 +80,46 @@ #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) -#define LNMFSR (WINDIVERT_LAYER_FLAG_NETWORK | \ +#define WINDIVERT_LAYER_FLAG_ETHERNET (1 << WINDIVERT_LAYER_ETHERNET) +#define LENMFSR (WINDIVERT_LAYER_FLAG_ETHERNET | \ + 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 | \ +#define LENMFS_ (WINDIVERT_LAYER_FLAG_ETHERNET | \ + WINDIVERT_LAYER_FLAG_NETWORK | \ WINDIVERT_LAYER_FLAG_NETWORK_FORWARD | \ WINDIVERT_LAYER_FLAG_FLOW | \ WINDIVERT_LAYER_FLAG_SOCKET) -#define L__F_R (WINDIVERT_LAYER_FLAG_FLOW | \ +#define LEN_F__ (WINDIVERT_LAYER_FLAG_ETHERNET | \ + WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_FLOW) +#define L___F_R (WINDIVERT_LAYER_FLAG_FLOW | \ WINDIVERT_LAYER_FLAG_REFLECT) -#define LN_FS_ (WINDIVERT_LAYER_FLAG_NETWORK | \ +#define LEN_FS_ (WINDIVERT_LAYER_FLAG_ETHERNET | \ + WINDIVERT_LAYER_FLAG_NETWORK | \ WINDIVERT_LAYER_FLAG_FLOW | \ WINDIVERT_LAYER_FLAG_SOCKET) -#define L__FS_ (WINDIVERT_LAYER_FLAG_FLOW | \ +#define L_N_FS_ (WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_FLOW | \ WINDIVERT_LAYER_FLAG_SOCKET) -#define L___SR (WINDIVERT_LAYER_FLAG_SOCKET | \ +#define L___FS_ (WINDIVERT_LAYER_FLAG_FLOW | \ + WINDIVERT_LAYER_FLAG_SOCKET) +#define L____SR (WINDIVERT_LAYER_FLAG_SOCKET | \ WINDIVERT_LAYER_FLAG_REFLECT) -#define L__FSR (WINDIVERT_LAYER_FLAG_FLOW | \ +#define L___FSR (WINDIVERT_LAYER_FLAG_FLOW | \ WINDIVERT_LAYER_FLAG_SOCKET | \ WINDIVERT_LAYER_FLAG_REFLECT) -#define LNM___ (WINDIVERT_LAYER_FLAG_NETWORK | \ +#define LENM___ (WINDIVERT_LAYER_FLAG_ETHERNET | \ + 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 +#define L_NM___ (WINDIVERT_LAYER_FLAG_NETWORK | \ + WINDIVERT_LAYER_FLAG_NETWORK_FORWARD) +#define LE_____ WINDIVERT_LAYER_FLAG_ETHERNET +#define L___F__ WINDIVERT_LAYER_FLAG_FLOW +#define L____S_ WINDIVERT_LAYER_FLAG_SOCKET +#define L_____R WINDIVERT_LAYER_FLAG_REFLECT #if defined(WIN32) && defined(_MSC_VER) #pragma intrinsic(__emulu) @@ -161,6 +187,7 @@ typedef struct UINT32 Truncated:1; UINT32 Extended:1; UINT32 Reserved1:6; + PWINDIVERT_ETHHDR EthHeader; PWINDIVERT_IPHDR IPHeader; PWINDIVERT_IPV6HDR IPv6Header; PWINDIVERT_ICMPHDR ICMPHeader; @@ -360,9 +387,10 @@ static void WinDivertSerializeFilter(PWINDIVERT_STREAM stream, /* * Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet. */ -static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, UINT packetLen, - PWINDIVERT_PACKET pInfo) +static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, + UINT packetLen, WINDIVERT_LAYER layer, PWINDIVERT_PACKET pInfo) { + PWINDIVERT_ETHHDR eth_header = NULL; PWINDIVERT_IPHDR ip_header = NULL; PWINDIVERT_IPV6HDR ipv6_header = NULL; PWINDIVERT_ICMPHDR icmp_header = NULL; @@ -370,109 +398,168 @@ static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, UINT packetLen, PWINDIVERT_TCPHDR tcp_header = NULL; PWINDIVERT_UDPHDR udp_header = NULL; PWINDIVERT_IPV6FRAGHDR frag_header; - UINT8 protocol = 0; + UINT8 ip_protocol = 0; UINT8 *data = NULL; - UINT packet_len, total_len, header_len, data_len = 0, frag_off = 0; - BOOL MF = FALSE, fragment = FALSE, is_ext_header; + UINT ip_packet_len = 0, ip_total_len = 0, ip_header_len = 0, + trans_header_len, header_len = 0, data_len, frag_off = 0; + BOOL ipv4 = FALSE, MF = FALSE, fragment = FALSE, is_ext_header; - if (pPacket == NULL || packetLen < sizeof(WINDIVERT_IPHDR)) + if (pPacket == NULL) { return FALSE; } data = (UINT8 *)pPacket; data_len = packetLen; - ip_header = (PWINDIVERT_IPHDR)data; - switch (ip_header->Version) + switch (layer) { - case 4: - if (packetLen < sizeof(WINDIVERT_IPHDR) || - ip_header->HdrLength < 5) + case WINDIVERT_LAYER_ETHERNET: + if (data_len < sizeof(WINDIVERT_ETHHDR)) { return FALSE; } - total_len = (UINT)ntohs(ip_header->Length); - protocol = ip_header->Protocol; - header_len = ip_header->HdrLength * sizeof(UINT32); - if (total_len < header_len || packetLen < header_len) + eth_header = (PWINDIVERT_ETHHDR)data; + data = (PVOID)(eth_header + 1); + data_len -= sizeof(WINDIVERT_ETHHDR); + header_len = sizeof(WINDIVERT_ETHHDR); + switch (ntohs(eth_header->Type)) { - return FALSE; - } - frag_off = ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)); - MF = (WINDIVERT_IPHDR_GET_MF(ip_header) != 0); - fragment = (MF || frag_off != 0); - packet_len = (total_len < packetLen? total_len: packetLen); - data += header_len; - data_len = packet_len - header_len; - break; - - case 6: - ip_header = NULL; - ipv6_header = (PWINDIVERT_IPV6HDR)data; - if (packetLen < sizeof(WINDIVERT_IPV6HDR)) - { - return FALSE; - } - protocol = ipv6_header->NextHdr; - total_len = (UINT)ntohs(ipv6_header->Length) + - sizeof(WINDIVERT_IPV6HDR); - packet_len = (total_len < packetLen? total_len: packetLen); - data += sizeof(WINDIVERT_IPV6HDR); - data_len = packet_len - sizeof(WINDIVERT_IPV6HDR); - - while (frag_off == 0 && data_len >= 2) - { - header_len = (UINT)data[1]; - is_ext_header = TRUE; - switch (protocol) - { - case IPPROTO_FRAGMENT: - header_len = 8; - if (fragment || data_len < header_len) - { - is_ext_header = FALSE; - break; - } - frag_header = (PWINDIVERT_IPV6FRAGHDR)data; - frag_off = ntohs( - WINDIVERT_IPV6FRAGHDR_GET_FRAGOFF(frag_header)); - MF = WINDIVERT_IPV6FRAGHDR_GET_MF(frag_header); - fragment = TRUE; - break; - case IPPROTO_AH: - header_len += 2; - header_len *= 4; - break; - case IPPROTO_HOPOPTS: - case IPPROTO_DSTOPTS: - case IPPROTO_ROUTING: - case IPPROTO_MH: - header_len++; - header_len *= 8; - break; - default: - is_ext_header = FALSE; - break; - } - if (!is_ext_header || data_len < header_len) - { + case ETHERTYPE_IP: + if (data_len < sizeof(WINDIVERT_IPHDR)) + { + goto WinDivertHelperParsePacketExit; + } + ipv4 = TRUE; break; - } - protocol = data[0]; - data += header_len; - data_len -= header_len; + case ETHERTYPE_IPV6: + if (data_len < sizeof(WINDIVERT_IPV6HDR)) + { + goto WinDivertHelperParsePacketExit; + } + break; + default: + goto WinDivertHelperParsePacketExit; } + ip_packet_len = data_len; + break; + + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + if (data_len < sizeof(WINDIVERT_IPHDR)) + { + return FALSE; + } + switch (((PWINDIVERT_IPHDR)data)->Version) + { + case 4: + ipv4 = TRUE; + break; + case 6: + break; + default: + return FALSE; + } + ip_packet_len = packetLen; break; default: return FALSE; } + if (ipv4) + { + ip_header = (PWINDIVERT_IPHDR)data; + if (ip_header->HdrLength < 5) + { +WinDivertHelperParsePacketIPError: + if (eth_header == NULL) + { + return FALSE; + } + goto WinDivertHelperParsePacketExit; + } + ip_total_len = (UINT)ntohs(ip_header->Length); + ip_protocol = ip_header->Protocol; + ip_header_len = ip_header->HdrLength * sizeof(UINT32); + if (ip_total_len < ip_header_len || ip_packet_len < ip_header_len) + { + goto WinDivertHelperParsePacketIPError; + } + frag_off = ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(ip_header)); + MF = (WINDIVERT_IPHDR_GET_MF(ip_header) != 0); + fragment = (MF || frag_off != 0); + ip_packet_len = + (ip_total_len < ip_packet_len? ip_total_len: ip_packet_len); + data += ip_header_len; + data_len = ip_packet_len - ip_header_len; + header_len += ip_header_len; + } + else + { + if (data_len < sizeof(WINDIVERT_IPV6HDR)) + { + goto WinDivertHelperParsePacketIPError; + } + ipv6_header = (PWINDIVERT_IPV6HDR)data; + ip_protocol = ipv6_header->NextHdr; + ip_total_len = (UINT)ntohs(ipv6_header->Length) + + sizeof(WINDIVERT_IPV6HDR); + ip_packet_len = + (ip_total_len < ip_packet_len? ip_total_len: ip_packet_len); + data += sizeof(WINDIVERT_IPV6HDR); + data_len = ip_packet_len - sizeof(WINDIVERT_IPV6HDR); + header_len += ip_header_len; + + while (frag_off == 0 && data_len >= 2) + { + ip_header_len = (UINT)data[1]; + is_ext_header = TRUE; + switch (ip_protocol) + { + case IPPROTO_FRAGMENT: + ip_header_len = 8; + if (fragment || data_len < ip_header_len) + { + is_ext_header = FALSE; + break; + } + frag_header = (PWINDIVERT_IPV6FRAGHDR)data; + frag_off = ntohs( + WINDIVERT_IPV6FRAGHDR_GET_FRAGOFF(frag_header)); + MF = WINDIVERT_IPV6FRAGHDR_GET_MF(frag_header); + fragment = TRUE; + break; + case IPPROTO_AH: + ip_header_len += 2; + ip_header_len *= 4; + break; + case IPPROTO_HOPOPTS: + case IPPROTO_DSTOPTS: + case IPPROTO_ROUTING: + case IPPROTO_MH: + ip_header_len++; + ip_header_len *= 8; + break; + default: + is_ext_header = FALSE; + break; + } + if (!is_ext_header || data_len < ip_header_len) + { + break; + } + ip_protocol = data[0]; + data += ip_header_len; + data_len -= ip_header_len; + header_len += ip_header_len; + } + } + if (frag_off != 0) { goto WinDivertHelperParsePacketExit; } - switch (protocol) + switch (ip_protocol) { case IPPROTO_TCP: tcp_header = (PWINDIVERT_TCPHDR)data; @@ -482,8 +569,9 @@ static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, UINT packetLen, tcp_header = NULL; goto WinDivertHelperParsePacketExit; } - header_len = tcp_header->HdrLength * sizeof(UINT32); - header_len = (header_len > data_len? data_len: header_len); + trans_header_len = tcp_header->HdrLength * sizeof(UINT32); + trans_header_len = + (trans_header_len > data_len? data_len: trans_header_len); break; case IPPROTO_UDP: @@ -492,7 +580,7 @@ static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, UINT packetLen, goto WinDivertHelperParsePacketExit; } udp_header = (PWINDIVERT_UDPHDR)data; - header_len = sizeof(WINDIVERT_UDPHDR); + trans_header_len = sizeof(WINDIVERT_UDPHDR); break; case IPPROTO_ICMP: @@ -502,7 +590,7 @@ static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, UINT packetLen, goto WinDivertHelperParsePacketExit; } icmp_header = (PWINDIVERT_ICMPHDR)data; - header_len = sizeof(WINDIVERT_ICMPHDR); + trans_header_len = sizeof(WINDIVERT_ICMPHDR); break; case IPPROTO_ICMPV6: @@ -512,14 +600,15 @@ static BOOL WinDivertHelperParsePacketEx(const VOID *pPacket, UINT packetLen, goto WinDivertHelperParsePacketExit; } icmpv6_header = (PWINDIVERT_ICMPV6HDR)data; - header_len = sizeof(WINDIVERT_ICMPV6HDR); + trans_header_len = sizeof(WINDIVERT_ICMPV6HDR); break; default: goto WinDivertHelperParsePacketExit; } - data += header_len; - data_len -= header_len; + data += trans_header_len; + data_len -= trans_header_len; + header_len += trans_header_len; WinDivertHelperParsePacketExit: if (pInfo == NULL) @@ -527,13 +616,14 @@ WinDivertHelperParsePacketExit: return TRUE; } data = (data_len == 0? NULL: data); - pInfo->Protocol = (UINT32)protocol; + pInfo->Protocol = (UINT32)ip_protocol; pInfo->Fragment = (fragment? 1: 0); pInfo->MF = (MF? 1: 0); pInfo->FragOff = (UINT32)frag_off; - pInfo->Truncated = (total_len > packetLen? 1: 0); - pInfo->Extended = (total_len < packetLen? 1: 0); + pInfo->Truncated = (ip_total_len > ip_packet_len? 1: 0); + pInfo->Extended = (ip_total_len < ip_packet_len? 1: 0); pInfo->Reserved1 = 0; + pInfo->EthHeader = eth_header; pInfo->IPHeader = ip_header; pInfo->IPv6Header = ipv6_header; pInfo->ICMPHeader = icmp_header; @@ -541,7 +631,7 @@ WinDivertHelperParsePacketExit: pInfo->TCPHeader = tcp_header; pInfo->UDPHeader = udp_header; pInfo->Payload = data; - pInfo->HeaderLength = (UINT32)(packet_len - data_len); + pInfo->HeaderLength = (UINT32)header_len; pInfo->PayloadLength = (UINT32)data_len; return TRUE; } @@ -550,7 +640,7 @@ WinDivertHelperParsePacketExit: * Calculate IPv4/IPv6/ICMP/ICMPv6/TCP/UDP checksums. */ BOOL WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen, - WINDIVERT_ADDRESS *pAddr, UINT64 flags) + WINDIVERT_LAYER layer, WINDIVERT_ADDRESS *pAddr, UINT64 flags) { UINT8 pseudo_header[ MAX(sizeof(WINDIVERT_PSEUDOHDR), sizeof(WINDIVERT_PSEUDOV6HDR))]; @@ -565,7 +655,7 @@ BOOL WinDivertHelperCalcChecksums(PVOID pPacket, UINT packetLen, UINT payload_len, checksum_len; BOOL truncated; - if (!WinDivertHelperParsePacketEx(pPacket, packetLen, &info)) + if (!WinDivertHelperParsePacketEx(pPacket, packetLen, layer, &info)) { return FALSE; } @@ -754,53 +844,104 @@ static UINT16 WinDivertCalcChecksum(PVOID pseudo_header, /* * Decrement the TTL. */ -BOOL WinDivertHelperDecrementTTL(VOID *packet, UINT packetLen) +BOOL WinDivertHelperDecrementTTL(VOID *packet, UINT packetLen, + WINDIVERT_LAYER layer) { + PWINDIVERT_ETHHDR eth_header; PWINDIVERT_IPHDR ip_header; PWINDIVERT_IPV6HDR ipv6_header; + BOOL is_ipv6 = FALSE; - if (packet == NULL || packetLen < sizeof(WINDIVERT_IPHDR)) + if (packet == NULL) { return FALSE; } - ip_header = (PWINDIVERT_IPHDR)packet; - switch (ip_header->Version) + switch (layer) { - case 4: - if (ip_header->TTL <= 1) + case WINDIVERT_LAYER_ETHERNET: + if (packetLen < sizeof(WINDIVERT_ETHHDR)) { return FALSE; } - ip_header->TTL--; - - // Incremental checksum update: - if (ip_header->Checksum >= 0xFFFE) + eth_header = (PWINDIVERT_ETHHDR)packet; + switch (ntohs(eth_header->Type)) { - ip_header->Checksum -= 0xFFFE; + case ETHERTYPE_IP: + if (packetLen < sizeof(WINDIVERT_IPHDR)) + { + return FALSE; + } + break; + case ETHERTYPE_IPV6: + if (packetLen < sizeof(WINDIVERT_IPV6HDR)) + { + return FALSE; + } + is_ipv6 = TRUE; + break; + default: + return FALSE; } - else - { - ip_header->Checksum += 1; - } - return TRUE; + packet = (VOID *)(eth_header + 1); + break; - case 6: - if (packetLen < sizeof(WINDIVERT_IPV6HDR)) + case WINDIVERT_LAYER_NETWORK: + case WINDIVERT_LAYER_NETWORK_FORWARD: + if (packetLen < sizeof(WINDIVERT_IPHDR)) { return FALSE; } - ipv6_header = (PWINDIVERT_IPV6HDR)packet; - if (ipv6_header->HopLimit <= 1) + ip_header = (PWINDIVERT_IPHDR)packet; + switch (ip_header->Version) { - return FALSE; + case 4: + break; + case 6: + if (packetLen < sizeof(WINDIVERT_IPV6HDR)) + { + return FALSE; + } + is_ipv6 = TRUE; + break; + default: + return FALSE; } - ipv6_header->HopLimit--; - return TRUE; + break; default: return FALSE; } + + if (!is_ipv6) + { + ip_header = (PWINDIVERT_IPHDR)packet; + if (ip_header->TTL <= 1) + { + return FALSE; + } + ip_header->TTL--; + + // Incremental checksum update: + if (ip_header->Checksum >= 0xFFFE) + { + ip_header->Checksum -= 0xFFFE; + } + else + { + ip_header->Checksum += 1; + } + } + else + { + ipv6_header = (PWINDIVERT_IPV6HDR)packet; + if (ipv6_header->HopLimit <= 1) + { + return FALSE; + } + ipv6_header->HopLimit--; + } + return TRUE; } /* @@ -810,92 +951,95 @@ static BOOL WinDivertValidateField(WINDIVERT_LAYER layer, UINT32 field) { static const UINT8 flags[] = { - LNMFSR, /* WINDIVERT_FILTER_FIELD_ZERO */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_INBOUND */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_OUTBOUND */ - LNM___, /* WINDIVERT_FILTER_FIELD_IFIDX */ - LNM___, /* WINDIVERT_FILTER_FIELD_SUBIFIDX */ - LNMFS_, /* WINDIVERT_FILTER_FIELD_IP */ - LNMFS_, /* WINDIVERT_FILTER_FIELD_IPV6 */ - LNMFS_, /* WINDIVERT_FILTER_FIELD_ICMP */ - LNMFS_, /* WINDIVERT_FILTER_FIELD_TCP */ - LNMFS_, /* WINDIVERT_FILTER_FIELD_UDP */ - LNMFS_, /* WINDIVERT_FILTER_FIELD_ICMPV6 */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_HDRLENGTH */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_TOS */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_LENGTH */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_ID */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_DF */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_MF */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_FRAGOFF */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_TTL */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_PROTOCOL */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_CHECKSUM */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_SRCADDR */ - LNM___, /* WINDIVERT_FILTER_FIELD_IP_DSTADDR */ - LNM___, /* WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS */ - LNM___, /* WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL */ - LNM___, /* WINDIVERT_FILTER_FIELD_IPV6_LENGTH */ - LNM___, /* WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR */ - LNM___, /* WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT */ - LNM___, /* WINDIVERT_FILTER_FIELD_IPV6_SRCADDR */ - LNM___, /* WINDIVERT_FILTER_FIELD_IPV6_DSTADDR */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMP_TYPE */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMP_CODE */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMP_BODY */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_TYPE */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_CODE */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM */ - LNM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_BODY */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_SRCPORT */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_DSTPORT */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_SEQNUM */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_ACKNUM */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_URG */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_ACK */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_PSH */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_RST */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_SYN */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_FIN */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_WINDOW */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_CHECKSUM */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_URGPTR */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_SRCPORT */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_DSTPORT */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_LENGTH */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_CHECKSUM */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_LOOPBACK */ - LNM___, /* WINDIVERT_FILTER_FIELD_IMPOSTOR */ - L__FSR, /* WINDIVERT_FILTER_FIELD_PROCESSID */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_LOCALADDR */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_REMOTEADDR */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_LOCALPORT */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_REMOTEPORT */ - LN_FS_, /* WINDIVERT_FILTER_FIELD_PROTOCOL */ - L__FS_, /* WINDIVERT_FILTER_FIELD_ENDPOINTID */ - L__FS_, /* WINDIVERT_FILTER_FIELD_PARENTENDPOINTID */ - L____R, /* WINDIVERT_FILTER_FIELD_LAYER */ - L____R, /* WINDIVERT_FILTER_FIELD_PRIORITY */ - LNMFSR, /* WINDIVERT_FILTER_FIELD_EVENT */ - LNM___, /* WINDIVERT_FILTER_FIELD_PACKET */ - LNM___, /* WINDIVERT_FILTER_FIELD_PACKET16 */ - LNM___, /* WINDIVERT_FILTER_FIELD_PACKET32 */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOAD */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16 */ - LNM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32 */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOAD */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16 */ - LNM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 */ - LNM___, /* WINDIVERT_FILTER_FIELD_LENGTH */ - LNMFSR, /* WINDIVERT_FILTER_FIELD_TIMESTAMP */ - LNM___, /* WINDIVERT_FILTER_FIELD_RANDOM8 */ - LNM___, /* WINDIVERT_FILTER_FIELD_RANDOM16 */ - LNM___, /* WINDIVERT_FILTER_FIELD_RANDOM32 */ - LNM___, /* WINDIVERT_FILTER_FIELD_FRAGMENT */ + LENMFSR, /* WINDIVERT_FILTER_FIELD_ZERO */ + LEN_FS_, /* WINDIVERT_FILTER_FIELD_INBOUND */ + LEN_FS_, /* WINDIVERT_FILTER_FIELD_OUTBOUND */ + LENM___, /* WINDIVERT_FILTER_FIELD_IFIDX */ + LENM___, /* WINDIVERT_FILTER_FIELD_SUBIFIDX */ + LENMFS_, /* WINDIVERT_FILTER_FIELD_IP */ + LENMFS_, /* WINDIVERT_FILTER_FIELD_IPV6 */ + LENMFS_, /* WINDIVERT_FILTER_FIELD_ICMP */ + LENMFS_, /* WINDIVERT_FILTER_FIELD_TCP */ + LENMFS_, /* WINDIVERT_FILTER_FIELD_UDP */ + LENMFS_, /* WINDIVERT_FILTER_FIELD_ICMPV6 */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_HDRLENGTH */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_TOS */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_LENGTH */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_ID */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_DF */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_MF */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_FRAGOFF */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_TTL */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_PROTOCOL */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_CHECKSUM */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_SRCADDR */ + LENM___, /* WINDIVERT_FILTER_FIELD_IP_DSTADDR */ + LENM___, /* WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS */ + LENM___, /* WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL */ + LENM___, /* WINDIVERT_FILTER_FIELD_IPV6_LENGTH */ + LENM___, /* WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR */ + LENM___, /* WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT */ + LENM___, /* WINDIVERT_FILTER_FIELD_IPV6_SRCADDR */ + LENM___, /* WINDIVERT_FILTER_FIELD_IPV6_DSTADDR */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMP_TYPE */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMP_CODE */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMP_BODY */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_TYPE */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_CODE */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM */ + LENM___, /* WINDIVERT_FILTER_FIELD_ICMPV6_BODY */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_SRCPORT */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_DSTPORT */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_SEQNUM */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_ACKNUM */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_URG */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_ACK */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_PSH */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_RST */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_SYN */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_FIN */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_WINDOW */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_CHECKSUM */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_URGPTR */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_SRCPORT */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_DSTPORT */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_LENGTH */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_CHECKSUM */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH */ + L_N_FS_, /* WINDIVERT_FILTER_FIELD_LOOPBACK */ + LENM___, /* WINDIVERT_FILTER_FIELD_IMPOSTOR */ + L___FSR, /* WINDIVERT_FILTER_FIELD_PROCESSID */ + LEN_FS_, /* WINDIVERT_FILTER_FIELD_LOCALADDR */ + LEN_FS_, /* WINDIVERT_FILTER_FIELD_REMOTEADDR */ + LEN_FS_, /* WINDIVERT_FILTER_FIELD_LOCALPORT */ + LEN_FS_, /* WINDIVERT_FILTER_FIELD_REMOTEPORT */ + LEN_FS_, /* WINDIVERT_FILTER_FIELD_PROTOCOL */ + L___FS_, /* WINDIVERT_FILTER_FIELD_ENDPOINTID */ + L___FS_, /* WINDIVERT_FILTER_FIELD_PARENTENDPOINTID */ + L_____R, /* WINDIVERT_FILTER_FIELD_LAYER */ + L_____R, /* WINDIVERT_FILTER_FIELD_PRIORITY */ + LENMFSR, /* WINDIVERT_FILTER_FIELD_EVENT */ + LENM___, /* WINDIVERT_FILTER_FIELD_PACKET */ + LENM___, /* WINDIVERT_FILTER_FIELD_PACKET16 */ + LENM___, /* WINDIVERT_FILTER_FIELD_PACKET32 */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOAD */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16 */ + LENM___, /* WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32 */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOAD */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16 */ + LENM___, /* WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32 */ + LENM___, /* WINDIVERT_FILTER_FIELD_LENGTH */ + LENMFSR, /* WINDIVERT_FILTER_FIELD_TIMESTAMP */ + LENM___, /* WINDIVERT_FILTER_FIELD_RANDOM8 */ + LENM___, /* WINDIVERT_FILTER_FIELD_RANDOM16 */ + LENM___, /* WINDIVERT_FILTER_FIELD_RANDOM32 */ + LENM___, /* WINDIVERT_FILTER_FIELD_FRAGMENT */ + LE_____, /* WINDIVERT_FILTER_FIELD_ETH_DST_ADDR */ + LE_____, /* WINDIVERT_FILTER_FIELD_ETH_SRC_ADDR */ + LE_____, /* WINDIVERT_FILTER_FIELD_ETH_TYPE */ }; if (field > WINDIVERT_FILTER_FIELD_MAX) @@ -972,10 +1116,12 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( BOOL loopback, BOOL impostor, BOOL fragment, + const WINDIVERT_DATA_ETHERNET *ethernet_data, const WINDIVERT_DATA_NETWORK *network_data, const WINDIVERT_DATA_FLOW *flow_data, const WINDIVERT_DATA_SOCKET *socket_data, const WINDIVERT_DATA_REFLECT *reflect_data, + const WINDIVERT_ETHHDR *eth_header, const WINDIVERT_IPHDR *ip_header, const WINDIVERT_IPV6HDR *ipv6_header, const WINDIVERT_ICMPHDR *icmp_header, @@ -994,6 +1140,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( UINT16 data16; UINT32 data32; ULARGE_INTEGER val64; + const UINT8 *eth_addr; ip = 0; ttl = WINDIVERT_FILTER_MAXLEN+1; @@ -1017,11 +1164,16 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( if (random64 == 0) { random64 = WinDivertHashPacket((UINT64)timestamp, - ip_header, ipv6_header, icmp_header, icmpv6_header, - tcp_header, udp_header); + eth_header, ip_header, ipv6_header, icmp_header, + icmpv6_header, tcp_header, udp_header); random64 |= 0xFF00000000000000ull; // Make non-zero. } break; + case WINDIVERT_FILTER_FIELD_ETH_DST_ADDR: + case WINDIVERT_FILTER_FIELD_ETH_SRC_ADDR: + case WINDIVERT_FILTER_FIELD_ETH_TYPE: + result = (eth_header != NULL); + break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: case WINDIVERT_FILTER_FIELD_IP_TOS: case WINDIVERT_FILTER_FIELD_IP_LENGTH: @@ -1174,6 +1326,9 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_IFIDX: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: + val[0] = ethernet_data->IfIdx; + break; case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: val[0] = network_data->IfIdx; @@ -1183,7 +1338,17 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( } break; case WINDIVERT_FILTER_FIELD_SUBIFIDX: - val[0] = network_data->SubIfIdx; + switch (layer) + { + case WINDIVERT_LAYER_ETHERNET: + val[0] = ethernet_data->SubIfIdx; + break; + case WINDIVERT_LAYER_NETWORK: + val[0] = network_data->SubIfIdx; + break; + default: + return -1; + } break; case WINDIVERT_FILTER_FIELD_LOOPBACK: val[0] = (UINT32)loopback; @@ -1200,6 +1365,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_ICMP: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: val[0] = (UINT32)(icmp_header != NULL); @@ -1219,6 +1385,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_ICMPV6: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: val[0] = (UINT32)(icmpv6_header != NULL); @@ -1238,6 +1405,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_TCP: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: val[0] = (UINT32)(tcp_header != NULL); @@ -1257,6 +1425,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_UDP: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: case WINDIVERT_LAYER_NETWORK_FORWARD: val[0] = (UINT32)(udp_header != NULL); @@ -1273,6 +1442,23 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( return -1; } break; + case WINDIVERT_FILTER_FIELD_ETH_DST_ADDR: + case WINDIVERT_FILTER_FIELD_ETH_SRC_ADDR: + big = TRUE; + eth_addr = + (filter[ip].field == WINDIVERT_FILTER_FIELD_ETH_DST_ADDR? + eth_header->DstAddr: eth_header->SrcAddr); + val[0] = ((UINT32)eth_addr[2] << 24) | + ((UINT32)eth_addr[3] << 16) | + ((UINT32)eth_addr[4] << 8) | + ((UINT32)eth_addr[5]); + val[1] = ((UINT32)eth_addr[0] << 8) | + ((UINT32)eth_addr[1]); + val[2] = val[3] = 0; + break; + case WINDIVERT_FILTER_FIELD_ETH_TYPE: + val[0] = (UINT32)ntohs(eth_header->Type); + break; case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH: val[0] = (UINT32)ip_header->HdrLength; break; @@ -1435,6 +1621,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( big = TRUE; switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: if (ip_header != NULL) { @@ -1483,6 +1670,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( big = TRUE; switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: if (ip_header != NULL) { @@ -1530,6 +1718,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_LOCALPORT: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: if (tcp_header != NULL) { @@ -1571,6 +1760,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_REMOTEPORT: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: if (tcp_header != NULL) { @@ -1612,6 +1802,7 @@ static WINDIVERT_INLINE int WinDivertExecuteFilter( case WINDIVERT_FILTER_FIELD_PROTOCOL: switch (layer) { + case WINDIVERT_LAYER_ETHERNET: case WINDIVERT_LAYER_NETWORK: val[0] = (UINT32)protocol; break; diff --git a/doc/windivert.html b/doc/windivert.html index b0d8090..bc375ab 100644 --- a/doc/windivert.html +++ b/doc/windivert.html @@ -1,11 +1,11 @@ - WinDivert 2.2 Documentation + WinDivert 3.0 Documentation -

WinDivert 2.2: Windows Packet Divert

+

WinDivert 3.0: Windows Packet Divert

Table of Contents

-The WINDIVERT_LAYER_NETWORK and -WINDIVERT_LAYER_NETWORK_FORWARD -layers allow the user application to capture/block/inject network packets +The WINDIVERT_LAYER_ETHERNET +layer allows the user application to capture/block/inject ethernet +frames passing to/from the local machine. +An ethernet frame will start with ethernet header, +followed by a packet from an upper layer protocol, such as +IPv4, IPv6, ARP, etc. +

+

+The WINDIVERT_LAYER_NETWORK (and +WINDIVERT_LAYER_NETWORK_FORWARD) +layers allow the user application to +capture/block/inject network packets passing to/from (and through) the local machine. -Due to technical limitations, process ID information is not available -at these layers. +Network layer packets start with either an IPv4 or IPv6 header, +typically followed by a transport layer payload (e.g., TCP or UDP).

The WINDIVERT_LAYER_FLOW layer captures information about @@ -393,8 +416,10 @@ The WINDIVERT_LAYER_SOCKET layer can capture or block events corresponding to socket operations, such as bind(), connect(), listen(), etc., or the termination of socket operations, such as a TCP socket disconnection. -Unlike the flow layer, most socket-related events can be blocked. -However, it is not possible to inject new or modified socket events. +Unlike the flow layer, most socket-related events can be blocked, +but it is not possible to inject new or modified socket events. +Some events at this layer may be implicit, meaning that the event +does not correspond to an explicit call to a WinSock2 function. Process ID information (of the process responsible for the socket operation) is available at this layer. Due to technical limitations, this layer cannot capture events that @@ -434,6 +459,7 @@ typedef enum WINDIVERT_EVENT_SOCKET_CLOSE, WINDIVERT_EVENT_REFLECT_OPEN, WINDIVERT_EVENT_REFLECT_CLOSE, + WINDIVERT_EVENT_ETHERNET_FRAME, } WINDIVERT_EVENT, *PWINDIVERT_EVENT; @@ -445,6 +471,27 @@ Each layer supports one or more events summarized below: