aboutsummaryrefslogtreecommitdiffstats
path: root/wg-dynamic-server.c
diff options
context:
space:
mode:
authorLinus Nordberg <linus@nordberg.se>2019-09-29 22:16:52 +0200
committerLinus Nordberg <linus@nordberg.se>2019-09-29 22:36:19 +0200
commit415a43be2ae31372a33e910913d6ae0ba401e167 (patch)
treebdb5e6fec4c4bd3fa1f61f491daad6e7f816bf58 /wg-dynamic-server.c
parentRemove allowed-ips from peers as leases expire (diff)
downloadwg-dynamic-415a43be2ae31372a33e910913d6ae0ba401e167.tar.xz
wg-dynamic-415a43be2ae31372a33e910913d6ae0ba401e167.zip
Server side lease handling
Extend when requested, release when being replaced. Separate address families so that one can be granted even when the pool for the other is empty.
Diffstat (limited to '')
-rw-r--r--wg-dynamic-server.c113
1 files changed, 72 insertions, 41 deletions
diff --git a/wg-dynamic-server.c b/wg-dynamic-server.c
index d1229cc..2b073f1 100644
--- a/wg-dynamic-server.c
+++ b/wg-dynamic-server.c
@@ -87,8 +87,7 @@ static int data_cb(const struct nlmsghdr *nlh, void *data)
static bool validate_link_local_ip(uint32_t ifindex)
{
struct mnl_cb_data cb_data = {
- .ifindex = ifindex,
- .valid_ip_found = false,
+ .ifindex = ifindex, .valid_ip_found = false,
};
iface_get_all_addrs(AF_INET6, data_cb, &cb_data);
@@ -228,18 +227,22 @@ static bool send_error(struct wg_dynamic_request *req, int error)
char buf[MAX_RESPONSE_SIZE];
size_t msglen = 0;
- print_to_buf(buf, sizeof buf, &msglen, "errno=%d\nerrmsg=%s\n\n", error,
- WG_DYNAMIC_ERR[error]);
+ debug("Parse error, errno=%d\n", error);
+
+ print_to_buf(buf, sizeof buf, &msglen, "errno=%d\nerrmsg=%s\n\n",
+ E_INVALID_REQ, WG_DYNAMIC_ERR[E_INVALID_REQ]);
return send_message(req, buf, msglen);
}
-static size_t serialize_lease(char *buf, size_t len,
- const struct wg_dynamic_lease *lease)
+static size_t serialize_request_ip(char *buf, size_t len,
+ const struct wg_dynamic_lease *lease)
{
char addrbuf[INET6_ADDRSTRLEN];
size_t off = 0;
+ print_to_buf(buf, len, &off, "request_ip=1\n");
+
if (lease->ipv4.s_addr) {
if (!inet_ntop(AF_INET, &lease->ipv4, addrbuf, sizeof addrbuf))
fatal("inet_ntop()");
@@ -254,47 +257,69 @@ static size_t serialize_lease(char *buf, size_t len,
print_to_buf(buf, len, &off, "ipv6=%s/%d\n", addrbuf, 128);
}
- print_to_buf(buf, len, &off, "leasestart=%u\nleasetime=%u\nerrno=0\n\n",
+ print_to_buf(buf, len, &off, "leasestart=%u\nleasetime=%u\n",
lease->start_real, lease->leasetime);
return off;
}
-static void add_allowed_ips(wg_key pubkey, struct in_addr *ipv4,
- struct in6_addr *ipv6)
+static void adjust_allowed_ips(wg_key pubkey, struct in_addr *ipv4,
+ struct in6_addr *ipv6)
{
- wg_allowedip allowed_v4, allowed_v6;
+ wg_allowedip lladdr, allowed_v4, allowed_v6;
wg_peer peer = { 0 };
- wg_device dev = { .first_peer = &peer };
+ wg_device dev = {.first_peer = &peer };
strcpy(dev.name, wg_interface);
memcpy(peer.public_key, pubkey, sizeof peer.public_key);
wg_allowedip **cur = &peer.first_allowedip;
- if (ipv4) {
+ wg_peer *ourpeer;
+ wg_for_each_peer (device, ourpeer) {
+ if (!memcmp(ourpeer->public_key, pubkey, sizeof(wg_key))) {
+ peer.flags |= WGPEER_REPLACE_ALLOWEDIPS;
+ memcpy(peer.public_key, pubkey, sizeof(wg_key));
+
+ wg_allowedip *allowedip;
+ wg_for_each_allowedip (ourpeer, allowedip) {
+ if (allowedip->family == AF_INET6 &&
+ allowedip->cidr == 128 &&
+ IN6_IS_ADDR_LINKLOCAL(&allowedip->ip6)) {
+ lladdr.family = AF_INET6;
+ memcpy(&lladdr.ip6, &allowedip->ip6,
+ sizeof(struct in6_addr));
+ lladdr.cidr = 128;
+ *cur = &lladdr;
+ cur = &lladdr.next_allowedip;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (ipv4 && ipv4->s_addr) {
allowed_v4 = (wg_allowedip){
- .family = AF_INET,
- .cidr = 32,
- .ip4 = *ipv4,
+ .family = AF_INET, .cidr = 32, .ip4 = *ipv4,
};
*cur = &allowed_v4;
cur = &allowed_v4.next_allowedip;
}
- if (ipv6) {
+ if (ipv6 && !IN6_IS_ADDR_UNSPECIFIED(ipv6)) {
allowed_v6 = (wg_allowedip){
- .family = AF_INET6,
- .cidr = 128,
- .ip6 = *ipv6,
+ .family = AF_INET6, .cidr = 128, .ip6 = *ipv6,
};
*cur = &allowed_v6;
}
- if (wg_set_device(&dev))
- fatal("wg_set_device()");
+ if ((ipv4 && ipv4->s_addr) || (ipv6 && !IN6_IS_ADDR_UNSPECIFIED(ipv6)))
+ if (wg_set_device(&dev))
+ fatal("wg_set_device()");
}
-/* TODO: have UPDATES contain {wg_key, ip4 and ip6} and remove only matching addrs */
+/* TODO: have UPDATES contain {wg_key, ip4, ip6} and remove only matching addrs */
+/* FIXME: rename to remove_allowed_ips() */
static void update_allowed_ips(wg_key *updates, int nupdates)
{
wg_device newdev = { 0 };
@@ -348,13 +373,12 @@ static void update_allowed_ips(wg_key *updates, int nupdates)
}
static int response_request_ip(struct wg_dynamic_attr *cur, wg_key pubkey,
- struct wg_dynamic_lease **lease)
+ struct wg_dynamic_lease **lease_out)
{
struct in_addr *ipv4 = NULL;
struct in6_addr *ipv6 = NULL;
uint32_t leasetime = WG_DYNAMIC_LEASETIME;
-
- *lease = get_leases(pubkey);
+ struct wg_dynamic_lease *current = NULL;
while (cur) {
switch (cur->key) {
@@ -364,9 +388,6 @@ static int response_request_ip(struct wg_dynamic_attr *cur, wg_key pubkey,
case WGKEY_IPV6:
ipv6 = &((struct wg_combined_ip *)cur->value)->ip6;
break;
- case WGKEY_LEASETIME:
- leasetime = *(uint32_t *)cur->value;
- break;
default:
debug("Ignoring invalid attribute for request_ip: %d\n",
cur->key);
@@ -374,12 +395,12 @@ static int response_request_ip(struct wg_dynamic_attr *cur, wg_key pubkey,
cur = cur->next;
}
- if (ipv4 && ipv6 && !ipv4->s_addr && IN6_IS_ADDR_UNSPECIFIED(ipv6))
- return E_INVALID_REQ;
+ current = get_leases(pubkey);
+ debug("current lease: %s\n", lease_to_str(current));
+
+ *lease_out = new_lease(pubkey, leasetime, ipv4, ipv6, current);
- *lease = new_lease(pubkey, leasetime, ipv4, ipv6);
- if (!*lease)
- return E_IP_UNAVAIL;
+ release_lease(current, pubkey);
return E_NO_ERROR;
}
@@ -388,27 +409,37 @@ static bool send_response(struct wg_dynamic_request *req)
{
char buf[MAX_RESPONSE_SIZE];
struct wg_dynamic_attr *cur = req->first;
- struct wg_dynamic_lease *lease;
- size_t msglen;
- int ret;
+ size_t msglen = 0;
+ int ret = 0;
switch (req->cmd) {
- case WGKEY_REQUEST_IP:
+ case WGKEY_REQUEST_IP: {
+ struct wg_dynamic_lease *lease = NULL;
ret = response_request_ip(cur, req->pubkey, &lease);
if (ret)
break;
- add_allowed_ips(req->pubkey, &lease->ipv4, &lease->ipv6);
- msglen = serialize_lease(buf, sizeof buf, lease);
+ if (lease) {
+ adjust_allowed_ips(req->pubkey, &lease->ipv4,
+ &lease->ipv6);
+ msglen = serialize_request_ip(buf, sizeof buf, lease);
+ }
break;
+ }
default:
debug("Unknown command: %d\n", req->cmd);
BUG();
}
- if (ret)
- return send_error(req, ret);
+ if (ret) {
+ print_to_buf(buf, sizeof buf, &msglen,
+ "request_ip=1\nerrno=%d\nerrmsg=%s\n\n", ret,
+ WG_DYNAMIC_ERR[ret]);
+
+ return send_message(req, buf, msglen);
+ }
+ print_to_buf(buf, sizeof buf, &msglen, "errno=0\n\n");
return send_message(req, buf, msglen);
}