diff options
author | Mikael Magnusson <mikma@users.sourceforge.net> | 2019-09-27 21:56:07 +0200 |
---|---|---|
committer | Mikael Magnusson <mikma@users.sourceforge.net> | 2021-01-12 23:34:17 +0100 |
commit | beb99f38ec4a889441f5675c1f5c8b8c815c8641 (patch) | |
tree | 7a21628c533e2e7ce6c320a4b2fac74b3f7e4921 | |
parent | d3bf043bf7aa5cac349d9472abad5246fce326f8 (diff) |
Wg-user: Refactor unix socket implementation
Move unix socket implementation for wireguard-go to sysdep/unix/.
Close socket fixing leak
-rw-r--r-- | proto/wireguard/wireguard.c | 249 | ||||
-rw-r--r-- | sysdep/unix/Makefile | 2 | ||||
-rw-r--r-- | sysdep/unix/wg_user.c | 248 | ||||
-rw-r--r-- | sysdep/unix/wg_user.h | 14 |
4 files changed, 269 insertions, 244 deletions
diff --git a/proto/wireguard/wireguard.c b/proto/wireguard/wireguard.c index 37783838..fa6ccb0e 100644 --- a/proto/wireguard/wireguard.c +++ b/proto/wireguard/wireguard.c @@ -7,256 +7,17 @@ #include <sys/un.h> #include <unistd.h> #include "lib/lists.h" -#include "lib/socket.h" +#include "lib/ip.h" #include "nest/protocol.h" #include "nest/iface.h" #include "sysdep/linux/wireguard.h" #include "sysdep/unix/unix.h" +#include "sysdep/unix/wg_user.h" #include "wireguard.h" -#define SOCKET_PATH PATH_RUNSTATEDIR "/wireguard/" - #define BA_TUNNEL_ENCAP 0x17 static -char *get_socket_path(struct wg_proto *p, char *buf, uint size) -{ - struct wg_config *c = (struct wg_config *) p->p.cf; - bsnprintf(buf, size, SOCKET_PATH "%s.sock", c->ifname); - return buf; -} - -static -bool has_userspace(struct wg_proto *p) -{ - struct wg_config *c = (struct wg_config *) p->p.cf; - struct stat sb; - char tmp[sizeof(struct sockaddr_un)]; - - if (stat(get_socket_path(p, tmp, sizeof(tmp)), &sb) == 0) - return (sb.st_mode & S_IFMT) == S_IFSOCK; - else - { - log(L_TRACE "WG: no socket %s", tmp); - return false; - } -} - -/* NULL=receiving turned off, returns 1 to clear rx buffer */ -static -int user_rx_hook(struct birdsock *sk, uint size) -{ - log(L_TRACE "WG: RX %d", size); - return 1; -} - -static -void user_tx_hook(struct birdsock *bs) -{ - log(L_TRACE "WG: TX"); -} - -/* errno or zero if EOF */ -static -void user_err_hook(struct birdsock *bs, int err) -{ - /* if (err == 0) */ - /* return; */ - - log(L_TRACE "WG: ERR %d %s", err, bs->err); - if (bs->fd >= 0) - close(bs->fd); - bs->fd = -1; -} - -static void -wg_puts(const char *str, byte **buf, uint *size) -{ - int len = strlen(str); - if (0 < len && len < (int)*size) - { - strcpy(*buf, str); - *size -= len; - *buf += len; - } - else - *size = 0; -} - -static void -wg_put_str(const char *key, const char *value, byte **buf, uint *size) -{ - char tmp[128]; - - int len = snprintf(tmp, sizeof(tmp), "%s=%s\n", key, value); - if (0 < len && len < (int)*size) - { - strcpy(*buf, tmp); - *size -= len; - *buf += len; - } - else - *size = 0; -} - -static void -wg_put_u16(const char *key, u16 value, byte **buf, uint *size) -{ - char tmp[64]; - - int len = snprintf(tmp, sizeof(tmp), "%u", value); - if (len > 0) - wg_put_str(key, tmp, buf, size); - else - *size = 0; -} - -static void -wg_put_bool(const char *key, bool value, byte **buf, uint *size) -{ - char tmp[64]; - - if (value) - wg_put_str(key, "true", buf, size); -} - -static void -wg_put_key(const char *key, wg_key value, byte **buf, uint *size) -{ - char tmp[128]; - - for (uint i=0; i < sizeof(wg_key); i++) - bsnprintf(tmp+2*i, sizeof(tmp)-2*i, "%02x", value[i]); - - wg_put_str(key, tmp, buf, size); -} - -static void -wg_put_endpoint(const char *key, const wg_endpoint *endpoint, byte **buf, uint *size) -{ - char tmp[INET6_ADDRSTRLEN + 16]; - ip_addr ip; - struct iface *ifa = NULL; - uint port = 0; - - if (sockaddr_read((sockaddr*)&endpoint->addr, endpoint->addr.sa_family, - &ip, &ifa, &port) == 0) - { - char *pos = NULL; - - if (ipa_is_ip4(ip)) - pos = ip4_ntop(ipa_to_ip4(ip), tmp); - else - { - tmp[0] = '['; - pos = ip6_ntop(ipa_to_ip6(ip), tmp + 1); - if (ifa) - pos += bsprintf(pos, "%%%u", ifa->index); - *pos++ = ']'; - } - bsprintf(pos, ":%u", port); - wg_put_str("endpoint", tmp, buf, size); - } -} - -static void -wg_put_allowedip(wg_allowedip *allowedip, byte **buf, uint *size) -{ - char tmp[INET6_ADDRSTRLEN + 10]; - ip_addr ip = IP6_NONE; - - switch (allowedip->family) - { - case AF_INET: - ip = ipa_from_in4(allowedip->ip4); - break; - case AF_INET6: - ip = ipa_from_in6(allowedip->ip6); - break; - default: - return; - } - - int res = bsnprintf(tmp, sizeof(tmp), "%I/%u", ip, allowedip->cidr); - - if (res < 0) - { - *size = 0; - return; - } - - wg_put_str("allowed_ip", tmp, buf, size); -} - -static int -user_put_device(wg_device *dev, byte **buf, uint *size) -{ - wg_put_u16("set", 1, buf, size); - wg_put_key("private_key", dev->private_key, buf, size); - wg_put_u16("listen_port", dev->listen_port, buf, size); - wg_put_bool("replace_peers", dev->flags & WGDEVICE_REPLACE_PEERS, buf, size); - - wg_peer *peer = NULL; - wg_for_each_peer(dev, peer) - { - wg_put_key("public_key", peer->public_key, buf, size); - wg_put_endpoint("endpoint", &peer->endpoint, buf, size); - wg_put_bool("replace_allowed_ips", peer->flags & WGPEER_REPLACE_ALLOWEDIPS, buf, size); - - wg_allowedip *allowedip = NULL; - wg_for_each_allowedip(peer, allowedip) - { - wg_put_allowedip(allowedip, buf, size); - } - } - wg_puts("\n", buf, size); - - if (*size > 0) - return 0; - else - return -1; -} - -static int -user_set_device(struct wg_proto *p) -{ - struct wg_config *c = (struct wg_config *) p->p.cf; - char path[sizeof(struct sockaddr_un)]; - - bsnprintf(path, sizeof(path), SOCKET_PATH "%s.sock", c->ifname); - - struct birdsock *sock = sk_new(p->p.pool); - sock->rx_hook = user_rx_hook; - sock->tx_hook = user_tx_hook; - sock->err_hook = user_err_hook; - int res = sk_connect_unix(sock, path); - log(L_TRACE "WG: socket %d %d %s", res, sock->fd, path); - if (res < 0) - return -1; - - uint tbsize = 8192; - sk_set_tbsize(sock, tbsize); - sk_set_rbsize(sock, 16); - byte *pos = sock->tbuf; - uint size = tbsize; - int len = user_put_device(p->dev, &pos, &size); - - log(L_TRACE "WG: put %d %s", size, sock->tbuf); - - if (len < 0) - { - /* FIXME close */ - return -1; - } - res = sk_send(sock, tbsize - size); - /* Send data, <0=err, >0=ok, 0=sleep */ - log(L_TRACE "WG: send %d", res); - - /* abort(); */ - return -1; -} - -static int get_device(struct wg_proto *p, wg_device **pdev, const char *device_name) { struct wg_config *c = (struct wg_config *) p->p.cf; @@ -339,8 +100,10 @@ int get_device(struct wg_proto *p, wg_device **pdev, const char *device_name) static int set_device(struct wg_proto *p) { - if (has_userspace(p)) - return user_set_device(p); + struct wg_config *c = (struct wg_config *) p->p.cf; + + if (wg_has_userspace(c->ifname)) + return wg_user_set_device(p->p.pool, c->ifname, p->dev); else { log(L_TRACE "WG: wg_set_device"); diff --git a/sysdep/unix/Makefile b/sysdep/unix/Makefile index f592399c..5272408b 100644 --- a/sysdep/unix/Makefile +++ b/sysdep/unix/Makefile @@ -1,4 +1,4 @@ -src := io.c krt.c log.c main.c random.c +src := io.c krt.c log.c main.c random.c wg_user.c obj := $(src-o-files) $(all-daemon) $(cf-local) diff --git a/sysdep/unix/wg_user.c b/sysdep/unix/wg_user.c new file mode 100644 index 00000000..54ab2333 --- /dev/null +++ b/sysdep/unix/wg_user.c @@ -0,0 +1,248 @@ +#include <stdio.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <unistd.h> +#include "lib/lists.h" +#include "lib/ip.h" +#include "lib/socket.h" +#include "nest/iface.h" +#include "sysdep/unix/unix.h" +#include "sysdep/unix/wg_user.h" +#include "sysdep/linux/wireguard.h" + +static +char *get_socket_path(const char *ifname, char *buf, uint size) +{ + bsnprintf(buf, size, SOCKET_PATH "%s.sock", ifname); + return buf; +} + +bool wg_has_userspace(const char *ifname) +{ + struct stat sb; + char tmp[sizeof(struct sockaddr_un)]; + + if (stat(get_socket_path(ifname, tmp, sizeof(tmp)), &sb) == 0) + return (sb.st_mode & S_IFMT) == S_IFSOCK; + else + { + DBG(L_TRACE "WG: no socket %s", tmp); + return false; + } +} + +/* NULL=receiving turned off, returns 1 to clear rx buffer */ +static +int user_rx_hook(struct birdsock *sk UNUSED, uint size) +{ + DBG(L_TRACE "WG: RX %d", size); + rfree(sk); + return 1; +} + +static +void user_tx_hook(struct birdsock *bs UNUSED) +{ + DBG(L_TRACE "WG: TX"); +} + +/* errno or zero if EOF */ +static +void user_err_hook(struct birdsock *bs, int err) +{ + /* if (err == 0) */ + /* return; */ + + log(L_TRACE "WG: ERR %d %s", err, bs->err); + if (bs->fd >= 0) + close(bs->fd); + bs->fd = -1; +} + +static void +wg_puts(const char *str, byte **buf, uint *size) +{ + int len = strlen(str); + if (0 < len && len < (int)*size) + { + strcpy(*buf, str); + *size -= len; + *buf += len; + } + else + *size = 0; +} + +static void +wg_put_str(const char *key, const char *value, byte **buf, uint *size) +{ + char tmp[128]; + + int len = snprintf(tmp, sizeof(tmp), "%s=%s\n", key, value); + if (0 < len && len < (int)*size) + { + strcpy(*buf, tmp); + *size -= len; + *buf += len; + } + else + *size = 0; +} + +static void +wg_put_u16(const char *key, u16 value, byte **buf, uint *size) +{ + char tmp[64]; + + int len = snprintf(tmp, sizeof(tmp), "%u", value); + if (len > 0) + wg_put_str(key, tmp, buf, size); + else + *size = 0; +} + +static void +wg_put_bool(const char *key, bool value, byte **buf, uint *size) +{ + if (value) + wg_put_str(key, "true", buf, size); +} + +static void +wg_put_key(const char *key, wg_key value, byte **buf, uint *size) +{ + char tmp[128]; + + for (uint i=0; i < sizeof(wg_key); i++) + bsnprintf(tmp+2*i, sizeof(tmp)-2*i, "%02x", value[i]); + + wg_put_str(key, tmp, buf, size); +} + +static void +wg_put_endpoint(const wg_endpoint *endpoint, byte **buf, uint *size) +{ + char tmp[INET6_ADDRSTRLEN + 16]; + ip_addr ip; + struct iface *ifa = NULL; + uint port = 0; + + if (sockaddr_read((sockaddr*)&endpoint->addr, endpoint->addr.sa_family, + &ip, &ifa, &port) == 0) + { + char *pos = NULL; + + if (ipa_is_ip4(ip)) + pos = ip4_ntop(ipa_to_ip4(ip), tmp); + else + { + tmp[0] = '['; + pos = ip6_ntop(ipa_to_ip6(ip), tmp + 1); + if (ifa) + pos += bsprintf(pos, "%%%u", ifa->index); + *pos++ = ']'; + } + + bsprintf(pos, ":%u", port); + wg_put_str("endpoint", tmp, buf, size); + } +} + +static void +wg_put_allowedip(wg_allowedip *allowedip, byte **buf, uint *size) +{ + char tmp[INET6_ADDRSTRLEN + 10]; + ip_addr ip = IP6_NONE; + + switch (allowedip->family) + { + case AF_INET: + ip = ipa_from_in4(allowedip->ip4); + break; + case AF_INET6: + ip = ipa_from_in6(allowedip->ip6); + break; + default: + return; + } + + int res = bsnprintf(tmp, sizeof(tmp), "%I/%u", ip, allowedip->cidr); + + if (res < 0) + { + *size = 0; + return; + } + + wg_put_str("allowed_ip", tmp, buf, size); +} + +static int +user_put_device(wg_device *dev, byte **buf, uint *size) +{ + wg_put_u16("set", 1, buf, size); + wg_put_key("private_key", dev->private_key, buf, size); + wg_put_u16("listen_port", dev->listen_port, buf, size); + wg_put_bool("replace_peers", dev->flags & WGDEVICE_REPLACE_PEERS, buf, size); + + wg_peer *peer = NULL; + wg_for_each_peer(dev, peer) + { + wg_put_key("public_key", peer->public_key, buf, size); + wg_put_endpoint(&peer->endpoint, buf, size); + wg_put_bool("replace_allowed_ips", peer->flags & WGPEER_REPLACE_ALLOWEDIPS, buf, size); + + wg_allowedip *allowedip = NULL; + wg_for_each_allowedip(peer, allowedip) + { + wg_put_allowedip(allowedip, buf, size); + } + } + wg_puts("\n", buf, size); + + if (*size > 0) + return 0; + else + return -1; +} + +int +wg_user_set_device(struct pool *pool, + const char *ifname, + struct wg_device *dev) +{ + char path[sizeof(struct sockaddr_un)]; + + bsnprintf(path, sizeof(path), SOCKET_PATH "%s.sock", ifname); + + struct birdsock *sock = sk_new(pool); + sock->rx_hook = user_rx_hook; + sock->tx_hook = user_tx_hook; + sock->err_hook = user_err_hook; + int res = sk_connect_unix(sock, path); + DBG(L_TRACE "WG: socket %d %d %s", res, sock->fd, path); + if (res < 0) + return -1; + + uint tbsize = 8192; + sk_set_tbsize(sock, tbsize); + sk_set_rbsize(sock, 16); + byte *pos = sock->tbuf; + uint size = tbsize; + int len = user_put_device(dev, &pos, &size); + + DBG(L_TRACE "WG: put %d %s", size, sock->tbuf); + + if (len < 0) + { + /* FIXME close */ + return -1; + } + res = sk_send(sock, tbsize - size); + /* Send data, <0=err, >0=ok, 0=sleep */ + DBG(L_TRACE "WG: send %d", res); + + /* abort(); */ + return -1; +} diff --git a/sysdep/unix/wg_user.h b/sysdep/unix/wg_user.h new file mode 100644 index 00000000..a5e4251a --- /dev/null +++ b/sysdep/unix/wg_user.h @@ -0,0 +1,14 @@ +#ifndef _BIRD_WG_USER_H +#define _BIRD_WG_USER_H + +#include "sysdep/config.h" + +#define SOCKET_PATH PATH_RUNSTATEDIR "/wireguard/" + +struct pool; +struct wg_device; + +bool wg_has_userspace(const char *ifname); +int wg_user_set_device(struct pool *pool, const char *ifname, struct wg_device *dev); + +#endif /* _BIRD_WG_USER_H */ |