xref: /freebsd/tests/sys/net/if_wg.sh (revision 2008043f386721d58158e37e0d7e50df8095942d)
1#
2# SPDX-License-Identifier: BSD-2-Clause
3#
4# Copyright (c) 2021 The FreeBSD Foundation
5#
6# This software was developed by Mark Johnston under sponsorship
7# from the FreeBSD Foundation.
8#
9# Redistribution and use in source and binary forms, with or without
10# modification, are permitted provided that the following conditions
11# are met:
12# 1. Redistributions of source code must retain the above copyright
13#    notice, this list of conditions and the following disclaimer.
14# 2. Redistributions in binary form must reproduce the above copyright
15#    notice, this list of conditions and the following disclaimer in the
16#    documentation and/or other materials provided with the distribution.
17#
18# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28# SUCH DAMAGE.
29
30. $(atf_get_srcdir)/../common/vnet.subr
31
32atf_test_case "wg_basic" "cleanup"
33wg_basic_head()
34{
35	atf_set descr 'Create a wg(4) tunnel over an epair and pass traffic between jails'
36	atf_set require.user root
37}
38
39wg_basic_body()
40{
41	local epair pri1 pri2 pub1 pub2 wg1 wg2
42        local endpoint1 endpoint2 tunnel1 tunnel2
43
44	kldload -n if_wg || atf_skip "This test requires if_wg and could not load it"
45
46	pri1=$(wg genkey)
47	pri2=$(wg genkey)
48
49	endpoint1=192.168.2.1
50	endpoint2=192.168.2.2
51	tunnel1=169.254.0.1
52	tunnel2=169.254.0.2
53
54	epair=$(vnet_mkepair)
55
56	vnet_init
57
58	vnet_mkjail wgtest1 ${epair}a
59	vnet_mkjail wgtest2 ${epair}b
60
61	jexec wgtest1 ifconfig ${epair}a ${endpoint1}/24 up
62	jexec wgtest2 ifconfig ${epair}b ${endpoint2}/24 up
63
64	wg1=$(jexec wgtest1 ifconfig wg create)
65	echo "$pri1" | jexec wgtest1 wg set $wg1 listen-port 12345 \
66	    private-key /dev/stdin
67	pub1=$(jexec wgtest1 wg show $wg1 public-key)
68	wg2=$(jexec wgtest2 ifconfig wg create)
69	echo "$pri2" | jexec wgtest2 wg set $wg2 listen-port 12345 \
70	    private-key /dev/stdin
71	pub2=$(jexec wgtest2 wg show $wg2 public-key)
72
73	atf_check -s exit:0 -o ignore \
74	    jexec wgtest1 wg set $wg1 peer "$pub2" \
75	    endpoint ${endpoint2}:12345 allowed-ips ${tunnel2}/32
76	atf_check -s exit:0 \
77	    jexec wgtest1 ifconfig $wg1 inet ${tunnel1}/24 up
78
79	atf_check -s exit:0 -o ignore \
80	    jexec wgtest2 wg set $wg2 peer "$pub1" \
81	    endpoint ${endpoint1}:12345 allowed-ips ${tunnel1}/32
82	atf_check -s exit:0 \
83	    jexec wgtest2 ifconfig $wg2 inet ${tunnel2}/24 up
84
85	# Generous timeout since the handshake takes some time.
86	atf_check -s exit:0 -o ignore jexec wgtest1 ping -c 1 -t 5 $tunnel2
87	atf_check -s exit:0 -o ignore jexec wgtest2 ping -c 1 $tunnel1
88}
89
90wg_basic_cleanup()
91{
92	vnet_cleanup
93}
94
95# The kernel is expected to silently ignore any attempt to add a peer with a
96# public key identical to the host's.
97atf_test_case "wg_key_peerdev_shared" "cleanup"
98wg_key_peerdev_shared_head()
99{
100	atf_set descr 'Create a wg(4) interface with a shared pubkey between device and a peer'
101	atf_set require.user root
102}
103
104wg_key_peerdev_shared_body()
105{
106	local epair pri1 pub1 wg1
107        local endpoint1 tunnel1
108
109	kldload -n if_wg || atf_skip "This test requires if_wg and could not load it"
110
111	pri1=$(wg genkey)
112
113	endpoint1=192.168.2.1
114	tunnel1=169.254.0.1
115
116	vnet_mkjail wgtest1
117
118	wg1=$(jexec wgtest1 ifconfig wg create)
119	echo "$pri1" | jexec wgtest1 wg set $wg1 listen-port 12345 \
120	    private-key /dev/stdin
121	pub1=$(jexec wgtest1 wg show $wg1 public-key)
122
123	atf_check -s exit:0 \
124	    jexec wgtest1 wg set ${wg1} peer "${pub1}" \
125	    allowed-ips "${tunnel1}/32"
126
127	atf_check -o empty jexec wgtest1 wg show ${wg1} peers
128}
129
130wg_key_peerdev_shared_cleanup()
131{
132	vnet_cleanup
133}
134
135# When a wg(8) interface has a private key reassigned that corresponds to the
136# public key already on a peer, the kernel is expected to deconfigure the peer
137# to resolve the conflict.
138atf_test_case "wg_key_peerdev_makeshared" "cleanup"
139wg_key_peerdev_makeshared_head()
140{
141	atf_set descr 'Create a wg(4) interface and assign peer key to device'
142	atf_set require.progs wg
143}
144
145wg_key_peerdev_makeshared_body()
146{
147	local epair pri1 pub1 pri2 wg1 wg2
148        local endpoint1 tunnel1
149
150	kldload -n if_wg || atf_skip "This test requires if_wg and could not load it"
151
152	pri1=$(wg genkey)
153	pri2=$(wg genkey)
154
155	endpoint1=192.168.2.1
156	tunnel1=169.254.0.1
157
158	vnet_mkjail wgtest1
159
160	wg1=$(jexec wgtest1 ifconfig wg create)
161	echo "$pri1" | jexec wgtest1 wg set $wg1 listen-port 12345 \
162	    private-key /dev/stdin
163	pub1=$(jexec wgtest1 wg show $wg1 public-key)
164	wg2=$(jexec wgtest1 ifconfig wg create)
165	echo "$pri2" | jexec wgtest1 wg set $wg2 listen-port 12345 \
166	    private-key /dev/stdin
167
168	atf_check -s exit:0 -o ignore \
169	    jexec wgtest1 wg set ${wg2} peer "${pub1}" \
170	    allowed-ips "${tunnel1}/32"
171
172	atf_check -o not-empty jexec wgtest1 wg show ${wg2} peers
173
174	jexec wgtest1 sh -c "echo '${pri1}' > pri1"
175
176	atf_check -s exit:0 \
177	   jexec wgtest1 wg set ${wg2} private-key pri1
178
179	atf_check -o empty jexec wgtest1 wg show ${wg2} peers
180}
181
182wg_key_peerdev_makeshared_cleanup()
183{
184	vnet_cleanup
185}
186
187# The kernel is expected to create the wg socket in the jail context that the
188# wg interface was created in, even if the interface is moved to a different
189# vnet.
190atf_test_case "wg_vnet_parent_routing" "cleanup"
191wg_vnet_parent_routing_head()
192{
193	atf_set descr 'Create a wg(4) tunnel without epairs and pass traffic between jails'
194	atf_set require.user root
195}
196
197wg_vnet_parent_routing_body()
198{
199	local pri1 pri2 pub1 pub2 wg1 wg2
200        local tunnel1 tunnel2
201
202	kldload -n if_wg
203
204	pri1=$(wg genkey)
205	pri2=$(wg genkey)
206
207	tunnel1=169.254.0.1
208	tunnel2=169.254.0.2
209
210	vnet_init
211
212	wg1=$(ifconfig wg create)
213	wg2=$(ifconfig wg create)
214
215	vnet_mkjail wgtest1 ${wg1}
216	vnet_mkjail wgtest2 ${wg2}
217
218	echo "$pri1" | jexec wgtest1 wg set $wg1 listen-port 12345 \
219	    private-key /dev/stdin
220	pub1=$(jexec wgtest1 wg show $wg1 public-key)
221	echo "$pri2" | jexec wgtest2 wg set $wg2 listen-port 12346 \
222	    private-key /dev/stdin
223	pub2=$(jexec wgtest2 wg show $wg2 public-key)
224
225	atf_check -s exit:0 -o ignore \
226	    jexec wgtest1 wg set $wg1 peer "$pub2" \
227	    endpoint 127.0.0.1:12346 allowed-ips ${tunnel2}/32
228	atf_check -s exit:0 \
229	    jexec wgtest1 ifconfig $wg1 inet ${tunnel1}/24 up
230
231	atf_check -s exit:0 -o ignore \
232	    jexec wgtest2 wg set $wg2 peer "$pub1" \
233	    endpoint 127.0.0.1:12345 allowed-ips ${tunnel1}/32
234	atf_check -s exit:0 \
235	    jexec wgtest2 ifconfig $wg2 inet ${tunnel2}/24 up
236
237	# Sanity check ICMP counters; should clearly be nothing on these new
238	# jails.  We'll check them as we go to ensure that the ICMP packets
239	# generated really are being handled by the jails' vnets.
240	atf_check -o not-match:"histogram" jexec wgtest1 netstat -s -p icmp
241	atf_check -o not-match:"histogram" jexec wgtest2 netstat -s -p icmp
242
243	# Generous timeout since the handshake takes some time.
244	atf_check -s exit:0 -o ignore jexec wgtest1 ping -c 1 -t 5 $tunnel2
245	atf_check -o match:"echo reply: 1" jexec wgtest1 netstat -s -p icmp
246	atf_check -o match:"echo: 1" jexec wgtest2 netstat -s -p icmp
247
248	atf_check -s exit:0 -o ignore jexec wgtest2 ping -c 1 $tunnel1
249	atf_check -o match:"echo reply: 1" jexec wgtest2 netstat -s -p icmp
250	atf_check -o match:"echo: 1" jexec wgtest1 netstat -s -p icmp
251}
252
253wg_vnet_parent_routing_cleanup()
254{
255	vnet_cleanup
256}
257
258atf_init_test_cases()
259{
260	atf_add_test_case "wg_basic"
261	atf_add_test_case "wg_key_peerdev_shared"
262	atf_add_test_case "wg_key_peerdev_makeshared"
263	atf_add_test_case "wg_vnet_parent_routing"
264}
265