Skip to content

Commit d2aad90

Browse files
bpf: test: add BPF Masq tests for unknown / handled protocols
For better or worse, currently expected behaviour for the NAT engine is 1. let completely unhandled protocol types (like IPIP) pass through, and 2. drop unhandled ICMP types (like ICMP_TIMESTAMP or ICMPV6_PARAMPROB). Add a few corresponding tests. Fixes: cilium#10541 Signed-off-by: Julian Wiedmann <jwi@isovalent.com>
1 parent a8d06cd commit d2aad90

1 file changed

Lines changed: 390 additions & 0 deletions

File tree

bpf/tests/host_bpf_masq.c

Lines changed: 390 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,390 @@
1+
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2+
/* Copyright Authors of Cilium */
3+
4+
#include <bpf/ctx/skb.h>
5+
#include "common.h"
6+
#include "pktgen.h"
7+
8+
/* Enable code paths under test */
9+
#define ENABLE_IPV4 1
10+
#define ENABLE_IPV6 1
11+
12+
#define ENABLE_MASQUERADE_IPV4 1
13+
#define ENABLE_MASQUERADE_IPV6 1
14+
15+
#define ENABLE_NODEPORT 1
16+
17+
#define NODE_IP v4_node_one
18+
#define NODE_IP_V6 v6_node_one
19+
#define NODE_PORT bpf_htons(50000)
20+
21+
#define SERVER_IP v4_ext_one
22+
#define SERVER_IP_V6 v6_ext_node_one
23+
#define SERVER_PORT bpf_htons(80)
24+
25+
#include <bpf/config/node.h>
26+
27+
static volatile const __u8 *node_mac = mac_one;
28+
static volatile const __u8 *server_mac = mac_two;
29+
30+
#include "lib/bpf_host.h"
31+
32+
ASSIGN_CONFIG(union v4addr, nat_ipv4_masquerade, { .be32 = NODE_IP})
33+
ASSIGN_CONFIG(union v6addr, nat_ipv6_masquerade, { .addr = v6_node_one_addr})
34+
35+
#include "lib/endpoint.h"
36+
#include "lib/ipcache.h"
37+
38+
/* Host-originating UDP should be tracked by BPF Masq. */
39+
PKTGEN("tc", "host_bpf_masq_v4_1_udp")
40+
int host_bpf_masq_v4_1_udp_pktgen(struct __ctx_buff *ctx)
41+
{
42+
struct pktgen builder;
43+
struct udphdr *udp;
44+
45+
/* Init packet builder */
46+
pktgen__init(&builder, ctx);
47+
48+
udp = pktgen__push_ipv4_udp_packet(&builder,
49+
(__u8 *)node_mac, (__u8 *)server_mac,
50+
NODE_IP, SERVER_IP,
51+
NODE_PORT, SERVER_PORT);
52+
if (!udp)
53+
return TEST_ERROR;
54+
55+
/* Calc lengths, set protocol fields and calc checksums */
56+
pktgen__finish(&builder);
57+
58+
return 0;
59+
}
60+
61+
SETUP("tc", "host_bpf_masq_v4_1_udp")
62+
int host_bpf_masq_v4_1_udp_setup(struct __ctx_buff *ctx)
63+
{
64+
endpoint_v4_add_entry(NODE_IP, 0, 0, ENDPOINT_F_HOST, HOST_ID,
65+
0, (__u8 *)node_mac, (__u8 *)node_mac);
66+
ipcache_v4_add_entry(NODE_IP, 0, HOST_ID, 0, 0);
67+
ipcache_v4_add_world_entry();
68+
69+
set_identity_mark(ctx, 0, MARK_MAGIC_HOST);
70+
71+
return netdev_send_packet(ctx);
72+
}
73+
74+
CHECK("tc", "host_bpf_masq_v4_1_udp")
75+
int host_bpf_masq_v4_1_udp_check(const struct __ctx_buff *ctx)
76+
{
77+
void *data, *data_end;
78+
__u32 *status_code;
79+
80+
test_init();
81+
82+
data = (void *)(long)ctx_data(ctx);
83+
data_end = (void *)(long)ctx->data_end;
84+
85+
if (data + sizeof(__u32) > data_end)
86+
test_fatal("status code out of bounds");
87+
88+
status_code = data;
89+
90+
assert(*status_code == CTX_ACT_OK);
91+
92+
/* Check whether BPF MASQ created a CT entry */
93+
struct ipv4_ct_tuple tuple = {
94+
.daddr = NODE_IP,
95+
.saddr = SERVER_IP,
96+
.dport = SERVER_PORT,
97+
.sport = NODE_PORT,
98+
.nexthdr = IPPROTO_UDP,
99+
.flags = TUPLE_F_OUT,
100+
};
101+
struct ct_entry *ct_entry = map_lookup_elem(get_ct_map4(&tuple), &tuple);
102+
103+
if (!ct_entry)
104+
test_fatal("no CT entry found");
105+
106+
assert(ct_entry->packets == 1);
107+
108+
test_finish();
109+
}
110+
111+
PKTGEN("tc", "host_bpf_masq_v6_1_udp")
112+
int host_bpf_masq_v6_1_udp_pktgen(struct __ctx_buff *ctx)
113+
{
114+
struct pktgen builder;
115+
struct udphdr *udp;
116+
117+
/* Init packet builder */
118+
pktgen__init(&builder, ctx);
119+
120+
udp = pktgen__push_ipv6_udp_packet(&builder,
121+
(__u8 *)node_mac, (__u8 *)server_mac,
122+
(__u8 *)NODE_IP_V6, (__u8 *)SERVER_IP_V6,
123+
NODE_PORT, SERVER_PORT);
124+
if (!udp)
125+
return TEST_ERROR;
126+
127+
/* Calc lengths, set protocol fields and calc checksums */
128+
pktgen__finish(&builder);
129+
130+
return 0;
131+
}
132+
133+
SETUP("tc", "host_bpf_masq_v6_1_udp")
134+
int host_bpf_masq_v6_1_udp_setup(struct __ctx_buff *ctx)
135+
{
136+
endpoint_v6_add_entry((union v6addr *)NODE_IP_V6, 0, 0, ENDPOINT_F_HOST, HOST_ID,
137+
(__u8 *)node_mac, (__u8 *)node_mac);
138+
ipcache_v6_add_entry((union v6addr *)NODE_IP_V6, 0, HOST_ID, 0, 0);
139+
ipcache_v6_add_world_entry();
140+
141+
set_identity_mark(ctx, 0, MARK_MAGIC_HOST);
142+
143+
return netdev_send_packet(ctx);
144+
}
145+
146+
CHECK("tc", "host_bpf_masq_v6_1_udp")
147+
int host_bpf_masq_v6_1_udp_check(const struct __ctx_buff *ctx)
148+
{
149+
void *data, *data_end;
150+
__u32 *status_code;
151+
152+
test_init();
153+
154+
data = (void *)(long)ctx_data(ctx);
155+
data_end = (void *)(long)ctx->data_end;
156+
157+
if (data + sizeof(__u32) > data_end)
158+
test_fatal("status code out of bounds");
159+
160+
status_code = data;
161+
162+
assert(*status_code == CTX_ACT_OK);
163+
164+
/* Check whether BPF MASQ created a CT entry */
165+
struct ipv6_ct_tuple tuple = {
166+
.dport = SERVER_PORT,
167+
.sport = NODE_PORT,
168+
.nexthdr = IPPROTO_UDP,
169+
.flags = TUPLE_F_OUT,
170+
};
171+
ipv6_addr_copy(&tuple.daddr, (union v6addr *)NODE_IP_V6);
172+
ipv6_addr_copy(&tuple.saddr, (union v6addr *)SERVER_IP_V6);
173+
174+
struct ct_entry *ct_entry = map_lookup_elem(get_ct_map6(&tuple), &tuple);
175+
176+
if (!ct_entry)
177+
test_fatal("no CT entry found");
178+
179+
assert(ct_entry->packets == 1);
180+
181+
test_finish();
182+
}
183+
184+
/* Host-originating IPIP should be skipped by BPF Masq. */
185+
PKTGEN("tc", "host_bpf_masq_v4_2_ipip")
186+
int host_bpf_masq_v4_2_ipip_pktgen(struct __ctx_buff *ctx)
187+
{
188+
struct pktgen builder;
189+
struct iphdr *ip4;
190+
191+
/* Init packet builder */
192+
pktgen__init(&builder, ctx);
193+
194+
ip4 = pktgen__push_ipv4_packet(&builder,
195+
(__u8 *)node_mac, (__u8 *)server_mac,
196+
NODE_IP, SERVER_IP);
197+
if (!ip4)
198+
return TEST_ERROR;
199+
200+
ip4->protocol = IPPROTO_IPIP;
201+
202+
/* Calc lengths, set protocol fields and calc checksums */
203+
pktgen__finish(&builder);
204+
205+
return 0;
206+
}
207+
208+
SETUP("tc", "host_bpf_masq_v4_2_ipip")
209+
int host_bpf_masq_v4_2_ipip_setup(struct __ctx_buff *ctx)
210+
{
211+
set_identity_mark(ctx, 0, MARK_MAGIC_HOST);
212+
213+
return netdev_send_packet(ctx);
214+
}
215+
216+
CHECK("tc", "host_bpf_masq_v4_2_ipip")
217+
int host_bpf_masq_v4_2_ipip_check(const struct __ctx_buff *ctx)
218+
{
219+
void *data, *data_end;
220+
__u32 *status_code;
221+
222+
test_init();
223+
224+
data = (void *)(long)ctx_data(ctx);
225+
data_end = (void *)(long)ctx->data_end;
226+
227+
if (data + sizeof(__u32) > data_end)
228+
test_fatal("status code out of bounds");
229+
230+
status_code = data;
231+
232+
assert(*status_code == CTX_ACT_OK);
233+
234+
test_finish();
235+
}
236+
237+
PKTGEN("tc", "host_bpf_masq_v6_2_ipip")
238+
int host_bpf_masq_v6_2_ipip_pktgen(struct __ctx_buff *ctx)
239+
{
240+
struct pktgen builder;
241+
struct ipv6hdr *ip6;
242+
243+
/* Init packet builder */
244+
pktgen__init(&builder, ctx);
245+
246+
ip6 = pktgen__push_ipv6_packet(&builder,
247+
(__u8 *)node_mac, (__u8 *)server_mac,
248+
(__u8 *)NODE_IP_V6, (__u8 *)SERVER_IP_V6);
249+
if (!ip6)
250+
return TEST_ERROR;
251+
252+
ip6->nexthdr = IPPROTO_IPIP;
253+
254+
/* Calc lengths, set protocol fields and calc checksums */
255+
pktgen__finish(&builder);
256+
257+
return 0;
258+
}
259+
260+
SETUP("tc", "host_bpf_masq_v6_2_ipip")
261+
int host_bpf_masq_v6_2_ipip_setup(struct __ctx_buff *ctx)
262+
{
263+
set_identity_mark(ctx, 0, MARK_MAGIC_HOST);
264+
265+
return netdev_send_packet(ctx);
266+
}
267+
268+
CHECK("tc", "host_bpf_masq_v6_2_ipip")
269+
int host_bpf_masq_v6_2_ipip_check(const struct __ctx_buff *ctx)
270+
{
271+
void *data, *data_end;
272+
__u32 *status_code;
273+
274+
test_init();
275+
276+
data = (void *)(long)ctx_data(ctx);
277+
data_end = (void *)(long)ctx->data_end;
278+
279+
if (data + sizeof(__u32) > data_end)
280+
test_fatal("status code out of bounds");
281+
282+
status_code = data;
283+
284+
assert(*status_code == CTX_ACT_OK);
285+
286+
test_finish();
287+
}
288+
289+
/* Host-originating unhandled ICMP should be dropped by BPF Masq. */
290+
PKTGEN("tc", "host_bpf_masq_v4_3_icmp_unhandled")
291+
int host_bpf_masq_v4_3_icmp_unhandled_pktgen(struct __ctx_buff *ctx)
292+
{
293+
struct pktgen builder;
294+
struct icmphdr *icmp;
295+
296+
/* Init packet builder */
297+
pktgen__init(&builder, ctx);
298+
299+
icmp = pktgen__push_ipv4_icmp_packet(&builder,
300+
(__u8 *)node_mac, (__u8 *)server_mac,
301+
NODE_IP, SERVER_IP,
302+
ICMP_TIMESTAMP);
303+
if (!icmp)
304+
return TEST_ERROR;
305+
306+
/* Calc lengths, set protocol fields and calc checksums */
307+
pktgen__finish(&builder);
308+
309+
return 0;
310+
}
311+
312+
SETUP("tc", "host_bpf_masq_v4_3_icmp_unhandled")
313+
int host_bpf_masq_v4_3_icmp_unhandledp_setup(struct __ctx_buff *ctx)
314+
{
315+
set_identity_mark(ctx, 0, MARK_MAGIC_HOST);
316+
317+
return netdev_send_packet(ctx);
318+
}
319+
320+
CHECK("tc", "host_bpf_masq_v4_3_icmp_unhandled")
321+
int host_bpf_masq_v4_3_icmp_timestamp_check(const struct __ctx_buff *ctx)
322+
{
323+
void *data, *data_end;
324+
__u32 *status_code;
325+
326+
test_init();
327+
328+
data = (void *)(long)ctx_data(ctx);
329+
data_end = (void *)(long)ctx->data_end;
330+
331+
if (data + sizeof(__u32) > data_end)
332+
test_fatal("status code out of bounds");
333+
334+
status_code = data;
335+
336+
assert(*status_code == CTX_ACT_DROP);
337+
338+
test_finish();
339+
}
340+
341+
PKTGEN("tc", "host_bpf_masq_v6_3_icmp_unhandled")
342+
int host_bpf_masq_v6_3_icmp_unhandled_pktgen(struct __ctx_buff *ctx)
343+
{
344+
struct pktgen builder;
345+
struct icmp6hdr *icmp;
346+
347+
/* Init packet builder */
348+
pktgen__init(&builder, ctx);
349+
350+
icmp = pktgen__push_ipv6_icmp6_packet(&builder,
351+
(__u8 *)node_mac, (__u8 *)server_mac,
352+
(__u8 *)NODE_IP_V6, (__u8 *)SERVER_IP_V6,
353+
ICMPV6_PARAMPROB);
354+
if (!icmp)
355+
return TEST_ERROR;
356+
357+
/* Calc lengths, set protocol fields and calc checksums */
358+
pktgen__finish(&builder);
359+
360+
return 0;
361+
}
362+
363+
SETUP("tc", "host_bpf_masq_v6_3_icmp_unhandled")
364+
int host_bpf_masq_v6_3_icmp_unhandled_setup(struct __ctx_buff *ctx)
365+
{
366+
set_identity_mark(ctx, 0, MARK_MAGIC_HOST);
367+
368+
return netdev_send_packet(ctx);
369+
}
370+
371+
CHECK("tc", "host_bpf_masq_v6_3_icmp_unhandled")
372+
int host_bpf_masq_v6_3_icmp_unhandled_check(const struct __ctx_buff *ctx)
373+
{
374+
void *data, *data_end;
375+
__u32 *status_code;
376+
377+
test_init();
378+
379+
data = (void *)(long)ctx_data(ctx);
380+
data_end = (void *)(long)ctx->data_end;
381+
382+
if (data + sizeof(__u32) > data_end)
383+
test_fatal("status code out of bounds");
384+
385+
status_code = data;
386+
387+
assert(*status_code == CTX_ACT_DROP);
388+
389+
test_finish();
390+
}

0 commit comments

Comments
 (0)