Skip to content

Commit 005e7bb

Browse files
committed
samples: net: echo-server: Add Wireguard VPN support
Add Wireguard configuration to echo-server application. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 6598094 commit 005e7bb

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed

samples/net/sockets/echo_server/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ target_sources_ifdef(CONFIG_NET_UDP app PRIVATE src/udp.c)
2323
target_sources_ifdef(CONFIG_NET_TCP app PRIVATE src/tcp.c)
2424
target_sources_ifdef(CONFIG_NET_VLAN app PRIVATE src/vlan.c)
2525
target_sources_ifdef(CONFIG_NET_L2_IPIP app PRIVATE src/tunnel.c)
26+
target_sources_ifdef(CONFIG_WIREGUARD app PRIVATE src/wg.c)
2627

2728
if (CONFIG_USB_DEVICE_STACK)
2829
target_sources(app PRIVATE src/usb.c)

samples/net/sockets/echo_server/Kconfig

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,47 @@ config NET_SAMPLE_HTTPS_SERVER_SERVICE_PORT
104104
default 443
105105
depends on NET_SAMPLE_HTTPS_SERVICE
106106

107+
config NET_SAMPLE_VPN_MY_PRIVATE_KEY
108+
string "My private key in base64 format"
109+
default ""
110+
depends on WIREGUARD
111+
help
112+
The public key will be calculated from the private one.
113+
114+
config NET_SAMPLE_VPN_PEER_PUBLIC_KEY
115+
string "Peer public key in base64 format"
116+
default ""
117+
depends on WIREGUARD
118+
help
119+
This specifies the public key of the peer that we are being
120+
connected from.
121+
122+
config NET_SAMPLE_VPN_PEER_IP_ADDR
123+
string "Peer IP address to connect to"
124+
default ""
125+
depends on WIREGUARD
126+
help
127+
This specifies the IP address of VPN service we are trying to
128+
connect to. You can also set the port number also here like
129+
this: 192.0.2.2:51821 or [2001:db8::2]:51822
130+
if using non standard Wireguard port which is 51820.
131+
132+
config NET_SAMPLE_VPN_ALLOWED_PEER_ADDR
133+
string "Allowed peer IP addresses"
134+
depends on WIREGUARD
135+
help
136+
What peer IP address is allowed to connect.
137+
Format is: ip/masklen
138+
Multiple addresses can be given and must be separated by "," or space
139+
characters.
140+
Example: 192.0.2.0/24,2001:db9::/64
141+
142+
config NET_SAMPLE_VPN_MY_ADDR
143+
string "My address for VPN connections"
144+
depends on WIREGUARD
145+
help
146+
The value depends on your network setup.
147+
107148
if USB_DEVICE_STACK_NEXT
108149
# Source common USB sample options used to initialize new experimental USB
109150
# device stack. The scope of these options is limited to USB samples in project

samples/net/sockets/echo_server/src/common.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,15 @@ static inline int init_vlan(void)
8282
}
8383
#endif /* CONFIG_NET_VLAN */
8484

85+
#if defined(CONFIG_WIREGUARD)
86+
int init_vpn(void);
87+
#else
88+
static inline int init_vpn(void)
89+
{
90+
return 0;
91+
}
92+
#endif /* CONFIG_WIREGUARD */
93+
8594
#if defined(CONFIG_NET_SAMPLE_WEBSOCKET_CONSOLE)
8695
int init_ws(void);
8796
#else

samples/net/sockets/echo_server/src/echo-server.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ static void init_app(void)
198198
init_tunnel();
199199
init_ws();
200200
init_usb();
201+
init_vpn();
201202
}
202203

