1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
5 * Based on wireguard-tools:
6 * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
17 #include <sys/types.h>
18 #include <sys/socket.h>
21 #include <arpa/inet.h>
22 #include <linux/rtnetlink.h>
23 #include <netlink/msg.h>
24 #include <netlink/attr.h>
25 #include <netlink/socket.h>
28 #include "linux/wireguard.h"
36 struct wg_linux_peer_req
{
39 struct nlattr
*peers
, *entry
, *ips
;
42 static struct unl unl
;
52 ret
= unl_genl_init(&unl
, "wireguard");
56 nl_socket_set_buffer_size(unl
.sock
, 32768, 32768);
57 nlmsg_set_default_size(32768);
62 static struct nl_msg
*
63 wg_genl_msg(struct network
*net
, bool set
)
67 msg
= unl_genl_msg(&unl
, set
? WG_CMD_SET_DEVICE
: WG_CMD_GET_DEVICE
, !set
);
68 nla_put_string(msg
, WGDEVICE_A_IFNAME
, network_name(net
));
74 wg_genl_call(struct nl_msg
*msg
)
76 return unl_request(&unl
, msg
, NULL
, NULL
);
80 __wg_linux_init(struct network
*net
, void *key
)
84 msg
= wg_genl_msg(net
, true);
85 nla_put(msg
, WGDEVICE_A_PRIVATE_KEY
, WG_KEY_LEN
, key
);
86 nla_put_u32(msg
, WGDEVICE_A_FLAGS
, WGDEVICE_F_REPLACE_PEERS
);
88 return wg_genl_call(msg
);
92 wg_linux_cleanup(struct network
*net
)
94 uint8_t key
[WG_KEY_LEN
] = {};
96 __wg_linux_init(net
, key
);
100 wg_linux_init(struct network
*net
)
105 return __wg_linux_init(net
, net
->config
.key
);
109 wg_linux_init_local(struct network
*net
, struct network_peer
*peer
)
113 msg
= wg_genl_msg(net
, true);
114 nla_put_u16(msg
, WGDEVICE_A_LISTEN_PORT
, peer
? peer
->port
: 0);
116 return wg_genl_call(msg
);
120 wg_linux_msg_add_ip(struct nl_msg
*msg
, int af
, void *addr
, int mask
)
126 len
= sizeof(struct in6_addr
);
128 len
= sizeof(struct in_addr
);
130 ip
= nla_nest_start(msg
, 0);
131 nla_put_u16(msg
, WGALLOWEDIP_A_FAMILY
, af
);
132 nla_put(msg
, WGALLOWEDIP_A_IPADDR
, len
, addr
);
133 nla_put_u8(msg
, WGALLOWEDIP_A_CIDR_MASK
, mask
);
134 nla_nest_end(msg
, ip
);
137 static struct nl_msg
*
138 wg_linux_peer_req_init(struct network
*net
, struct network_peer
*peer
,
139 struct wg_linux_peer_req
*req
)
141 req
->msg
= wg_genl_msg(net
, true);
143 req
->peers
= nla_nest_start(req
->msg
, WGDEVICE_A_PEERS
);
144 req
->entry
= nla_nest_start(req
->msg
, 0);
145 nla_put(req
->msg
, WGPEER_A_PUBLIC_KEY
, WG_KEY_LEN
, peer
->key
);
151 wg_linux_peer_req_done(struct wg_linux_peer_req
*req
)
153 nla_nest_end(req
->msg
, req
->entry
);
154 nla_nest_end(req
->msg
, req
->peers
);
156 return wg_genl_call(req
->msg
);
159 static struct nl_msg
*
160 wg_linux_peer_msg_size_check(struct wg_linux_peer_req
*req
, struct network
*net
,
161 struct network_peer
*peer
)
163 if (nlmsg_get_max_size(req
->msg
) >
164 nlmsg_total_size(nlmsg_hdr(req
->msg
)->nlmsg_len
) + 256)
167 nla_nest_end(req
->msg
, req
->ips
);
168 wg_linux_peer_req_done(req
);
170 wg_linux_peer_req_init(net
, peer
, req
);
171 req
->ips
= nla_nest_start(req
->msg
, WGPEER_A_ALLOWEDIPS
);
177 wg_linux_peer_msg_add_allowed_ip(struct wg_linux_peer_req
*req
, struct network
*net
,
178 struct network_peer
*peer
)
180 struct nl_msg
*msg
= req
->msg
;
181 struct blob_attr
*cur
;
184 wg_linux_msg_add_ip(msg
, AF_INET6
, &peer
->local_addr
.in6
, 128);
185 msg
= wg_linux_peer_msg_size_check(req
, net
, peer
);
187 blobmsg_for_each_attr(cur
, peer
->ipaddr
, rem
) {
188 const char *str
= blobmsg_get_string(cur
);
192 if (strchr(str
, ':')) {
200 if (inet_pton(af
, str
, &in6
) != 1)
203 wg_linux_msg_add_ip(msg
, af
, &in6
, mask
);
204 msg
= wg_linux_peer_msg_size_check(req
, net
, peer
);
207 blobmsg_for_each_attr(cur
, peer
->subnet
, rem
) {
208 const char *str
= blobmsg_get_string(cur
);
209 union network_addr addr
;
213 af
= strchr(str
, ':') ? AF_INET6
: AF_INET
;
214 if (network_get_subnet(af
, &addr
, &mask
, str
))
217 wg_linux_msg_add_ip(msg
, af
, &addr
, mask
);
218 msg
= wg_linux_peer_msg_size_check(req
, net
, peer
);
223 wg_linux_peer_update(struct network
*net
, struct network_peer
*peer
, enum wg_update_cmd cmd
)
225 struct wg_linux_peer_req req
;
226 struct network_host
*host
;
228 wg_linux_peer_req_init(net
, peer
, &req
);
230 if (cmd
== WG_PEER_DELETE
) {
231 nla_put_u32(req
.msg
, WGPEER_A_FLAGS
, WGPEER_F_REMOVE_ME
);
235 nla_put_u32(req
.msg
, WGPEER_A_FLAGS
, WGPEER_F_REPLACE_ALLOWEDIPS
);
237 req
.ips
= nla_nest_start(req
.msg
, WGPEER_A_ALLOWEDIPS
);
239 wg_linux_peer_msg_add_allowed_ip(&req
, net
, peer
);
241 for_each_routed_host(host
, net
, peer
)
242 wg_linux_peer_msg_add_allowed_ip(&req
, net
, &host
->peer
);
244 nla_nest_end(req
.msg
, req
.ips
);
247 return wg_linux_peer_req_done(&req
);
251 wg_linux_parse_peer(struct network
*net
, struct nlattr
*data
, time_t now
)
253 struct network_peer
*peer
= NULL
;
254 struct nlattr
*tb
[__WGPEER_A_LAST
];
257 nla_parse_nested(tb
, WGPEER_A_MAX
, data
, NULL
);
259 cur
= tb
[WGPEER_A_PUBLIC_KEY
];
263 peer
= wg_peer_update_start(net
, nla_data(cur
));
267 if ((cur
= tb
[WGPEER_A_LAST_HANDSHAKE_TIME
]) != NULL
) {
268 struct timespec64
*tv
= nla_data(cur
);
270 wg_peer_set_last_handshake(net
, peer
, now
, tv
->tv_sec
);
273 if ((cur
= tb
[WGPEER_A_RX_BYTES
]) != NULL
)
274 wg_peer_set_rx_bytes(net
, peer
, nla_get_u64(cur
));
276 if ((cur
= tb
[WGPEER_A_ENDPOINT
]) != NULL
)
277 wg_peer_set_endpoint(net
, peer
, nla_data(cur
), nla_len(cur
));
279 wg_peer_update_done(net
, peer
);
283 wg_linux_parse_peer_list(struct network
*net
, struct nlattr
*data
, time_t now
)
291 nla_for_each_nested(cur
, data
, rem
)
292 wg_linux_parse_peer(net
, cur
, now
);
296 wg_linux_get_cb(struct nl_msg
*msg
, void *arg
)
298 struct nlmsghdr
*nh
= nlmsg_hdr(msg
);
299 struct network
*net
= arg
;
300 struct nlattr
*tb
[__WGDEVICE_A_LAST
];
301 time_t now
= time(NULL
);
303 nlmsg_parse(nh
, sizeof(struct genlmsghdr
), tb
, __WGDEVICE_A_LAST
, NULL
);
304 wg_linux_parse_peer_list(net
, tb
[WGDEVICE_A_PEERS
], now
);
310 wg_linux_peer_refresh(struct network
*net
)
312 struct nl_msg
*msg
= wg_genl_msg(net
, false);
314 return unl_request(&unl
, msg
, wg_linux_get_cb
, net
);
318 wg_linux_peer_connect(struct network
*net
, struct network_peer
*peer
,
319 union network_endpoint
*ep
)
321 struct wg_linux_peer_req req
;
325 msg
= wg_linux_peer_req_init(net
, peer
, &req
);
327 if (net
->net_config
.keepalive
) {
328 nla_put_u16(msg
, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL
, 0);
329 wg_linux_peer_req_done(&req
);
331 msg
= wg_linux_peer_req_init(net
, peer
, &req
);
332 nla_put_u16(msg
, WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL
,
333 net
->net_config
.keepalive
);
336 if (ep
->in
.sin_family
== AF_INET6
)
337 len
= sizeof(ep
->in6
);
339 len
= sizeof(ep
->in
);
340 nla_put(msg
, WGPEER_A_ENDPOINT
, len
, &ep
->in6
);
342 return wg_linux_peer_req_done(&req
);
345 const struct wg_ops wg_linux_ops
= {
347 .init
= wg_linux_init
,
348 .cleanup
= wg_linux_cleanup
,
349 .init_local
= wg_linux_init_local
,
350 .peer_update
= wg_linux_peer_update
,
351 .peer_refresh
= wg_linux_peer_refresh
,
352 .peer_connect
= wg_linux_peer_connect
,