1 #[allow(dead_code)]
2 mod common;
3
4 use std::net::IpAddr;
5 use std::net::Ipv4Addr;
6 use std::net::Ipv6Addr;
7 use std::net::TcpListener;
8 use std::net::TcpStream;
9
10 use libbpf_rs::NetfilterOpts;
11 use libbpf_rs::Object;
12
13 use libbpf_rs::NFPROTO_IPV4;
14 use libbpf_rs::NFPROTO_IPV6;
15
16 use libbpf_rs::NF_INET_POST_ROUTING;
17 use libbpf_rs::NF_INET_PRE_ROUTING;
18
19 use crate::common::bump_rlimit_mlock;
20 use crate::common::get_map_mut;
21 use crate::common::get_prog_mut;
22 use crate::common::get_test_object;
23 use crate::common::with_ringbuffer;
24 use test_tag::tag;
25
26
test_attach_and_detach(obj: &mut Object, protocol_family: i32, hooknum: i32, hook_desc: &str)27 fn test_attach_and_detach(obj: &mut Object, protocol_family: i32, hooknum: i32, hook_desc: &str) {
28 let prog = get_prog_mut(obj, "handle_netfilter");
29 let netfilter_opt = libbpf_rs::NetfilterOpts {
30 protocol_family,
31 hooknum,
32 ..NetfilterOpts::default()
33 };
34 let link = prog
35 .attach_netfilter_with_opts(netfilter_opt)
36 .unwrap_or_else(|err| {
37 panic!(
38 "Failed to attach netfilter protocol {}, hook: {}: {err}",
39 protocol_family, hook_desc
40 )
41 });
42
43 let map = get_map_mut(obj, "ringbuf");
44
45 let addr = match protocol_family {
46 NFPROTO_IPV4 => IpAddr::V4(Ipv4Addr::LOCALHOST),
47 NFPROTO_IPV6 => IpAddr::V6(Ipv6Addr::LOCALHOST),
48 _ => panic!("unknow protocol family: {protocol_family}"),
49 };
50 // We let the kernel decide what port to bind to.
51 let listener = TcpListener::bind((addr, 0)).unwrap();
52 let trigger_addr = listener.local_addr().unwrap();
53
54 let result = match hooknum {
55 NF_INET_PRE_ROUTING | NF_INET_POST_ROUTING => {
56 let action = || {
57 let _ = TcpStream::connect(trigger_addr);
58 };
59 with_ringbuffer(&map, action)
60 }
61 _ => panic!("unsupported hook: {hooknum} ({hook_desc})"),
62 };
63 assert_eq!(result, 1);
64 assert!(link.detach().is_ok());
65 }
66
67 #[tag(root)]
68 #[test]
test_netfilter()69 fn test_netfilter() {
70 bump_rlimit_mlock();
71 let mut obj = get_test_object("netfilter.bpf.o");
72
73 // We don't test all hooks here, because support for some may be
74 // more limited.
75
76 // IPv4 hook
77 test_attach_and_detach(&mut obj, NFPROTO_IPV4, NF_INET_PRE_ROUTING, "PRE_ROUTING");
78 test_attach_and_detach(&mut obj, NFPROTO_IPV4, NF_INET_POST_ROUTING, "POST_ROUTING");
79
80 // IPv6 hook
81 test_attach_and_detach(&mut obj, NFPROTO_IPV6, NF_INET_PRE_ROUTING, "PRE_ROUTING");
82 test_attach_and_detach(&mut obj, NFPROTO_IPV6, NF_INET_POST_ROUTING, "POST_ROUTING");
83 }
84
85 #[tag(root)]
86 #[test]
test_invalid_netfilter_opts()87 fn test_invalid_netfilter_opts() {
88 let mut obj = get_test_object("netfilter.bpf.o");
89 let prog = get_prog_mut(&mut obj, "handle_netfilter");
90
91 let invalid_opts = NetfilterOpts {
92 protocol_family: 999,
93 hooknum: 999,
94 ..NetfilterOpts::default()
95 };
96
97 let result = prog.attach_netfilter_with_opts(invalid_opts);
98 assert!(
99 result.is_err(),
100 "Expected error for invalid NetfilterOpts, but got Ok."
101 );
102 }
103