aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/config.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-09-25 04:22:09 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2017-10-02 02:45:53 +0200
commitf129bdab552d21ae3cd77412342b94b5f23587b2 (patch)
tree4cb9ebc3ed181a9fd463ac00dbca0274c647a79c /src/config.c
parenttools: uapi: only make sure socket file is socket (diff)
downloadwireguard-monolithic-historical-f129bdab552d21ae3cd77412342b94b5f23587b2.tar.xz
wireguard-monolithic-historical-f129bdab552d21ae3cd77412342b94b5f23587b2.zip
netlink: switch from ioctl to netlink for configuration
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c353
1 files changed, 0 insertions, 353 deletions
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 <Jason@zx2c4.com>. 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 <crypto/algapi.h>
-
-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;
-}