aboutsummaryrefslogtreecommitdiffstats
path: root/src/if_wg.c
diff options
context:
space:
mode:
authorMatt Dunwoodie <ncon@noconroy.net>2021-04-16 22:21:34 +1000
committerMatt Dunwoodie <ncon@noconroy.net>2021-04-19 10:38:03 +1000
commit0b005923e758cec6d7420dff0c08a62f7c347066 (patch)
tree841e7bb0e2f763c025c988dcb7058f9b81fd21cf /src/if_wg.c
parentif_wg: warn when we can't bind to sockets (diff)
downloadwireguard-freebsd-0b005923e758cec6d7420dff0c08a62f7c347066.tar.xz
wireguard-freebsd-0b005923e758cec6d7420dff0c08a62f7c347066.zip
if_wg: import latest wg_noise.{c,h}
Note: this is a partial diff, introducing temporary bugs that will be resolved in following commits, detailed below. This commit brings wg_noise.{c,h} up to date with wireguard-openbsd. The primary motivator for this large patchset is to allow checking nonces serial, requiring a reference to the receiving keypair across noise_* calls. Due to requiring reference counting on the keypairs, we also take this opportunity to throw away the old locking and bring in EPOCH (roughly equivalent to SMR on OpenBSD and RCU on Linux). The changes to if_wg.c are purely to allow it to compile, there are most certainly refcount leaks present (to be addressed in the following commits). Readers should review wg_noise.{c,h} in their entirety rather than the diffs, as there are significant changes. if_wg.c can be reviewed, but must be contextualised with the following commits (repace wg_tag with wg_packet, encrypt mbuf in place). Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
Diffstat (limited to 'src/if_wg.c')
-rw-r--r--src/if_wg.c569
1 files changed, 152 insertions, 417 deletions
diff --git a/src/if_wg.c b/src/if_wg.c
index 6f4d225..70f6b4b 100644
--- a/src/if_wg.c
+++ b/src/if_wg.c
@@ -89,13 +89,7 @@ __FBSDID("$FreeBSD$");
#define MAX_QUEUED_HANDSHAKES 4096
-#define HASHTABLE_PEER_SIZE (1 << 11)
-#define HASHTABLE_INDEX_SIZE (1 << 13)
-#define MAX_PEERS_PER_IFACE (1 << 20)
-
-#define REKEY_TIMEOUT 5
#define REKEY_TIMEOUT_JITTER 334 /* 1/3 sec, round for arc4random_uniform */
-#define KEEPALIVE_TIMEOUT 10
#define MAX_TIMER_HANDSHAKES (90 / REKEY_TIMEOUT)
#define NEW_HANDSHAKE_TIMEOUT (REKEY_TIMEOUT + KEEPALIVE_TIMEOUT)
#define UNDERLOAD_TIMEOUT 1
@@ -163,19 +157,13 @@ struct wg_endpoint {
struct wg_tag {
struct m_tag t_tag;
struct wg_endpoint t_endpoint;
- struct wg_peer *t_peer;
+ struct noise_keypair *t_keypair;
+ uint64_t t_nonce;
struct mbuf *t_mbuf;
int t_done;
int t_mtu;
};
-struct wg_index {
- LIST_ENTRY(wg_index) i_entry;
- SLIST_ENTRY(wg_index) i_unused_entry;
- uint32_t i_key;
- struct noise_remote *i_value;
-};
-
struct wg_timers {
/* t_lock is for blocking wg_timers_event_* when setting t_disabled. */
struct rwlock t_lock;
@@ -190,7 +178,6 @@ struct wg_timers {
struct callout t_persistent_keepalive;
struct mtx t_handshake_mtx;
- struct timespec t_handshake_last_sent;
struct timespec t_handshake_complete;
volatile int t_handshake_retries;
};
@@ -209,26 +196,21 @@ struct wg_queue {
};
struct wg_peer {
- CK_LIST_ENTRY(wg_peer) p_hash_entry;
- CK_LIST_ENTRY(wg_peer) p_entry;
+ TAILQ_ENTRY(wg_peer) p_entry;
uint64_t p_id;
struct wg_softc *p_sc;
- struct noise_remote p_remote;
+ struct noise_remote *p_remote;
struct cookie_maker p_cookie;
struct wg_timers p_timers;
struct rwlock p_endpoint_lock;
struct wg_endpoint p_endpoint;
- SLIST_HEAD(,wg_index) p_unused_index;
- struct wg_index p_index[3];
-
struct wg_queue p_stage_queue;
struct wg_queue p_encap_queue;
struct wg_queue p_decap_queue;
- struct grouptask p_clear_secrets;
struct grouptask p_send_initiation;
struct grouptask p_send_keepalive;
struct grouptask p_send;
@@ -238,8 +220,6 @@ struct wg_peer {
counter_u64_t p_rx_bytes;
CK_LIST_HEAD(, wg_aip) p_aips;
- struct mtx p_lock;
- struct epoch_context p_ctx;
};
enum route_direction {
@@ -264,15 +244,6 @@ struct wg_allowedip {
uint8_t cidr;
};
-struct wg_hashtable {
- struct mtx h_mtx;
- SIPHASH_KEY h_secret;
- CK_LIST_HEAD(, wg_peer) h_peers_list;
- CK_LIST_HEAD(, wg_peer) *h_peers;
- u_long h_peers_mask;
- size_t h_num_peers;
-};
-
struct wg_socket {
struct mtx so_mtx;
struct socket *so_so4;
@@ -289,13 +260,15 @@ struct wg_softc {
struct ucred *sc_ucred;
struct wg_socket sc_socket;
- struct wg_hashtable sc_hashtable;
struct wg_aip_table sc_aips;
+ TAILQ_HEAD(,wg_peer) sc_peers;
+ size_t sc_peers_num;
+
struct mbufq sc_handshake_queue;
struct grouptask sc_handshake;
- struct noise_local sc_local;
+ struct noise_local *sc_local;
struct cookie_checker sc_cookie;
struct buf_ring *sc_encap_ring;
@@ -304,12 +277,7 @@ struct wg_softc {
struct grouptask *sc_encrypt;
struct grouptask *sc_decrypt;
- struct rwlock sc_index_lock;
- LIST_HEAD(,wg_index) *sc_index;
- u_long sc_index_mask;
-
struct sx sc_lock;
- volatile u_int sc_peer_count;
};
#define WGF_DYING 0x0001
@@ -369,11 +337,9 @@ static void wg_timers_event_any_authenticated_packet_sent(struct wg_timers *);
static void wg_timers_event_any_authenticated_packet_received(struct wg_timers *);
static void wg_timers_event_any_authenticated_packet_traversal(struct wg_timers *);
static void wg_timers_event_handshake_initiated(struct wg_timers *);
-static void wg_timers_event_handshake_responded(struct wg_timers *);
static void wg_timers_event_handshake_complete(struct wg_timers *);
static void wg_timers_event_session_derived(struct wg_timers *);
static void wg_timers_event_want_initiation(struct wg_timers *);
-static void wg_timers_event_reset_handshake_last_sent(struct wg_timers *);
static void wg_timers_run_send_initiation(struct wg_timers *, int);
static void wg_timers_run_retry_handshake(struct wg_timers *);
static void wg_timers_run_send_keepalive(struct wg_timers *);
@@ -385,8 +351,6 @@ static void wg_timers_enable(struct wg_timers *);
static void wg_timers_disable(struct wg_timers *);
static void wg_timers_set_persistent_keepalive(struct wg_timers *, uint16_t);
static void wg_timers_get_last_handshake(struct wg_timers *, struct wg_timespec64 *);
-static int wg_timers_expired_handshake_last_sent(struct wg_timers *);
-static int wg_timers_check_handshake_last_sent(struct wg_timers *);
static void wg_queue_init(struct wg_queue *, const char *);
static void wg_queue_deinit(struct wg_queue *);
static void wg_queue_purge(struct wg_queue *);
@@ -404,14 +368,9 @@ static int wg_peer_remove(struct radix_node *, void *);
static void wg_peer_remove_all(struct wg_softc *);
static int wg_aip_delete(struct wg_aip_table *, struct wg_peer *);
static struct wg_peer *wg_aip_lookup(struct wg_aip_table *, struct mbuf *, enum route_direction);
-static void wg_hashtable_init(struct wg_hashtable *);
-static void wg_hashtable_destroy(struct wg_hashtable *);
-static void wg_hashtable_peer_insert(struct wg_hashtable *, struct wg_peer *);
-static struct wg_peer *wg_peer_lookup(struct wg_softc *, const uint8_t [32]);
-static void wg_hashtable_peer_remove(struct wg_hashtable *, struct wg_peer *);
static int wg_cookie_validate_packet(struct cookie_checker *, struct mbuf *, int);
static struct wg_peer *wg_peer_alloc(struct wg_softc *);
-static void wg_peer_free_deferred(epoch_context_t);
+static void wg_peer_free_deferred(struct noise_remote *);
static void wg_peer_destroy(struct wg_peer *);
static void wg_peer_send_buf(struct wg_peer *, uint8_t *, size_t);
static void wg_send_initiation(struct wg_peer *);
@@ -430,10 +389,6 @@ static void wg_decap(struct wg_softc *, struct mbuf *);
static void wg_softc_handshake_receive(struct wg_softc *);
static void wg_softc_decrypt(struct wg_softc *);
static void wg_softc_encrypt(struct wg_softc *);
-static struct noise_remote *wg_remote_get(struct wg_softc *, uint8_t [NOISE_PUBLIC_KEY_LEN]);
-static uint32_t wg_index_set(struct wg_softc *, struct noise_remote *);
-static struct noise_remote *wg_index_get(struct wg_softc *, uint32_t);
-static void wg_index_drop(struct wg_softc *, uint32_t);
static int wg_update_endpoint_addrs(struct wg_endpoint *, const struct sockaddr *, struct ifnet *);
static void wg_input(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *);
static void wg_encrypt_dispatch(struct wg_softc *);
@@ -480,9 +435,6 @@ wg_peer_alloc(struct wg_softc *sc)
taskqgroup_attach(qgroup_wg_tqg, &peer->p_send_initiation, peer, NULL, NULL, "wg initiation");
GROUPTASK_INIT(&peer->p_send_keepalive, 0, (gtask_fn_t *)wg_send_keepalive, peer);
taskqgroup_attach(qgroup_wg_tqg, &peer->p_send_keepalive, peer, NULL, NULL, "wg keepalive");
- GROUPTASK_INIT(&peer->p_clear_secrets, 0, (gtask_fn_t *)noise_remote_clear, &peer->p_remote);
- taskqgroup_attach(qgroup_wg_tqg, &peer->p_clear_secrets,
- &peer->p_remote, NULL, NULL, "wg clear secrets");
GROUPTASK_INIT(&peer->p_send, 0, (gtask_fn_t *)wg_deliver_out, peer);
taskqgroup_attach(qgroup_wg_tqg, &peer->p_send, peer, NULL, NULL, "wg send");
@@ -494,91 +446,13 @@ wg_peer_alloc(struct wg_softc *sc)
peer->p_tx_bytes = counter_u64_alloc(M_WAITOK);
peer->p_rx_bytes = counter_u64_alloc(M_WAITOK);
- SLIST_INIT(&peer->p_unused_index);
- SLIST_INSERT_HEAD(&peer->p_unused_index, &peer->p_index[0],
- i_unused_entry);
- SLIST_INSERT_HEAD(&peer->p_unused_index, &peer->p_index[1],
- i_unused_entry);
- SLIST_INSERT_HEAD(&peer->p_unused_index, &peer->p_index[2],
- i_unused_entry);
-
return (peer);
}
-#define WG_HASHTABLE_PEER_FOREACH(peer, i, ht) \
- for (i = 0; i < HASHTABLE_PEER_SIZE; i++) \
- LIST_FOREACH(peer, &(ht)->h_peers[i], p_hash_entry)
-#define WG_HASHTABLE_PEER_FOREACH_SAFE(peer, i, ht, tpeer) \
- for (i = 0; i < HASHTABLE_PEER_SIZE; i++) \
- CK_LIST_FOREACH_SAFE(peer, &(ht)->h_peers[i], p_hash_entry, tpeer)
-static void
-wg_hashtable_init(struct wg_hashtable *ht)
-{
- mtx_init(&ht->h_mtx, "hash lock", NULL, MTX_DEF);
- arc4random_buf(&ht->h_secret, sizeof(ht->h_secret));
- ht->h_num_peers = 0;
- ht->h_peers = hashinit(HASHTABLE_PEER_SIZE, M_DEVBUF,
- &ht->h_peers_mask);
-}
-
-static void
-wg_hashtable_destroy(struct wg_hashtable *ht)
-{
- MPASS(ht->h_num_peers == 0);
- mtx_destroy(&ht->h_mtx);
- hashdestroy(ht->h_peers, M_DEVBUF, ht->h_peers_mask);
-}
-
static void
-wg_hashtable_peer_insert(struct wg_hashtable *ht, struct wg_peer *peer)
+wg_peer_free_deferred(struct noise_remote *r)
{
- uint64_t key;
-
- key = siphash24(&ht->h_secret, peer->p_remote.r_public,
- sizeof(peer->p_remote.r_public));
-
- mtx_lock(&ht->h_mtx);
- ht->h_num_peers++;
- CK_LIST_INSERT_HEAD(&ht->h_peers[key & ht->h_peers_mask], peer, p_hash_entry);
- CK_LIST_INSERT_HEAD(&ht->h_peers_list, peer, p_entry);
- mtx_unlock(&ht->h_mtx);
-}
-
-static struct wg_peer *
-wg_peer_lookup(struct wg_softc *sc,
- const uint8_t pubkey[WG_KEY_SIZE])
-{
- struct wg_hashtable *ht = &sc->sc_hashtable;
- uint64_t key;
- struct wg_peer *i = NULL;
-
- key = siphash24(&ht->h_secret, pubkey, WG_KEY_SIZE);
-
- mtx_lock(&ht->h_mtx);
- CK_LIST_FOREACH(i, &ht->h_peers[key & ht->h_peers_mask], p_hash_entry) {
- if (timingsafe_bcmp(i->p_remote.r_public, pubkey,
- WG_KEY_SIZE) == 0)
- break;
- }
- mtx_unlock(&ht->h_mtx);
-
- return i;
-}
-
-static void
-wg_hashtable_peer_remove(struct wg_hashtable *ht, struct wg_peer *peer)
-{
- mtx_lock(&ht->h_mtx);
- ht->h_num_peers--;
- CK_LIST_REMOVE(peer, p_hash_entry);
- CK_LIST_REMOVE(peer, p_entry);
- mtx_unlock(&ht->h_mtx);
-}
-
-static void
-wg_peer_free_deferred(epoch_context_t ctx)
-{
- struct wg_peer *peer = __containerof(ctx, struct wg_peer, p_ctx);
+ struct wg_peer *peer = noise_remote_arg(r);
counter_u64_free(peer->p_tx_bytes);
counter_u64_free(peer->p_rx_bytes);
rw_destroy(&peer->p_timers.t_lock);
@@ -599,13 +473,11 @@ wg_peer_destroy(struct wg_peer *peer)
wg_timers_disable(&peer->p_timers);
/* Ensure the tasks have finished running */
- GROUPTASK_DRAIN(&peer->p_clear_secrets);
GROUPTASK_DRAIN(&peer->p_send_initiation);
GROUPTASK_DRAIN(&peer->p_send_keepalive);
GROUPTASK_DRAIN(&peer->p_recv);
GROUPTASK_DRAIN(&peer->p_send);
- taskqgroup_detach(qgroup_wg_tqg, &peer->p_clear_secrets);
taskqgroup_detach(qgroup_wg_tqg, &peer->p_send_initiation);
taskqgroup_detach(qgroup_wg_tqg, &peer->p_send_keepalive);
taskqgroup_detach(qgroup_wg_tqg, &peer->p_recv);
@@ -616,10 +488,10 @@ wg_peer_destroy(struct wg_peer *peer)
wg_queue_deinit(&peer->p_stage_queue);
/* Final cleanup */
- --peer->p_sc->sc_peer_count;
- noise_remote_clear(&peer->p_remote);
+ peer->p_sc->sc_peers_num--;
+ TAILQ_REMOVE(&peer->p_sc->sc_peers, peer, p_entry);
DPRINTF(peer->p_sc, "Peer %llu destroyed\n", (unsigned long long)peer->p_id);
- NET_EPOCH_CALL(wg_peer_free_deferred, &peer->p_ctx);
+ noise_remote_free(peer->p_remote, wg_peer_free_deferred);
}
static void
@@ -888,11 +760,8 @@ wg_peer_remove_all(struct wg_softc *sc)
sx_assert(&sc->sc_lock, SX_XLOCKED);
- CK_LIST_FOREACH_SAFE(peer, &sc->sc_hashtable.h_peers_list,
- p_entry, tpeer) {
- wg_hashtable_peer_remove(&sc->sc_hashtable, peer);
+ TAILQ_FOREACH_SAFE(peer, &sc->sc_peers, p_entry, tpeer)
wg_peer_destroy(peer);
- }
}
static int
@@ -1253,29 +1122,6 @@ wg_timers_get_last_handshake(struct wg_timers *t, struct wg_timespec64 *time)
rw_runlock(&t->t_lock);
}
-static int
-wg_timers_expired_handshake_last_sent(struct wg_timers *t)
-{
- struct timespec uptime;
- struct timespec expire = { .tv_sec = REKEY_TIMEOUT, .tv_nsec = 0 };
-
- getnanouptime(&uptime);
- timespecadd(&t->t_handshake_last_sent, &expire, &expire);
- return timespeccmp(&uptime, &expire, >) ? ETIMEDOUT : 0;
-}
-
-static int
-wg_timers_check_handshake_last_sent(struct wg_timers *t)
-{
- int ret;
-
- rw_wlock(&t->t_lock);
- if ((ret = wg_timers_expired_handshake_last_sent(t)) == ETIMEDOUT)
- getnanouptime(&t->t_handshake_last_sent);
- rw_wunlock(&t->t_lock);
- return (ret);
-}
-
/* Should be called after an authenticated data packet is sent. */
static void
wg_timers_event_data_sent(struct wg_timers *t)
@@ -1354,14 +1200,6 @@ wg_timers_event_handshake_initiated(struct wg_timers *t)
rw_runlock(&t->t_lock);
}
-static void
-wg_timers_event_handshake_responded(struct wg_timers *t)
-{
- rw_wlock(&t->t_lock);
- getnanouptime(&t->t_handshake_last_sent);
- rw_wunlock(&t->t_lock);
-}
-
/*
* Should be called after a handshake response message is received and processed
* or when getting key confirmation via the first data message.
@@ -1405,20 +1243,12 @@ wg_timers_event_want_initiation(struct wg_timers *t)
}
static void
-wg_timers_event_reset_handshake_last_sent(struct wg_timers *t)
-{
- rw_wlock(&t->t_lock);
- t->t_handshake_last_sent.tv_sec -= (REKEY_TIMEOUT + 1);
- rw_wunlock(&t->t_lock);
-}
-
-static void
wg_timers_run_send_initiation(struct wg_timers *t, int is_retry)
{
struct wg_peer *peer = __containerof(t, struct wg_peer, p_timers);
if (!is_retry)
t->t_handshake_retries = 0;
- if (wg_timers_expired_handshake_last_sent(t) == ETIMEDOUT)
+ if (noise_remote_initiation_expired(peer->p_remote) == ETIMEDOUT)
GROUPTASK_ENQUEUE(&peer->p_send_initiation);
}
@@ -1489,7 +1319,7 @@ wg_timers_run_zero_key_material(struct wg_timers *t)
DPRINTF(peer->p_sc, "Zeroing out all keys for peer %llu, since we "
"haven't received a new one in %d seconds\n",
(unsigned long long)peer->p_id, REJECT_AFTER_TIME * 3);
- GROUPTASK_ENQUEUE(&peer->p_clear_secrets);
+ noise_remote_keypairs_clear(peer->p_remote);
}
static void
@@ -1520,15 +1350,14 @@ wg_send_initiation(struct wg_peer *peer)
struct wg_pkt_initiation pkt;
struct epoch_tracker et;
- if (wg_timers_check_handshake_last_sent(&peer->p_timers) != ETIMEDOUT)
- return;
- DPRINTF(peer->p_sc, "Sending handshake initiation to peer %llu\n",
- (unsigned long long)peer->p_id);
-
NET_EPOCH_ENTER(et);
- if (noise_create_initiation(&peer->p_remote, &pkt.s_idx, pkt.ue,
+ if (noise_create_initiation(peer->p_remote, &pkt.s_idx, pkt.ue,
pkt.es, pkt.ets) != 0)
goto out;
+
+ DPRINTF(peer->p_sc, "Sending handshake initiation to peer %llu\n",
+ (unsigned long long)peer->p_id);
+
pkt.t = WG_PKT_INITIATION;
cookie_maker_mac(&peer->p_cookie, &pkt.m, &pkt,
sizeof(pkt)-sizeof(pkt.m));
@@ -1545,21 +1374,17 @@ wg_send_response(struct wg_peer *peer)
struct epoch_tracker et;
NET_EPOCH_ENTER(et);
+ if (noise_create_response(peer->p_remote, &pkt.s_idx, &pkt.r_idx,
+ pkt.ue, pkt.en) != 0)
+ goto out;
DPRINTF(peer->p_sc, "Sending handshake response to peer %llu\n",
(unsigned long long)peer->p_id);
- if (noise_create_response(&peer->p_remote, &pkt.s_idx, &pkt.r_idx,
- pkt.ue, pkt.en) != 0)
- goto out;
- if (noise_remote_begin_session(&peer->p_remote) != 0)
- goto out;
-
wg_timers_event_session_derived(&peer->p_timers);
pkt.t = WG_PKT_RESPONSE;
cookie_maker_mac(&peer->p_cookie, &pkt.m, &pkt,
sizeof(pkt)-sizeof(pkt.m));
- wg_timers_event_handshake_responded(&peer->p_timers);
wg_peer_send_buf(peer, (uint8_t*)&pkt, sizeof(pkt));
out:
NET_EPOCH_EXIT(et);
@@ -1600,7 +1425,6 @@ wg_send_keepalive(struct wg_peer *peer)
m_freem(m);
return;
}
- t->t_peer = peer;
t->t_mbuf = NULL;
t->t_done = 0;
t->t_mtu = 0; /* MTU == 0 OK for keepalive */
@@ -1673,10 +1497,6 @@ wg_handshake(struct wg_softc *sc, struct mbuf *m)
res = wg_cookie_validate_packet(&sc->sc_cookie, m, underload);
- if (res && res != EAGAIN) {
- printf("validate_packet got %d\n", res);
- goto free;
- }
if (res == EINVAL) {
DPRINTF(sc, "Invalid initiation MAC\n");
goto free;
@@ -1699,13 +1519,13 @@ wg_handshake(struct wg_softc *sc, struct mbuf *m)
wg_send_cookie(sc, &init->m, init->s_idx, m);
goto free;
}
- if (noise_consume_initiation(&sc->sc_local, &remote,
+ if (noise_consume_initiation(sc->sc_local, &remote,
init->s_idx, init->ue, init->es, init->ets) != 0) {
DPRINTF(sc, "Invalid handshake initiation");
goto free;
}
- peer = __containerof(remote, struct wg_peer, p_remote);
+ peer = noise_remote_arg(remote);
DPRINTF(sc, "Receiving handshake initiation from peer %llu\n",
(unsigned long long)peer->p_id);
counter_u64_add(peer->p_rx_bytes, sizeof(*init));
@@ -1721,46 +1541,43 @@ wg_handshake(struct wg_softc *sc, struct mbuf *m)
wg_send_cookie(sc, &resp->m, resp->s_idx, m);
goto free;
}
-
- if ((remote = wg_index_get(sc, resp->r_idx)) == NULL) {
- DPRINTF(sc, "Unknown handshake response\n");
- goto free;
- }
- peer = __containerof(remote, struct wg_peer, p_remote);
- if (noise_consume_response(remote, resp->s_idx, resp->r_idx,
- resp->ue, resp->en) != 0) {
+ if (noise_consume_response(sc->sc_local, &remote, resp->s_idx,
+ resp->r_idx, resp->ue, resp->en) != 0) {
DPRINTF(sc, "Invalid handshake response\n");
goto free;
}
+ peer = noise_remote_arg(remote);
+
DPRINTF(sc, "Receiving handshake response from peer %llu\n",
(unsigned long long)peer->p_id);
+
+ wg_timers_event_session_derived(&peer->p_timers);
+ wg_timers_event_handshake_complete(&peer->p_timers);
+
counter_u64_add(peer->p_rx_bytes, sizeof(*resp));
if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, sizeof(*resp));
wg_peer_set_endpoint_from_tag(peer, t);
- if (noise_remote_begin_session(&peer->p_remote) == 0) {
- wg_timers_event_session_derived(&peer->p_timers);
- wg_timers_event_handshake_complete(&peer->p_timers);
- }
break;
case WG_PKT_COOKIE:
cook = mtod(m, struct wg_pkt_cookie *);
- if ((remote = wg_index_get(sc, cook->r_idx)) == NULL) {
+ if ((remote = noise_remote_index_lookup(sc->sc_local,
+ cook->r_idx)) == NULL) {
DPRINTF(sc, "Unknown cookie index\n");
goto free;
}
- peer = __containerof(remote, struct wg_peer, p_remote);
+ peer = noise_remote_arg(remote);
if (cookie_maker_consume_payload(&peer->p_cookie,
- cook->nonce, cook->ec) != 0) {
+ cook->nonce, cook->ec) == 0) {
+ DPRINTF(sc, "Receiving cookie response\n");
+ } else {
DPRINTF(sc, "Could not decrypt cookie response\n");
- goto free;
}
-
- DPRINTF(sc, "Receiving cookie response\n");
+ noise_remote_put(remote);
goto free;
default:
goto free;
@@ -1788,15 +1605,19 @@ wg_encap(struct wg_softc *sc, struct mbuf *m)
{
struct wg_pkt_data *data;
size_t padding_len, plaintext_len, out_len;
+ struct noise_remote *remote;
struct mbuf *mc;
struct wg_peer *peer;
struct wg_tag *t;
uint64_t nonce;
- int res, allocation_order;
+ int allocation_order;
NET_EPOCH_ASSERT();
t = wg_tag_get(m);
- peer = t->t_peer;
+ remote = noise_keypair_remote(t->t_keypair);
+ peer = noise_remote_arg(remote);
+ /* We can put the remote as we still hold a keypair ref */
+ noise_remote_put(remote);
plaintext_len = MIN(WG_PKT_WITH_PADDING(m->m_pkthdr.len), t->t_mtu);
padding_len = plaintext_len - m->m_pkthdr.len;
@@ -1822,23 +1643,11 @@ wg_encap(struct wg_softc *sc, struct mbuf *m)
data->t = WG_PKT_DATA;
- res = noise_remote_encrypt(&peer->p_remote, &data->r_idx, &nonce,
+ noise_keypair_encrypt(t->t_keypair, &data->r_idx, t->t_nonce,
data->buf, plaintext_len);
- nonce = htole64(nonce); /* Wire format is little endian. */
- memcpy(data->nonce, &nonce, sizeof(data->nonce));
- if (__predict_false(res)) {
- if (res == EINVAL) {
- wg_timers_event_want_initiation(&peer->p_timers);
- m_freem(mc);
- goto error;
- } else if (res == ESTALE) {
- wg_timers_event_want_initiation(&peer->p_timers);
- } else {
- m_freem(mc);
- goto error;
- }
- }
+ nonce = htole64(t->t_nonce); /* Wire format is little endian. */
+ memcpy(data->nonce, &nonce, sizeof(data->nonce));
/* A packet with length 0 is a keepalive packet */
if (m->m_pkthdr.len == 0)
@@ -1863,6 +1672,7 @@ wg_decap(struct wg_softc *sc, struct mbuf *m)
{
struct wg_pkt_data *data;
struct wg_peer *peer, *routed_peer;
+ struct noise_remote *remote;
struct wg_tag *t;
size_t plaintext_len;
uint8_t version;
@@ -1874,21 +1684,22 @@ wg_decap(struct wg_softc *sc, struct mbuf *m)
plaintext_len = m->m_pkthdr.len - sizeof(struct wg_pkt_data);
t = wg_tag_get(m);
- peer = t->t_peer;
+ remote = noise_keypair_remote(t->t_keypair);
+ peer = noise_remote_arg(remote);
+ /* We can put the remote as we still hold a keypair ref */
+ noise_remote_put(remote);
memcpy(&nonce, data->nonce, sizeof(nonce));
- nonce = le64toh(nonce); /* Wire format is little endian. */
+ t->t_nonce = le64toh(nonce); /* Wire format is little endian. */
- res = noise_remote_decrypt(&peer->p_remote, data->r_idx, nonce,
- data->buf, plaintext_len);
+ res = noise_keypair_decrypt(t->t_keypair, t->t_nonce, data->buf,
+ plaintext_len);
if (__predict_false(res)) {
if (res == EINVAL) {
goto error;
} else if (res == ECONNRESET) {
wg_timers_event_handshake_complete(&peer->p_timers);
- } else if (res == ESTALE) {
- wg_timers_event_want_initiation(&peer->p_timers);
} else {
panic("unexpected response: %d\n", res);
}
@@ -1994,6 +1805,7 @@ wg_deliver_out(struct wg_peer *peer)
continue;
}
len = t->t_mbuf->m_pkthdr.len;
+ noise_keypair_put(t->t_keypair);
ret = wg_send(peer->p_sc, &endpoint, t->t_mbuf);
if (ret == 0) {
@@ -2010,6 +1822,9 @@ wg_deliver_out(struct wg_peer *peer)
wg_peer_get_endpoint(peer, &endpoint);
}
m_freem(m);
+
+ if (noise_keep_key_fresh_send(peer->p_remote) == 0)
+ wg_timers_event_want_initiation(&peer->p_timers);
}
NET_EPOCH_EXIT(et);
@@ -2039,6 +1854,14 @@ wg_deliver_in(struct wg_peer *peer)
}
MPASS(m == t->t_mbuf);
+ if (noise_keypair_nonce_check(t->t_keypair, t->t_nonce) != 0) {
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ noise_keypair_put(t->t_keypair);
+ m_freem(m);
+ continue;
+ }
+ noise_keypair_put(t->t_keypair);
+
wg_timers_event_any_authenticated_packet_received(
&peer->p_timers);
wg_timers_event_any_authenticated_packet_traversal(
@@ -2048,6 +1871,9 @@ wg_deliver_in(struct wg_peer *peer)
if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1);
if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len + sizeof(struct wg_pkt_data) + NOISE_AUTHTAG_LEN);
+ if (noise_keep_key_fresh_recv(peer->p_remote) == 0)
+ wg_timers_event_want_initiation(&peer->p_timers);
+
if (m->m_pkthdr.len == 0) {
m_freem(m);
continue;
@@ -2129,10 +1955,11 @@ wg_queue_out(struct wg_peer *peer)
struct buf_ring *parallel = peer->p_sc->sc_encap_ring;
struct wg_queue *serial = &peer->p_encap_queue;
struct wg_tag *t;
+ struct noise_keypair *keypair;
struct mbufq staged;
struct mbuf *m;
- if (noise_remote_ready(&peer->p_remote) != 0) {
+ if ((keypair = noise_keypair_current(peer->p_remote)) == NULL) {
if (wg_queue_len(&peer->p_stage_queue))
wg_timers_event_want_initiation(&peer->p_timers);
return;
@@ -2153,10 +1980,18 @@ wg_queue_out(struct wg_peer *peer)
m_freem(m);
continue;
}
- t->t_peer = peer;
+ if (noise_keypair_nonce_next(keypair, &t->t_nonce) != 0) {
+ /* TODO if we get here, it means we are about to
+ * overflow this keypair sending nonce. We should place
+ * this back on the staged queue. */
+ m_freem(m);
+ continue;
+ }
+ t->t_keypair = noise_keypair_ref(keypair);
mtx_lock(&serial->q_mtx);
if (mbufq_enqueue(&serial->q, m) != 0) {
m_freem(m);
+ noise_keypair_put(keypair);
if_inc_counter(peer->p_sc->sc_ifp, IFCOUNTER_OQDROPS, 1);
} else {
m->m_flags |= M_ENQUEUED;
@@ -2215,90 +2050,6 @@ wg_queue_purge(struct wg_queue *q)
mtx_unlock(&q->q_mtx);
}
-/* TODO Indexes */
-static struct noise_remote *
-wg_remote_get(struct wg_softc *sc, uint8_t public[NOISE_PUBLIC_KEY_LEN])
-{
- struct wg_peer *peer;
-
- if ((peer = wg_peer_lookup(sc, public)) == NULL)
- return (NULL);
- return (&peer->p_remote);
-}
-
-static uint32_t
-wg_index_set(struct wg_softc *sc, struct noise_remote *remote)
-{
- struct wg_index *index, *iter;
- struct wg_peer *peer;
- uint32_t key;
-
- /* We can modify this without a lock as wg_index_set, wg_index_drop are
- * guaranteed to be serialised (per remote). */
- peer = __containerof(remote, struct wg_peer, p_remote);
- index = SLIST_FIRST(&peer->p_unused_index);
- MPASS(index != NULL);
- SLIST_REMOVE_HEAD(&peer->p_unused_index, i_unused_entry);
-
- index->i_value = remote;
-
- rw_wlock(&sc->sc_index_lock);
-assign_id:
- key = index->i_key = arc4random();
- key &= sc->sc_index_mask;
- LIST_FOREACH(iter, &sc->sc_index[key], i_entry)
- if (iter->i_key == index->i_key)
- goto assign_id;
-
- LIST_INSERT_HEAD(&sc->sc_index[key], index, i_entry);
-
- rw_wunlock(&sc->sc_index_lock);
-
- /* Likewise, no need to lock for index here. */
- return index->i_key;
-}
-
-static struct noise_remote *
-wg_index_get(struct wg_softc *sc, uint32_t key0)
-{
- struct wg_index *iter;
- struct noise_remote *remote = NULL;
- uint32_t key = key0 & sc->sc_index_mask;
-
- rw_enter_read(&sc->sc_index_lock);
- LIST_FOREACH(iter, &sc->sc_index[key], i_entry)
- if (iter->i_key == key0) {
- remote = iter->i_value;
- break;
- }
- rw_exit_read(&sc->sc_index_lock);
- return remote;
-}
-
-static void
-wg_index_drop(struct wg_softc *sc, uint32_t key0)
-{
- struct wg_index *iter;
- struct wg_peer *peer = NULL;
- uint32_t key = key0 & sc->sc_index_mask;
-
- rw_enter_write(&sc->sc_index_lock);
- LIST_FOREACH(iter, &sc->sc_index[key], i_entry)
- if (iter->i_key == key0) {
- LIST_REMOVE(iter, i_entry);
- break;
- }
- rw_exit_write(&sc->sc_index_lock);
-
- if (iter == NULL)
- return;
-
- /* We expect a peer */
- peer = __containerof(iter->i_value, struct wg_peer, p_remote);
- MPASS(peer != NULL);
- SLIST_INSERT_HEAD(&peer->p_unused_index, iter, i_unused_entry);
-}
-
static int
wg_update_endpoint_addrs(struct wg_endpoint *e, const struct sockaddr *srcsa,
struct ifnet *rcvif)
@@ -2339,6 +2090,7 @@ wg_input(struct mbuf *m0, int offset, struct inpcb *inpcb,
struct wg_softc *sc = _sc;
struct mbuf *m;
int pktlen, pkttype;
+ struct noise_keypair *keypair;
struct noise_remote *remote;
struct wg_tag *t;
void *data;
@@ -2406,21 +2158,23 @@ wg_input(struct mbuf *m0, int offset, struct inpcb *inpcb,
} else if (pktlen >= sizeof(struct wg_pkt_data) + NOISE_AUTHTAG_LEN
&& pkttype == WG_PKT_DATA) {
pkt_data = data;
- remote = wg_index_get(sc, pkt_data->r_idx);
- if (remote == NULL) {
+ keypair = noise_keypair_lookup(sc->sc_local, pkt_data->r_idx);
+ if (keypair == NULL) {
if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1);
m_freem(m);
} else if (buf_ring_count(sc->sc_decap_ring) > MAX_QUEUED_PKT) {
if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1);
+ noise_keypair_put(keypair);
m_freem(m);
} else {
- t->t_peer = __containerof(remote, struct wg_peer,
- p_remote);
+ t->t_keypair = keypair;
t->t_mbuf = NULL;
t->t_done = 0;
- wg_queue_in(t->t_peer, m);
+ remote = noise_keypair_remote(keypair);
+ wg_queue_in(noise_remote_arg(remote), m);
wg_decrypt_dispatch(sc);
+ noise_remote_put(remote);
}
} else {
free:
@@ -2465,7 +2219,6 @@ wg_transmit(struct ifnet *ifp, struct mbuf *m)
rc = EHOSTUNREACH;
goto err;
}
- t->t_peer = peer;
t->t_mbuf = NULL;
t->t_done = 0;
t->t_mtu = ifp->if_mtu;
@@ -2494,10 +2247,11 @@ static int
wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl)
{
uint8_t public[WG_KEY_SIZE];
- const void *pub_key;
+ const void *pub_key, *preshared_key = NULL;
const struct sockaddr *endpoint;
int err;
size_t size;
+ struct noise_remote *remote;
struct wg_peer *peer = NULL;
bool need_insert = false;
@@ -2510,17 +2264,16 @@ wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl)
if (size != WG_KEY_SIZE) {
return (EINVAL);
}
- if (noise_local_keys(&sc->sc_local, public, NULL) == 0 &&
+ if (noise_local_keys(sc->sc_local, public, NULL) == 0 &&
bcmp(public, pub_key, WG_KEY_SIZE) == 0) {
return (0); // Silently ignored; not actually a failure.
}
- peer = wg_peer_lookup(sc, pub_key);
+ if ((remote = noise_remote_lookup(sc->sc_local, pub_key)) != NULL)
+ peer = noise_remote_arg(remote);
if (nvlist_exists_bool(nvl, "remove") &&
nvlist_get_bool(nvl, "remove")) {
- if (peer != NULL) {
- wg_hashtable_peer_remove(&sc->sc_hashtable, peer);
+ if (peer != NULL)
wg_peer_destroy(peer);
- }
return (0);
}
if (nvlist_exists_bool(nvl, "replace-allowedips") &&
@@ -2530,14 +2283,9 @@ wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl)
wg_aip_delete(&peer->p_sc->sc_aips, peer);
}
if (peer == NULL) {
- if (sc->sc_peer_count >= MAX_PEERS_PER_IFACE)
- return (E2BIG);
- sc->sc_peer_count++;
-
need_insert = true;
peer = wg_peer_alloc(sc);
MPASS(peer != NULL);
- noise_remote_init(&peer->p_remote, pub_key, &sc->sc_local);
cookie_maker_init(&peer->p_cookie, pub_key);
}
if (nvlist_exists_binary(nvl, "endpoint")) {
@@ -2549,14 +2297,13 @@ wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl)
memcpy(&peer->p_endpoint.e_remote, endpoint, size);
}
if (nvlist_exists_binary(nvl, "preshared-key")) {
- const void *key;
-
- key = nvlist_get_binary(nvl, "preshared-key", &size);
+ preshared_key = nvlist_get_binary(nvl, "preshared-key", &size);
if (size != WG_KEY_SIZE) {
err = EINVAL;
goto out;
}
- noise_remote_set_psk(&peer->p_remote, key);
+ if (!need_insert)
+ noise_remote_set_psk(peer->p_remote, preshared_key);
}
if (nvlist_exists_number(nvl, "persistent-keepalive-interval")) {
uint64_t pki = nvlist_get_number(nvl, "persistent-keepalive-interval");
@@ -2606,7 +2353,11 @@ wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl)
}
}
if (need_insert) {
- wg_hashtable_peer_insert(&sc->sc_hashtable, peer);
+ if ((peer->p_remote = noise_remote_alloc(sc->sc_local, peer,
+ pub_key, preshared_key)) == NULL)
+ goto out;
+ TAILQ_INSERT_TAIL(&sc->sc_peers, peer, p_entry);
+ sc->sc_peers_num++;
if (sc->sc_ifp->if_link_state == LINK_STATE_UP)
wg_timers_enable(&peer->p_timers);
}
@@ -2672,19 +2423,18 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd)
goto out;
}
- if (noise_local_keys(&sc->sc_local, NULL, private) != 0 ||
+ if (noise_local_keys(sc->sc_local, NULL, private) != 0 ||
timingsafe_bcmp(private, key, WG_KEY_SIZE) != 0) {
- struct noise_local *local;
struct wg_peer *peer;
- struct wg_hashtable *ht = &sc->sc_hashtable;
- bool has_identity;
if (curve25519_generate_public(public, key)) {
/* Peer conflict: remove conflicting peer. */
- if ((peer = wg_peer_lookup(sc, public)) !=
- NULL) {
- wg_hashtable_peer_remove(ht, peer);
+ struct noise_remote *remote;
+ if ((remote = noise_remote_lookup(sc->sc_local,
+ public)) != NULL) {
+ peer = noise_remote_arg(remote);
wg_peer_destroy(peer);
+ noise_remote_put(remote);
}
}
@@ -2692,21 +2442,12 @@ wgc_set(struct wg_softc *sc, struct wg_data_io *wgd)
* Set the private key and invalidate all existing
* handshakes.
*/
- local = &sc->sc_local;
- noise_local_lock_identity(local);
/* Note: we might be removing the private key. */
- has_identity = noise_local_set_private(local, key) == 0;
- mtx_lock(&ht->h_mtx);
- CK_LIST_FOREACH(peer, &ht->h_peers_list, p_entry) {
- noise_remote_precompute(&peer->p_remote);
- wg_timers_event_reset_handshake_last_sent(
- &peer->p_timers);
- noise_remote_expire_current(&peer->p_remote);
- }
- mtx_unlock(&ht->h_mtx);
- cookie_checker_update(&sc->sc_cookie,
- has_identity ? public : NULL);
- noise_local_unlock_identity(local);
+ noise_local_private(sc->sc_local, key);
+ if (noise_local_keys(sc->sc_local, NULL, NULL) == 0)
+ cookie_checker_update(&sc->sc_cookie, public);
+ else
+ cookie_checker_update(&sc->sc_cookie, NULL);
}
}
if (nvlist_exists_number(nvl, "user-cookie")) {
@@ -2742,7 +2483,9 @@ out:
static int
wgc_get(struct wg_softc *sc, struct wg_data_io *wgd)
{
- uint8_t public_key[WG_KEY_SIZE] = { 0 }, preshared_key[NOISE_SYMMETRIC_KEY_LEN] = { 0 };
+ uint8_t public_key[WG_KEY_SIZE] = { 0 };
+ uint8_t private_key[WG_KEY_SIZE] = { 0 };
+ uint8_t preshared_key[NOISE_SYMMETRIC_KEY_LEN] = { 0 };
nvlist_t *nvl, *nvl_peer, *nvl_aip, **nvl_peers, **nvl_aips;
size_t size, peer_count, aip_count, i, j;
struct wg_timespec64 ts64;
@@ -2761,16 +2504,17 @@ wgc_get(struct wg_softc *sc, struct wg_data_io *wgd)
nvlist_add_number(nvl, "listen-port", sc->sc_socket.so_port);
if (sc->sc_socket.so_user_cookie != 0)
nvlist_add_number(nvl, "user-cookie", sc->sc_socket.so_user_cookie);
- if (sc->sc_local.l_has_identity) {
- nvlist_add_binary(nvl, "public-key", sc->sc_local.l_public, WG_KEY_SIZE);
+ if (noise_local_keys(sc->sc_local, public_key, private_key) == 0) {
+ nvlist_add_binary(nvl, "public-key", public_key, WG_KEY_SIZE);
if (wgc_privileged(sc))
- nvlist_add_binary(nvl, "private-key", sc->sc_local.l_private, WG_KEY_SIZE);
+ nvlist_add_binary(nvl, "private-key", private_key, WG_KEY_SIZE);
+ explicit_bzero(private_key, sizeof(private_key));
}
- peer_count = sc->sc_hashtable.h_num_peers;
+ peer_count = sc->sc_peers_num;
if (peer_count) {
nvl_peers = mallocarray(peer_count, sizeof(void *), M_NVLIST, M_WAITOK | M_ZERO);
i = 0;
- CK_LIST_FOREACH(peer, &sc->sc_hashtable.h_peers_list, p_entry) {
+ TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) {
if (i >= peer_count)
panic("peers changed from under us");
@@ -2780,7 +2524,7 @@ wgc_get(struct wg_softc *sc, struct wg_data_io *wgd)
goto err_peer;
}
- (void)noise_remote_keys(&peer->p_remote, public_key, preshared_key);
+ (void)noise_remote_keys(peer->p_remote, public_key, preshared_key);
nvlist_add_binary(nvl_peer, "public-key", public_key, sizeof(public_key));
if (wgc_privileged(sc))
nvlist_add_binary(nvl_peer, "preshared-key", preshared_key, sizeof(preshared_key));
@@ -2941,7 +2685,6 @@ out:
static int
wg_up(struct wg_softc *sc)
{
- struct wg_hashtable *ht = &sc->sc_hashtable;
struct ifnet *ifp = sc->sc_ifp;
struct wg_peer *peer;
int rc = EBUSY;
@@ -2959,13 +2702,10 @@ wg_up(struct wg_softc *sc)
rc = wg_socket_init(sc, sc->sc_socket.so_port);
if (rc == 0) {
- mtx_lock(&ht->h_mtx);
- CK_LIST_FOREACH(peer, &ht->h_peers_list, p_entry) {
+ TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) {
wg_timers_enable(&peer->p_timers);
wg_queue_out(peer);
}
- mtx_unlock(&ht->h_mtx);
-
if_link_state_change(sc->sc_ifp, LINK_STATE_UP);
} else {
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
@@ -2979,7 +2719,6 @@ out:
static void
wg_down(struct wg_softc *sc)
{
- struct wg_hashtable *ht = &sc->sc_hashtable;
struct ifnet *ifp = sc->sc_ifp;
struct wg_peer *peer;
@@ -2990,21 +2729,17 @@ wg_down(struct wg_softc *sc)
}
ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
- mtx_lock(&ht->h_mtx);
- CK_LIST_FOREACH(peer, &ht->h_peers_list, p_entry) {
+ TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) {
wg_queue_purge(&peer->p_stage_queue);
wg_timers_disable(&peer->p_timers);
}
- mtx_unlock(&ht->h_mtx);
mbufq_drain(&sc->sc_handshake_queue);
- mtx_lock(&ht->h_mtx);
- CK_LIST_FOREACH(peer, &ht->h_peers_list, p_entry) {
- noise_remote_clear(&peer->p_remote);
- wg_timers_event_reset_handshake_last_sent(&peer->p_timers);
+ TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) {
+ noise_remote_handshake_clear(peer->p_remote);
+ noise_remote_keypairs_clear(peer->p_remote);
}
- mtx_unlock(&ht->h_mtx);
if_link_state_change(sc->sc_ifp, LINK_STATE_DOWN);
wg_socket_uninit(sc);
@@ -3045,7 +2780,6 @@ wg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
{
struct wg_softc *sc;
struct ifnet *ifp;
- struct noise_upcall noise_upcall;
sc = malloc(sizeof(*sc), M_WG, M_WAITOK | M_ZERO);
sc->sc_ucred = crhold(curthread->td_ucred);
@@ -3054,14 +2788,15 @@ wg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
ifp->if_softc = sc;
if_initname(ifp, wgname, unit);
- noise_upcall.u_arg = sc;
- noise_upcall.u_remote_get =
- (struct noise_remote *(*)(void *, uint8_t *))wg_remote_get;
- noise_upcall.u_index_set =
- (uint32_t (*)(void *, struct noise_remote *))wg_index_set;
- noise_upcall.u_index_drop =
- (void (*)(void *, uint32_t))wg_index_drop;
- noise_local_init(&sc->sc_local, &noise_upcall);
+ TAILQ_INIT(&sc->sc_peers);
+ sc->sc_peers_num = 0;
+
+ if ((sc->sc_local = noise_local_alloc(sc)) == NULL) {
+ free(sc, M_WG);
+ return ENOMEM;
+ }
+
+ /* TODO check checker_init return value */
cookie_checker_init(&sc->sc_cookie, ratelimit_zone);
sc->sc_socket.so_port = 0;
@@ -3071,8 +2806,6 @@ wg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
mbufq_init(&sc->sc_handshake_queue, MAX_QUEUED_HANDSHAKES);
sx_init(&sc->sc_lock, "wg softc lock");
- rw_init(&sc->sc_index_lock, "wg index lock");
- sc->sc_peer_count = 0;
sc->sc_encap_ring = buf_ring_alloc(MAX_QUEUED_PKT, M_WG, M_WAITOK, NULL);
sc->sc_decap_ring = buf_ring_alloc(MAX_QUEUED_PKT, M_WG, M_WAITOK, NULL);
GROUPTASK_INIT(&sc->sc_handshake, 0,
@@ -3080,8 +2813,6 @@ wg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
taskqgroup_attach(qgroup_wg_tqg, &sc->sc_handshake, sc, NULL, NULL, "wg tx initiation");
crypto_taskq_setup(sc);
- wg_hashtable_init(&sc->sc_hashtable);
- sc->sc_index = hashinit(HASHTABLE_INDEX_SIZE, M_DEVBUF, &sc->sc_index_mask);
wg_aip_init(&sc->sc_aips);
if_setmtu(ifp, ETHERMTU - 80);
@@ -3108,6 +2839,15 @@ wg_clone_create(struct if_clone *ifc, int unit, caddr_t params)
}
static void
+wg_clone_deferred_free(struct noise_local *l)
+{
+ struct wg_softc *sc = noise_local_arg(l);
+
+ free(sc, M_WG);
+ atomic_add_int(&clone_count, -1);
+}
+
+static void
wg_clone_destroy(struct ifnet *ifp)
{
struct wg_softc *sc = ifp->if_softc;
@@ -3144,24 +2884,19 @@ wg_clone_destroy(struct ifnet *ifp)
epoch_drain_callbacks(net_epoch_preempt);
sx_xunlock(&sc->sc_lock);
sx_destroy(&sc->sc_lock);
- rw_destroy(&sc->sc_index_lock);
taskqgroup_detach(qgroup_wg_tqg, &sc->sc_handshake);
crypto_taskq_destroy(sc);
buf_ring_free(sc->sc_encap_ring, M_WG);
buf_ring_free(sc->sc_decap_ring, M_WG);
wg_aip_destroy(&sc->sc_aips);
- wg_hashtable_destroy(&sc->sc_hashtable);
if (cred != NULL)
crfree(cred);
if_detach(sc->sc_ifp);
if_free(sc->sc_ifp);
- /* Ensure any local/private keys are cleaned up */
- explicit_bzero(sc, sizeof(*sc));
- free(sc, M_WG);
- atomic_add_int(&clone_count, -1);
+ noise_local_free(sc->sc_local, wg_clone_deferred_free);
}
static void