203204
static int cmd_sample_quit(const struct shell *sh,
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* Copyright (c) 2025 Intel Corporation.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <zephyr/logging/log.h>
8+
LOG_MODULE_DECLARE(net_echo_server_sample, LOG_LEVEL_DBG);
9+
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/sys/base64.h>
12+
#include <zephyr/net/virtual.h>
13+
#include <zephyr/net/virtual_mgmt.h>
14+
#include <zephyr/net/wireguard.h>
15+
16+
/* User data for the interface callback */
17+
struct ud {
18+
struct net_if *vpn[CONFIG_WIREGUARD_MAX_PEER];
19+
};
20+
21+
static void iface_cb(struct net_if *iface, void *user_data)
22+
{
23+
struct ud *ud = user_data;
24+
25+
if (net_if_l2(iface) != &NET_L2_GET_NAME(VIRTUAL)) {
26+
return;
27+
}
28+
29+
if (!(net_virtual_get_iface_capabilities(iface) & VIRTUAL_INTERFACE_VPN)) {
30+
return;
31+
}
32+
33+
for (int i = 0; i < CONFIG_WIREGUARD_MAX_PEER; i++) {
34+
if (ud->vpn[i] != NULL) {
35+
continue;
36+
}
37+
38+
ud->vpn[i] = iface;
39+
return;
40+
}
41+
}
42+
43+
static int setup_iface(struct net_if *iface,
44+
const char *my_ip_addr,
45+
const char *allowed_ip_addr,
46+
const char *my_private_key,
47+
const char *peer_public_key)
48+
{
49+
struct virtual_interface_req_params params = { 0 };
50+
struct wireguard_peer_config peer_config = { 0 };
51+
struct sockaddr_storage addr = { 0 };
52+
struct sockaddr *paddr = (struct sockaddr *)&addr;
53+
struct net_if *peer_iface = NULL;
54+
uint8_t mask_len = 0;
55+
uint8_t private_key[NET_VIRTUAL_MAX_PUBLIC_KEY_LEN];
56+
struct net_if_addr *ifaddr;
57+
const char *addr_str, *next;
58+
bool status, found;
59+
size_t olen;
60+
int ret;
61+
62+
(void)base64_decode(private_key, sizeof(private_key), &olen,
63+
my_private_key, strlen(my_private_key));
64+
65+
params.private_key.data = private_key;
66+
params.private_key.len = sizeof(private_key);
67+
68+
ret = net_mgmt(NET_REQUEST_VIRTUAL_INTERFACE_SET_PRIVATE_KEY,
69+
iface, &params, sizeof(params));
70+
71+
memset(private_key, 0, sizeof(private_key));
72+
73+
if (ret < 0) {
74+
LOG_ERR("Cannot set private key (%d)", ret);
75+
return ret;
76+
}
77+
78+
addr_str = net_ipaddr_parse_mask(my_ip_addr, strlen(my_ip_addr),
79+
paddr, &mask_len);
80+
if (addr_str == NULL) {
81+
LOG_ERR("Cannot parse IP address \"%s\"", my_ip_addr);
82+
return -EINVAL;
83+
}
84+
85+
if (paddr->sa_family == AF_INET) {
86+
struct sockaddr_in *addr4 = (struct sockaddr_in *)paddr;
87+
struct sockaddr_in mask;
88+
89+
ifaddr = net_if_ipv4_addr_add(iface, &addr4->sin_addr,
90+
NET_ADDR_MANUAL, 0);
91+
92+
ret = net_mask_len_to_netmask(AF_INET, mask_len,
93+
(struct sockaddr *)&mask);
94+
if (ret < 0) {
95+
LOG_ERR("Invalid network mask length (%d)", ret);
96+
return ret;
97+
}
98+
99+
status = net_if_ipv4_set_netmask_by_addr(iface,
100+
&addr4->sin_addr,
101+
&mask.sin_addr);
102+
103+
} else if (paddr->sa_family == AF_INET6) {
104+
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)paddr;
105+
struct in6_addr netaddr6;
106+
107+
ifaddr = net_if_ipv6_addr_add(iface, &addr6->sin6_addr,
108+
NET_ADDR_MANUAL, 0);
109+
110+
net_ipv6_addr_prefix_mask((uint8_t *)&addr6->sin6_addr,
111+
(uint8_t *)&netaddr6,
112+
mask_len);
113+
114+
if (!net_if_ipv6_prefix_add(iface, &netaddr6, mask_len,
115+
(uint32_t)0xffffffff)) {
116+
LOG_ERR("Cannot add %s to interface %d", my_ip_addr,
117+
net_if_get_by_iface(iface));
118+
return -EINVAL;
119+
}
120+
121+
} else {
122+
LOG_ERR("Cannot parse IP address \"%s\"", my_ip_addr);
123+
return -EAFNOSUPPORT;
124+
}
125+
126+
if (ifaddr == NULL) {
127+
LOG_ERR("Cannot add IP address \"%s\" to interface %d",
128+
my_ip_addr, net_if_get_by_iface(iface));
129+
return -ENOENT;
130+
}
131+
132+
peer_config.public_key = peer_public_key;
133+
134+
addr_str = allowed_ip_addr;
135+
found = false;
136+
137+
do {
138+
next = net_ipaddr_parse_mask(addr_str, strlen(addr_str),
139+
paddr, &mask_len);
140+
if (next == NULL) {
141+
LOG_ERR("Cannot parse IP address \"%s\"", allowed_ip_addr);
142+
return -EINVAL;
143+
}
144+
145+
ARRAY_FOR_EACH(peer_config.allowed_ip, i) {
146+
if (peer_config.allowed_ip[i].is_valid) {
147+
continue;
148+
}
149+
150+
if (paddr->sa_family == AF_INET) {
151+
struct sockaddr_in *addr4 = (struct sockaddr_in *)paddr;
152+
153+
memcpy(&peer_config.allowed_ip[i].addr.in_addr,
154+
&addr4->sin_addr,
155+
sizeof(struct in_addr));
156+
peer_config.allowed_ip[i].addr.family = AF_INET;
157+
peer_config.allowed_ip[i].is_valid = true;
158+
peer_config.allowed_ip[i].mask_len = mask_len;
159+
found = true;
160+
161+
} else if (addr.ss_family == AF_INET6) {
162+
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)paddr;
163+
164+
memcpy(&peer_config.allowed_ip[i].addr.in6_addr,
165+
&addr6->sin6_addr,
166+
sizeof(struct in6_addr));
167+
peer_config.allowed_ip[i].addr.family = AF_INET6;
168+
peer_config.allowed_ip[i].is_valid = true;
169+
peer_config.allowed_ip[i].mask_len = mask_len;
170+
found = true;
171+
172+
} else {
173+
LOG_ERR("Cannot parse IP address \"%s\"", allowed_ip_addr);
174+
return -EAFNOSUPPORT;
175+
}
176+
177+
break;
178+
}
179+
180+
addr_str = next;
181+
} while (addr_str != NULL && *addr_str != '\0');
182+
183+
if (!found) {
184+
LOG_ERR("Not enough space for allowed IP addresses");
185+
return -ENOMEM;
186+
}
187+
188+
if (CONFIG_NET_SAMPLE_VPN_PEER_IP_ADDR[0] == '\0') {
189+
LOG_ERR("Peer IP address is not set");
190+
return -EINVAL;
191+
}
192+
193+
if (!net_ipaddr_parse(CONFIG_NET_SAMPLE_VPN_PEER_IP_ADDR,
194+
strlen(CONFIG_NET_SAMPLE_VPN_PEER_IP_ADDR),
195+
paddr)) {
196+
LOG_ERR("Cannot parse peer IP address \"%s\"", CONFIG_NET_SAMPLE_VPN_PEER_IP_ADDR);
197+
return -EINVAL;
198+
}
199+
200+
if (paddr->sa_family == AF_INET6) {
201+
memcpy(&peer_config.endpoint_ip, paddr, sizeof(struct sockaddr_in6));
202+
} else {
203+
memcpy(&peer_config.endpoint_ip, paddr, sizeof(struct sockaddr_in));
204+
}
205+
206+
ret = wireguard_peer_add(&peer_config, &peer_iface);
207+
if (ret < 0) {
208+
LOG_ERR("Cannot add peer (%d)", ret);
209+
} else if (ret > 0) {
210+
if (peer_iface != NULL) {
211+
LOG_INF("Added peer id %d using interface %d", ret,
212+
net_if_get_by_iface(peer_iface));
213+
} else {
214+
LOG_INF("Added peer id %d", ret);
215+
}
216+
}
217+
218+
LOG_DBG("Interface %d VPN setup done.", net_if_get_by_iface(iface));
219+
220+
return 0;
221+
}
222+
223+
int init_vpn(void)
224+
{
225+
struct ud ud;
226+
int ret;
227+
228+
memset(&ud, 0, sizeof(ud));
229+
230+
net_if_foreach(iface_cb, &ud);
231+
232+
/* This sample has support for one VPN connection.
233+
*/
234+
ret = setup_iface(ud.vpn[0],
235+
CONFIG_NET_SAMPLE_VPN_MY_ADDR,
236+
CONFIG_NET_SAMPLE_VPN_ALLOWED_PEER_ADDR,
237+
CONFIG_NET_SAMPLE_VPN_MY_PRIVATE_KEY,
238+
CONFIG_NET_SAMPLE_VPN_PEER_PUBLIC_KEY);
239+
if (ret < 0) {
240+
return ret;
241+
}
242+
243+
return 0;
244+
}

0 commit comments

Comments
 (0)