Skip to content

Commit 9ad5cb6

Browse files
Merge pull request #1287 from Luap99/test-fixes
Introduce our own test helper instead of using ncat.
2 parents 4ceabbb + f7c3883 commit 9ad5cb6

File tree

8 files changed

+207
-179
lines changed

8 files changed

+207
-179
lines changed

.cargo/config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[target.'cfg(linux)']
2+
runner = 'unshare -rn'

Cargo.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,16 @@ tier = "2"
2121
name = "netavark"
2222
path = "src/main.rs"
2323

24+
25+
# Only used for testing, do not ship to end users.
2426
[[bin]]
2527
name = "netavark-dhcp-proxy-client"
2628
path = "src/dhcp_proxy_client/client.rs"
2729

30+
[[bin]]
31+
name = "netavark-connection-tester"
32+
path = "src/test/main.rs"
33+
2834
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
2935
[dependencies]
3036
anyhow = "1.0.93"
@@ -37,7 +43,7 @@ log = "0.4.27"
3743
serde = { version = "1.0.219", features = ["derive"] }
3844
serde_json = "1.0.141"
3945
zbus = { version = "5.9.0" }
40-
nix = { version = "0.30.1", features = ["sched", "signal", "user"] }
46+
nix = { version = "0.30.1", features = ["net", "sched", "signal", "socket", "user"] }
4147
rand = "0.9.2"
4248
sha2 = "0.10.9"
4349
netlink-packet-route = "0.23.0"

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ bin/netavark: $(SOURCES) bin $(CARGO_TARGET_DIR)
5858
$(CARGO) build $(release)
5959
cp $(CARGO_TARGET_DIR)/$(profile)/netavark bin/netavark
6060
cp $(CARGO_TARGET_DIR)/$(profile)/netavark-dhcp-proxy-client bin/netavark-dhcp-proxy-client
61+
cp $(CARGO_TARGET_DIR)/$(profile)/netavark-connection-tester bin/netavark-connection-tester
6162

6263

6364
.PHONY: examples

