From f129bdab552d21ae3cd77412342b94b5f23587b2 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Mon, 25 Sep 2017 04:22:09 +0200 Subject: netlink: switch from ioctl to netlink for configuration --- src/config.c | 353 ----------------------------------------------------------- 1 file changed, 353 deletions(-) delete mode 100644 src/config.c (limited to 'src/config.c') diff --git a/src/config.c b/src/config.c deleted file mode 100644 index a4a6782..0000000 --- a/src/config.c +++ /dev/null @@ -1,353 +0,0 @@ -/* Copyright (C) 2015-2017 Jason A. Donenfeld . All Rights Reserved. */ - -#include "config.h" -#include "device.h" -#include "socket.h" -#include "queueing.h" -#include "timers.h" -#include "hashtables.h" -#include "peer.h" -#include "uapi.h" -#include - -static int set_device_port(struct wireguard_device *wg, u16 port) -{ - struct wireguard_peer *peer, *temp; - if (wg->incoming_port == port) - return 0; - socket_uninit(wg); - wg->incoming_port = port; - peer_for_each (wg, peer, temp, false) - socket_clear_peer_endpoint_src(peer); - if (!netif_running(wg->dev)) - return 0; - return socket_init(wg); -} - -static int set_ipmask(struct wireguard_peer *peer, void __user *user_ipmask) -{ - int ret = -EINVAL; - struct wgipmask in_ipmask; - - if (copy_from_user(&in_ipmask, user_ipmask, sizeof(in_ipmask))) - return -EFAULT; - - if (in_ipmask.family == AF_INET && in_ipmask.cidr <= 32) - ret = routing_table_insert_v4(&peer->device->peer_routing_table, &in_ipmask.ip4, in_ipmask.cidr, peer); - else if (in_ipmask.family == AF_INET6 && in_ipmask.cidr <= 128) - ret = routing_table_insert_v6(&peer->device->peer_routing_table, &in_ipmask.ip6, in_ipmask.cidr, peer); - - return ret; -} - -static const u8 zeros[WG_KEY_LEN] = { 0 }; - -static int set_peer(struct wireguard_device *wg, void __user *user_peer, size_t *len) -{ - int ret = 0; - size_t i; - struct wgpeer in_peer; - void __user *user_ipmask; - struct wireguard_peer *peer = NULL; - - if (copy_from_user(&in_peer, user_peer, sizeof(in_peer))) - return -EFAULT; - - if (!memcmp(zeros, in_peer.public_key, NOISE_PUBLIC_KEY_LEN)) - return -EINVAL; /* Can't add a peer with no public key. */ - - peer = pubkey_hashtable_lookup(&wg->peer_hashtable, in_peer.public_key); - if (!peer) { /* Peer doesn't exist yet. Add a new one. */ - if (in_peer.flags & WGPEER_REMOVE_ME) - return -ENODEV; /* Tried to remove a non-existing peer. */ - if (in_peer.flags & WGPEER_REMOVE_PRESHARED_KEY) - return -EINVAL; /* Tried to remove a psk for a non-existing peer. */ - - down_read(&wg->static_identity.lock); - if (wg->static_identity.has_identity && !memcmp(in_peer.public_key, wg->static_identity.static_public, NOISE_PUBLIC_KEY_LEN)) { - /* We silently ignore peers that have the same public key as the device. The reason we do it silently - * is that we'd like for people to be able to reuse the same set of API calls across peers. */ - up_read(&wg->static_identity.lock); - goto out; - } - up_read(&wg->static_identity.lock); - - peer = peer_rcu_get(peer_create(wg, in_peer.public_key, in_peer.preshared_key)); - if (!peer) - return -ENOMEM; - } - - if (in_peer.flags & WGPEER_REMOVE_ME) { - peer_put(peer); - peer_remove(peer); - goto out; - } - - if (in_peer.flags & WGPEER_REMOVE_PRESHARED_KEY) { - down_write(&peer->handshake.lock); - memset(&peer->handshake.preshared_key, 0, NOISE_SYMMETRIC_KEY_LEN); - up_write(&peer->handshake.lock); - } else if (crypto_memneq(zeros, in_peer.preshared_key, WG_KEY_LEN)) { - down_write(&peer->handshake.lock); - memcpy(&peer->handshake.preshared_key, in_peer.preshared_key, NOISE_SYMMETRIC_KEY_LEN); - up_write(&peer->handshake.lock); - } - - if (in_peer.endpoint.addr.sa_family == AF_INET || in_peer.endpoint.addr.sa_family == AF_INET6) { - struct endpoint endpoint = { { { 0 } } }; - memcpy(&endpoint, &in_peer.endpoint, sizeof(in_peer.endpoint)); - socket_set_peer_endpoint(peer, &endpoint); - } - - if (in_peer.flags & WGPEER_REPLACE_IPMASKS) - routing_table_remove_by_peer(&wg->peer_routing_table, peer); - for (i = 0, user_ipmask = user_peer + sizeof(struct wgpeer); i < in_peer.num_ipmasks; ++i, user_ipmask += sizeof(struct wgipmask)) { - ret = set_ipmask(peer, user_ipmask); - if (ret) - break; - } - - if (in_peer.persistent_keepalive_interval != (u16)-1) { - const bool send_keepalive = !peer->persistent_keepalive_interval && in_peer.persistent_keepalive_interval && netif_running(wg->dev); - peer->persistent_keepalive_interval = (unsigned long)in_peer.persistent_keepalive_interval * HZ; - if (send_keepalive) - packet_send_keepalive(peer); - } - - if (netif_running(wg->dev)) - packet_send_staged_packets(peer); - - peer_put(peer); - -out: - if (!ret) - *len = sizeof(struct wgpeer) + (in_peer.num_ipmasks * sizeof(struct wgipmask)); - - return ret; -} - -int config_set_device(struct wireguard_device *wg, void __user *user_device) -{ - int ret; - size_t i, offset; - struct wireguard_peer *peer, *temp; - struct wgdevice in_device; - void __user *user_peer; - bool modified_static_identity = false; - - BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); - BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); - - mutex_lock(&wg->device_update_lock); - - ret = -EFAULT; - if (copy_from_user(&in_device, user_device, sizeof(in_device))) - goto out; - - ret = -EPROTO; - if (in_device.version_magic != WG_API_VERSION_MAGIC) - goto out; - - if (in_device.fwmark || (!in_device.fwmark && (in_device.flags & WGDEVICE_REMOVE_FWMARK))) { - wg->fwmark = in_device.fwmark; - peer_for_each (wg, peer, temp, false) - socket_clear_peer_endpoint_src(peer); - } - - if (in_device.port) { - ret = set_device_port(wg, in_device.port); - if (ret) - goto out; - } - - if (in_device.flags & WGDEVICE_REPLACE_PEERS) - peer_remove_all(wg); - - if (in_device.flags & WGDEVICE_REMOVE_PRIVATE_KEY) { - noise_set_static_identity_private_key(&wg->static_identity, NULL); - modified_static_identity = true; - } else if (crypto_memneq(zeros, in_device.private_key, WG_KEY_LEN)) { - u8 public_key[NOISE_PUBLIC_KEY_LEN] = { 0 }; - struct wireguard_peer *peer; - /* We remove before setting, to prevent race, which means doing two 25519-genpub ops. */ - bool unused __attribute((unused)) = curve25519_generate_public(public_key, in_device.private_key); - peer = pubkey_hashtable_lookup(&wg->peer_hashtable, public_key); - if (peer) { - peer_put(peer); - peer_remove(peer); - } - - noise_set_static_identity_private_key(&wg->static_identity, in_device.private_key); - modified_static_identity = true; - } - - if (modified_static_identity) { - peer_for_each (wg, peer, temp, false) { - if (!noise_precompute_static_static(peer)) - peer_remove(peer); - } - cookie_checker_precompute_device_keys(&wg->cookie_checker); - } - - for (i = 0, offset = 0, user_peer = user_device + sizeof(struct wgdevice); i < in_device.num_peers; ++i, user_peer += offset) { - ret = set_peer(wg, user_peer, &offset); - if (ret) - goto out; - } - ret = 0; -out: - mutex_unlock(&wg->device_update_lock); - memzero_explicit(&in_device.private_key, NOISE_PUBLIC_KEY_LEN); - return ret; -} - -struct data_remaining { - void __user *data; - size_t out_len; - size_t count; -}; - -static inline int use_data(struct data_remaining *data, size_t size) -{ - if (data->out_len < size) - return -EMSGSIZE; - data->out_len -= size; - data->data += size; - ++data->count; - return 0; -} - -static int populate_ipmask(void *ctx, union nf_inet_addr ip, u8 cidr, int family) -{ - int ret; - struct data_remaining *data = ctx; - void __user *uipmask = data->data; - struct wgipmask out_ipmask; - - memset(&out_ipmask, 0, sizeof(struct wgipmask)); - - ret = use_data(data, sizeof(struct wgipmask)); - if (ret) - return ret; - - out_ipmask.cidr = cidr; - out_ipmask.family = family; - if (family == AF_INET) - out_ipmask.ip4 = ip.in; - else if (family == AF_INET6) - out_ipmask.ip6 = ip.in6; - - if (copy_to_user(uipmask, &out_ipmask, sizeof(out_ipmask))) - ret = -EFAULT; - - return ret; -} - -static int populate_peer(struct wireguard_peer *peer, struct data_remaining *data) -{ - int ret = 0; - void __user *upeer = data->data; - struct wgpeer out_peer; - struct data_remaining ipmasks_data = { NULL }; - - memset(&out_peer, 0, sizeof(struct wgpeer)); - - ret = use_data(data, sizeof(struct wgpeer)); - if (ret) - return ret; - - down_read(&peer->handshake.lock); - memcpy(out_peer.public_key, peer->handshake.remote_static, NOISE_PUBLIC_KEY_LEN); - memcpy(out_peer.preshared_key, peer->handshake.preshared_key, NOISE_SYMMETRIC_KEY_LEN); - up_read(&peer->handshake.lock); - - read_lock_bh(&peer->endpoint_lock); - if (peer->endpoint.addr.sa_family == AF_INET) - out_peer.endpoint.addr4 = peer->endpoint.addr4; - else if (peer->endpoint.addr.sa_family == AF_INET6) - out_peer.endpoint.addr6 = peer->endpoint.addr6; - read_unlock_bh(&peer->endpoint_lock); - out_peer.last_handshake_time = peer->walltime_last_handshake; - out_peer.tx_bytes = peer->tx_bytes; - out_peer.rx_bytes = peer->rx_bytes; - out_peer.persistent_keepalive_interval = (u16)(peer->persistent_keepalive_interval / HZ); - - ipmasks_data.out_len = data->out_len; - ipmasks_data.data = data->data; - ret = routing_table_walk_ips_by_peer_sleepable(&peer->device->peer_routing_table, &ipmasks_data, peer, populate_ipmask); - if (ret) - return ret; - data->out_len = ipmasks_data.out_len; - data->data = ipmasks_data.data; - out_peer.num_ipmasks = ipmasks_data.count; - - if (copy_to_user(upeer, &out_peer, sizeof(out_peer))) - ret = -EFAULT; - return ret; -} - -int config_get_device(struct wireguard_device *wg, void __user *user_device) -{ - int ret; - struct wireguard_peer *peer, *temp; - struct data_remaining peer_data = { NULL }; - struct wgdevice out_device; - struct wgdevice in_device; - - BUILD_BUG_ON(WG_KEY_LEN != NOISE_PUBLIC_KEY_LEN); - BUILD_BUG_ON(WG_KEY_LEN != NOISE_SYMMETRIC_KEY_LEN); - - memset(&out_device, 0, sizeof(struct wgdevice)); - - mutex_lock(&wg->device_update_lock); - - if (!user_device) { - ret = peer_total_count(wg) * sizeof(struct wgpeer) - + routing_table_count_nodes(&wg->peer_routing_table) * sizeof(struct wgipmask); - goto out; - } - - ret = -EFAULT; - if (copy_from_user(&in_device, user_device, sizeof(in_device))) - goto out; - - ret = -EPROTO; - if (in_device.version_magic != WG_API_VERSION_MAGIC) - goto out; - - out_device.version_magic = WG_API_VERSION_MAGIC; - out_device.port = wg->incoming_port; - out_device.fwmark = wg->fwmark; - memcpy(out_device.interface, wg->dev->name, IFNAMSIZ); - - down_read(&wg->static_identity.lock); - if (wg->static_identity.has_identity) { - memcpy(out_device.private_key, wg->static_identity.static_private, WG_KEY_LEN); - memcpy(out_device.public_key, wg->static_identity.static_public, WG_KEY_LEN); - } - up_read(&wg->static_identity.lock); - - peer_data.out_len = in_device.peers_size; - peer_data.data = user_device + sizeof(struct wgdevice); - - ret = 0; - peer_for_each (wg, peer, temp, false) { - ret = populate_peer(peer, &peer_data); - if (ret) - break; - } - if (ret) - goto out; - out_device.num_peers = peer_data.count; - - ret = -EFAULT; - if (copy_to_user(user_device, &out_device, sizeof(out_device))) - goto out; - - ret = 0; - -out: - mutex_unlock(&wg->device_update_lock); - memzero_explicit(&out_device.private_key, NOISE_PUBLIC_KEY_LEN); - return ret; -} -- cgit v1.2.3-59-g8ed1b