Skip to content

Commit 079729c

Browse files
Add new ICMP Echo Reply Rule (#912)
* init * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * add traces * wip * working finally * address comments wave 1 * address comments wave 2 * separate out icmp parsing * do not parse icmp if ip not valid * pktbuildicmp * memset ipv6 mem to 0 * rename frame to tmpframe * why does this fix the issue? * spinxsk changes * add rule * improve xdp icmp helper functions * iterate on feedback * remove duplicate helpers * respond to feedback * check ip payload validity * fix logic error
1 parent 6567fdf commit 079729c

File tree

10 files changed

+437
-6
lines changed

10 files changed

+437
-6
lines changed

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<PackageVersion Include="Microsoft.Windows.SDK.cpp.$(Platform)" Version="$(XdpWdkVersion)" />
1616
<PackageVersion Include="Microsoft.Windows.WDK.$(HostPlatform)" Version="$(XdpWdkVersion)" Condition="'$(Platform)' != '$(HostPlatform)'"/>
1717
<PackageVersion Include="Microsoft.Windows.WDK.$(Platform)" Version="$(XdpWdkVersion)" />
18-
<PackageVersion Include="win-net-test" Version="1.3.0" />
18+
<PackageVersion Include="win-net-test" Version="1.4.0" />
1919
<PackageVersion Include="WixToolset.UI.wixext" Version="$(XdpWixVer)" />
2020
<PackageVersion Include="WixToolset.Util.wixext" Version="$(XdpWixVer)" />
2121
</ItemGroup>

published/external/xdp/program.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ typedef enum _XDP_MATCH_TYPE {
3838
XDP_MATCH_IP_NEXT_HEADER,
3939
XDP_MATCH_INNER_IPV4_DST_MASK_UDP,
4040
XDP_MATCH_INNER_IPV6_DST_MASK_UDP,
41+
XDP_MATCH_ICMPV4_ECHO_REPLY_IP_DST,
42+
XDP_MATCH_ICMPV6_ECHO_REPLY_IP_DST,
4143
} XDP_MATCH_TYPE;
4244

4345
typedef union _XDP_INET_ADDR {

samples/rxfilter/rxfilter.c

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//
55

66
#include <xdpapi.h>
7-
7+
#include <ws2tcpip.h>
88
#include <assert.h>
99
#include <math.h>
1010
#include <stdio.h>
@@ -43,6 +43,20 @@ CONST CHAR *UsageText =
4343
" -UdpDstPort <Port>\n"
4444
" The UDP destination port\n"
4545
"\n"
46+
" IcmpEchoReplyIpv4 \n"
47+
"\n"
48+
" Matches all ICMPv4 echo reply frames with the specified IPv4 destination address\n"
49+
"\n"
50+
" -IcmpDstIpv4 <IPv4 address>\n"
51+
" The destination IPv4 address\n"
52+
"\n"
53+
" IcmpEchoReplyIpv6 \n"
54+
"\n"
55+
" Matches all ICMPv6 echo reply frames with the specified IPv6 destination address\n"
56+
"\n"
57+
" -IcmpDstIpv6 <IPv6 address>\n"
58+
" The destination IPv6 address\n"
59+
"\n"
4660
"OPTIONS:\n"
4761
"\n"
4862
" -XdpMode <Mode>\n"
@@ -57,6 +71,7 @@ CONST CHAR *UsageText =
5771
"\n"
5872
" rxfilter.exe -IfIndex 6 -QueueId 0 -MatchType All -Action Drop\n"
5973
" rxfilter.exe -IfIndex 6 -QueueId * -MatchType UdpDstPort -UdpDstPort 53 -Action Drop\n"
74+
" rxfilter.exe -IfIndex 6 -QueueId * -MatchType IcmpEchoReplyIpv4 -IcmpDstIpv4 '172.169.0.22' -Action Drop\n"
6075
;
6176

6277
#define LOGERR(...) \
@@ -123,6 +138,10 @@ ParseArgs(
123138
Rule.Match = XDP_MATCH_ALL;
124139
} else if (!_stricmp(ArgV[i], "UdpDstPort")) {
125140
Rule.Match = XDP_MATCH_UDP_DST;
141+
} else if (!_stricmp(ArgV[i], "IcmpEchoReplyIpv4")) {
142+
Rule.Match = XDP_MATCH_ICMPV4_ECHO_REPLY_IP_DST;
143+
} else if (!_stricmp(ArgV[i], "IcmpEchoReplyIpv6")) {
144+
Rule.Match = XDP_MATCH_ICMPV6_ECHO_REPLY_IP_DST;
126145
} else {
127146
LOGERR("Invalid MatchType");
128147
goto Usage;
@@ -152,6 +171,50 @@ ParseArgs(
152171
} else {
153172
LOGERR("Unexpected UdpDstPort");
154173
}
174+
} else if (!_stricmp(ArgV[i], "-IcmpDstIpv4")) {
175+
if (++i >= ArgC) {
176+
LOGERR("Missing IcmpDstIpv4");
177+
goto Usage;
178+
}
179+
if (Rule.Match == XDP_MATCH_ICMPV4_ECHO_REPLY_IP_DST) {
180+
const char *IpStr = ArgV[i];
181+
182+
// Parse dotted-quad into IN_ADDR (network byte order)
183+
int rc = inet_pton(AF_INET, IpStr, &Rule.Pattern.IpMask.Address.Ipv4);
184+
if (rc != 1) {
185+
if (rc == 0) {
186+
LOGERR("Invalid IPv4 address format: %s\n", IpStr);
187+
} else {
188+
LOGERR("InetPtonA error: %d\n", WSAGetLastError());
189+
}
190+
goto Usage;
191+
}
192+
} else {
193+
LOGERR("Unexpected IcmpDstIpv4");
194+
goto Usage;
195+
}
196+
} else if (!_stricmp(ArgV[i], "-IcmpDstIpv6")) {
197+
if (++i >= ArgC) {
198+
LOGERR("Missing IcmpDstIpv6");
199+
goto Usage;
200+
}
201+
if (Rule.Match == XDP_MATCH_ICMPV6_ECHO_REPLY_IP_DST) {
202+
const char *IpStr = ArgV[i];
203+
204+
// Parse dotted-quad into IN_ADDR (network byte order)
205+
int rc = inet_pton(AF_INET6, IpStr, &Rule.Pattern.IpMask.Address.Ipv6);
206+
if (rc != 1) {
207+
if (rc == 0) {
208+
LOGERR("Invalid IPv6 address format: %s\n", IpStr);
209+
} else {
210+
LOGERR("InetPtonA error: %d\n", WSAGetLastError());
211+
}
212+
goto Usage;
213+
}
214+
} else {
215+
LOGERR("Unexpected IcmpDstIpv6");
216+
goto Usage;
217+
}
155218
} else {
156219
LOGERR("Unexpected parameter \"%s\"", ArgV[i]);
157220
goto Usage;

src/xdp/program.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,20 @@ XdpProgramTrace(
588588
Program, i, ntohs(Rule->Pattern.NextHeader));
589589
break;
590590

591+
case XDP_MATCH_ICMPV4_ECHO_REPLY_IP_DST:
592+
TraceInfo(
593+
TRACE_CORE,
594+
"Program=%p Rule[%u]=XDP_MATCH_ICMPV4_ECHO_REPLY_IP_DST Ip=%!IPADDR!",
595+
Program, i, Rule->Pattern.IpMask.Address.Ipv4.s_addr);
596+
break;
597+
598+
case XDP_MATCH_ICMPV6_ECHO_REPLY_IP_DST:
599+
TraceInfo(
600+
TRACE_CORE,
601+
"Program=%p Rule[%u]=XDP_MATCH_ICMPV6_ECHO_REPLY_IP_DST Ip=%!IPV6ADDR!",
602+
Program, i, Rule->Pattern.IpMask.Address.Ipv6.u.Byte);
603+
break;
604+
591605
default:
592606
ASSERT(FALSE);
593607
break;

src/xdp/programinspect.c

Lines changed: 178 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
#include "precomp.h"
1111
#include "programinspect.h"
1212

13+
#define ICMP4_ECHOREPLY_TYPE 0
14+
#define ICMP4_ECHOREPLY_CODE 0
15+
#define ICMP6_ECHOREPLY_TYPE 129
16+
#define ICMP6_ECHOREPLY_CODE 0
1317
#define TCP_HDR_LEN_TO_BYTES(x) (((UINT64)(x)) * 4)
1418

1519
//
@@ -232,6 +236,123 @@ XdpParseFragmentedUdp(
232236
VirtualAddressExtension, &Storage->UdpHdr, sizeof(Storage->UdpHdr), &Cache->UdpHdr);
233237
}
234238

239+
static
240+
VOID
241+
XdpParseFragmentedIcmpHeader(
242+
_In_ XDP_FRAME *Frame,
243+
_In_ XDP_RING *FragmentRing,
244+
_In_ XDP_EXTENSION *FragmentExtension,
245+
_In_ UINT32 FragmentIndex,
246+
_In_ XDP_EXTENSION *VirtualAddressExtension,
247+
_In_ IPPROTO IpProto,
248+
_Inout_ XDP_PROGRAM_FRAME_STORAGE *FrameStore,
249+
_Inout_ XDP_PROGRAM_FRAME_CACHE *FrameCache
250+
)
251+
{
252+
XDP_BUFFER *Buffer = FrameCache->IpPayload.Buffer;
253+
UINT32 BufferDataOffset = FrameCache->IpPayload.BufferDataOffset;
254+
UINT32 FragmentCount = FrameCache->IpPayload.FragmentCount;
255+
256+
if (FrameCache->IpPayload.IsFragmentedBuffer) {
257+
FragmentIndex = FrameCache->IpPayload.FragmentIndex;
258+
} else {
259+
FragmentIndex--;
260+
FragmentCount = XdpGetFragmentExtension(Frame, FragmentExtension)->FragmentBufferCount;
261+
}
262+
263+
if (IpProto == IPPROTO_IPV4) {
264+
FrameCache->Icmp4Valid =
265+
XdpGetContiguousHeader(
266+
Frame, &Buffer, &BufferDataOffset, &FragmentIndex, &FragmentCount, FragmentRing,
267+
VirtualAddressExtension, &FrameStore->Icmpv4Hdr, sizeof(FrameStore->Icmpv4Hdr), &FrameCache->Icmpv4Hdr);
268+
} else if (IpProto == IPPROTO_IPV6) {
269+
FrameCache->Icmp6Valid =
270+
XdpGetContiguousHeader(
271+
Frame, &Buffer, &BufferDataOffset, &FragmentIndex, &FragmentCount, FragmentRing,
272+
VirtualAddressExtension, &FrameStore->Icmpv6Hdr, sizeof(FrameStore->Icmpv6Hdr), &FrameCache->Icmpv6Hdr);
273+
}
274+
}
275+
276+
static
277+
VOID
278+
XdpParseIcmp4Header(
279+
_In_ XDP_FRAME *Frame,
280+
_In_opt_ XDP_RING *FragmentRing,
281+
_In_opt_ XDP_EXTENSION *FragmentExtension,
282+
_In_ UINT32 FragmentIndex,
283+
_In_ XDP_EXTENSION *VirtualAddressExtension,
284+
_In_ XDP_PROGRAM_PAYLOAD_CACHE *Payload,
285+
_Inout_ XDP_PROGRAM_FRAME_STORAGE *FrameStore,
286+
_Inout_ XDP_PROGRAM_FRAME_CACHE *FrameCache
287+
)
288+
{
289+
UINT32 BufferDataOffset = Payload->BufferDataOffset;
290+
XDP_BUFFER *Buffer = Payload->Buffer;
291+
UCHAR *Va = XdpGetVirtualAddressExtension(Buffer, VirtualAddressExtension)->VirtualAddress + Buffer->DataOffset;
292+
FrameCache->Icmp4Cached = TRUE;
293+
294+
IPPROTO IpProto = IPPROTO_MAX;
295+
if (FrameCache->Ip4Valid) {
296+
IpProto = FrameCache->Ip4Hdr->Protocol;
297+
if (Buffer->DataLength < BufferDataOffset + sizeof(*FrameCache->Icmpv4Hdr)) {
298+
goto BufferTooSmall;
299+
}
300+
FrameCache->Icmp4Valid = TRUE;
301+
FrameCache->Icmpv4Hdr = (ICMP_HEADER *) &Va[BufferDataOffset];
302+
} else {
303+
return;
304+
}
305+
306+
BufferTooSmall:
307+
308+
if (FragmentRing != NULL) {
309+
ASSERT(FragmentExtension);
310+
XdpParseFragmentedIcmpHeader(
311+
Frame, FragmentRing, FragmentExtension, FragmentIndex, VirtualAddressExtension,
312+
IpProto, FrameStore, FrameCache);
313+
}
314+
}
315+
316+
static
317+
VOID
318+
XdpParseIcmp6Header(
319+
_In_ XDP_FRAME *Frame,
320+
_In_opt_ XDP_RING *FragmentRing,
321+
_In_opt_ XDP_EXTENSION *FragmentExtension,
322+
_In_ UINT32 FragmentIndex,
323+
_In_ XDP_EXTENSION *VirtualAddressExtension,
324+
_In_ XDP_PROGRAM_PAYLOAD_CACHE *Payload,
325+
_Inout_ XDP_PROGRAM_FRAME_STORAGE *FrameStore,
326+
_Inout_ XDP_PROGRAM_FRAME_CACHE *FrameCache
327+
)
328+
{
329+
UINT32 BufferDataOffset = Payload->BufferDataOffset;
330+
XDP_BUFFER *Buffer = Payload->Buffer;
331+
UCHAR *Va = XdpGetVirtualAddressExtension(Buffer, VirtualAddressExtension)->VirtualAddress + Buffer->DataOffset;
332+
FrameCache->Icmp6Cached = TRUE;
333+
334+
IPPROTO IpProto = IPPROTO_MAX;
335+
if (FrameCache->Ip6Valid) {
336+
IpProto = FrameCache->Ip6Hdr->NextHeader;
337+
if (Buffer->DataLength < BufferDataOffset + sizeof(*FrameCache->Icmpv6Hdr)) {
338+
goto BufferTooSmall;
339+
}
340+
FrameCache->Icmp6Valid = TRUE;
341+
FrameCache->Icmpv6Hdr = (ICMPV6_HEADER *) &Va[BufferDataOffset];
342+
} else {
343+
return;
344+
}
345+
346+
BufferTooSmall:
347+
348+
if (FragmentRing != NULL) {
349+
ASSERT(FragmentExtension);
350+
XdpParseFragmentedIcmpHeader(
351+
Frame, FragmentRing, FragmentExtension, FragmentIndex, VirtualAddressExtension,
352+
IpProto, FrameStore, FrameCache);
353+
}
354+
}
355+
235356
static
236357
VOID
237358
XdpParseFragmentedTcp(
@@ -1205,6 +1326,62 @@ XdpInspect(
12051326
}
12061327
break;
12071328

1329+
case XDP_MATCH_ICMPV4_ECHO_REPLY_IP_DST:
1330+
if (!FrameCache.Ip4Cached) {
1331+
XdpParseFrame(
1332+
Frame, FragmentRing, FragmentExtension, FragmentIndex, VirtualAddressExtension,
1333+
&FrameCache, &Program->FrameStorage);
1334+
}
1335+
1336+
if (!FrameCache.IpPayloadValid || !FrameCache.Ip4Valid) {
1337+
break;
1338+
}
1339+
1340+
if (!FrameCache.Icmp4Cached) {
1341+
XdpParseIcmp4Header(
1342+
Frame, FragmentRing, FragmentExtension, FragmentIndex, VirtualAddressExtension,
1343+
&FrameCache.IpPayload, &Program->FrameStorage, &FrameCache);
1344+
}
1345+
1346+
if (FrameCache.Icmp4Valid &&
1347+
FrameCache.Icmpv4Hdr->Type == ICMP4_ECHOREPLY_TYPE &&
1348+
FrameCache.Icmpv4Hdr->Code == ICMP4_ECHOREPLY_CODE &&
1349+
IN4_ADDR_EQUAL(
1350+
&FrameCache.Ip4Hdr->DestinationAddress,
1351+
&Rule->Pattern.IpMask.Address.Ipv4)) {
1352+
ASSERT(FrameCache.Ip4Valid);
1353+
Matched = TRUE;
1354+
}
1355+
break;
1356+
1357+
case XDP_MATCH_ICMPV6_ECHO_REPLY_IP_DST:
1358+
if (!FrameCache.Ip6Cached) {
1359+
XdpParseFrame(
1360+
Frame, FragmentRing, FragmentExtension, FragmentIndex, VirtualAddressExtension,
1361+
&FrameCache, &Program->FrameStorage);
1362+
}
1363+
1364+
if (!FrameCache.IpPayloadValid || !FrameCache.Ip6Valid) {
1365+
break;
1366+
}
1367+
1368+
if (!FrameCache.Icmp6Cached) {
1369+
XdpParseIcmp6Header(
1370+
Frame, FragmentRing, FragmentExtension, FragmentIndex, VirtualAddressExtension,
1371+
&FrameCache.IpPayload, &Program->FrameStorage, &FrameCache);
1372+
}
1373+
1374+
if (FrameCache.Icmp6Valid &&
1375+
FrameCache.Icmpv6Hdr->Type == ICMP6_ECHOREPLY_TYPE &&
1376+
FrameCache.Icmpv6Hdr->Code == ICMP6_ECHOREPLY_CODE &&
1377+
IN6_ADDR_EQUAL(
1378+
&FrameCache.Ip6Hdr->DestinationAddress,
1379+
&Rule->Pattern.IpMask.Address.Ipv6)) {
1380+
ASSERT(FrameCache.Ip6Valid);
1381+
Matched = TRUE;
1382+
}
1383+
break;
1384+
12081385
default:
12091386
ASSERT(FALSE);
12101387
break;
@@ -1355,7 +1532,7 @@ XdpProgramValidateRule(
13551532
//
13561533
RtlZeroMemory(ValidatedRule, sizeof(*ValidatedRule));
13571534

1358-
if (UserRule->Match < XDP_MATCH_ALL || UserRule->Match > XDP_MATCH_INNER_IPV6_DST_MASK_UDP) {
1535+
if (UserRule->Match < XDP_MATCH_ALL || UserRule->Match > XDP_MATCH_ICMPV6_ECHO_REPLY_IP_DST) {
13591536
Status = STATUS_INVALID_PARAMETER;
13601537
goto Exit;
13611538
}

src/xdp/programinspect.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ typedef struct _XDP_PROGRAM_FRAME_STORAGE {
4747
union {
4848
UDP_HDR UdpHdr;
4949
TCP_HDR TcpHdr;
50+
ICMP_HEADER Icmpv4Hdr;
51+
ICMPV6_HEADER Icmpv6Hdr;
5052
};
5153
UINT8 TcpHdrOptions[40]; // Up to 40B options/paddings
5254
// Invariant header + 1 for SourceCidLength + 2x CIDS
@@ -86,6 +88,10 @@ typedef struct _XDP_PROGRAM_FRAME_CACHE {
8688
UINT32 QuicCached : 1;
8789
UINT32 QuicValid : 1;
8890
UINT32 QuicIsLongHeader : 1;
91+
UINT32 Icmp4Cached : 1;
92+
UINT32 Icmp4Valid : 1;
93+
UINT32 Icmp6Cached : 1;
94+
UINT32 Icmp6Valid : 1;
8995
};
9096
UINT32 Flags;
9197
};
@@ -102,6 +108,8 @@ typedef struct _XDP_PROGRAM_FRAME_CACHE {
102108
union {
103109
UDP_HDR *UdpHdr;
104110
TCP_HDR *TcpHdr;
111+
ICMP_HEADER *Icmpv4Hdr;
112+
ICMPV6_HEADER *Icmpv6Hdr;
105113
};
106114
UINT8 *TcpHdrOptions;
107115
UINT8 QuicCidLength;

0 commit comments

Comments
 (0)