src/network/core_utils.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,7 @@ pub fn join_netns<Fd: AsFd>(fd: Fd) -> NetavarkResult<()> {
259259

260260
/// safe way to join the namespace and join back to the host after the task is done
261261
/// This first arg should be the hostns fd, the second is the container ns fd.
262-
/// The third is the result variable name and the last the closure that should be
263-
/// executed in the ns.
262+
/// The third and last the closure that should be executed in the ns.
264263
#[macro_export]
265264
macro_rules! exec_netns {
266265
($host:expr, $netns:expr, $exec:expr) => {{

src/test/main.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
//! Test program only, unsupported outside of our test suite.
2+
use std::{
3+
io::Read,
4+
os::fd::{AsRawFd, OwnedFd},
5+
};
6+
7+
use netavark::exec_netns;
8+
use netavark::network::core_utils::join_netns;
9+
use nix::sys::socket;
10+
11+
fn main() -> Result<(), Box<dyn std::error::Error>> {
12+
let mut args = std::env::args();
13+
_ = args.next(); // skip argv0
14+
15+
let mut i = 0;
16+
let mut netns = String::new();
17+
let mut connect = String::new();
18+
let mut listen = String::new();
19+
20+
let mut sock_type = socket::SockType::Stream;
21+
let mut protocol = socket::SockProtocol::Tcp;
22+
23+
for arg in args {
24+
match arg.as_str() {
25+
"--tcp" => {
26+
protocol = socket::SockProtocol::Tcp;
27+
sock_type = socket::SockType::Stream;
28+
}
29+
"--udp" => {
30+
protocol = socket::SockProtocol::Udp;
31+
sock_type = socket::SockType::Datagram;
32+
}
33+
"--sctp" => {
34+
protocol = socket::SockProtocol::Sctp;
35+
sock_type = socket::SockType::Stream;
36+
}
37+
_ => {
38+
match i {
39+
0 => netns = arg,
40+
1 => connect = arg,
41+
2 => listen = arg,
42+
_ => {
43+
eprintln!("To many arguments\nUsage: NETNS CONNECT_ADDRESS LISTEN_PORT");
44+
std::process::exit(1)
45+
}
46+
};
47+
i += 1;
48+
}
49+
}
50+
}
51+
52+
let hostns = std::fs::File::open("/proc/self/ns/net").expect("open host netns");
53+
let containerns = std::fs::File::open(netns).expect("open netns");
54+
55+
let connect_addr: std::net::SocketAddr =
56+
connect.parse().expect("failed to parse connect address");
57+
58+
let listen_port: u16 = listen.parse().expect("parse listne port");
59+
60+
let (address_family, listen_addr) = match connect_addr {
61+
std::net::SocketAddr::V4(_) => (
62+
socket::AddressFamily::Inet,
63+
std::net::SocketAddr::V4(std::net::SocketAddrV4::new(
64+
std::net::Ipv4Addr::UNSPECIFIED,
65+
listen_port,
66+
)),
67+
),
68+
std::net::SocketAddr::V6(_) => (
69+
socket::AddressFamily::Inet6,
70+
std::net::SocketAddr::V6(std::net::SocketAddrV6::new(
71+
std::net::Ipv6Addr::UNSPECIFIED,
72+
listen_port,
73+
0,
74+
0,
75+
)),
76+
),
77+
};
78+
79+
// create socket in namespace
80+
let listen_sock = exec_netns!(&hostns, &containerns, {
81+
let listen_sock = socket::socket(
82+
address_family,
83+
sock_type,
84+
socket::SockFlag::empty(),
85+
Some(protocol),
86+
)
87+
.expect("listen socket");
88+
89+
socket::bind(
90+
listen_sock.as_raw_fd(),
91+
&socket::SockaddrStorage::from(listen_addr),
92+
)
93+
.expect("bind listen socket");
94+
95+
listen_sock
96+
});
97+
98+
let connect_sock = socket::socket(
99+
address_family,
100+
sock_type,
101+
socket::SockFlag::empty(),
102+
Some(protocol),
103+
)
104+
.expect("connect socket");
105+
106+
let mut send_buf = Vec::new();
107+
std::io::stdin()
108+
.read_to_end(&mut send_buf)
109+
.expect("read stdin");
110+
111+
match sock_type {
112+
socket::SockType::Stream => stream_test(listen_sock, connect_sock, connect_addr, &send_buf),
113+
socket::SockType::Datagram => {
114+
datagram_test(listen_sock, connect_sock, connect_addr, &send_buf)
115+
}
116+
_ => unreachable!(),
117+
}
118+
119+
Ok(())
120+
}
121+
122+
fn stream_test(
123+
listen_sock: OwnedFd,
124+
connect_sock: OwnedFd,
125+
connect_addr: std::net::SocketAddr,
126+
buf: &[u8],
127+
) {
128+
socket::listen(&listen_sock, socket::Backlog::new(5).unwrap()).expect("listen on socket");
129+
130+
socket::connect(
131+
connect_sock.as_raw_fd(),
132+
&socket::SockaddrStorage::from(connect_addr),
133+
)
134+
.expect("connect to remote socket");
135+
136+
let conn = socket::accept4(listen_sock.as_raw_fd(), socket::SockFlag::empty())
137+
.expect("accept connection");
138+
139+
let peer_addr = socket::getpeername::<socket::SockaddrStorage>(conn).expect("getpeername");
140+
println!("Peer address: {peer_addr}");
141+
142+
socket::send(connect_sock.as_raw_fd(), buf, socket::MsgFlags::empty()).expect("send msg");
143+
144+
let mut read_buf = vec![0; buf.len()];
145+
146+
let len = socket::recv(conn, &mut read_buf, socket::MsgFlags::empty()).expect("recv msg");
147+
148+
println!(
149+
"Message: {}",
150+
std::str::from_utf8(&read_buf[..len]).expect("parse msg")
151+
);
152+
}
153+
154+
fn datagram_test(
155+
listen_sock: OwnedFd,
156+
connect_sock: OwnedFd,
157+
connect_addr: std::net::SocketAddr,
158+
buf: &[u8],
159+
) {
160+
socket::sendto(
161+
connect_sock.as_raw_fd(),
162+
buf,
163+
&socket::SockaddrStorage::from(connect_addr),
164+
socket::MsgFlags::empty(),
165+
)
166+
.expect("sendto msg");
167+
168+
let mut read_buf = vec![0; buf.len()];
169+
170+
let (len, peer_addr) =
171+
socket::recvfrom::<socket::SockaddrStorage>(listen_sock.as_raw_fd(), &mut read_buf)
172+
.expect("recvfrom msg");
173+
174+
let peer_addr = peer_addr.expect("no peer address");
175+
println!("Peer address: {peer_addr}");
176+
177+
println!(
178+
"Message: {}",
179+
std::str::from_utf8(&read_buf[..len]).expect("parse msg")
180+
);
181+
}

test/100-bridge-iptables.bats

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ fw_driver=iptables
590590
assert "2" "rp_filter eth1 interface"
591591

592592
# Important: Use the "host" ip here and not localhost or bridge ip.
593-
run_nc_test "0" "tcp" 8080 "10.0.0.1" 8080
593+
run_connection_test "0" "tcp" 8080 "10.0.0.1" 8080
594594
}
595595

596596
@test "bridge ipam none" {

test/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,3 @@ The tests need root privileges to create network namespaces, so you either have
1414
- iptables
1515
- firewalld
1616
- dbus-daemon
17-
- ncat (NMAP)

0 commit comments

Comments
 (0)