-// SPDX-License-Identifier: GPL-2.0+
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
*
#include <sys/un.h>
#include <arpa/inet.h>
#include <linux/rtnetlink.h>
-#include <linux/wireguard.h>
#include <netlink/msg.h>
#include <netlink/attr.h>
#include <netlink/socket.h>
#include <unl.h>
+#include "linux/wireguard.h"
#include "unetd.h"
struct timespec64 {
struct wg_linux_peer_req {
struct nl_msg *msg;
- struct nlattr *peers, *entry;
+ struct nlattr *peers, *entry, *ips;
};
static struct unl unl;
static int
wg_nl_init(void)
{
+ int ret;
+
if (unl.sock)
return 0;
- return unl_genl_init(&unl, "wireguard");
+ ret = unl_genl_init(&unl, "wireguard");
+ if (ret)
+ return ret;
+
+ nl_socket_set_buffer_size(unl.sock, 32768, 32768);
+ nlmsg_set_default_size(32768);
+
+ return 0;
}
static struct nl_msg *
struct nl_msg *msg;
msg = wg_genl_msg(net, true);
- nla_put_u16(msg, WGDEVICE_A_LISTEN_PORT, peer->port);
+ nla_put_u16(msg, WGDEVICE_A_LISTEN_PORT, peer ? peer->port : 0);
return wg_genl_call(msg);
}
return wg_genl_call(req->msg);
}
-static int
-wg_linux_peer_update(struct network *net, struct network_peer *peer, enum wg_update_cmd cmd)
+static struct nl_msg *
+wg_linux_peer_msg_size_check(struct wg_linux_peer_req *req, struct network *net,
+ struct network_peer *peer)
{
- struct wg_linux_peer_req req;
- struct blob_attr *cur;
- struct nl_msg *msg;
- struct nlattr *ips;
- int rem;
+ if (nlmsg_get_max_size(req->msg) >
+ nlmsg_total_size(nlmsg_hdr(req->msg)->nlmsg_len) + 256)
+ return req->msg;
- msg = wg_linux_peer_req_init(net, peer, &req);
+ nla_nest_end(req->msg, req->ips);
+ wg_linux_peer_req_done(req);
- if (cmd == WG_PEER_DELETE) {
- nla_put_u32(msg, WGPEER_A_FLAGS, WGPEER_F_REMOVE_ME);
- goto out;
- }
+ wg_linux_peer_req_init(net, peer, req);
+ req->ips = nla_nest_start(req->msg, WGPEER_A_ALLOWEDIPS);
- nla_put_u32(msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS);
+ return req->msg;
+}
+
+static void
+wg_linux_peer_msg_add_allowed_ip(struct wg_linux_peer_req *req, struct network *net,
+ struct network_peer *peer)
+{
+ struct nl_msg *msg = req->msg;
+ struct blob_attr *cur;
+ int rem;
- ips = nla_nest_start(msg, WGPEER_A_ALLOWEDIPS);
wg_linux_msg_add_ip(msg, AF_INET6, &peer->local_addr.in6, 128);
+ msg = wg_linux_peer_msg_size_check(req, net, peer);
blobmsg_for_each_attr(cur, peer->ipaddr, rem) {
const char *str = blobmsg_get_string(cur);
continue;
wg_linux_msg_add_ip(msg, af, &in6, mask);
+ msg = wg_linux_peer_msg_size_check(req, net, peer);
}
blobmsg_for_each_attr(cur, peer->subnet, rem) {
continue;
wg_linux_msg_add_ip(msg, af, &addr, mask);
+ msg = wg_linux_peer_msg_size_check(req, net, peer);
+ }
+}
+
+static int
+wg_linux_peer_update(struct network *net, struct network_peer *peer, enum wg_update_cmd cmd)
+{
+ struct wg_linux_peer_req req;
+ struct network_host *host;
+
+ wg_linux_peer_req_init(net, peer, &req);
+
+ if (cmd == WG_PEER_DELETE) {
+ nla_put_u32(req.msg, WGPEER_A_FLAGS, WGPEER_F_REMOVE_ME);
+ goto out;
}
- nla_nest_end(msg, ips);
+ nla_put_u32(req.msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS);
+
+ req.ips = nla_nest_start(req.msg, WGPEER_A_ALLOWEDIPS);
+
+ wg_linux_peer_msg_add_allowed_ip(&req, net, peer);
+
+ for_each_routed_host(host, net, peer)
+ wg_linux_peer_msg_add_allowed_ip(&req, net, &host->peer);
+
+ nla_nest_end(req.msg, req.ips);
out:
return wg_linux_peer_req_done(&req);