Files
basil00_WinDivert/dll/windivert_helper.c
basil00 29c6fda167 Improve & expand WinDivert test suite.
- Include tests for random*.
- Include latency timings in microseconds.
- More tests.
2018-11-19 07:21:54 +08:00

4578 lines
146 KiB
C

/*
* windivert_helper.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 <http://www.gnu.org/licenses/>.
*
* 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.
*/
/****************************************************************************/
/* WINDIVERT HELPER IMPLEMENTATION */
/****************************************************************************/
/*
* Protocols.
*/
#define IPPROTO_HOPOPTS 0
#define IPPROTO_ICMP 1
#define IPPROTO_TCP 6
#define IPPROTO_UDP 17
#define IPPROTO_ROUTING 43
#define IPPROTO_FRAGMENT 44
#define IPPROTO_AH 51
#define IPPROTO_ICMPV6 58
#define IPPROTO_NONE 59
#define IPPROTO_DSTOPTS 60
/*
* Filter tokens.
*/
typedef enum
{
TOKEN_ICMP,
TOKEN_ICMP_BODY,
TOKEN_ICMP_CHECKSUM,
TOKEN_ICMP_CODE,
TOKEN_ICMP_TYPE,
TOKEN_ICMPV6,
TOKEN_ICMPV6_BODY,
TOKEN_ICMPV6_CHECKSUM,
TOKEN_ICMPV6_CODE,
TOKEN_ICMPV6_TYPE,
TOKEN_IP,
TOKEN_IP_CHECKSUM,
TOKEN_IP_DF,
TOKEN_IP_DST_ADDR,
TOKEN_IP_FRAG_OFF,
TOKEN_IP_HDR_LENGTH,
TOKEN_IP_ID,
TOKEN_IP_LENGTH,
TOKEN_IP_MF,
TOKEN_IP_PROTOCOL,
TOKEN_IP_SRC_ADDR,
TOKEN_IP_TOS,
TOKEN_IP_TTL,
TOKEN_IPV6,
TOKEN_IPV6_DST_ADDR,
TOKEN_IPV6_FLOW_LABEL,
TOKEN_IPV6_HOP_LIMIT,
TOKEN_IPV6_LENGTH,
TOKEN_IPV6_NEXT_HDR,
TOKEN_IPV6_SRC_ADDR,
TOKEN_IPV6_TRAFFIC_CLASS,
TOKEN_TCP,
TOKEN_TCP_ACK,
TOKEN_TCP_ACK_NUM,
TOKEN_TCP_CHECKSUM,
TOKEN_TCP_DST_PORT,
TOKEN_TCP_FIN,
TOKEN_TCP_HDR_LENGTH,
TOKEN_TCP_PAYLOAD,
TOKEN_TCP_PAYLOAD16,
TOKEN_TCP_PAYLOAD32,
TOKEN_TCP_PAYLOAD_LENGTH,
TOKEN_TCP_PSH,
TOKEN_TCP_RST,
TOKEN_TCP_SEQ_NUM,
TOKEN_TCP_SRC_PORT,
TOKEN_TCP_SYN,
TOKEN_TCP_URG,
TOKEN_TCP_URG_PTR,
TOKEN_TCP_WINDOW,
TOKEN_UDP,
TOKEN_UDP_CHECKSUM,
TOKEN_UDP_DST_PORT,
TOKEN_UDP_LENGTH,
TOKEN_UDP_PAYLOAD,
TOKEN_UDP_PAYLOAD16,
TOKEN_UDP_PAYLOAD32,
TOKEN_UDP_PAYLOAD_LENGTH,
TOKEN_UDP_SRC_PORT,
TOKEN_ZERO,
TOKEN_EVENT,
TOKEN_RANDOM8,
TOKEN_RANDOM16,
TOKEN_RANDOM32,
TOKEN_PACKET,
TOKEN_PACKET16,
TOKEN_PACKET32,
TOKEN_TRUE,
TOKEN_FALSE,
TOKEN_INBOUND,
TOKEN_OUTBOUND,
TOKEN_IF_IDX,
TOKEN_SUB_IF_IDX,
TOKEN_LOOPBACK,
TOKEN_IMPOSTOR,
TOKEN_PROCESS_ID,
TOKEN_LOCAL_ADDR,
TOKEN_REMOTE_ADDR,
TOKEN_LOCAL_PORT,
TOKEN_REMOTE_PORT,
TOKEN_PROTOCOL,
TOKEN_LAYER,
TOKEN_FLOW,
TOKEN_SOCKET,
TOKEN_NETWORK,
TOKEN_NETWORK_FORWARD,
TOKEN_REFLECT,
TOKEN_EVENT_PACKET,
TOKEN_EVENT_ESTABLISHED,
TOKEN_EVENT_DELETED,
TOKEN_EVENT_BIND,
TOKEN_EVENT_CONNECT,
TOKEN_EVENT_LISTEN,
TOKEN_EVENT_ACCEPT,
TOKEN_EVENT_OPEN,
TOKEN_EVENT_CLOSE,
TOKEN_OPEN,
TOKEN_CLOSE,
TOKEN_SQUARE_OPEN,
TOKEN_SQUARE_CLOSE,
TOKEN_MINUS,
TOKEN_BYTES,
TOKEN_EQ,
TOKEN_NEQ,
TOKEN_LT,
TOKEN_LEQ,
TOKEN_GT,
TOKEN_GEQ,
TOKEN_NOT,
TOKEN_AND,
TOKEN_OR,
TOKEN_COLON,
TOKEN_QUESTION,
TOKEN_NUMBER,
TOKEN_END,
} KIND;
typedef struct
{
KIND kind;
UINT pos;
UINT32 val[4];
} TOKEN;
#define TOKEN_MAXLEN 32
typedef struct
{
char *name;
KIND kind;
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 L__F_R (WINDIVERT_LAYER_FLAG_FLOW | \
WINDIVERT_LAYER_FLAG_REFLECT)
#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.
*/
typedef struct EXPR EXPR;
typedef struct EXPR *PEXPR;
struct EXPR
{
union
{
UINT32 val[4];
PEXPR arg[3];
};
UINT8 kind;
UINT8 count;
UINT16 succ;
UINT16 fail;
};
/*
* Error handling.
*/
#undef ERROR
typedef UINT64 ERROR, *PERROR;
#define WINDIVERT_ERROR_NONE 0
#define WINDIVERT_ERROR_NO_MEMORY 1
#define WINDIVERT_ERROR_TOO_DEEP 2
#define WINDIVERT_ERROR_TOO_LONG 3
#define WINDIVERT_ERROR_BAD_TOKEN 4
#define WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER 5
#define WINDIVERT_ERROR_UNEXPECTED_TOKEN 6
#define WINDIVERT_ERROR_INDEX_OOB 7
#define WINDIVERT_ERROR_OUTPUT_TOO_SHORT 8
#define WINDIVERT_ERROR_BAD_OBJECT 9
#define WINDIVERT_ERROR_ASSERTION_FAILED 10
#define MAKE_ERROR(code, pos) \
(((ERROR)(code) << 32) | (ERROR)(pos));
#define GET_CODE(err) \
((UINT)((err) >> 32))
#define GET_POS(err) \
((UINT)((err) & 0xFFFFFFFF))
#undef IS_ERROR
#define IS_ERROR(err) \
(GET_CODE(err) != WINDIVERT_ERROR_NONE)
/*
* Prototypes.
*/
static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i,
INT depth, BOOL and, PERROR error);
static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
UINT8 field, UINT32 arg);
static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
PWINDIVERT_FILTER filter, UINT *length);
static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
WINDIVERT_LAYER layer, BOOL top_level, BOOL and);
/*
* Parse IPv4/IPv6/ICMP/ICMPv6/TCP/UDP headers from a raw packet.
*/
extern BOOL WinDivertHelperParsePacket(const VOID *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 WinDivertParsePacket((PVOID)pPacket, packetLen, ppIpHdr, ppIpv6Hdr,
ppIcmpHdr, ppIcmpv6Hdr, ppTcpHdr, ppUdpHdr, NULL, ppData, pDataLen);
}
/*
* Parse an IPv4 address.
*/
extern BOOL WinDivertHelperParseIPv4Address(const char *str, UINT32 *addr_ptr)
{
UINT32 addr = 0;
UINT32 part, i;
if (str == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
for (i = 0; i < 4; i++)
{
if (!WinDivertAToI(str, (char **)&str, &part) || part > UINT8_MAX)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (i != 3 && *str++ != '.')
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
addr |= part << (8*(3-i));
}
if (*str != '\0')
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (addr_ptr != NULL)
{
*addr_ptr = addr;
}
return TRUE;
}
/*
* Parse an IPv6 address.
*/
extern BOOL WinDivertHelperParseIPv6Address(const char *str, UINT32 *addr_ptr)
{
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];
j = 0;
if (*str == ':')
{
str++;
if (*str != ':')
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
left = FALSE;
str++;
if (*str == '\0')
{
goto WinDivertHelperParseIPv6AddressSuccess;
}
}
for (i = 0, k = 0; k < 8; k++)
{
if (*str == ':')
{
if (!left)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
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++)
{
part_str[l] = *str;
str++;
}
if (l == 0)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
part_str[l] = '\0';
if (*str != ':' && *str != '\0')
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WinDivertAToX(part_str, NULL, &part);
if (left)
{
laddr[i++] = (UINT16)part;
}
else
{
raddr[j++] = (UINT16)part;
}
if (*str == '\0')
{
if (!left || k == 7)
{
break;
}
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
str++;
}
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[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_INFO WinDivertTokenLookup(PTOKEN_INFO token_info,
size_t token_info_len, const char *name)
{
int lo = 0, hi = (int)token_info_len-1, mid;
int cmp;
while (hi >= lo)
{
mid = (lo + hi) / 2;
cmp = WinDivertStrCmp(token_info[mid].name, name);
if (cmp < 0)
{
lo = mid+1;
}
else if (cmp > 0)
{
hi = mid-1;
}
else
{
return &token_info[mid];
}
}
return NULL;
}
/*
* Expand a "macro" value.
*/
static BOOL WinDivertExpandMacro(KIND kind, WINDIVERT_LAYER layer,
UINT32 *val)
{
switch (kind)
{
case TOKEN_NETWORK:
*val = WINDIVERT_LAYER_NETWORK;
return TRUE;
case TOKEN_NETWORK_FORWARD:
*val = WINDIVERT_LAYER_NETWORK_FORWARD;
return TRUE;
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;
case TOKEN_EVENT_PACKET:
*val = WINDIVERT_EVENT_NETWORK_PACKET;
return (layer == WINDIVERT_LAYER_NETWORK);
case TOKEN_EVENT_ESTABLISHED:
*val = WINDIVERT_EVENT_FLOW_ESTABLISHED;
return (layer == WINDIVERT_LAYER_FLOW);
case TOKEN_EVENT_DELETED:
*val = WINDIVERT_EVENT_FLOW_DELETED;
return (layer == WINDIVERT_LAYER_FLOW);
case TOKEN_EVENT_BIND:
*val = WINDIVERT_EVENT_SOCKET_BIND;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_CONNECT:
*val = WINDIVERT_EVENT_SOCKET_CONNECT;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_LISTEN:
*val = WINDIVERT_EVENT_SOCKET_LISTEN;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_ACCEPT:
*val = WINDIVERT_EVENT_SOCKET_ACCEPT;
return (layer == WINDIVERT_LAYER_SOCKET);
case TOKEN_EVENT_OPEN:
*val = WINDIVERT_EVENT_REFLECT_OPEN;
return (layer == WINDIVERT_LAYER_REFLECT);
case TOKEN_EVENT_CLOSE:
*val = WINDIVERT_EVENT_REFLECT_CLOSE;
return (layer == WINDIVERT_LAYER_REFLECT);
default:
return FALSE;
}
}
/*
* Tokenize the given filter string.
*/
static ERROR WinDivertTokenizeFilter(const char *filter, WINDIVERT_LAYER layer,
TOKEN *tokens, UINT tokensmax)
{
static const TOKEN_INFO token_info[] =
{
{"ACCEPT", TOKEN_EVENT_ACCEPT, L___S_},
{"BIND", TOKEN_EVENT_BIND, L___S_},
{"CLOSE", TOKEN_EVENT_CLOSE, L____R},
{"CONNECT", TOKEN_EVENT_CONNECT, L___S_},
{"DELETED", TOKEN_EVENT_DELETED, L__F__},
{"ESTABLISHED", TOKEN_EVENT_ESTABLISHED, L__F_R},
{"FLOW", TOKEN_FLOW, L____R},
{"LISTEN", TOKEN_EVENT_LISTEN, L___S_},
{"NETWORK", TOKEN_NETWORK, L____R},
{"NETWORK_FORWARD", TOKEN_NETWORK_FORWARD, L____R},
{"OPEN", TOKEN_EVENT_OPEN, L____R},
{"PACKET", TOKEN_EVENT_PACKET, LNM___},
{"REFLECT", TOKEN_REFLECT, L____R},
{"SOCKET", TOKEN_SOCKET, L____R},
{"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__},
{"packet", TOKEN_PACKET, LNM___},
{"packet16", TOKEN_PACKET16, LNM___},
{"packet32", TOKEN_PACKET32, LNM___},
{"processId", TOKEN_PROCESS_ID, L__FSR},
{"protocol", TOKEN_PROTOCOL, LN_FS_},
{"random16", TOKEN_RANDOM16, LNM___},
{"random32", TOKEN_RANDOM32, LNM___},
{"random8", TOKEN_RANDOM8, LNM___},
{"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.Payload", TOKEN_TCP_PAYLOAD, LNM___},
{"tcp.Payload16", TOKEN_TCP_PAYLOAD16, LNM___},
{"tcp.Payload32", TOKEN_TCP_PAYLOAD32, 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.Payload", TOKEN_UDP_PAYLOAD, LNM___},
{"udp.Payload16", TOKEN_UDP_PAYLOAD16, LNM___},
{"udp.Payload32", TOKEN_UDP_PAYLOAD32, LNM___},
{"udp.PayloadLength", TOKEN_UDP_PAYLOAD_LENGTH, LNM___},
{"udp.SrcPort", TOKEN_UDP_SRC_PORT, LNM___},
{"zero", TOKEN_ZERO, LNMFSR},
};
TOKEN_INFO *result;
char c;
char token[TOKEN_MAXLEN];
UINT i = 0, j;
UINT tp = 0;
while (TRUE)
{
if (tp >= tokensmax-1)
{
return MAKE_ERROR(WINDIVERT_ERROR_TOO_LONG, i);
}
memset(tokens[tp].val, 0, sizeof(tokens[tp].val));
while (WinDivertIsSpace(filter[i]))
{
i++;
}
tokens[tp].pos = i;
c = filter[i++];
switch (c)
{
case '\0':
tokens[tp].kind = TOKEN_END;
return MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
case '(':
tokens[tp++].kind = TOKEN_OPEN;
continue;
case ')':
tokens[tp++].kind = TOKEN_CLOSE;
continue;
case '[':
tokens[tp++].kind = TOKEN_SQUARE_OPEN;
continue;
case ']':
tokens[tp++].kind = TOKEN_SQUARE_CLOSE;
continue;
case '-':
tokens[tp++].kind = TOKEN_MINUS;
continue;
case '!':
if (filter[i] == '=')
{
i++;
tokens[tp++].kind = TOKEN_NEQ;
}
else
{
tokens[tp++].kind = TOKEN_NOT;
}
continue;
case '=':
if (filter[i] == '=')
{
i++;
}
tokens[tp++].kind = TOKEN_EQ;
continue;
case '<':
if (filter[i] == '=')
{
i++;
tokens[tp++].kind = TOKEN_LEQ;
}
else
{
tokens[tp++].kind = TOKEN_LT;
}
continue;
case '>':
if (filter[i] == '=')
{
i++;
tokens[tp++].kind = TOKEN_GEQ;
}
else
{
tokens[tp++].kind = TOKEN_GT;
}
continue;
case ':':
if (filter[i] == ':')
{
break; // Probably ipv6 address, e.g. ::1.
}
tokens[tp++].kind = TOKEN_COLON;
continue;
case '?':
tokens[tp++].kind = TOKEN_QUESTION;
continue;
case '&':
if (filter[i++] != '&')
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN, i-1);
}
tokens[tp++].kind = TOKEN_AND;
continue;
case '|':
if (filter[i++] != '|')
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN, i-1);
}
tokens[tp++].kind = TOKEN_OR;
continue;
default:
break;
}
token[0] = c;
if (WinDivertIsAlNum(c) || c == '.' || c == ':' || c == '_')
{
UINT32 num;
char *end;
for (j = 1; j < TOKEN_MAXLEN && (WinDivertIsAlNum(filter[i]) ||
filter[i] == '.' || filter[i] == ':' || filter[i] == '_');
j++, i++)
{
token[j] = filter[i];
}
if (j >= TOKEN_MAXLEN)
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN, i-j);
}
token[j] = '\0';
// Handle trailing colons:
if (j >= 1 && token[j-1] == ':')
{
if (j == 1 || token[j-2] != ':')
{
token[j-1] = '\0';
i--;
}
}
// Check for symbol:
result = WinDivertTokenLookup((PTOKEN_INFO)token_info,
sizeof(token_info) / sizeof(TOKEN_INFO), token);
if (result != NULL)
{
if ((result->flags & (1 << layer)) == 0)
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER, i-j);
}
if (WinDivertExpandMacro(result->kind, layer,
&tokens[tp].val[0]))
{
tokens[tp].kind = TOKEN_NUMBER;
}
else
{
tokens[tp].kind = result->kind;
}
tp++;
continue;
}
// Check for base 10 number:
if (WinDivertAToI(token, &end, &num))
{
BOOL b = (*end == 'b' && *(end+1) == '\0');
if (*end == '\0' || b)
{
tokens[tp].kind = TOKEN_NUMBER;
tokens[tp].val[0] = num;
tp++;
if (b)
{
tokens[tp].kind = TOKEN_BYTES;
tp++;
}
continue;
}
}
// Check for base 16 number:
if (token[0] == '0' && token[1] == 'x' &&
WinDivertAToX(token, &end, &num) && *end == '\0')
{
tokens[tp].kind = TOKEN_NUMBER;
tokens[tp].val[0] = num;
tp++;
continue;
}
// Check for IPv4 address:
if (WinDivertHelperParseIPv4Address(token, tokens[tp].val))
{
tokens[tp].val[1] = 0x0000FFFF;
tokens[tp].kind = TOKEN_NUMBER;
tp++;
continue;
}
// Check for IPv6 address:
SetLastError(0);
if (WinDivertHelperParseIPv6Address(token, tokens[tp].val))
{
tokens[tp].kind = TOKEN_NUMBER;
tp++;
continue;
}
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN, i-j);
}
else
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_TOKEN, i);
}
}
}
/*
* Construct a variable/field.
*/
static PEXPR WinDivertMakeVar(KIND kind, PERROR error)
{
// NOTE: must be in order of kind.
static const EXPR vars[] =
{
{{{0}}, TOKEN_ICMP},
{{{0}}, TOKEN_ICMP_BODY},
{{{0}}, TOKEN_ICMP_CHECKSUM},
{{{0}}, TOKEN_ICMP_CODE},
{{{0}}, TOKEN_ICMP_TYPE},
{{{0}}, TOKEN_ICMPV6},
{{{0}}, TOKEN_ICMPV6_BODY},
{{{0}}, TOKEN_ICMPV6_CHECKSUM},
{{{0}}, TOKEN_ICMPV6_CODE},
{{{0}}, TOKEN_ICMPV6_TYPE},
{{{0}}, TOKEN_IP},
{{{0}}, TOKEN_IP_CHECKSUM},
{{{0}}, TOKEN_IP_DF},
{{{0}}, TOKEN_IP_DST_ADDR},
{{{0}}, TOKEN_IP_FRAG_OFF},
{{{0}}, TOKEN_IP_HDR_LENGTH},
{{{0}}, TOKEN_IP_ID},
{{{0}}, TOKEN_IP_LENGTH},
{{{0}}, TOKEN_IP_MF},
{{{0}}, TOKEN_IP_PROTOCOL},
{{{0}}, TOKEN_IP_SRC_ADDR},
{{{0}}, TOKEN_IP_TOS},
{{{0}}, TOKEN_IP_TTL},
{{{0}}, TOKEN_IPV6},
{{{0}}, TOKEN_IPV6_DST_ADDR},
{{{0}}, TOKEN_IPV6_FLOW_LABEL},
{{{0}}, TOKEN_IPV6_HOP_LIMIT},
{{{0}}, TOKEN_IPV6_LENGTH},
{{{0}}, TOKEN_IPV6_NEXT_HDR},
{{{0}}, TOKEN_IPV6_SRC_ADDR},
{{{0}}, TOKEN_IPV6_TRAFFIC_CLASS},
{{{0}}, TOKEN_TCP},
{{{0}}, TOKEN_TCP_ACK},
{{{0}}, TOKEN_TCP_ACK_NUM},
{{{0}}, TOKEN_TCP_CHECKSUM},
{{{0}}, TOKEN_TCP_DST_PORT},
{{{0}}, TOKEN_TCP_FIN},
{{{0}}, TOKEN_TCP_HDR_LENGTH},
{{{0}}, TOKEN_TCP_PAYLOAD_LENGTH},
{{{0}}, TOKEN_TCP_PSH},
{{{0}}, TOKEN_TCP_RST},
{{{0}}, TOKEN_TCP_SEQ_NUM},
{{{0}}, TOKEN_TCP_SRC_PORT},
{{{0}}, TOKEN_TCP_SYN},
{{{0}}, TOKEN_TCP_URG},
{{{0}}, TOKEN_TCP_URG_PTR},
{{{0}}, TOKEN_TCP_WINDOW},
{{{0}}, TOKEN_UDP},
{{{0}}, TOKEN_UDP_CHECKSUM},
{{{0}}, TOKEN_UDP_DST_PORT},
{{{0}}, TOKEN_UDP_LENGTH},
{{{0}}, TOKEN_UDP_PAYLOAD_LENGTH},
{{{0}}, TOKEN_UDP_SRC_PORT},
{{{0}}, TOKEN_ZERO},
{{{0}}, TOKEN_EVENT},
{{{0}}, TOKEN_RANDOM8},
{{{0}}, TOKEN_RANDOM16},
{{{0}}, TOKEN_RANDOM32},
{{{0}}, TOKEN_TRUE},
{{{0}}, TOKEN_FALSE},
{{{0}}, TOKEN_INBOUND},
{{{0}}, TOKEN_OUTBOUND},
{{{0}}, TOKEN_IF_IDX},
{{{0}}, TOKEN_SUB_IF_IDX},
{{{0}}, TOKEN_LOOPBACK},
{{{0}}, TOKEN_IMPOSTOR},
{{{0}}, TOKEN_PROCESS_ID},
{{{0}}, TOKEN_LOCAL_ADDR},
{{{0}}, TOKEN_REMOTE_ADDR},
{{{0}}, TOKEN_LOCAL_PORT},
{{{0}}, TOKEN_REMOTE_PORT},
{{{0}}, TOKEN_PROTOCOL},
{{{0}}, TOKEN_LAYER},
};
// Binary search:
UINT lo = 0, hi = sizeof(vars) / sizeof(vars[0]) - 1, mid;
while (lo <= hi)
{
mid = (hi + lo) / 2;
if (vars[mid].kind < kind)
{
lo = mid + 1;
continue;
}
if (vars[mid].kind > kind)
{
hi = mid - 1;
continue;
}
return (PEXPR)(vars + mid);
}
*error = MAKE_ERROR(WINDIVERT_ERROR_ASSERTION_FAILED, 0);
return NULL;
}
/*
* Construct array varable.
*/
static PEXPR WinDivertMakeArrayVar(HANDLE pool, KIND kind, INT idx,
PERROR error)
{
PEXPR var = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (var == NULL)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
return NULL;
}
var->kind = kind;
var->val[0] = (UINT32)idx;
return var;
}
/*
* Construct zero.
*/
static PEXPR WinDivertMakeZero(void)
{
static const EXPR zero = {{{0, 0, 0, 0}}, TOKEN_NUMBER};
return (PEXPR)&zero;
}
/*
* Construct a number.
*/
static PEXPR WinDivertMakeNumber(HANDLE pool, UINT32 *val, PERROR error)
{
if (val[0] == 0 && val[1] == 0 && val[2] == 0 && val[3] == 0)
{
return WinDivertMakeZero();
}
PEXPR expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (expr == NULL)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
return NULL;
}
expr->kind = TOKEN_NUMBER;
expr->val[0] = val[0];
expr->val[1] = val[1];
expr->val[2] = val[2];
expr->val[3] = val[3];
return expr;
}
/*
* Construct a binary operator.
*/
static PEXPR WinDivertMakeBinOp(HANDLE pool, KIND kind, PEXPR arg0, PEXPR arg1,
PERROR error)
{
PEXPR expr;
if (arg0 == NULL || arg1 == NULL)
{
return NULL;
}
expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (expr == NULL)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
return NULL;
}
expr->kind = kind;
expr->arg[0] = arg0;
expr->arg[1] = arg1;
return expr;
}
/*
* Construct an if-then-else.
*/
static PEXPR WinDivertMakeIfThenElse(HANDLE pool, PEXPR cond, PEXPR th,
PEXPR el, PERROR error)
{
PEXPR expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (expr == NULL)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
return NULL;
}
expr->kind = TOKEN_QUESTION;
expr->arg[0] = cond;
expr->arg[1] = th;
expr->arg[2] = el;
return expr;
}
/*
* Parse a filter test.
*/
static PEXPR WinDivertParseTest(HANDLE pool, TOKEN *toks, UINT *i, PERROR error)
{
PEXPR var, val;
KIND kind;
BOOL not = FALSE, neg;
UINT idx, size;
while (toks[*i].kind == TOKEN_NOT)
{
not = !not;
*i = *i + 1;
}
switch (toks[*i].kind)
{
case TOKEN_ZERO:
case TOKEN_EVENT:
case TOKEN_RANDOM8:
case TOKEN_RANDOM16:
case TOKEN_RANDOM32:
case TOKEN_TRUE:
case TOKEN_FALSE:
case TOKEN_OUTBOUND:
case TOKEN_INBOUND:
case TOKEN_IF_IDX:
case TOKEN_SUB_IF_IDX:
case TOKEN_LOOPBACK:
case TOKEN_IMPOSTOR:
case TOKEN_IP:
case TOKEN_IPV6:
case TOKEN_ICMP:
case TOKEN_ICMPV6:
case TOKEN_TCP:
case TOKEN_UDP:
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_IP_HDR_LENGTH:
case TOKEN_IP_TOS:
case TOKEN_IP_LENGTH:
case TOKEN_IP_ID:
case TOKEN_IP_DF:
case TOKEN_IP_MF:
case TOKEN_IP_FRAG_OFF:
case TOKEN_IP_TTL:
case TOKEN_IP_PROTOCOL:
case TOKEN_IP_CHECKSUM:
case TOKEN_IP_SRC_ADDR:
case TOKEN_IP_DST_ADDR:
case TOKEN_IPV6_TRAFFIC_CLASS:
case TOKEN_IPV6_FLOW_LABEL:
case TOKEN_IPV6_LENGTH:
case TOKEN_IPV6_NEXT_HDR:
case TOKEN_IPV6_HOP_LIMIT:
case TOKEN_IPV6_SRC_ADDR:
case TOKEN_IPV6_DST_ADDR:
case TOKEN_ICMP_TYPE:
case TOKEN_ICMP_CODE:
case TOKEN_ICMP_CHECKSUM:
case TOKEN_ICMP_BODY:
case TOKEN_ICMPV6_TYPE:
case TOKEN_ICMPV6_CODE:
case TOKEN_ICMPV6_CHECKSUM:
case TOKEN_ICMPV6_BODY:
case TOKEN_TCP_SRC_PORT:
case TOKEN_TCP_DST_PORT:
case TOKEN_TCP_SEQ_NUM:
case TOKEN_TCP_ACK_NUM:
case TOKEN_TCP_HDR_LENGTH:
case TOKEN_TCP_URG:
case TOKEN_TCP_ACK:
case TOKEN_TCP_PSH:
case TOKEN_TCP_RST:
case TOKEN_TCP_SYN:
case TOKEN_TCP_FIN:
case TOKEN_TCP_WINDOW:
case TOKEN_TCP_CHECKSUM:
case TOKEN_TCP_URG_PTR:
case TOKEN_TCP_PAYLOAD_LENGTH:
case TOKEN_UDP_SRC_PORT:
case TOKEN_UDP_DST_PORT:
case TOKEN_UDP_LENGTH:
case TOKEN_UDP_CHECKSUM:
case TOKEN_UDP_PAYLOAD_LENGTH:
var = WinDivertMakeVar(toks[*i].kind, error);
*i = *i + 1;
break;
case TOKEN_PACKET:
case TOKEN_TCP_PAYLOAD:
case TOKEN_UDP_PAYLOAD:
size = sizeof(UINT8);
goto array;
case TOKEN_PACKET16:
case TOKEN_TCP_PAYLOAD16:
case TOKEN_UDP_PAYLOAD16:
size = sizeof(UINT16);
goto array;
case TOKEN_PACKET32:
case TOKEN_TCP_PAYLOAD32:
case TOKEN_UDP_PAYLOAD32:
size = sizeof(UINT32);
array:
kind = toks[*i].kind;
*i = *i + 1;
if (toks[*i].kind != TOKEN_SQUARE_OPEN)
{
goto unexpected_token;
}
*i = *i + 1;
neg = FALSE;
if (toks[*i].kind == TOKEN_MINUS)
{
neg = TRUE;
*i = *i + 1;
}
if (toks[*i].kind != TOKEN_NUMBER)
{
goto unexpected_token;
}
if (toks[*i].val[3] != 0 || toks[*i].val[2] != 0 ||
toks[*i].val[1] != 0 || toks[*i].val[0] > UINT16_MAX)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_INDEX_OOB, toks[*i].pos);
return NULL;
}
idx = toks[*i].val[0];
*i = *i + 1;
if (toks[*i].kind == TOKEN_BYTES)
{
*i = *i + 1;
}
else
{
idx *= size;
}
if ((!neg && idx > UINT16_MAX - size) ||
(neg && idx > UINT16_MAX) || (neg && idx < size))
{
*error = MAKE_ERROR(WINDIVERT_ERROR_INDEX_OOB, toks[*i].pos);
return NULL;
}
var = WinDivertMakeArrayVar(pool, kind, (neg? -(INT)idx: (INT)idx),
error);
if (var == NULL)
{
return NULL;
}
if (toks[*i].kind != TOKEN_SQUARE_CLOSE)
{
goto unexpected_token;
}
*i = *i + 1;
break;
default:
unexpected_token:
*error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
}
switch (toks[*i].kind)
{
case TOKEN_EQ:
case TOKEN_NEQ:
case TOKEN_LT:
case TOKEN_LEQ:
case TOKEN_GT:
case TOKEN_GEQ:
kind = toks[*i].kind;
break;
default:
return WinDivertMakeBinOp(pool, (not? TOKEN_EQ: TOKEN_NEQ), var,
WinDivertMakeZero(), error);
}
if (not)
{
switch (kind)
{
case TOKEN_EQ:
kind = TOKEN_NEQ;
break;
case TOKEN_NEQ:
kind = TOKEN_EQ;
break;
case TOKEN_LT:
kind = TOKEN_GEQ;
break;
case TOKEN_LEQ:
kind = TOKEN_GT;
break;
case TOKEN_GT:
kind = TOKEN_LEQ;
break;
case TOKEN_GEQ:
kind = TOKEN_LT;
break;
default:
break;
}
}
*i = *i + 1;
if (toks[*i].kind != TOKEN_NUMBER)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
}
val = WinDivertMakeNumber(pool, toks[*i].val, error);
*i = *i + 1;
return WinDivertMakeBinOp(pool, kind, var, val, error);
}
/*
* Parse a filter argument to an (and) (or) operator.
*/
static PEXPR WinDivertParseArg(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
PERROR error)
{
PEXPR arg, th, el;
if (depth-- < 0)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_TOO_DEEP, toks[*i].pos);
return NULL;
}
switch (toks[*i].kind)
{
case TOKEN_OPEN:
*i = *i + 1;
arg = WinDivertParseFilter(pool, toks, i, depth, FALSE, error);
if (toks[*i].kind == TOKEN_CLOSE)
{
*i = *i + 1;
return arg;
}
if (toks[*i].kind == TOKEN_QUESTION)
{
*i = *i + 1;
th = WinDivertParseFilter(pool, toks, i, depth, FALSE, error);
if (th == NULL)
{
return NULL;
}
if (toks[*i].kind != TOKEN_COLON)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
toks[*i].pos);
return NULL;
}
*i = *i + 1;
el = WinDivertParseFilter(pool, toks, i, depth, FALSE, error);
if (el == NULL)
{
return NULL;
}
if (toks[*i].kind != TOKEN_CLOSE)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN,
toks[*i].pos);
return NULL;
}
*i = *i + 1;
arg = WinDivertMakeIfThenElse(pool, arg, th, el, error);
return arg;
}
*error = MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, toks[*i].pos);
return NULL;
default:
return WinDivertParseTest(pool, toks, i, error);
}
}
/*
* Parse the filter into an expression object.
*/
static PEXPR WinDivertParseFilter(HANDLE pool, TOKEN *toks, UINT *i, INT depth,
BOOL and, PERROR error)
{
PEXPR expr, arg;
if (depth-- < 0)
{
*error = MAKE_ERROR(WINDIVERT_ERROR_TOO_DEEP, toks[*i].pos);
return NULL;
}
if (and)
expr = WinDivertParseArg(pool, toks, i, depth, error);
else
expr = WinDivertParseFilter(pool, toks, i, depth, TRUE, error);
do
{
if (expr == NULL)
{
return NULL;
}
switch (toks[*i].kind)
{
case TOKEN_AND:
*i = *i + 1;
arg = WinDivertParseArg(pool, toks, i, depth, error);
expr = WinDivertMakeBinOp(pool, TOKEN_AND, expr, arg, error);
continue;
case TOKEN_OR:
*i = *i + 1;
arg = WinDivertParseFilter(pool, toks, i, depth, TRUE, error);
expr = WinDivertMakeBinOp(pool, TOKEN_OR, expr, arg, error);
continue;
default:
return expr;
}
}
while (TRUE);
}
/*
* Statically evaluate a test if possible.
*/
static BOOL WinDivertEvalTest(PEXPR test, BOOL *res)
{
PEXPR var = test->arg[0];
PEXPR val = test->arg[1];
UINT32 val32 = val->val[0];
BOOL big = (val->val[1] != 0 || val->val[2] != 0 || val->val[3] != 0);
UINT32 lb, ub;
switch (var->kind)
{
case TOKEN_ZERO:
lb = ub = 0;
break;
case TOKEN_TRUE:
lb = ub = 1;
break;
case TOKEN_FALSE:
lb = ub = 0;
break;
case TOKEN_LAYER:
lb = 0; ub = WINDIVERT_LAYER_MAX;
break;
case TOKEN_EVENT:
lb = 0; ub = WINDIVERT_EVENT_MAX;
break;
case TOKEN_INBOUND:
case TOKEN_OUTBOUND:
case TOKEN_IP:
case TOKEN_IPV6:
case TOKEN_ICMP:
case TOKEN_ICMPV6:
case TOKEN_TCP:
case TOKEN_UDP:
case TOKEN_IP_DF:
case TOKEN_IP_MF:
case TOKEN_TCP_URG:
case TOKEN_TCP_ACK:
case TOKEN_TCP_PSH:
case TOKEN_TCP_RST:
case TOKEN_TCP_SYN:
case TOKEN_TCP_FIN:
lb = 0; ub = 1;
break;
case TOKEN_IP_HDR_LENGTH:
case TOKEN_TCP_HDR_LENGTH:
lb = 0; ub = 0x0F;
break;
case TOKEN_IP_TTL:
case TOKEN_IP_PROTOCOL:
case TOKEN_IPV6_TRAFFIC_CLASS:
case TOKEN_IPV6_NEXT_HDR:
case TOKEN_IPV6_HOP_LIMIT:
case TOKEN_ICMP_TYPE:
case TOKEN_ICMP_CODE:
case TOKEN_ICMPV6_TYPE:
case TOKEN_ICMPV6_CODE:
case TOKEN_PROTOCOL:
case TOKEN_PACKET:
case TOKEN_TCP_PAYLOAD:
case TOKEN_UDP_PAYLOAD:
case TOKEN_RANDOM8:
lb = 0; ub = 0xFF;
break;
case TOKEN_IP_FRAG_OFF:
lb = 0; ub = 0x1FFF;
break;
case TOKEN_IP_TOS:
case TOKEN_IP_LENGTH:
case TOKEN_IP_ID:
case TOKEN_IP_CHECKSUM:
case TOKEN_IPV6_LENGTH:
case TOKEN_ICMP_CHECKSUM:
case TOKEN_ICMPV6_CHECKSUM:
case TOKEN_TCP_SRC_PORT:
case TOKEN_TCP_DST_PORT:
case TOKEN_TCP_WINDOW:
case TOKEN_TCP_CHECKSUM:
case TOKEN_TCP_URG_PTR:
case TOKEN_TCP_PAYLOAD_LENGTH:
case TOKEN_UDP_SRC_PORT:
case TOKEN_UDP_DST_PORT:
case TOKEN_UDP_LENGTH:
case TOKEN_UDP_CHECKSUM:
case TOKEN_UDP_PAYLOAD_LENGTH:
case TOKEN_LOCAL_PORT:
case TOKEN_REMOTE_PORT:
case TOKEN_PACKET16:
case TOKEN_TCP_PAYLOAD16:
case TOKEN_UDP_PAYLOAD16:
case TOKEN_RANDOM16:
lb = 0; ub = 0xFFFF;
break;
case TOKEN_IPV6_FLOW_LABEL:
lb = 0; ub = 0x000FFFFF;
break;
case TOKEN_IP_SRC_ADDR:
case TOKEN_IP_DST_ADDR:
case TOKEN_IPV6_SRC_ADDR:
case TOKEN_IPV6_DST_ADDR:
case TOKEN_LOCAL_ADDR:
case TOKEN_REMOTE_ADDR:
return FALSE;
default:
lb = 0; ub = 0xFFFFFFFF;
}
switch (test->kind)
{
case TOKEN_EQ:
if (big || val32 < lb || val32 > ub)
{
*res = FALSE;
return TRUE;
}
if (lb == ub && val32 == lb)
{
*res = TRUE;
return TRUE;
}
return FALSE;
case TOKEN_NEQ:
if (big || val32 < lb || val32 > ub)
{
*res = TRUE;
return TRUE;
}
if (lb == ub && val32 == lb)
{
*res = FALSE;
return TRUE;
}
return FALSE;
case TOKEN_LT:
if (big || val32 > ub)
{
*res = TRUE;
return TRUE;
}
if (val32 <= lb)
{
*res = FALSE;
return TRUE;
}
return FALSE;
case TOKEN_LEQ:
if (big || val32 >= ub)
{
*res = TRUE;
return TRUE;
}
if (val32 < lb)
{
*res = FALSE;
return TRUE;
}
return FALSE;
case TOKEN_GT:
if (big || val32 >= ub)
{
*res = FALSE;
return TRUE;
}
if (val32 < lb)
{
*res = TRUE;
return TRUE;
}
return FALSE;
case TOKEN_GEQ:
if (big || val32 > ub)
{
*res = FALSE;
return TRUE;
}
if (val32 <= lb)
{
*res = TRUE;
return TRUE;
}
return FALSE;
default:
return FALSE;
}
}
/*
* Flatten an expression into a sequence of tests and jumps.
*/
static INT16 WinDivertFlattenExpr(PEXPR expr, INT16 *label, INT16 succ,
INT16 fail, PEXPR *stack)
{
INT16 succ1, fail1;
BOOL res;
if (succ < 0 || fail < 0)
{
return -1;
}
switch (expr->kind)
{
case TOKEN_AND:
succ = WinDivertFlattenExpr(expr->arg[1], label, succ, fail, stack);
succ = WinDivertFlattenExpr(expr->arg[0], label, succ, fail, stack);
return succ;
case TOKEN_OR:
fail = WinDivertFlattenExpr(expr->arg[1], label, succ, fail, stack);
fail = WinDivertFlattenExpr(expr->arg[0], label, succ, fail, stack);
return fail;
case TOKEN_QUESTION:
fail1 = WinDivertFlattenExpr(expr->arg[2], label, succ, fail,
stack);
succ1 = WinDivertFlattenExpr(expr->arg[1], label, succ, fail,
stack);
succ = WinDivertFlattenExpr(expr->arg[0], label, succ1, fail1,
stack);
return succ;
default:
if (WinDivertEvalTest(expr, &res))
{
return (res? succ: fail);
}
if (*label >= WINDIVERT_FILTER_MAXLEN)
{
return -1;
}
stack[*label] = expr;
expr->succ = succ;
expr->fail = fail;
succ = *label;
*label = *label + 1;
return succ;
}
}
/*
* Emit a test.
*/
static void WinDivertEmitTest(PEXPR test, UINT16 offset,
PWINDIVERT_FILTER object)
{
BOOL big;
PEXPR var = test->arg[0], val = test->arg[1];
switch (test->kind)
{
case TOKEN_EQ:
object->test = WINDIVERT_FILTER_TEST_EQ;
break;
case TOKEN_NEQ:
object->test = WINDIVERT_FILTER_TEST_NEQ;
break;
case TOKEN_LT:
object->test = WINDIVERT_FILTER_TEST_LT;
break;
case TOKEN_LEQ:
object->test = WINDIVERT_FILTER_TEST_LEQ;
break;
case TOKEN_GT:
object->test = WINDIVERT_FILTER_TEST_GT;
break;
case TOKEN_GEQ:
object->test = WINDIVERT_FILTER_TEST_GEQ;
break;
default:
return;
}
big = FALSE;
object->arg[1] = object->arg[2] = object->arg[3] = 0;
switch (var->kind)
{
case TOKEN_ZERO:
object->field = WINDIVERT_FILTER_FIELD_ZERO;
break;
case TOKEN_EVENT:
object->field = WINDIVERT_FILTER_FIELD_EVENT;
break;
case TOKEN_RANDOM8:
object->field = WINDIVERT_FILTER_FIELD_RANDOM8;
break;
case TOKEN_RANDOM16:
object->field = WINDIVERT_FILTER_FIELD_RANDOM16;
break;
case TOKEN_RANDOM32:
object->field = WINDIVERT_FILTER_FIELD_RANDOM32;
break;
case TOKEN_PACKET:
object->field = WINDIVERT_FILTER_FIELD_PACKET;
object->arg[1] = var->val[0];
break;
case TOKEN_PACKET16:
object->field = WINDIVERT_FILTER_FIELD_PACKET16;
object->arg[1] = var->val[0];
break;
case TOKEN_PACKET32:
object->field = WINDIVERT_FILTER_FIELD_PACKET32;
object->arg[1] = var->val[0];
break;
case TOKEN_TCP_PAYLOAD:
object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD;
object->arg[1] = var->val[0];
break;
case TOKEN_TCP_PAYLOAD16:
object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16;
object->arg[1] = var->val[0];
break;
case TOKEN_TCP_PAYLOAD32:
object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32;
object->arg[1] = var->val[0];
break;
case TOKEN_UDP_PAYLOAD:
object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD;
object->arg[1] = var->val[0];
break;
case TOKEN_UDP_PAYLOAD16:
object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16;
object->arg[1] = var->val[0];
break;
case TOKEN_UDP_PAYLOAD32:
object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32;
object->arg[1] = var->val[0];
break;
case TOKEN_OUTBOUND:
object->field = WINDIVERT_FILTER_FIELD_OUTBOUND;
break;
case TOKEN_INBOUND:
object->field = WINDIVERT_FILTER_FIELD_INBOUND;
break;
case TOKEN_IF_IDX:
object->field = WINDIVERT_FILTER_FIELD_IFIDX;
break;
case TOKEN_SUB_IF_IDX:
object->field = WINDIVERT_FILTER_FIELD_SUBIFIDX;
break;
case TOKEN_LOOPBACK:
object->field = WINDIVERT_FILTER_FIELD_LOOPBACK;
break;
case TOKEN_IMPOSTOR:
object->field = WINDIVERT_FILTER_FIELD_IMPOSTOR;
break;
case TOKEN_PROCESS_ID:
object->field = WINDIVERT_FILTER_FIELD_PROCESSID;
break;
case TOKEN_LOCAL_ADDR:
object->field = WINDIVERT_FILTER_FIELD_LOCALADDR;
big = TRUE;
break;
case TOKEN_REMOTE_ADDR:
object->field = WINDIVERT_FILTER_FIELD_REMOTEADDR;
big = TRUE;
break;
case TOKEN_LOCAL_PORT:
object->field = WINDIVERT_FILTER_FIELD_LOCALPORT;
break;
case TOKEN_REMOTE_PORT:
object->field = WINDIVERT_FILTER_FIELD_REMOTEPORT;
break;
case TOKEN_PROTOCOL:
object->field = WINDIVERT_FILTER_FIELD_PROTOCOL;
break;
case TOKEN_LAYER:
object->field = WINDIVERT_FILTER_FIELD_LAYER;
break;
case TOKEN_IP:
object->field = WINDIVERT_FILTER_FIELD_IP;
break;
case TOKEN_IPV6:
object->field = WINDIVERT_FILTER_FIELD_IPV6;
break;
case TOKEN_ICMP:
object->field = WINDIVERT_FILTER_FIELD_ICMP;
break;
case TOKEN_ICMPV6:
object->field = WINDIVERT_FILTER_FIELD_ICMPV6;
break;
case TOKEN_TCP:
object->field = WINDIVERT_FILTER_FIELD_TCP;
break;
case TOKEN_UDP:
object->field = WINDIVERT_FILTER_FIELD_UDP;
break;
case TOKEN_IP_HDR_LENGTH:
object->field = WINDIVERT_FILTER_FIELD_IP_HDRLENGTH;
break;
case TOKEN_IP_TOS:
object->field = WINDIVERT_FILTER_FIELD_IP_TOS;
break;
case TOKEN_IP_LENGTH:
object->field = WINDIVERT_FILTER_FIELD_IP_LENGTH;
break;
case TOKEN_IP_ID:
object->field = WINDIVERT_FILTER_FIELD_IP_ID;
break;
case TOKEN_IP_DF:
object->field = WINDIVERT_FILTER_FIELD_IP_DF;
break;
case TOKEN_IP_MF:
object->field = WINDIVERT_FILTER_FIELD_IP_MF;
break;
case TOKEN_IP_FRAG_OFF:
object->field = WINDIVERT_FILTER_FIELD_IP_FRAGOFF;
break;
case TOKEN_IP_TTL:
object->field = WINDIVERT_FILTER_FIELD_IP_TTL;
break;
case TOKEN_IP_PROTOCOL:
object->field = WINDIVERT_FILTER_FIELD_IP_PROTOCOL;
break;
case TOKEN_IP_CHECKSUM:
object->field = WINDIVERT_FILTER_FIELD_IP_CHECKSUM;
break;
case TOKEN_IP_SRC_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IP_SRCADDR;
big = TRUE;
break;
case TOKEN_IP_DST_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IP_DSTADDR;
big = TRUE;
break;
case TOKEN_IPV6_TRAFFIC_CLASS:
object->field = WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS;
break;
case TOKEN_IPV6_FLOW_LABEL:
object->field = WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL;
break;
case TOKEN_IPV6_LENGTH:
object->field = WINDIVERT_FILTER_FIELD_IPV6_LENGTH;
break;
case TOKEN_IPV6_NEXT_HDR:
object->field = WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR;
break;
case TOKEN_IPV6_HOP_LIMIT:
object->field = WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT;
break;
case TOKEN_IPV6_SRC_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IPV6_SRCADDR;
big = TRUE;
break;
case TOKEN_IPV6_DST_ADDR:
object->field = WINDIVERT_FILTER_FIELD_IPV6_DSTADDR;
big = TRUE;
break;
case TOKEN_ICMP_TYPE:
object->field = WINDIVERT_FILTER_FIELD_ICMP_TYPE;
break;
case TOKEN_ICMP_CODE:
object->field = WINDIVERT_FILTER_FIELD_ICMP_CODE;
break;
case TOKEN_ICMP_CHECKSUM:
object->field = WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM;
break;
case TOKEN_ICMP_BODY:
object->field = WINDIVERT_FILTER_FIELD_ICMP_BODY;
break;
case TOKEN_ICMPV6_TYPE:
object->field = WINDIVERT_FILTER_FIELD_ICMPV6_TYPE;
break;
case TOKEN_ICMPV6_CODE:
object->field = WINDIVERT_FILTER_FIELD_ICMPV6_CODE;
break;
case TOKEN_ICMPV6_CHECKSUM:
object->field = WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM;
break;
case TOKEN_ICMPV6_BODY:
object->field = WINDIVERT_FILTER_FIELD_ICMPV6_BODY;
break;
case TOKEN_TCP_SRC_PORT:
object->field = WINDIVERT_FILTER_FIELD_TCP_SRCPORT;
break;
case TOKEN_TCP_DST_PORT:
object->field = WINDIVERT_FILTER_FIELD_TCP_DSTPORT;
break;
case TOKEN_TCP_SEQ_NUM:
object->field = WINDIVERT_FILTER_FIELD_TCP_SEQNUM;
break;
case TOKEN_TCP_ACK_NUM:
object->field = WINDIVERT_FILTER_FIELD_TCP_ACKNUM;
break;
case TOKEN_TCP_HDR_LENGTH:
object->field = WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH;
break;
case TOKEN_TCP_URG:
object->field = WINDIVERT_FILTER_FIELD_TCP_URG;
break;
case TOKEN_TCP_ACK:
object->field = WINDIVERT_FILTER_FIELD_TCP_ACK;
break;
case TOKEN_TCP_PSH:
object->field = WINDIVERT_FILTER_FIELD_TCP_PSH;
break;
case TOKEN_TCP_RST:
object->field = WINDIVERT_FILTER_FIELD_TCP_RST;
break;
case TOKEN_TCP_SYN:
object->field = WINDIVERT_FILTER_FIELD_TCP_SYN;
break;
case TOKEN_TCP_FIN:
object->field = WINDIVERT_FILTER_FIELD_TCP_FIN;
break;
case TOKEN_TCP_WINDOW:
object->field = WINDIVERT_FILTER_FIELD_TCP_WINDOW;
break;
case TOKEN_TCP_CHECKSUM:
object->field = WINDIVERT_FILTER_FIELD_TCP_CHECKSUM;
break;
case TOKEN_TCP_URG_PTR:
object->field = WINDIVERT_FILTER_FIELD_TCP_URGPTR;
break;
case TOKEN_TCP_PAYLOAD_LENGTH:
object->field = WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH;
break;
case TOKEN_UDP_SRC_PORT:
object->field = WINDIVERT_FILTER_FIELD_UDP_SRCPORT;
break;
case TOKEN_UDP_DST_PORT:
object->field = WINDIVERT_FILTER_FIELD_UDP_DSTPORT;
break;
case TOKEN_UDP_LENGTH:
object->field = WINDIVERT_FILTER_FIELD_UDP_LENGTH;
break;
case TOKEN_UDP_CHECKSUM:
object->field = WINDIVERT_FILTER_FIELD_UDP_CHECKSUM;
break;
case TOKEN_UDP_PAYLOAD_LENGTH:
object->field = WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH;
break;
default:
return;
}
object->arg[0] = val->val[0];
if (big)
{
object->arg[1] = val->val[1];
object->arg[2] = val->val[2];
object->arg[3] = val->val[3];
}
switch (test->succ)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
object->success = test->succ;
break;
default:
object->success = offset - test->succ;
break;
}
switch (test->fail)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
object->failure = test->fail;
break;
default:
object->failure = offset - test->fail;
break;
}
return;
}
/*
* Emit a filter object.
*/
static void WinDivertEmitFilter(PEXPR *stack, UINT len, UINT16 label,
PWINDIVERT_FILTER object, UINT *obj_len)
{
UINT i;
switch (label)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
object[0].field = WINDIVERT_FILTER_FIELD_ZERO;
object[0].test = WINDIVERT_FILTER_TEST_EQ;
object[0].arg[0] = object[0].arg[1] = object[0].arg[2] =
object[0].arg[3] = 0;
object[0].success = label;
object[0].failure = label;
*obj_len = 1;
return;
default:
break;
}
*obj_len = len + 1;
for (i = 0; i <= len; i++)
{
WinDivertEmitTest(stack[len - i], label, object + i);
}
}
/*
* Analyze a filter object.
*/
static UINT64 WinDivertAnalyzeFilter(WINDIVERT_LAYER layer,
PWINDIVERT_FILTER filter, UINT length)
{
BOOL result;
UINT64 flags = 0;
// False filter?
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_ZERO, 0);
if (!result)
{
return 0;
}
if (layer == WINDIVERT_LAYER_NETWORK ||
layer == WINDIVERT_LAYER_NETWORK_FORWARD)
{
// Inbound?
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_INBOUND, 1);
if (result)
{
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_OUTBOUND, 0);
}
flags |= (result? WINDIVERT_FILTER_FLAG_INBOUND: 0);
// Outbound?
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_OUTBOUND, 1);
if (result)
{
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_INBOUND, 0);
}
flags |= (result? WINDIVERT_FILTER_FLAG_OUTBOUND: 0);
}
if (layer != WINDIVERT_LAYER_REFLECT)
{
// IPv4?
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_IP, 1);
if (result)
{
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_IPV6, 0);
}
flags |= (result? WINDIVERT_FILTER_FLAG_IP: 0);
// Ipv6?
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_IPV6, 1);
if (result)
{
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_IP, 0);
}
flags |= (result? WINDIVERT_FILTER_FLAG_IPV6: 0);
}
// Events:
switch (layer)
{
case WINDIVERT_LAYER_FLOW:
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_FLOW_DELETED);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_FLOW_DELETED: 0);
break;
case WINDIVERT_LAYER_SOCKET:
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_BIND);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_BIND: 0);
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_CONNECT);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_CONNECT: 0);
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_LISTEN);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_LISTEN: 0);
result = WinDivertCondExecFilter(filter, length,
WINDIVERT_FILTER_FIELD_EVENT, WINDIVERT_EVENT_SOCKET_ACCEPT);
flags |= (result? WINDIVERT_FILTER_FLAG_EVENT_SOCKET_ACCEPT: 0);
break;
default:
break;
}
return flags;
}
/*
* Execute a filter object with respect to an assumption/condition.
* FALSE = definite reject; TRUE = maybe accept.
*/
static BOOL WinDivertCondExecFilter(PWINDIVERT_FILTER filter, UINT length,
UINT8 field, UINT32 arg)
{
INT16 ip;
UINT8 succ, fail;
BOOL result[WINDIVERT_FILTER_MAXLEN];
BOOL result_succ, result_fail, result_test;
if (length == 0)
{
return TRUE;
}
for (ip = (INT16)(length-1); ip >= 0; ip--)
{
succ = filter[ip].success;
if (succ == WINDIVERT_FILTER_RESULT_ACCEPT || succ <= ip ||
succ >= length)
{
result_succ = TRUE;
}
else if (succ == WINDIVERT_FILTER_RESULT_REJECT)
{
result_succ = FALSE;
}
else
{
result_succ = result[succ];
}
fail = filter[ip].failure;
if (fail == WINDIVERT_FILTER_RESULT_ACCEPT || fail <= ip ||
fail >= length)
{
result_fail = TRUE;
}
else if (fail == WINDIVERT_FILTER_RESULT_REJECT)
{
result_fail = FALSE;
}
else
{
result_fail = result[fail];
}
if (result_succ && result_fail)
{
result[ip] = TRUE;
}
else if (!result_succ && !result_fail)
{
result[ip] = FALSE;
}
else if (filter[ip].field == field)
{
switch (filter[ip].test)
{
case WINDIVERT_FILTER_TEST_EQ:
result_test = (arg == filter[ip].arg[0]);
break;
case WINDIVERT_FILTER_TEST_NEQ:
result_test = (arg != filter[ip].arg[0]);
break;
case WINDIVERT_FILTER_TEST_LT:
result_test = (arg < filter[ip].arg[0]);
break;
case WINDIVERT_FILTER_TEST_LEQ:
result_test = (arg <= filter[ip].arg[0]);
break;
case WINDIVERT_FILTER_TEST_GT:
result_test = (arg > filter[ip].arg[0]);
break;
case WINDIVERT_FILTER_TEST_GEQ:
result_test = (arg >= filter[ip].arg[0]);
break;
default:
return TRUE; // abort.
}
result[ip] = (result_test? result_succ: result_fail);
}
else
{
result[ip] = TRUE;
}
}
return result[0];
}
/*
* Compile a filter string into an executable filter object.
*/
static ERROR WinDivertCompileFilter(const char *filter,
WINDIVERT_LAYER layer, PWINDIVERT_FILTER object, UINT *obj_len)
{
TOKEN *tokens;
PEXPR *stack;
HANDLE pool;
PEXPR expr;
UINT i, max_depth;
INT16 label;
const SIZE_T min_pool_size = 8192;
const SIZE_T tokens_size = 5 * WINDIVERT_FILTER_MAXLEN;
ERROR error;
// Check for pre-compiled filter object:
if (filter[0] == '@')
{
WINDIVERT_STREAM stream;
stream.data = (char *)filter;
stream.pos = 0;
stream.max = UINT_MAX;
stream.overflow = FALSE;
if (!WinDivertDeserializeFilter(&stream, object, obj_len))
{
return MAKE_ERROR(WINDIVERT_ERROR_BAD_OBJECT, 0);
}
return MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
}
// Allocate memory for the compiler:
pool = HeapCreate(HEAP_NO_SERIALIZE, min_pool_size, 16 * min_pool_size);
if (pool == NULL)
{
return MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
}
tokens = (TOKEN *)HeapAlloc(pool, 0, tokens_size * sizeof(TOKEN));
stack = (PEXPR *)HeapAlloc(pool, 0,
WINDIVERT_FILTER_MAXLEN * sizeof(PEXPR));
if (tokens == NULL || stack == NULL)
{
HeapDestroy(pool);
return MAKE_ERROR(WINDIVERT_ERROR_NO_MEMORY, 0);
}
// Tokenize the filter string:
error = WinDivertTokenizeFilter(filter, layer, tokens, tokens_size-1);
if (IS_ERROR(error))
{
HeapDestroy(pool);
return error;
}
// Parse the filter into an expression:
i = 0;
max_depth = 1024;
expr = WinDivertParseFilter(pool, tokens, &i, max_depth, FALSE, &error);
if (expr == NULL)
{
HeapDestroy(pool);
return error;
}
if (tokens[i].kind != TOKEN_END)
{
HeapDestroy(pool);
return MAKE_ERROR(WINDIVERT_ERROR_UNEXPECTED_TOKEN, tokens[i].pos);
}
// Construct the filter tree:
label = 0;
label = WinDivertFlattenExpr(expr, &label, WINDIVERT_FILTER_RESULT_ACCEPT,
WINDIVERT_FILTER_RESULT_REJECT, stack);
if (label < 0)
{
HeapDestroy(pool);
return MAKE_ERROR(WINDIVERT_ERROR_TOO_LONG, 0);
}
// Emit the final object.
if (object != NULL)
{
WinDivertEmitFilter(stack, label, label, object, obj_len);
}
HeapDestroy(pool);
return MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
}
/*
* Convert a error code into a user readable string.
*/
static const char *WinDivertErrorString(UINT code)
{
switch (code)
{
case WINDIVERT_ERROR_NONE:
return "No error";
case WINDIVERT_ERROR_NO_MEMORY:
return "Out of memory";
case WINDIVERT_ERROR_TOO_DEEP:
return "Filter expression too deep";
case WINDIVERT_ERROR_TOO_LONG:
return "Filter expression too long";
case WINDIVERT_ERROR_BAD_TOKEN:
return "Filter expression contains a bad token";
case WINDIVERT_ERROR_BAD_TOKEN_FOR_LAYER:
return "Filter expression contains a bad token for layer";
case WINDIVERT_ERROR_UNEXPECTED_TOKEN:
return "Filter expression parse error";
case WINDIVERT_ERROR_INDEX_OOB:
return "Filter expression array index is out-of-bounds";
case WINDIVERT_ERROR_OUTPUT_TOO_SHORT:
return "Filter object buffer is too short";
case WINDIVERT_ERROR_BAD_OBJECT:
return "Filter object is invalid";
case WINDIVERT_ERROR_ASSERTION_FAILED:
return "Internal assertion failed";
default:
return "Unknown error";
}
}
/*
* Compile the given filter string.
*/
extern BOOL WinDivertHelperCompileFilter(const char *filter_str,
WINDIVERT_LAYER layer, char *object, UINT obj_len, const char **error,
UINT *error_pos)
{
ERROR err;
if (filter_str == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
SetLastError(ERROR_SUCCESS);
if (object == NULL)
{
err = WinDivertCompileFilter(filter_str, layer, NULL, NULL);
}
else
{
WINDIVERT_FILTER object0[WINDIVERT_FILTER_MAXLEN];
UINT obj0_len;
err = WinDivertCompileFilter(filter_str, layer, object0, &obj0_len);
if (!IS_ERROR(err))
{
WINDIVERT_STREAM stream;
stream.data = object;
stream.pos = 0;
stream.max = obj_len;
stream.overflow = FALSE;
WinDivertSerializeFilter(&stream, object0, obj0_len);
if (stream.overflow)
{
SetLastError(ERROR_INSUFFICIENT_BUFFER);
err = MAKE_ERROR(WINDIVERT_ERROR_OUTPUT_TOO_SHORT, 0);
}
}
}
if (error != NULL)
{
*error = WinDivertErrorString(GET_CODE(err));
}
if (error_pos != NULL)
{
*error_pos = GET_POS(err);
}
return !IS_ERROR(err);
}
/*
* Big number comparison.
*/
static int WinDivertBigNumCompare(const UINT32 *a, const UINT32 *b, BOOL big)
{
if (big)
{
if (a[3] < b[3])
{
return -1;
}
if (a[3] > b[3])
{
return 1;
}
if (a[2] < b[2])
{
return -1;
}
if (a[2] > b[2])
{
return 1;
}
if (a[1] < b[1])
{
return -1;
}
if (a[1] > b[1])
{
return 1;
}
}
if (a[0] < b[0])
{
return -1;
}
if (a[0] > b[0])
{
return 1;
}
return 0;
}
/*
* Get packet/payload data.
*/
static BOOL WinDivertGetData(const VOID *packet, UINT packet_len, UINT offset,
INT idx, UINT size, PVOID data)
{
if (idx < 0)
{
idx += (INT)packet_len;
}
else
{
idx += (INT)offset;
}
if (idx < (INT)offset || idx > (INT)(packet_len - size))
{
return FALSE;
}
memcpy(data, (UINT8 *)packet + idx, size);
return TRUE;
}
/*
* Evaluate the given filter with the given packet as input.
*/
extern BOOL WinDivertHelperEvalFilter(const char *filter, const VOID *packet,
UINT packet_len, const WINDIVERT_ADDRESS *addr)
{
UINT16 pc;
ERROR err;
PWINDIVERT_IPHDR iphdr = NULL;
PWINDIVERT_IPV6HDR ipv6hdr = NULL;
PWINDIVERT_ICMPHDR icmphdr = NULL;
PWINDIVERT_ICMPV6HDR icmpv6hdr = NULL;
PWINDIVERT_TCPHDR tcphdr = NULL;
PWINDIVERT_UDPHDR udphdr = NULL;
UINT8 protocol = 0;
UINT header_len = 0, payload_len = 0;
UINT64 random64 = 0;
UINT32 val[4];
UINT8 data8;
UINT16 data16;
UINT32 data32;
BOOL pass, big;
int cmp;
WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
if (filter == NULL || addr == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
switch (addr->Layer)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
if (packet == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
WinDivertParsePacket((PVOID)packet, packet_len, &iphdr, &ipv6hdr,
&icmphdr, &icmpv6hdr, &tcphdr, &udphdr, &protocol, NULL,
&payload_len);
header_len = packet_len - payload_len;
if ((addr->IPv6 && ipv6hdr == NULL) ||
(!addr->IPv6 && iphdr == NULL))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
break;
case WINDIVERT_LAYER_FLOW:
case WINDIVERT_LAYER_SOCKET:
if (packet != NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
break;
case WINDIVERT_LAYER_REFLECT:
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
err = WinDivertCompileFilter(filter, addr->Layer, object, &obj_len);
if (IS_ERROR(err))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pc = 0;
while (TRUE)
{
switch (pc)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
return TRUE;
case WINDIVERT_FILTER_RESULT_REJECT:
return FALSE;
default:
if (pc >= obj_len)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
break;
}
pass = TRUE;
big = FALSE;
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_RANDOM8:
case WINDIVERT_FILTER_FIELD_RANDOM16:
case WINDIVERT_FILTER_FIELD_RANDOM32:
pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
if (pass && random64 == 0)
{
random64 = WinDivertHashPacket((UINT64)addr->Timestamp,
iphdr, ipv6hdr, icmphdr, icmpv6hdr, tcphdr, udphdr);
random64 |= 0xFF00000000000000ull;
}
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
case WINDIVERT_FILTER_FIELD_PACKET:
case WINDIVERT_FILTER_FIELD_PACKET16:
case WINDIVERT_FILTER_FIELD_PACKET32:
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:
case WINDIVERT_FILTER_FIELD_IP_ID:
case WINDIVERT_FILTER_FIELD_IP_DF:
case WINDIVERT_FILTER_FIELD_IP_MF:
case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
case WINDIVERT_FILTER_FIELD_IP_TTL:
case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
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:
case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
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 = (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 = (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:
case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
case WINDIVERT_FILTER_FIELD_TCP_URG:
case WINDIVERT_FILTER_FIELD_TCP_ACK:
case WINDIVERT_FILTER_FIELD_TCP_PSH:
case WINDIVERT_FILTER_FIELD_TCP_RST:
case WINDIVERT_FILTER_FIELD_TCP_SYN:
case WINDIVERT_FILTER_FIELD_TCP_FIN:
case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
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_PAYLOAD:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
pass = (addr->Layer == WINDIVERT_LAYER_NETWORK ||
addr->Layer == WINDIVERT_LAYER_NETWORK_FORWARD);
pass = pass && (udphdr != NULL);
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!pass)
{
pc = object[pc].failure;
continue;
}
switch (object[pc].field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
val[0] = 0;
break;
case WINDIVERT_FILTER_FIELD_EVENT:
val[0] = addr->Event;
break;
case WINDIVERT_FILTER_FIELD_RANDOM8:
val[0] = (UINT32)((random64 >> 48) & 0xFF);
break;
case WINDIVERT_FILTER_FIELD_RANDOM16:
val[0] = (UINT32)((random64 >> 32) & 0xFFFF);
break;
case WINDIVERT_FILTER_FIELD_RANDOM32:
val[0] = (UINT32)random64;
break;
case WINDIVERT_FILTER_FIELD_PACKET:
pass = WinDivertGetData(packet, packet_len, /*offset=*/0,
object[pc].arg[1], sizeof(data8), &data8);
val[0] = data8;
break;
case WINDIVERT_FILTER_FIELD_PACKET16:
pass = WinDivertGetData(packet, packet_len, /*offset=*/0,
object[pc].arg[1], sizeof(data16), &data16);
val[0] = ntohs(data16);
break;
case WINDIVERT_FILTER_FIELD_PACKET32:
pass = WinDivertGetData(packet, packet_len, /*offset=*/0,
object[pc].arg[1], sizeof(data32), &data32);
val[0] = ntohl(data32);
break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
pass = WinDivertGetData(packet, packet_len, header_len,
object[pc].arg[1], sizeof(data8), &data8);
val[0] = data8;
break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
pass = WinDivertGetData(packet, packet_len, header_len,
object[pc].arg[1], sizeof(data16), &data16);
val[0] = ntohs(data16);
break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
pass = WinDivertGetData(packet, packet_len, header_len,
object[pc].arg[1], sizeof(data32), &data32);
val[0] = ntohl(data32);
break;
case WINDIVERT_FILTER_FIELD_INBOUND:
val[0] = !addr->Outbound;
break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
val[0] = addr->Outbound;
break;
case WINDIVERT_FILTER_FIELD_IFIDX:
val[0] = addr->Network.IfIdx;
break;
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
val[0] = addr->Network.SubIfIdx;
break;
case WINDIVERT_FILTER_FIELD_LOOPBACK:
val[0] = addr->Loopback;
break;
case WINDIVERT_FILTER_FIELD_IMPOSTOR:
val[0] = addr->Impostor;
break;
case WINDIVERT_FILTER_FIELD_IP:
val[0] = !addr->IPv6;
break;
case WINDIVERT_FILTER_FIELD_IPV6:
val[0] = addr->IPv6;
break;
case WINDIVERT_FILTER_FIELD_ICMP:
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:
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:
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:
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;
break;
case WINDIVERT_FILTER_FIELD_IP_TOS:
val[0] = iphdr->TOS;
break;
case WINDIVERT_FILTER_FIELD_IP_LENGTH:
val[0] = ntohs(iphdr->Length);
break;
case WINDIVERT_FILTER_FIELD_IP_ID:
val[0] = ntohs(iphdr->Id);
break;
case WINDIVERT_FILTER_FIELD_IP_DF:
val[0] = WINDIVERT_IPHDR_GET_DF(iphdr);
break;
case WINDIVERT_FILTER_FIELD_IP_MF:
val[0] = WINDIVERT_IPHDR_GET_MF(iphdr);
break;
case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
val[0] = ntohs(WINDIVERT_IPHDR_GET_FRAGOFF(iphdr));
break;
case WINDIVERT_FILTER_FIELD_IP_TTL:
val[0] = iphdr->TTL;
break;
case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
val[0] = iphdr->Protocol;
break;
case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
val[0] = ntohs(iphdr->Checksum);
break;
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
val[1] = 0x0000FFFF;
val[0] = ntohl(iphdr->SrcAddr);
break;
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
val[1] = 0x0000FFFF;
val[0] = ntohl(iphdr->DstAddr);
break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
val[0] = WINDIVERT_IPV6HDR_GET_TRAFFICCLASS(ipv6hdr);
break;
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
val[0] = ntohl(WINDIVERT_IPV6HDR_GET_FLOWLABEL(ipv6hdr));
break;
case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
val[0] = ntohs(ipv6hdr->Length);
break;
case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
val[0] = ipv6hdr->NextHdr;
break;
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
val[0] = ipv6hdr->HopLimit;
break;
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
big = TRUE;
val[3] = ntohl(ipv6hdr->SrcAddr[0]);
val[2] = ntohl(ipv6hdr->SrcAddr[1]);
val[1] = ntohl(ipv6hdr->SrcAddr[2]);
val[0] = ntohl(ipv6hdr->SrcAddr[3]);
break;
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
big = TRUE;
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_FILTER_FIELD_ICMP_TYPE:
val[0] = icmphdr->Type;
break;
case WINDIVERT_FILTER_FIELD_ICMP_CODE:
val[0] = icmphdr->Code;
break;
case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
val[0] = ntohs(icmphdr->Checksum);
break;
case WINDIVERT_FILTER_FIELD_ICMP_BODY:
val[0] = ntohl(icmphdr->Body);
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
val[0] = icmpv6hdr->Type;
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
val[0] = icmpv6hdr->Code;
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
val[0] = ntohs(icmpv6hdr->Checksum);
break;
case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
val[0] = ntohl(icmpv6hdr->Body);
break;
case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
val[0] = ntohs(tcphdr->SrcPort);
break;
case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
val[0] = ntohs(tcphdr->DstPort);
break;
case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
val[0] = ntohl(tcphdr->SeqNum);
break;
case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
val[0] = ntohl(tcphdr->AckNum);
break;
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
val[0] = tcphdr->HdrLength;
break;
case WINDIVERT_FILTER_FIELD_TCP_URG:
val[0] = tcphdr->Urg;
break;
case WINDIVERT_FILTER_FIELD_TCP_ACK:
val[0] = tcphdr->Ack;
break;
case WINDIVERT_FILTER_FIELD_TCP_PSH:
val[0] = tcphdr->Psh;
break;
case WINDIVERT_FILTER_FIELD_TCP_RST:
val[0] = tcphdr->Rst;
break;
case WINDIVERT_FILTER_FIELD_TCP_SYN:
val[0] = tcphdr->Syn;
break;
case WINDIVERT_FILTER_FIELD_TCP_FIN:
val[0] = tcphdr->Fin;
break;
case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
val[0] = ntohs(tcphdr->Window);
break;
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
val[0] = ntohs(tcphdr->Checksum);
break;
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
val[0] = ntohs(tcphdr->UrgPtr);
break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
val[0] = payload_len;
break;
case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
val[0] = ntohs(udphdr->SrcPort);
break;
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
val[0] = ntohs(udphdr->DstPort);
break;
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
val[0] = ntohs(udphdr->Length);
break;
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
val[0] = ntohs(udphdr->Checksum);
break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
val[0] = payload_len;
break;
case WINDIVERT_FILTER_FIELD_LOCALADDR:
big = TRUE;
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:
big = TRUE;
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:
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:
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:
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);
return FALSE;
}
if (!pass)
{
pc = object[pc].failure;
continue;
}
cmp = WinDivertBigNumCompare(val, object[pc].arg, big);
switch (object[pc].test)
{
case WINDIVERT_FILTER_TEST_EQ:
pass = (cmp == 0);
break;
case WINDIVERT_FILTER_TEST_NEQ:
pass = (cmp != 0);
break;
case WINDIVERT_FILTER_TEST_LT:
pass = (cmp < 0);
break;
case WINDIVERT_FILTER_TEST_LEQ:
pass = (cmp <= 0);
break;
case WINDIVERT_FILTER_TEST_GT:
pass = (cmp > 0);
break;
case WINDIVERT_FILTER_TEST_GEQ:
pass = (cmp >= 0);
break;
default:
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pc = (pass? object[pc].success: object[pc].failure);
}
}
/*
* Get a char from a stream.
*/
static char WinDivertGetChar(PWINDIVERT_STREAM stream)
{
char c;
if (stream->pos >= stream->max)
{
stream->overflow = TRUE;
return EOF;
}
c = stream->data[stream->pos];
stream->pos++;
return c;
}
/*
* Deserialize a number.
*/
static BOOL WinDivertDeserializeNumber(PWINDIVERT_STREAM stream, UINT max_len,
UINT32 *result)
{
UINT32 i, val = 0;
char c;
for (i = 0; i < max_len; i++)
{
if ((val & 0xF8000000) != 0)
{
return FALSE; // Overflow
}
val <<= 5;
c = WinDivertGetChar(stream);
if (c >= '!' && c <= '!' + 31)
{
val += (UINT32)(c - '!');
}
else if (c >= '!' + 32 && c <= '!' + 64)
{
val += (UINT32)(c - '!' - 32);
*result = val;
return TRUE;
}
else
{
return FALSE;
}
}
return FALSE;
}
/*
* Deserialize a test.
*/
static BOOL WinDivertDeserializeTest(PWINDIVERT_STREAM stream,
PWINDIVERT_FILTER filter)
{
UINT32 val;
UINT i;
if (WinDivertGetChar(stream) != '_')
{
return FALSE;
}
if (!WinDivertDeserializeNumber(stream, 2, &val) ||
val > WINDIVERT_FILTER_FIELD_MAX)
{
return FALSE;
}
filter->field = (UINT8)val;
if (!WinDivertDeserializeNumber(stream, 2, &val) ||
val > WINDIVERT_FILTER_TEST_MAX)
{
return FALSE;
}
filter->test = (UINT8)val;
if (!WinDivertDeserializeNumber(stream, 7, &filter->arg[0]))
{
return FALSE;
}
switch (filter->field)
{
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
case WINDIVERT_FILTER_FIELD_LOCALADDR:
case WINDIVERT_FILTER_FIELD_REMOTEADDR:
for (i = 1; i < 4; i++)
{
if (!WinDivertDeserializeNumber(stream, 7, &filter->arg[i]))
{
return FALSE;
}
}
break;
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
filter->arg[1] = 0x0000FFFF;
filter->arg[2] = filter->arg[3] = 0;
break;
case WINDIVERT_FILTER_FIELD_PACKET:
case WINDIVERT_FILTER_FIELD_PACKET16:
case WINDIVERT_FILTER_FIELD_PACKET32:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
if (!WinDivertDeserializeNumber(stream, 7, &val))
{
return FALSE;
}
filter->arg[1] = (UINT32)((INT)val - UINT16_MAX);
filter->arg[2] = filter->arg[3] = 0;
break;
default:
filter->arg[1] = filter->arg[2] = filter->arg[3] = 0;
break;
}
if (!WinDivertDeserializeNumber(stream, 2, &val) || val > UINT8_MAX)
{
return FALSE;
}
filter->success = (UINT8)val - 2;
if (!WinDivertDeserializeNumber(stream, 2, &val) || val > UINT8_MAX)
{
return FALSE;
}
filter->failure = (UINT8)val - 2;
return TRUE;
}
/*
* Deserialize a filter header.
*/
static BOOL WinDivertDeserializeFilterHeader(PWINDIVERT_STREAM stream,
UINT *length)
{
UINT32 version, length32;
if (WinDivertGetChar(stream) != '@' ||
WinDivertGetChar(stream) != 'W' ||
WinDivertGetChar(stream) != 'i' ||
WinDivertGetChar(stream) != 'n' ||
WinDivertGetChar(stream) != 'D' ||
WinDivertGetChar(stream) != 'i' ||
WinDivertGetChar(stream) != 'v' ||
WinDivertGetChar(stream) != '_')
{
return FALSE;
}
if (!WinDivertDeserializeNumber(stream, 4, &version) || (version != 0))
{
return FALSE;
}
if (!WinDivertDeserializeNumber(stream, 2, &length32) ||
length32 == 0 || length32 > WINDIVERT_FILTER_MAXLEN)
{
return FALSE;
}
*length = length32;
return TRUE;
}
/*
* Deserialize a filter.
*/
static BOOL WinDivertDeserializeFilter(PWINDIVERT_STREAM stream,
PWINDIVERT_FILTER filter, UINT *length)
{
UINT i;
if (!WinDivertDeserializeFilterHeader(stream, length))
{
return FALSE;
}
for (i = 0; i < *length; i++)
{
if (!WinDivertDeserializeTest(stream, filter + i))
{
return FALSE;
}
}
if (WinDivertGetChar(stream) != '\0')
{
return FALSE;
}
return TRUE;
}
/*
* Decompile a test into an expression.
*/
static PEXPR WinDivertDecompileTest(HANDLE pool, PWINDIVERT_FILTER test)
{
KIND kind;
PEXPR var, val, expr;
UINT32 tmp[4];
ERROR error;
switch (test->field)
{
case WINDIVERT_FILTER_FIELD_ZERO:
kind = TOKEN_ZERO; break;
case WINDIVERT_FILTER_FIELD_EVENT:
kind = TOKEN_EVENT; break;
case WINDIVERT_FILTER_FIELD_RANDOM8:
kind = TOKEN_RANDOM8; break;
case WINDIVERT_FILTER_FIELD_RANDOM16:
kind = TOKEN_RANDOM16; break;
case WINDIVERT_FILTER_FIELD_RANDOM32:
kind = TOKEN_RANDOM32; break;
case WINDIVERT_FILTER_FIELD_PACKET:
kind = TOKEN_PACKET; break;
case WINDIVERT_FILTER_FIELD_PACKET16:
kind = TOKEN_PACKET16; break;
case WINDIVERT_FILTER_FIELD_PACKET32:
kind = TOKEN_PACKET32; break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD:
kind = TOKEN_TCP_PAYLOAD; break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD16:
kind = TOKEN_TCP_PAYLOAD16; break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOAD32:
kind = TOKEN_TCP_PAYLOAD32; break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD:
kind = TOKEN_UDP_PAYLOAD; break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD16:
kind = TOKEN_UDP_PAYLOAD16; break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOAD32:
kind = TOKEN_UDP_PAYLOAD32; break;
case WINDIVERT_FILTER_FIELD_INBOUND:
kind = TOKEN_INBOUND; break;
case WINDIVERT_FILTER_FIELD_OUTBOUND:
kind = TOKEN_OUTBOUND; break;
case WINDIVERT_FILTER_FIELD_IFIDX:
kind = TOKEN_IF_IDX; break;
case WINDIVERT_FILTER_FIELD_SUBIFIDX:
kind = TOKEN_SUB_IF_IDX; break;
case WINDIVERT_FILTER_FIELD_IP:
kind = TOKEN_IP; break;
case WINDIVERT_FILTER_FIELD_IPV6:
kind = TOKEN_IPV6; break;
case WINDIVERT_FILTER_FIELD_ICMP:
kind = TOKEN_ICMP; break;
case WINDIVERT_FILTER_FIELD_TCP:
kind = TOKEN_TCP; break;
case WINDIVERT_FILTER_FIELD_UDP:
kind = TOKEN_UDP; break;
case WINDIVERT_FILTER_FIELD_ICMPV6:
kind = TOKEN_ICMPV6; break;
case WINDIVERT_FILTER_FIELD_IP_HDRLENGTH:
kind = TOKEN_IP_HDR_LENGTH; break;
case WINDIVERT_FILTER_FIELD_IP_TOS:
kind = TOKEN_IP_TOS; break;
case WINDIVERT_FILTER_FIELD_IP_LENGTH:
kind = TOKEN_IP_LENGTH; break;
case WINDIVERT_FILTER_FIELD_IP_ID:
kind = TOKEN_IP_ID; break;
case WINDIVERT_FILTER_FIELD_IP_DF:
kind = TOKEN_IP_DF; break;
case WINDIVERT_FILTER_FIELD_IP_MF:
kind = TOKEN_IP_MF; break;
case WINDIVERT_FILTER_FIELD_IP_FRAGOFF:
kind = TOKEN_IP_FRAG_OFF; break;
case WINDIVERT_FILTER_FIELD_IP_TTL:
kind = TOKEN_IP_TTL; break;
case WINDIVERT_FILTER_FIELD_IP_PROTOCOL:
kind = TOKEN_IP_PROTOCOL; break;
case WINDIVERT_FILTER_FIELD_IP_CHECKSUM:
kind = TOKEN_IP_CHECKSUM; break;
case WINDIVERT_FILTER_FIELD_IP_SRCADDR:
kind = TOKEN_IP_SRC_ADDR; break;
case WINDIVERT_FILTER_FIELD_IP_DSTADDR:
kind = TOKEN_IP_DST_ADDR; break;
case WINDIVERT_FILTER_FIELD_IPV6_TRAFFICCLASS:
kind = TOKEN_IPV6_TRAFFIC_CLASS; break;
case WINDIVERT_FILTER_FIELD_IPV6_FLOWLABEL:
kind = TOKEN_IPV6_FLOW_LABEL; break;
case WINDIVERT_FILTER_FIELD_IPV6_LENGTH:
kind = TOKEN_IPV6_LENGTH; break;
case WINDIVERT_FILTER_FIELD_IPV6_NEXTHDR:
kind = TOKEN_IPV6_NEXT_HDR; break;
case WINDIVERT_FILTER_FIELD_IPV6_HOPLIMIT:
kind = TOKEN_IPV6_HOP_LIMIT; break;
case WINDIVERT_FILTER_FIELD_IPV6_SRCADDR:
kind = TOKEN_IPV6_SRC_ADDR; break;
case WINDIVERT_FILTER_FIELD_IPV6_DSTADDR:
kind = TOKEN_IPV6_DST_ADDR; break;
case WINDIVERT_FILTER_FIELD_ICMP_TYPE:
kind = TOKEN_ICMP_TYPE; break;
case WINDIVERT_FILTER_FIELD_ICMP_CODE:
kind = TOKEN_ICMP_CODE; break;
case WINDIVERT_FILTER_FIELD_ICMP_CHECKSUM:
kind = TOKEN_ICMP_CHECKSUM; break;
case WINDIVERT_FILTER_FIELD_ICMP_BODY:
kind = TOKEN_ICMP_BODY; break;
case WINDIVERT_FILTER_FIELD_ICMPV6_TYPE:
kind = TOKEN_ICMPV6_TYPE; break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CODE:
kind = TOKEN_ICMPV6_CODE; break;
case WINDIVERT_FILTER_FIELD_ICMPV6_CHECKSUM:
kind = TOKEN_ICMPV6_CHECKSUM; break;
case WINDIVERT_FILTER_FIELD_ICMPV6_BODY:
kind = TOKEN_ICMPV6_BODY; break;
case WINDIVERT_FILTER_FIELD_TCP_SRCPORT:
kind = TOKEN_TCP_SRC_PORT; break;
case WINDIVERT_FILTER_FIELD_TCP_DSTPORT:
kind = TOKEN_TCP_DST_PORT; break;
case WINDIVERT_FILTER_FIELD_TCP_SEQNUM:
kind = TOKEN_TCP_SEQ_NUM; break;
case WINDIVERT_FILTER_FIELD_TCP_ACKNUM:
kind = TOKEN_TCP_ACK_NUM; break;
case WINDIVERT_FILTER_FIELD_TCP_HDRLENGTH:
kind = TOKEN_TCP_HDR_LENGTH; break;
case WINDIVERT_FILTER_FIELD_TCP_URG:
kind = TOKEN_TCP_URG; break;
case WINDIVERT_FILTER_FIELD_TCP_ACK:
kind = TOKEN_TCP_ACK; break;
case WINDIVERT_FILTER_FIELD_TCP_PSH:
kind = TOKEN_TCP_PSH; break;
case WINDIVERT_FILTER_FIELD_TCP_RST:
kind = TOKEN_TCP_RST; break;
case WINDIVERT_FILTER_FIELD_TCP_SYN:
kind = TOKEN_TCP_SYN; break;
case WINDIVERT_FILTER_FIELD_TCP_FIN:
kind = TOKEN_TCP_FIN; break;
case WINDIVERT_FILTER_FIELD_TCP_WINDOW:
kind = TOKEN_TCP_WINDOW; break;
case WINDIVERT_FILTER_FIELD_TCP_CHECKSUM:
kind = TOKEN_TCP_CHECKSUM; break;
case WINDIVERT_FILTER_FIELD_TCP_URGPTR:
kind = TOKEN_TCP_URG_PTR; break;
case WINDIVERT_FILTER_FIELD_TCP_PAYLOADLENGTH:
kind = TOKEN_TCP_PAYLOAD_LENGTH; break;
case WINDIVERT_FILTER_FIELD_UDP_SRCPORT:
kind = TOKEN_UDP_SRC_PORT; break;
case WINDIVERT_FILTER_FIELD_UDP_DSTPORT:
kind = TOKEN_UDP_DST_PORT; break;
case WINDIVERT_FILTER_FIELD_UDP_LENGTH:
kind = TOKEN_UDP_LENGTH; break;
case WINDIVERT_FILTER_FIELD_UDP_CHECKSUM:
kind = TOKEN_UDP_CHECKSUM; break;
case WINDIVERT_FILTER_FIELD_UDP_PAYLOADLENGTH:
kind = TOKEN_UDP_PAYLOAD_LENGTH; break;
case WINDIVERT_FILTER_FIELD_LOOPBACK:
kind = TOKEN_LOOPBACK; break;
case WINDIVERT_FILTER_FIELD_IMPOSTOR:
kind = TOKEN_IMPOSTOR; break;
case WINDIVERT_FILTER_FIELD_PROCESSID:
kind = TOKEN_PROCESS_ID; break;
case WINDIVERT_FILTER_FIELD_LOCALADDR:
kind = TOKEN_LOCAL_ADDR; break;
case WINDIVERT_FILTER_FIELD_REMOTEADDR:
kind = TOKEN_REMOTE_ADDR; break;
case WINDIVERT_FILTER_FIELD_LOCALPORT:
kind = TOKEN_LOCAL_PORT; break;
case WINDIVERT_FILTER_FIELD_REMOTEPORT:
kind = TOKEN_REMOTE_PORT; break;
case WINDIVERT_FILTER_FIELD_PROTOCOL:
kind = TOKEN_PROTOCOL; break;
case WINDIVERT_FILTER_FIELD_LAYER:
kind = TOKEN_LAYER; break;
default:
return NULL;
}
switch (kind)
{
case TOKEN_PACKET:
case TOKEN_PACKET16:
case TOKEN_PACKET32:
case TOKEN_TCP_PAYLOAD:
case TOKEN_TCP_PAYLOAD16:
case TOKEN_TCP_PAYLOAD32:
case TOKEN_UDP_PAYLOAD:
case TOKEN_UDP_PAYLOAD16:
case TOKEN_UDP_PAYLOAD32:
var = WinDivertMakeArrayVar(pool, kind, test->arg[1], &error);
if (var == NULL)
{
return NULL;
}
tmp[0] = test->arg[0];
tmp[1] = tmp[2] = tmp[3] = 0;
val = WinDivertMakeNumber(pool, tmp, &error);
if (val == NULL)
{
return NULL;
}
break;
default:
var = WinDivertMakeVar(kind, &error);
if (var == NULL)
{
return NULL;
}
val = WinDivertMakeNumber(pool, test->arg, &error);
if (val == NULL)
{
return NULL;
}
break;
}
switch (test->test)
{
case WINDIVERT_FILTER_TEST_EQ:
kind = TOKEN_EQ; break;
case WINDIVERT_FILTER_TEST_NEQ:
kind = TOKEN_NEQ; break;
case WINDIVERT_FILTER_TEST_LT:
kind = TOKEN_LT; break;
case WINDIVERT_FILTER_TEST_LEQ:
kind = TOKEN_LEQ; break;
case WINDIVERT_FILTER_TEST_GT:
kind = TOKEN_GT; break;
case WINDIVERT_FILTER_TEST_GEQ:
kind = TOKEN_GEQ; break;
default:
return NULL;
}
expr = WinDivertMakeBinOp(pool, kind, var, val, &error);
if (expr == NULL)
{
return NULL;
}
expr->succ = test->success;
expr->fail = test->failure;
return expr;
}
/*
* Dereference an expression.
*/
static void WinDivertDerefExpr(PEXPR *exprs, UINT8 i)
{
switch (i)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
return;
default:
exprs[i]->count--;
if (exprs[i]->count == 0)
{
exprs[i] = NULL;
}
return;
}
}
/*
* Apply an and/or simplification for WinDivertCoalesceAndOr().
*/
static PEXPR WinDivertSimplifyAndOr(HANDLE pool, PEXPR *exprs, PEXPR expr,
BOOL and, UINT8 next, UINT8 other)
{
PEXPR next_expr = exprs[next], new_expr;
ERROR error;
new_expr = WinDivertMakeBinOp(pool, (and? TOKEN_AND: TOKEN_OR), expr,
next_expr, &error);
if (new_expr == NULL)
{
return NULL;
}
new_expr->succ = next_expr->succ;
new_expr->fail = next_expr->fail;
new_expr->count = expr->count;
WinDivertDerefExpr(exprs, next);
WinDivertDerefExpr(exprs, other);
return new_expr;
}
/*
* Detect and coalesce and/or (& (?:)) expression patterns.
*/
static PEXPR WinDivertCoalesceAndOr(HANDLE pool, PEXPR *exprs, UINT8 i,
ERROR *error)
{
PEXPR expr, next_expr, new_expr;
BOOL singleton;
static const EXPR true_expr = {{{0}}, TOKEN_TRUE};
expr = exprs[i];
while (TRUE)
{
if (expr == NULL || expr->count == 0)
{
return NULL;
}
singleton = FALSE;
switch (expr->succ)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
break;
default:
next_expr = exprs[expr->succ];
if (next_expr->count != 1)
{
break;
}
singleton = TRUE;
if (next_expr->fail == expr->fail)
{
expr = WinDivertSimplifyAndOr(pool, exprs, expr,
/*and=*/TRUE, expr->succ, expr->fail);
continue;
}
else if (next_expr->succ == expr->fail)
{
new_expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY,
sizeof(EXPR));
if (new_expr == NULL)
{
return NULL;
}
new_expr->kind = TOKEN_QUESTION;
new_expr->arg[0] = expr;
new_expr->arg[1] = next_expr;
new_expr->arg[2] = (PEXPR)&true_expr;
new_expr->succ = next_expr->succ;
new_expr->fail = next_expr->fail;
new_expr->count = expr->count;
WinDivertDerefExpr(exprs, expr->succ);
WinDivertDerefExpr(exprs, expr->fail);
expr = new_expr;
continue;
}
break;
}
switch (expr->fail)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
singleton = FALSE;
break;
default:
next_expr = exprs[expr->fail];
if (next_expr->count != 1)
{
singleton = FALSE;
break;
}
if (next_expr->succ == expr->succ)
{
expr = WinDivertSimplifyAndOr(pool, exprs, expr,
/*and=*/FALSE, expr->fail, expr->succ);
continue;
}
else if (next_expr->fail == expr->succ)
{
expr = WinDivertSimplifyAndOr(pool, exprs, expr,
/*and=*/TRUE, expr->fail, expr->succ);
continue;
}
break;
}
if (singleton)
{
// Both branches have count==1; simplify into a (?:) expression:
PEXPR succ_expr, fail_expr;
succ_expr = exprs[expr->succ];
fail_expr = exprs[expr->fail];
if (succ_expr->succ != fail_expr->succ ||
succ_expr->fail != fail_expr->fail)
{
break;
}
new_expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (new_expr == NULL)
{
return NULL;
}
new_expr->kind = TOKEN_QUESTION;
new_expr->arg[0] = expr;
new_expr->arg[1] = succ_expr;
new_expr->arg[2] = fail_expr;
new_expr->succ = succ_expr->succ;
new_expr->fail = fail_expr->fail;
new_expr->count = expr->count;
WinDivertDerefExpr(exprs, expr->succ);
WinDivertDerefExpr(exprs, expr->fail);
WinDivertDerefExpr(exprs, new_expr->succ);
WinDivertDerefExpr(exprs, new_expr->fail);
expr = new_expr;
continue;
}
// No simplifications, so we are done.
break;
}
exprs[i] = expr;
return expr;
}
/*
* Coalesce all remaining expressions.
*/
static PEXPR WinDivertCoalesceExpr(HANDLE pool, PEXPR *exprs, UINT8 i)
{
PEXPR expr, succ_expr, fail_expr, new_expr;
static const EXPR true_expr = {{{0}}, TOKEN_TRUE};
static const EXPR false_expr = {{{0}}, TOKEN_FALSE};
switch (i)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
return (PEXPR)&true_expr;
case WINDIVERT_FILTER_RESULT_REJECT:
return (PEXPR)&false_expr;
default:
break;
}
expr = exprs[i];
if (expr == NULL)
{
return NULL;
}
if (expr->succ == expr->fail)
{
return WinDivertCoalesceExpr(pool, exprs, expr->succ);
}
succ_expr = WinDivertCoalesceExpr(pool, exprs, expr->succ);
fail_expr = WinDivertCoalesceExpr(pool, exprs, expr->fail);
if (succ_expr == NULL || fail_expr == NULL)
{
return NULL;
}
if (succ_expr->kind == TOKEN_TRUE && fail_expr->kind == TOKEN_FALSE)
{
return expr;
}
new_expr = (PEXPR)HeapAlloc(pool, HEAP_ZERO_MEMORY, sizeof(EXPR));
if (new_expr == NULL)
{
return NULL;
}
new_expr->kind = TOKEN_QUESTION;
new_expr->arg[0] = expr;
new_expr->arg[1] = succ_expr;
new_expr->arg[2] = fail_expr;
return new_expr;
}
/*
* Format a decimal number.
*/
static void WinDivertFormatNumber(PWINDIVERT_STREAM stream, UINT32 val)
{
UINT64 r = 1000000000, dig;
BOOL zeroes = FALSE;
while (r != 0)
{
dig = val / r;
val = val % r;
r = r / 10;
if (dig == 0 && !zeroes && r != 0)
{
continue;
}
WinDivertPutChar(stream, '0' + dig);
zeroes = TRUE;
}
}
/*
* Format a hexidecimal number.
*/
static void WinDivertFormatHexNumber(PWINDIVERT_STREAM stream, UINT32 val)
{
INT s = 28;
UINT32 dig;
BOOL zeroes = FALSE;
while (s >= 0)
{
dig = (val & ((UINT32)0xF << s)) >> s;
s -= 4;
if (dig == 0 && !zeroes && s >= 0)
{
continue;
}
WinDivertPutChar(stream, (dig <= 9? '0' + dig: 'a' + (dig - 10)));
zeroes = TRUE;
}
}
/*
* Format an IPv4 address.
*/
static void WinDivertFormatIPv4Addr(PWINDIVERT_STREAM stream, UINT32 addr)
{
WinDivertFormatNumber(stream, (addr & 0xFF000000) >> 24);
WinDivertPutChar(stream, '.');
WinDivertFormatNumber(stream, (addr & 0x00FF0000) >> 16);
WinDivertPutChar(stream, '.');
WinDivertFormatNumber(stream, (addr & 0x0000FF00) >> 8);
WinDivertPutChar(stream, '.');
WinDivertFormatNumber(stream, (addr & 0x000000FF) >> 0);
}
/*
* Format an IPv6 address.
*/
static void WinDivertFormatIPv6Addr(PWINDIVERT_STREAM stream,
const UINT32 *addr32)
{
INT i, z_curr, z_count, z_start, z_max;
UINT16 addr[8];
// IPv4 special case:
if (addr32[3] == 0 && addr32[2] == 0 && addr32[1] == 0x0000FFFF)
{
WinDivertFormatIPv4Addr(stream, addr32[0]);
return;
}
// Find zeroes:
memcpy(addr, addr32, sizeof(addr));
z_curr = 7;
z_count = 0;
z_start = z_max = -1;
for (i = 7; i >= 0; i--)
{
if (addr[i] == 0)
{
z_count++;
z_start = (z_count > z_max? z_curr: z_start);
z_max = (z_count > z_max? z_count: z_max);
}
else
{
z_curr = i-1;
z_count = 0;
}
}
// Format address:
for (i = 7; i >= 0; i--)
{
if (i == z_start)
{
WinDivertPutString(stream, (i == 7? "::": ":"));
i -= (z_max-1);
continue;
}
WinDivertFormatHexNumber(stream, addr[i]);
WinDivertPutString(stream, (i != 0? ":": ""));
}
}
/*
* 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.
*/
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;
switch (field->kind)
{
case TOKEN_ZERO:
case TOKEN_INBOUND:
case TOKEN_OUTBOUND:
case TOKEN_IP:
case TOKEN_IPV6:
case TOKEN_ICMP:
case TOKEN_TCP:
case TOKEN_UDP:
case TOKEN_ICMPV6:
case TOKEN_IP_DF:
case TOKEN_IP_MF:
case TOKEN_TCP_URG:
case TOKEN_TCP_ACK:
case TOKEN_TCP_PSH:
case TOKEN_TCP_RST:
case TOKEN_TCP_SYN:
case TOKEN_TCP_FIN:
case TOKEN_LOOPBACK:
case TOKEN_IMPOSTOR:
if (val->val[1] != 0 || val->val[2] != 0 || val->val[3] != 0 ||
val->val[0] > 1)
{
break;
}
switch (expr->kind)
{
case TOKEN_EQ:
WinDivertPutString(stream, (val->val[0] == 0? "not ": ""));
WinDivertFormatExpr(stream, field, layer,
/*top_level=*/FALSE, /*and=*/FALSE);
return;
case TOKEN_NEQ:
WinDivertPutString(stream, (val->val[0] != 0? "not ": ""));
WinDivertFormatExpr(stream, field, layer,
/*top_level=*/FALSE, /*and=*/FALSE);
return;
default:
break;
}
break;
case TOKEN_IP_SRC_ADDR:
case TOKEN_IP_DST_ADDR:
is_ipv4_addr = TRUE;
break;
case TOKEN_IPV6_SRC_ADDR:
case TOKEN_IPV6_DST_ADDR:
case TOKEN_LOCAL_ADDR:
case TOKEN_REMOTE_ADDR:
is_ipv6_addr = TRUE;
break;
case TOKEN_LAYER:
is_layer = TRUE;
break;
case TOKEN_EVENT:
is_event = TRUE;
break;
case TOKEN_PACKET:
case TOKEN_PACKET16:
case TOKEN_PACKET32:
case TOKEN_IP_ID:
case TOKEN_IP_CHECKSUM:
case TOKEN_TCP_CHECKSUM:
case TOKEN_TCP_PAYLOAD:
case TOKEN_TCP_PAYLOAD16:
case TOKEN_TCP_PAYLOAD32:
case TOKEN_UDP_CHECKSUM:
case TOKEN_UDP_PAYLOAD:
case TOKEN_UDP_PAYLOAD16:
case TOKEN_UDP_PAYLOAD32:
case TOKEN_ICMP_CHECKSUM:
case TOKEN_ICMPV6_CHECKSUM:
is_hex = TRUE;
break;
default:
break;
}
WinDivertFormatExpr(stream, field, layer, /*top_level=*/FALSE,
/*and=*/FALSE);
switch (expr->kind)
{
case TOKEN_EQ:
WinDivertPutString(stream, " = "); break;
case TOKEN_NEQ:
WinDivertPutString(stream, " != "); break;
case TOKEN_LT:
WinDivertPutString(stream, " < "); break;
case TOKEN_LEQ:
WinDivertPutString(stream, " <= "); break;
case TOKEN_GT:
WinDivertPutString(stream, " > "); break;
case TOKEN_GEQ:
WinDivertPutString(stream, " >= "); break;
}
if (is_ipv4_addr)
{
WinDivertFormatIPv4Addr(stream, val->val[0]);
}
else if (is_ipv6_addr)
{
WinDivertFormatIPv6Addr(stream, val->val);
}
else if (is_layer)
{
switch (val->val[0])
{
case WINDIVERT_LAYER_NETWORK:
WinDivertPutString(stream, "NETWORK"); break;
case WINDIVERT_LAYER_NETWORK_FORWARD:
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:
WinDivertFormatNumber(stream, val->val[0]); break;
}
}
else if (is_event)
{
switch (layer)
{
case WINDIVERT_LAYER_NETWORK:
case WINDIVERT_LAYER_NETWORK_FORWARD:
if (val->val[0] == WINDIVERT_EVENT_NETWORK_PACKET)
{
WinDivertPutString(stream, "PACKET");
}
else
{
WinDivertFormatNumber(stream, val->val[0]);
}
break;
case WINDIVERT_LAYER_FLOW:
switch (val->val[0])
{
case WINDIVERT_EVENT_FLOW_ESTABLISHED:
WinDivertPutString(stream, "ESTABLISHED"); break;
case WINDIVERT_EVENT_FLOW_DELETED:
WinDivertPutString(stream, "DELETED"); break;
default:
WinDivertFormatNumber(stream, val->val[0]); break;
}
break;
case WINDIVERT_LAYER_SOCKET:
switch (val->val[0])
{
case WINDIVERT_EVENT_SOCKET_BIND:
WinDivertPutString(stream, "BIND"); break;
case WINDIVERT_EVENT_SOCKET_CONNECT:
WinDivertPutString(stream, "CONNECT"); break;
case WINDIVERT_EVENT_SOCKET_LISTEN:
WinDivertPutString(stream, "LISTEN"); break;
case WINDIVERT_EVENT_SOCKET_ACCEPT:
WinDivertPutString(stream, "ACCEPT"); break;
default:
WinDivertFormatNumber(stream, val->val[0]); break;
}
break;
case WINDIVERT_LAYER_REFLECT:
switch (val->val[0])
{
case WINDIVERT_EVENT_REFLECT_OPEN:
WinDivertPutString(stream, "OPEN"); break;
case WINDIVERT_EVENT_REFLECT_CLOSE:
WinDivertPutString(stream, "CLOSE"); break;
default:
WinDivertFormatNumber(stream, val->val[0]); break;
}
break;
default:
WinDivertFormatNumber(stream, val->val[0]); break;
}
}
else if (is_hex)
{
WinDivertPutString(stream, "0x");
WinDivertFormatHexNumber(stream, val->val[0]);
}
else
{
WinDivertFormatNumber(stream, val->val[0]);
}
}
/*
* Format an expression.
*/
static void WinDivertFormatExpr(PWINDIVERT_STREAM stream, PEXPR expr,
WINDIVERT_LAYER layer, BOOL top_level, BOOL and)
{
INT idx;
if (stream->pos >= stream->max)
{
return;
}
switch (expr->kind)
{
case TOKEN_AND:
if (!top_level && !and)
{
WinDivertPutChar(stream, '(');
}
WinDivertFormatExpr(stream, expr->arg[0], layer,
/*top_level=*/FALSE, /*and=*/TRUE);
WinDivertPutString(stream, " and ");
WinDivertFormatExpr(stream, expr->arg[1], layer,
/*top_level=*/FALSE, /*and=*/TRUE);
if (!top_level && !and)
{
WinDivertPutChar(stream, ')');
}
return;
case TOKEN_OR:
if (!top_level && and)
{
WinDivertPutChar(stream, '(');
}
WinDivertFormatExpr(stream, expr->arg[0], layer,
/*top_level=*/FALSE, /*and=*/FALSE);
WinDivertPutString(stream, " or ");
WinDivertFormatExpr(stream, expr->arg[1], layer,
/*top_level=*/FALSE, /*and=*/FALSE);
if (!top_level && and)
{
WinDivertPutChar(stream, ')');
}
return;
case TOKEN_QUESTION:
WinDivertPutChar(stream, '(');
WinDivertFormatExpr(stream, expr->arg[0], layer,
/*top_level=*/TRUE, /*and=*/FALSE);
WinDivertPutString(stream, "? ");
WinDivertFormatExpr(stream, expr->arg[1], layer,
/*top_level=*/TRUE, /*and=*/FALSE);
WinDivertPutString(stream, ": ");
WinDivertFormatExpr(stream, expr->arg[2], layer,
/*top_level=*/TRUE, /*and=*/FALSE);
WinDivertPutChar(stream, ')');
return;
case TOKEN_TRUE:
WinDivertPutString(stream, "true");
return;
case TOKEN_FALSE:
WinDivertPutString(stream, "false");
return;
case TOKEN_EQ:
case TOKEN_NEQ:
case TOKEN_LT:
case TOKEN_LEQ:
case TOKEN_GT:
case TOKEN_GEQ:
WinDivertFormatTestExpr(stream, expr, layer);
return;
case TOKEN_ZERO:
WinDivertPutString(stream, "zero"); return;
case TOKEN_EVENT:
WinDivertPutString(stream, "event"); return;
case TOKEN_RANDOM8:
WinDivertPutString(stream, "random8"); return;
case TOKEN_RANDOM16:
WinDivertPutString(stream, "random16"); return;
case TOKEN_RANDOM32:
WinDivertPutString(stream, "random32"); return;
case TOKEN_PACKET:
WinDivertPutString(stream, "packet"); break;
case TOKEN_PACKET16:
WinDivertPutString(stream, "packet16"); break;
case TOKEN_PACKET32:
WinDivertPutString(stream, "packet32"); break;
case TOKEN_TCP_PAYLOAD:
WinDivertPutString(stream, "tcp.Payload"); break;
case TOKEN_TCP_PAYLOAD16:
WinDivertPutString(stream, "tcp.Payload16"); break;
case TOKEN_TCP_PAYLOAD32:
WinDivertPutString(stream, "tcp.Payload32"); break;
case TOKEN_UDP_PAYLOAD:
WinDivertPutString(stream, "udp.Payload"); break;
case TOKEN_UDP_PAYLOAD16:
WinDivertPutString(stream, "udp.Payload16"); break;
case TOKEN_UDP_PAYLOAD32:
WinDivertPutString(stream, "udp.Payload32"); break;
case TOKEN_INBOUND:
WinDivertPutString(stream, "inbound"); return;
case TOKEN_OUTBOUND:
WinDivertPutString(stream, "outbound"); return;
case TOKEN_IF_IDX:
WinDivertPutString(stream, "ifIdx"); return;
case TOKEN_SUB_IF_IDX:
WinDivertPutString(stream, "subIfIdx"); return;
case TOKEN_IP:
WinDivertPutString(stream, "ip"); return;
case TOKEN_IPV6:
WinDivertPutString(stream, "ipv6"); return;
case TOKEN_ICMP:
WinDivertPutString(stream, "icmp"); return;
case TOKEN_TCP:
WinDivertPutString(stream, "tcp"); return;
case TOKEN_UDP:
WinDivertPutString(stream, "udp"); return;
case TOKEN_ICMPV6:
WinDivertPutString(stream, "icmpv6"); return;
case TOKEN_IP_HDR_LENGTH:
WinDivertPutString(stream, "ip.HdrLength"); return;
case TOKEN_IP_TOS:
WinDivertPutString(stream, "ip.TOS"); return;
case TOKEN_IP_LENGTH:
WinDivertPutString(stream, "ip.Length"); return;
case TOKEN_IP_ID:
WinDivertPutString(stream, "ip.Id"); return;
case TOKEN_IP_DF:
WinDivertPutString(stream, "ip.DF"); return;
case TOKEN_IP_MF:
WinDivertPutString(stream, "ip.MF"); return;
case TOKEN_IP_FRAG_OFF:
WinDivertPutString(stream, "ip.FragOff"); return;
case TOKEN_IP_TTL:
WinDivertPutString(stream, "ip.TTL"); return;
case TOKEN_IP_PROTOCOL:
WinDivertPutString(stream, "ip.Protocol"); return;
case TOKEN_IP_CHECKSUM:
WinDivertPutString(stream, "ip.Checksum"); return;
case TOKEN_IP_SRC_ADDR:
WinDivertPutString(stream, "ip.SrcAddr"); return;
case TOKEN_IP_DST_ADDR:
WinDivertPutString(stream, "ip.DstAddr"); return;
case TOKEN_IPV6_TRAFFIC_CLASS:
WinDivertPutString(stream, "ipv6.TrafficClass"); return;
case TOKEN_IPV6_FLOW_LABEL:
WinDivertPutString(stream, "ipv6.FlowLabel"); return;
case TOKEN_IPV6_LENGTH:
WinDivertPutString(stream, "ipv6.Length"); return;
case TOKEN_IPV6_NEXT_HDR:
WinDivertPutString(stream, "ipv6.NextHdr"); return;
case TOKEN_IPV6_HOP_LIMIT:
WinDivertPutString(stream, "ipv6.HopLimit"); return;
case TOKEN_IPV6_SRC_ADDR:
WinDivertPutString(stream, "ipv6.SrcAddr"); return;
case TOKEN_IPV6_DST_ADDR:
WinDivertPutString(stream, "ipv6.DstAddr"); return;
case TOKEN_ICMP_TYPE:
WinDivertPutString(stream, "icmp.Type"); return;
case TOKEN_ICMP_CODE:
WinDivertPutString(stream, "icmp.Code"); return;
case TOKEN_ICMP_CHECKSUM:
WinDivertPutString(stream, "icmp.Checksum"); return;
case TOKEN_ICMP_BODY:
WinDivertPutString(stream, "icmp.Body"); return;
case TOKEN_ICMPV6_TYPE:
WinDivertPutString(stream, "icmpv6.Type"); return;
case TOKEN_ICMPV6_CODE:
WinDivertPutString(stream, "icmpv6.Code"); return;
case TOKEN_ICMPV6_CHECKSUM:
WinDivertPutString(stream, "icmpv6.Checksum"); return;
case TOKEN_ICMPV6_BODY:
WinDivertPutString(stream, "icmpv6.Body"); return;
case TOKEN_TCP_SRC_PORT:
WinDivertPutString(stream, "tcp.SrcPort"); return;
case TOKEN_TCP_DST_PORT:
WinDivertPutString(stream, "tcp.DstPort"); return;
case TOKEN_TCP_SEQ_NUM:
WinDivertPutString(stream, "tcp.SeqNum"); return;
case TOKEN_TCP_ACK_NUM:
WinDivertPutString(stream, "tcp.AckNum"); return;
case TOKEN_TCP_HDR_LENGTH:
WinDivertPutString(stream, "tcp.HdrLength"); return;
case TOKEN_TCP_URG:
WinDivertPutString(stream, "tcp.Urg"); return;
case TOKEN_TCP_ACK:
WinDivertPutString(stream, "tcp.Ack"); return;
case TOKEN_TCP_PSH:
WinDivertPutString(stream, "tcp.Psh"); return;
case TOKEN_TCP_RST:
WinDivertPutString(stream, "tcp.Rst"); return;
case TOKEN_TCP_SYN:
WinDivertPutString(stream, "tcp.Syn"); return;
case TOKEN_TCP_FIN:
WinDivertPutString(stream, "tcp.Fin"); return;
case TOKEN_TCP_WINDOW:
WinDivertPutString(stream, "tcp.Window"); return;
case TOKEN_TCP_CHECKSUM:
WinDivertPutString(stream, "tcp.Checksum"); return;
case TOKEN_TCP_URG_PTR:
WinDivertPutString(stream, "tcp.UrgPtr"); return;
case TOKEN_TCP_PAYLOAD_LENGTH:
WinDivertPutString(stream, "tcp.PayloadLength"); return;
case TOKEN_UDP_SRC_PORT:
WinDivertPutString(stream, "udp.SrcPort"); return;
case TOKEN_UDP_DST_PORT:
WinDivertPutString(stream, "udp.DstPort"); return;
case TOKEN_UDP_LENGTH:
WinDivertPutString(stream, "udp.Length"); return;
case TOKEN_UDP_CHECKSUM:
WinDivertPutString(stream, "udp.Checksum"); return;
case TOKEN_UDP_PAYLOAD_LENGTH:
WinDivertPutString(stream, "udp.PayloadLength"); return;
case TOKEN_LOOPBACK:
WinDivertPutString(stream, "loopback"); return;
case TOKEN_IMPOSTOR:
WinDivertPutString(stream, "impostor"); return;
case TOKEN_PROCESS_ID:
WinDivertPutString(stream, "processId"); return;
case TOKEN_LOCAL_ADDR:
WinDivertPutString(stream, "localAddr"); return;
case TOKEN_REMOTE_ADDR:
WinDivertPutString(stream, "remoteAddr"); return;
case TOKEN_LOCAL_PORT:
WinDivertPutString(stream, "localPort"); return;
case TOKEN_REMOTE_PORT:
WinDivertPutString(stream, "remotePort"); return;
case TOKEN_PROTOCOL:
WinDivertPutString(stream, "protocol"); return;
case TOKEN_LAYER:
WinDivertPutString(stream, "layer"); return;
case TOKEN_NUMBER:
WinDivertFormatNumber(stream, expr->val[0]); return;
}
WinDivertPutChar(stream, '[');
idx = (INT)expr->val[0];
if (idx < 0)
{
WinDivertPutChar(stream, '-');
idx = -idx;
}
WinDivertFormatNumber(stream, (UINT32)idx);
WinDivertPutString(stream, "b]");
}
/*
* Format a filter string.
*/
BOOL WinDivertHelperFormatFilter(const char *filter, WINDIVERT_LAYER layer,
char *buffer, UINT buflen)
{
PEXPR exprs[WINDIVERT_FILTER_MAXLEN], expr;
ERROR err;
WINDIVERT_FILTER object[WINDIVERT_FILTER_MAXLEN];
UINT obj_len;
INT i;
HANDLE pool;
WINDIVERT_STREAM stream;
ERROR error;
const SIZE_T min_pool_size = 8192;
if (filter == NULL || buffer == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
err = WinDivertCompileFilter(filter, layer, object, &obj_len);
if (IS_ERROR(err))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pool = HeapCreate(HEAP_NO_SERIALIZE, min_pool_size, 16 * min_pool_size);
if (pool == NULL)
{
return FALSE;
}
// Decompile all tests:
for (i = (INT)obj_len-1; i >= 0; i--)
{
expr = WinDivertDecompileTest(pool, object + i);
if (expr == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
exprs[i] = expr;
switch (expr->succ)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
break;
default:
exprs[expr->succ]->count++;
break;
}
switch (expr->fail)
{
case WINDIVERT_FILTER_RESULT_ACCEPT:
case WINDIVERT_FILTER_RESULT_REJECT:
break;
default:
exprs[expr->fail]->count++;
break;
}
}
exprs[0]->count++;
// Coalesce (unflatten) tests into and/or expressions:
for (i = (INT)obj_len-1; i >= 0; i--)
{
error = MAKE_ERROR(WINDIVERT_ERROR_NONE, 0);
(PVOID)WinDivertCoalesceAndOr(pool, exprs, i, &error);
if (IS_ERROR(error))
{
HeapDestroy(pool);
return FALSE;
}
}
// Coalesce remaining expressions:
expr = WinDivertCoalesceExpr(pool, exprs, 0);
if (expr == NULL)
{
HeapDestroy(pool);
return FALSE;
}
// Format the final expression:
stream.data = buffer;
stream.pos = 0;
stream.max = buflen;
stream.overflow = FALSE;
WinDivertFormatExpr(&stream, expr, layer, /*top_level=*/TRUE,
/*and=*/FALSE);
WinDivertPutNul(&stream);
// Clean-up:
HeapDestroy(pool);
if (!stream.overflow)
{
return TRUE;
}
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
/*
* WinDivert packet hash function.
*/
extern UINT64 WinDivertHelperHashPacket(const VOID *pPacket, UINT packetLen,
UINT64 seed)
{
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;
WinDivertParsePacket((PVOID)pPacket, packetLen, &ip_header, &ipv6_header,
&icmp_header, &icmpv6_header, &tcp_header, &udp_header, NULL,
NULL, NULL);
return WinDivertHashPacket(seed, ip_header, ipv6_header, icmp_header,
icmpv6_header, tcp_header, udp_header);
}
/*
* Byte ordering.
*/
extern UINT16 WinDivertHelperNtohs(UINT16 x)
{
return BYTESWAP16(x);
}
extern UINT16 WinDivertHelperHtons(UINT16 x)
{
return BYTESWAP16(x);
}
extern UINT32 WinDivertHelperNtohl(UINT32 x)
{
return BYTESWAP32(x);
}
extern UINT32 WinDivertHelperHtonl(UINT32 x)
{
return BYTESWAP32(x);
}
extern UINT64 WinDivertHelperNtohll(UINT64 x)
{
return BYTESWAP64(x);
}
extern UINT64 WinDivertHelperHtonll(UINT64 x)
{
return BYTESWAP64(x);
}
static void WinDivertByteSwap128(const UINT *inAddr, UINT *outAddr)
{
UINT32 tmp[4], i; // tmp[] allows overlapping
for (i = 0; i < 4; i++)
{
tmp[3-i] = BYTESWAP32(inAddr[0]);
}
for (i = 0; i < 4; i++)
{
outAddr[i] = tmp[i];
}
}
extern void WinDivertHelperNtohIpv6Address(const UINT *inAddr, UINT *outAddr)
{
WinDivertByteSwap128(inAddr, outAddr);
}
extern void WinDivertHelperHtonIpv6Address(const UINT *inAddr, UINT *outAddr)
{
WinDivertByteSwap128(inAddr, outAddr);
}