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