From 205f288e1dfebfb049621528d38c9723105bea55 Mon Sep 17 00:00:00 2001 From: b-m-f Date: Thu, 3 Nov 2022 14:22:28 +0100 Subject: [PATCH] WIP: adds testing and begin interface creation --- src/commands/setup.rs | 1 - src/network/NOTES.md | 3 ++ src/network/netlink.rs | 19 +++++++++-- src/network/wireguard.rs | 59 ++++++++++++++++++++++++----------- test/400-wireguard.bats | 40 ++++++++++++++++++++++++ test/testfiles/wireguard.json | 18 +++++------ 6 files changed, 107 insertions(+), 33 deletions(-) create mode 100644 test/400-wireguard.bats diff --git a/src/commands/setup.rs b/src/commands/setup.rs index 1ca5bf3f6..24c1e803b 100644 --- a/src/commands/setup.rs +++ b/src/commands/setup.rs @@ -42,7 +42,6 @@ impl Setup { } } debug!("{:?}", "Setting up..."); - // TODO_WG: load wg-config file here let network_options = network::types::NetworkOptions::load(input_file)?; let firewall_driver = match firewall::get_supported_firewall_driver() { diff --git a/src/network/NOTES.md b/src/network/NOTES.md index 1100e7086..62be74160 100644 --- a/src/network/NOTES.md +++ b/src/network/NOTES.md @@ -4,6 +4,9 @@ - properly parse config - set up interface +## To change +create network interface name from podman + ## To test - interface config without - address diff --git a/src/network/netlink.rs b/src/network/netlink.rs index 8f2951537..ecf324191 100644 --- a/src/network/netlink.rs +++ b/src/network/netlink.rs @@ -9,10 +9,13 @@ use crate::{ }; use log::trace; use netlink_packet_route::{ + constants::AF_UNSPEC, nlas::link::{Info, InfoData, InfoKind, Nla}, - AddressMessage, LinkMessage, NetlinkHeader, NetlinkMessage, NetlinkPayload, RouteMessage, - RtnlMessage, AF_INET, AF_INET6, IFF_UP, NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, NLM_F_EXCL, - NLM_F_REQUEST, RTN_UNICAST, RTPROT_STATIC, RTPROT_UNSPEC, RT_SCOPE_UNIVERSE, RT_TABLE_MAIN, + nlas::nsid, + AddressMessage, LinkMessage, NetlinkHeader, NetlinkMessage, NetlinkPayload, NsidMessage, + RouteMessage, RtnlMessage, AF_INET, AF_INET6, IFF_UP, NLM_F_ACK, NLM_F_CREATE, NLM_F_DUMP, + NLM_F_EXCL, NLM_F_REQUEST, RTN_UNICAST, RTPROT_STATIC, RTPROT_UNSPEC, RT_SCOPE_UNIVERSE, + RT_TABLE_MAIN, }; use netlink_sys::{protocols::NETLINK_ROUTE, SocketAddr}; @@ -154,6 +157,16 @@ impl Socket { Ok(()) } + pub fn set_link_ns(&mut self, link_id: u32, netns_fd: i32) -> NetavarkResult<()> { + let mut msg = LinkMessage::default(); + msg.header.index = link_id; + msg.nlas.push(Nla::NetNsFd(netns_fd)); + + let result = self.make_netlink_request(RtnlMessage::SetLink(msg), NLM_F_ACK)?; + expect_netlink_result!(result, 0); + Ok(()) + } + fn create_addr_msg(link_id: u32, addr: &ipnet::IpNet) -> AddressMessage { let mut msg = AddressMessage::default(); msg.header.index = link_id; diff --git a/src/network/wireguard.rs b/src/network/wireguard.rs index bfefaabda..a9f2d0619 100644 --- a/src/network/wireguard.rs +++ b/src/network/wireguard.rs @@ -70,9 +70,9 @@ impl driver::NetworkDriver for WireGuard<'_> { } fn validate(&mut self) -> NetavarkResult<()> { - if self.info.per_network_opts.interface_name.is_empty() { - return Err(NetavarkError::msg(NO_CONTAINER_INTERFACE_ERROR)); - } + // if self.info.per_network_opts.interface_name.is_empty() { + // return Err(NetavarkError::msg(NO_CONTAINER_INTERFACE_ERROR)); + // } // TODO_WG: Document the option const WIREGUARD_CONFIG_PATH_OPTION: &str = "wireguard_config_path"; @@ -154,10 +154,9 @@ impl driver::NetworkDriver for WireGuard<'_> { let (host_sock, netns_sock) = netlink_sockets; - let container_wireguard_interface = setup( + let container_wireguard_interface = create_wireguard_interface( host_sock, netns_sock, - &self.info.per_network_opts.interface_name, data, self.info.netns_host, self.info.netns_container, @@ -193,30 +192,52 @@ impl driver::NetworkDriver for WireGuard<'_> { } } -fn setup( +fn create_wireguard_interface( host: &mut netlink::Socket, netns: &mut netlink::Socket, - if_name: &str, data: &InternalData, hostns_fd: RawFd, netns_fd: RawFd, ) -> NetavarkResult { // TODO_WG: set up interface on host - let mut create_link_opts = CreateLinkOptions::new(if_name.to_string(), InfoKind::Wireguard); + let mut create_link_opts = + CreateLinkOptions::new(data.interface_name.to_string(), InfoKind::Wireguard); create_link_opts.mtu = data.mtu as u32; + debug!( + "Creating WireGuard interface {}", + data.interface_name.to_string() + ); host.create_link(create_link_opts.clone()) - .wrap("create WireGuard interface: {}"); + .wrap("create WireGuard interface: {}")?; let link = host - .get_link(netlink::LinkID::Name( - data.bridge_interface_name.to_string(), - )) - .wrap("get bridge interface")?; + .get_link(netlink::LinkID::Name(data.interface_name.to_string())) + .wrap("get WireGuard interface")?; + + for addr in &data.addresses { + debug!( + "Adding Address {} to WireGuard interface {}", + addr, + data.interface_name.to_string() + ); + host.add_addr(link.header.index, addr) + .wrap("add ip addr to WireGuard interface")?; + } // TODO_WG: move interface into container namespace - // TODO_WG: set up routes using AllowedIPs and Address + debug!( + "Moving WireGuard interface {} from namespace {} to container namespace {}", + data.interface_name.to_string(), + hostns_fd, + netns_fd + ); + host.set_link_ns(link.header.index, netns_fd) + .wrap("moving WireGuard interface to container network namespace")?; + + Ok(data.interface_name.clone()) + // // let master_ifname = match data.host_interface_name.as_ref() { // "" => get_default_route_interface(host)?, @@ -260,9 +281,9 @@ fn setup( // } // } // - Err(NetavarkError::msg( - "failed to get the mac address from the container veth interface", - )) + // Err(NetavarkError::msg( + // "failed to get the mac address from the container veth interface", + // )) } fn get_default_route_interface(host: &mut netlink::Socket) -> NetavarkResult { @@ -445,8 +466,8 @@ fn parse_config(path: &String) -> Result { } } - let random_string: String = Alphanumeric.sample_string(&mut thread_rng(), 12); - interface.interface_name = format!("wg-{}", random_string); + // TODO_WG: pass interface name from outside + interface.interface_name = "wg-test".to_string(); interface.peers = peers; return Ok(interface); diff --git a/test/400-wireguard.bats b/test/400-wireguard.bats new file mode 100644 index 000000000..7f2653782 --- /dev/null +++ b/test/400-wireguard.bats @@ -0,0 +1,40 @@ +#!/usr/bin/env bats -*- bats -*- +# +# macvlan driver test +# + +load helpers + +function setup() { + basic_setup +} + +@test "simple WireGuard setup" { + run_netavark --file ${TESTSDIR}/testfiles/wireguard.json setup $(get_container_netns_path) + result="$output" + + # mac=$(jq -r '.podman.interfaces.wg-test.mac_address' <<< "$result" ) + # check that interface exists + run_in_container_netns ip -j --details link show wg-test + link_info="$output" + assert_json "$link_info" ".[].address" "==" "$mac" "MAC matches container mac" + assert_json "$link_info" '.[].flags[] | select(.=="UP")' "==" "UP" "Container interface is up" + assert_json "$link_info" ".[].linkinfo.info_kind" "==" "macvlan" "Container interface is a macvlan device" + + ipaddr="10.88.0.2/16" + run_in_container_netns ip addr show eth0 + assert "$output" "=~" "$ipaddr" "IP address matches container address" + assert_json "$result" ".podman.interfaces.eth0.subnets[0].ipnet" "==" "$ipaddr" "Result contains correct IP address" + + # check gateway assignment + run_in_container_netns ip r + assert "$output" "=~" "default via 10.88.0.1" "gateway must be there in default route" + assert_json "$result" ".podman.interfaces.eth0.subnets[0].gateway" == "10.88.0.1" "Result contains gateway address" + + run_in_container_netns cat /proc/sys/net/ipv6/conf/eth0/autoconf + assert "0" "autoconf is disabled" + + run_netavark --file ${TESTSDIR}/testfiles/macvlan.json teardown $(get_container_netns_path) + assert "" "no errors" +} + diff --git a/test/testfiles/wireguard.json b/test/testfiles/wireguard.json index 53fc1897d..9f5202049 100644 --- a/test/testfiles/wireguard.json +++ b/test/testfiles/wireguard.json @@ -2,23 +2,21 @@ "container_id": "someID", "container_name": "wireguard_test_container", "networks": { - "wg": {} + "wg": { + "options": { + "wireguard_config_path": "../test.conf" + }, + "interface_name": "wg-test" + } }, "network_info": { "wg": { "dns_enabled": false, - "driver": "bridge", + "driver": "wireguard", "id": "53ce4390f2adb1681eb1a90ec8b48c49c015e0a8d336c197637e7f65e365fa9e", "internal": false, "ipv6_enabled": false, - "name": "podman", - "network_interface": "podman0", - "subnets": [ - { - "gateway": "10.88.0.1", - "subnet": "10.88.0.0/16" - } - ] + "name": "wg" } } }