1744bfb21SJohn Baldwin /* SPDX-License-Identifier: ISC 2744bfb21SJohn Baldwin * 3744bfb21SJohn Baldwin * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 4744bfb21SJohn Baldwin * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net> 5744bfb21SJohn Baldwin * Copyright (c) 2019-2020 Rubicon Communications, LLC (Netgate) 6744bfb21SJohn Baldwin * Copyright (c) 2021 Kyle Evans <kevans@FreeBSD.org> 7744bfb21SJohn Baldwin * Copyright (c) 2022 The FreeBSD Foundation 8744bfb21SJohn Baldwin */ 9744bfb21SJohn Baldwin 10744bfb21SJohn Baldwin #include "opt_inet.h" 11744bfb21SJohn Baldwin #include "opt_inet6.h" 12744bfb21SJohn Baldwin 13744bfb21SJohn Baldwin #include <sys/param.h> 14744bfb21SJohn Baldwin #include <sys/systm.h> 15744bfb21SJohn Baldwin #include <sys/counter.h> 16744bfb21SJohn Baldwin #include <sys/gtaskqueue.h> 17744bfb21SJohn Baldwin #include <sys/jail.h> 18744bfb21SJohn Baldwin #include <sys/kernel.h> 19744bfb21SJohn Baldwin #include <sys/lock.h> 20744bfb21SJohn Baldwin #include <sys/mbuf.h> 21744bfb21SJohn Baldwin #include <sys/module.h> 22744bfb21SJohn Baldwin #include <sys/nv.h> 23744bfb21SJohn Baldwin #include <sys/priv.h> 24744bfb21SJohn Baldwin #include <sys/protosw.h> 25744bfb21SJohn Baldwin #include <sys/rmlock.h> 26744bfb21SJohn Baldwin #include <sys/rwlock.h> 27744bfb21SJohn Baldwin #include <sys/smp.h> 28744bfb21SJohn Baldwin #include <sys/socket.h> 29744bfb21SJohn Baldwin #include <sys/socketvar.h> 30744bfb21SJohn Baldwin #include <sys/sockio.h> 31744bfb21SJohn Baldwin #include <sys/sysctl.h> 32744bfb21SJohn Baldwin #include <sys/sx.h> 33744bfb21SJohn Baldwin #include <machine/_inttypes.h> 34744bfb21SJohn Baldwin #include <net/bpf.h> 35744bfb21SJohn Baldwin #include <net/ethernet.h> 36744bfb21SJohn Baldwin #include <net/if.h> 37744bfb21SJohn Baldwin #include <net/if_clone.h> 38744bfb21SJohn Baldwin #include <net/if_types.h> 39744bfb21SJohn Baldwin #include <net/if_var.h> 40744bfb21SJohn Baldwin #include <net/netisr.h> 41744bfb21SJohn Baldwin #include <net/radix.h> 42744bfb21SJohn Baldwin #include <netinet/in.h> 43744bfb21SJohn Baldwin #include <netinet6/in6_var.h> 44744bfb21SJohn Baldwin #include <netinet/ip.h> 45744bfb21SJohn Baldwin #include <netinet/ip6.h> 46744bfb21SJohn Baldwin #include <netinet/ip_icmp.h> 47744bfb21SJohn Baldwin #include <netinet/icmp6.h> 48744bfb21SJohn Baldwin #include <netinet/udp_var.h> 49744bfb21SJohn Baldwin #include <netinet6/nd6.h> 50744bfb21SJohn Baldwin 51744bfb21SJohn Baldwin #include "wg_noise.h" 52744bfb21SJohn Baldwin #include "wg_cookie.h" 53744bfb21SJohn Baldwin #include "version.h" 54744bfb21SJohn Baldwin #include "if_wg.h" 55744bfb21SJohn Baldwin 56744bfb21SJohn Baldwin #define DEFAULT_MTU (ETHERMTU - 80) 57744bfb21SJohn Baldwin #define MAX_MTU (IF_MAXMTU - 80) 58744bfb21SJohn Baldwin 59744bfb21SJohn Baldwin #define MAX_STAGED_PKT 128 60744bfb21SJohn Baldwin #define MAX_QUEUED_PKT 1024 61744bfb21SJohn Baldwin #define MAX_QUEUED_PKT_MASK (MAX_QUEUED_PKT - 1) 62744bfb21SJohn Baldwin 63744bfb21SJohn Baldwin #define MAX_QUEUED_HANDSHAKES 4096 64744bfb21SJohn Baldwin 65744bfb21SJohn Baldwin #define REKEY_TIMEOUT_JITTER 334 /* 1/3 sec, round for arc4random_uniform */ 66744bfb21SJohn Baldwin #define MAX_TIMER_HANDSHAKES (90 / REKEY_TIMEOUT) 67744bfb21SJohn Baldwin #define NEW_HANDSHAKE_TIMEOUT (REKEY_TIMEOUT + KEEPALIVE_TIMEOUT) 68744bfb21SJohn Baldwin #define UNDERLOAD_TIMEOUT 1 69744bfb21SJohn Baldwin 70744bfb21SJohn Baldwin #define DPRINTF(sc, ...) if (sc->sc_ifp->if_flags & IFF_DEBUG) if_printf(sc->sc_ifp, ##__VA_ARGS__) 71744bfb21SJohn Baldwin 72744bfb21SJohn Baldwin /* First byte indicating packet type on the wire */ 73744bfb21SJohn Baldwin #define WG_PKT_INITIATION htole32(1) 74744bfb21SJohn Baldwin #define WG_PKT_RESPONSE htole32(2) 75744bfb21SJohn Baldwin #define WG_PKT_COOKIE htole32(3) 76744bfb21SJohn Baldwin #define WG_PKT_DATA htole32(4) 77744bfb21SJohn Baldwin 78744bfb21SJohn Baldwin #define WG_PKT_PADDING 16 79744bfb21SJohn Baldwin #define WG_KEY_SIZE 32 80744bfb21SJohn Baldwin 81744bfb21SJohn Baldwin struct wg_pkt_initiation { 82744bfb21SJohn Baldwin uint32_t t; 83744bfb21SJohn Baldwin uint32_t s_idx; 84744bfb21SJohn Baldwin uint8_t ue[NOISE_PUBLIC_KEY_LEN]; 85744bfb21SJohn Baldwin uint8_t es[NOISE_PUBLIC_KEY_LEN + NOISE_AUTHTAG_LEN]; 86744bfb21SJohn Baldwin uint8_t ets[NOISE_TIMESTAMP_LEN + NOISE_AUTHTAG_LEN]; 87744bfb21SJohn Baldwin struct cookie_macs m; 88744bfb21SJohn Baldwin }; 89744bfb21SJohn Baldwin 90744bfb21SJohn Baldwin struct wg_pkt_response { 91744bfb21SJohn Baldwin uint32_t t; 92744bfb21SJohn Baldwin uint32_t s_idx; 93744bfb21SJohn Baldwin uint32_t r_idx; 94744bfb21SJohn Baldwin uint8_t ue[NOISE_PUBLIC_KEY_LEN]; 95744bfb21SJohn Baldwin uint8_t en[0 + NOISE_AUTHTAG_LEN]; 96744bfb21SJohn Baldwin struct cookie_macs m; 97744bfb21SJohn Baldwin }; 98744bfb21SJohn Baldwin 99744bfb21SJohn Baldwin struct wg_pkt_cookie { 100744bfb21SJohn Baldwin uint32_t t; 101744bfb21SJohn Baldwin uint32_t r_idx; 102744bfb21SJohn Baldwin uint8_t nonce[COOKIE_NONCE_SIZE]; 103744bfb21SJohn Baldwin uint8_t ec[COOKIE_ENCRYPTED_SIZE]; 104744bfb21SJohn Baldwin }; 105744bfb21SJohn Baldwin 106744bfb21SJohn Baldwin struct wg_pkt_data { 107744bfb21SJohn Baldwin uint32_t t; 108744bfb21SJohn Baldwin uint32_t r_idx; 109744bfb21SJohn Baldwin uint64_t nonce; 110744bfb21SJohn Baldwin uint8_t buf[]; 111744bfb21SJohn Baldwin }; 112744bfb21SJohn Baldwin 113744bfb21SJohn Baldwin struct wg_endpoint { 114744bfb21SJohn Baldwin union { 115744bfb21SJohn Baldwin struct sockaddr r_sa; 116744bfb21SJohn Baldwin struct sockaddr_in r_sin; 117744bfb21SJohn Baldwin #ifdef INET6 118744bfb21SJohn Baldwin struct sockaddr_in6 r_sin6; 119744bfb21SJohn Baldwin #endif 120744bfb21SJohn Baldwin } e_remote; 121744bfb21SJohn Baldwin union { 122744bfb21SJohn Baldwin struct in_addr l_in; 123744bfb21SJohn Baldwin #ifdef INET6 124744bfb21SJohn Baldwin struct in6_pktinfo l_pktinfo6; 125744bfb21SJohn Baldwin #define l_in6 l_pktinfo6.ipi6_addr 126744bfb21SJohn Baldwin #endif 127744bfb21SJohn Baldwin } e_local; 128744bfb21SJohn Baldwin }; 129744bfb21SJohn Baldwin 130744bfb21SJohn Baldwin struct aip_addr { 131744bfb21SJohn Baldwin uint8_t length; 132744bfb21SJohn Baldwin union { 133744bfb21SJohn Baldwin uint8_t bytes[16]; 134744bfb21SJohn Baldwin uint32_t ip; 135744bfb21SJohn Baldwin uint32_t ip6[4]; 136744bfb21SJohn Baldwin struct in_addr in; 137744bfb21SJohn Baldwin struct in6_addr in6; 138744bfb21SJohn Baldwin }; 139744bfb21SJohn Baldwin }; 140744bfb21SJohn Baldwin 141744bfb21SJohn Baldwin struct wg_aip { 142744bfb21SJohn Baldwin struct radix_node a_nodes[2]; 143744bfb21SJohn Baldwin LIST_ENTRY(wg_aip) a_entry; 144744bfb21SJohn Baldwin struct aip_addr a_addr; 145744bfb21SJohn Baldwin struct aip_addr a_mask; 146744bfb21SJohn Baldwin struct wg_peer *a_peer; 147744bfb21SJohn Baldwin sa_family_t a_af; 148744bfb21SJohn Baldwin }; 149744bfb21SJohn Baldwin 150744bfb21SJohn Baldwin struct wg_packet { 151744bfb21SJohn Baldwin STAILQ_ENTRY(wg_packet) p_serial; 152744bfb21SJohn Baldwin STAILQ_ENTRY(wg_packet) p_parallel; 153744bfb21SJohn Baldwin struct wg_endpoint p_endpoint; 154744bfb21SJohn Baldwin struct noise_keypair *p_keypair; 155744bfb21SJohn Baldwin uint64_t p_nonce; 156744bfb21SJohn Baldwin struct mbuf *p_mbuf; 157744bfb21SJohn Baldwin int p_mtu; 158744bfb21SJohn Baldwin sa_family_t p_af; 159744bfb21SJohn Baldwin enum wg_ring_state { 160744bfb21SJohn Baldwin WG_PACKET_UNCRYPTED, 161744bfb21SJohn Baldwin WG_PACKET_CRYPTED, 162744bfb21SJohn Baldwin WG_PACKET_DEAD, 163744bfb21SJohn Baldwin } p_state; 164744bfb21SJohn Baldwin }; 165744bfb21SJohn Baldwin 166744bfb21SJohn Baldwin STAILQ_HEAD(wg_packet_list, wg_packet); 167744bfb21SJohn Baldwin 168744bfb21SJohn Baldwin struct wg_queue { 169744bfb21SJohn Baldwin struct mtx q_mtx; 170744bfb21SJohn Baldwin struct wg_packet_list q_queue; 171744bfb21SJohn Baldwin size_t q_len; 172744bfb21SJohn Baldwin }; 173744bfb21SJohn Baldwin 174744bfb21SJohn Baldwin struct wg_peer { 175744bfb21SJohn Baldwin TAILQ_ENTRY(wg_peer) p_entry; 176744bfb21SJohn Baldwin uint64_t p_id; 177744bfb21SJohn Baldwin struct wg_softc *p_sc; 178744bfb21SJohn Baldwin 179744bfb21SJohn Baldwin struct noise_remote *p_remote; 180744bfb21SJohn Baldwin struct cookie_maker p_cookie; 181744bfb21SJohn Baldwin 182744bfb21SJohn Baldwin struct rwlock p_endpoint_lock; 183744bfb21SJohn Baldwin struct wg_endpoint p_endpoint; 184744bfb21SJohn Baldwin 185744bfb21SJohn Baldwin struct wg_queue p_stage_queue; 186744bfb21SJohn Baldwin struct wg_queue p_encrypt_serial; 187744bfb21SJohn Baldwin struct wg_queue p_decrypt_serial; 188744bfb21SJohn Baldwin 189744bfb21SJohn Baldwin bool p_enabled; 190744bfb21SJohn Baldwin bool p_need_another_keepalive; 191744bfb21SJohn Baldwin uint16_t p_persistent_keepalive_interval; 192744bfb21SJohn Baldwin struct callout p_new_handshake; 193744bfb21SJohn Baldwin struct callout p_send_keepalive; 194744bfb21SJohn Baldwin struct callout p_retry_handshake; 195744bfb21SJohn Baldwin struct callout p_zero_key_material; 196744bfb21SJohn Baldwin struct callout p_persistent_keepalive; 197744bfb21SJohn Baldwin 198744bfb21SJohn Baldwin struct mtx p_handshake_mtx; 199744bfb21SJohn Baldwin struct timespec p_handshake_complete; /* nanotime */ 200744bfb21SJohn Baldwin int p_handshake_retries; 201744bfb21SJohn Baldwin 202744bfb21SJohn Baldwin struct grouptask p_send; 203744bfb21SJohn Baldwin struct grouptask p_recv; 204744bfb21SJohn Baldwin 205744bfb21SJohn Baldwin counter_u64_t p_tx_bytes; 206744bfb21SJohn Baldwin counter_u64_t p_rx_bytes; 207744bfb21SJohn Baldwin 208744bfb21SJohn Baldwin LIST_HEAD(, wg_aip) p_aips; 209744bfb21SJohn Baldwin size_t p_aips_num; 210744bfb21SJohn Baldwin }; 211744bfb21SJohn Baldwin 212744bfb21SJohn Baldwin struct wg_socket { 213744bfb21SJohn Baldwin struct socket *so_so4; 214744bfb21SJohn Baldwin struct socket *so_so6; 215744bfb21SJohn Baldwin uint32_t so_user_cookie; 216744bfb21SJohn Baldwin int so_fibnum; 217744bfb21SJohn Baldwin in_port_t so_port; 218744bfb21SJohn Baldwin }; 219744bfb21SJohn Baldwin 220744bfb21SJohn Baldwin struct wg_softc { 221744bfb21SJohn Baldwin LIST_ENTRY(wg_softc) sc_entry; 222744bfb21SJohn Baldwin struct ifnet *sc_ifp; 223744bfb21SJohn Baldwin int sc_flags; 224744bfb21SJohn Baldwin 225744bfb21SJohn Baldwin struct ucred *sc_ucred; 226744bfb21SJohn Baldwin struct wg_socket sc_socket; 227744bfb21SJohn Baldwin 228744bfb21SJohn Baldwin TAILQ_HEAD(,wg_peer) sc_peers; 229744bfb21SJohn Baldwin size_t sc_peers_num; 230744bfb21SJohn Baldwin 231744bfb21SJohn Baldwin struct noise_local *sc_local; 232744bfb21SJohn Baldwin struct cookie_checker sc_cookie; 233744bfb21SJohn Baldwin 234744bfb21SJohn Baldwin struct radix_node_head *sc_aip4; 235744bfb21SJohn Baldwin struct radix_node_head *sc_aip6; 236744bfb21SJohn Baldwin 237744bfb21SJohn Baldwin struct grouptask sc_handshake; 238744bfb21SJohn Baldwin struct wg_queue sc_handshake_queue; 239744bfb21SJohn Baldwin 240744bfb21SJohn Baldwin struct grouptask *sc_encrypt; 241744bfb21SJohn Baldwin struct grouptask *sc_decrypt; 242744bfb21SJohn Baldwin struct wg_queue sc_encrypt_parallel; 243744bfb21SJohn Baldwin struct wg_queue sc_decrypt_parallel; 244744bfb21SJohn Baldwin u_int sc_encrypt_last_cpu; 245744bfb21SJohn Baldwin u_int sc_decrypt_last_cpu; 246744bfb21SJohn Baldwin 247744bfb21SJohn Baldwin struct sx sc_lock; 248744bfb21SJohn Baldwin }; 249744bfb21SJohn Baldwin 250744bfb21SJohn Baldwin #define WGF_DYING 0x0001 251744bfb21SJohn Baldwin 252744bfb21SJohn Baldwin #define MAX_LOOPS 8 253744bfb21SJohn Baldwin #define MTAG_WGLOOP 0x77676c70 /* wglp */ 254744bfb21SJohn Baldwin #ifndef ENOKEY 255744bfb21SJohn Baldwin #define ENOKEY ENOTCAPABLE 256744bfb21SJohn Baldwin #endif 257744bfb21SJohn Baldwin 258744bfb21SJohn Baldwin #define GROUPTASK_DRAIN(gtask) \ 259744bfb21SJohn Baldwin gtaskqueue_drain((gtask)->gt_taskqueue, &(gtask)->gt_task) 260744bfb21SJohn Baldwin 261744bfb21SJohn Baldwin #define BPF_MTAP2_AF(ifp, m, af) do { \ 262744bfb21SJohn Baldwin uint32_t __bpf_tap_af = (af); \ 263744bfb21SJohn Baldwin BPF_MTAP2(ifp, &__bpf_tap_af, sizeof(__bpf_tap_af), m); \ 264744bfb21SJohn Baldwin } while (0) 265744bfb21SJohn Baldwin 266744bfb21SJohn Baldwin static int clone_count; 267744bfb21SJohn Baldwin static uma_zone_t wg_packet_zone; 268744bfb21SJohn Baldwin static volatile unsigned long peer_counter = 0; 269744bfb21SJohn Baldwin static const char wgname[] = "wg"; 270744bfb21SJohn Baldwin static unsigned wg_osd_jail_slot; 271744bfb21SJohn Baldwin 272744bfb21SJohn Baldwin static struct sx wg_sx; 273744bfb21SJohn Baldwin SX_SYSINIT(wg_sx, &wg_sx, "wg_sx"); 274744bfb21SJohn Baldwin 275744bfb21SJohn Baldwin static LIST_HEAD(, wg_softc) wg_list = LIST_HEAD_INITIALIZER(wg_list); 276744bfb21SJohn Baldwin 277744bfb21SJohn Baldwin static TASKQGROUP_DEFINE(wg_tqg, mp_ncpus, 1); 278744bfb21SJohn Baldwin 279744bfb21SJohn Baldwin MALLOC_DEFINE(M_WG, "WG", "wireguard"); 280744bfb21SJohn Baldwin 281744bfb21SJohn Baldwin VNET_DEFINE_STATIC(struct if_clone *, wg_cloner); 282744bfb21SJohn Baldwin 283744bfb21SJohn Baldwin #define V_wg_cloner VNET(wg_cloner) 284744bfb21SJohn Baldwin #define WG_CAPS IFCAP_LINKSTATE 285744bfb21SJohn Baldwin 286744bfb21SJohn Baldwin struct wg_timespec64 { 287744bfb21SJohn Baldwin uint64_t tv_sec; 288744bfb21SJohn Baldwin uint64_t tv_nsec; 289744bfb21SJohn Baldwin }; 290744bfb21SJohn Baldwin 291744bfb21SJohn Baldwin static int wg_socket_init(struct wg_softc *, in_port_t); 292744bfb21SJohn Baldwin static int wg_socket_bind(struct socket **, struct socket **, in_port_t *); 293744bfb21SJohn Baldwin static void wg_socket_set(struct wg_softc *, struct socket *, struct socket *); 294744bfb21SJohn Baldwin static void wg_socket_uninit(struct wg_softc *); 295744bfb21SJohn Baldwin static int wg_socket_set_sockopt(struct socket *, struct socket *, int, void *, size_t); 296744bfb21SJohn Baldwin static int wg_socket_set_cookie(struct wg_softc *, uint32_t); 297744bfb21SJohn Baldwin static int wg_socket_set_fibnum(struct wg_softc *, int); 298744bfb21SJohn Baldwin static int wg_send(struct wg_softc *, struct wg_endpoint *, struct mbuf *); 299744bfb21SJohn Baldwin static void wg_timers_enable(struct wg_peer *); 300744bfb21SJohn Baldwin static void wg_timers_disable(struct wg_peer *); 301744bfb21SJohn Baldwin static void wg_timers_set_persistent_keepalive(struct wg_peer *, uint16_t); 302744bfb21SJohn Baldwin static void wg_timers_get_last_handshake(struct wg_peer *, struct wg_timespec64 *); 303744bfb21SJohn Baldwin static void wg_timers_event_data_sent(struct wg_peer *); 304744bfb21SJohn Baldwin static void wg_timers_event_data_received(struct wg_peer *); 305744bfb21SJohn Baldwin static void wg_timers_event_any_authenticated_packet_sent(struct wg_peer *); 306744bfb21SJohn Baldwin static void wg_timers_event_any_authenticated_packet_received(struct wg_peer *); 307744bfb21SJohn Baldwin static void wg_timers_event_any_authenticated_packet_traversal(struct wg_peer *); 308744bfb21SJohn Baldwin static void wg_timers_event_handshake_initiated(struct wg_peer *); 309744bfb21SJohn Baldwin static void wg_timers_event_handshake_complete(struct wg_peer *); 310744bfb21SJohn Baldwin static void wg_timers_event_session_derived(struct wg_peer *); 311744bfb21SJohn Baldwin static void wg_timers_event_want_initiation(struct wg_peer *); 312744bfb21SJohn Baldwin static void wg_timers_run_send_initiation(struct wg_peer *, bool); 313744bfb21SJohn Baldwin static void wg_timers_run_retry_handshake(void *); 314744bfb21SJohn Baldwin static void wg_timers_run_send_keepalive(void *); 315744bfb21SJohn Baldwin static void wg_timers_run_new_handshake(void *); 316744bfb21SJohn Baldwin static void wg_timers_run_zero_key_material(void *); 317744bfb21SJohn Baldwin static void wg_timers_run_persistent_keepalive(void *); 318744bfb21SJohn Baldwin static int wg_aip_add(struct wg_softc *, struct wg_peer *, sa_family_t, const void *, uint8_t); 319744bfb21SJohn Baldwin static struct wg_peer *wg_aip_lookup(struct wg_softc *, sa_family_t, void *); 320744bfb21SJohn Baldwin static void wg_aip_remove_all(struct wg_softc *, struct wg_peer *); 321744bfb21SJohn Baldwin static struct wg_peer *wg_peer_alloc(struct wg_softc *, const uint8_t [WG_KEY_SIZE]); 322744bfb21SJohn Baldwin static void wg_peer_free_deferred(struct noise_remote *); 323744bfb21SJohn Baldwin static void wg_peer_destroy(struct wg_peer *); 324744bfb21SJohn Baldwin static void wg_peer_destroy_all(struct wg_softc *); 325744bfb21SJohn Baldwin static void wg_peer_send_buf(struct wg_peer *, uint8_t *, size_t); 326744bfb21SJohn Baldwin static void wg_send_initiation(struct wg_peer *); 327744bfb21SJohn Baldwin static void wg_send_response(struct wg_peer *); 328744bfb21SJohn Baldwin static void wg_send_cookie(struct wg_softc *, struct cookie_macs *, uint32_t, struct wg_endpoint *); 329744bfb21SJohn Baldwin static void wg_peer_set_endpoint(struct wg_peer *, struct wg_endpoint *); 330744bfb21SJohn Baldwin static void wg_peer_clear_src(struct wg_peer *); 331744bfb21SJohn Baldwin static void wg_peer_get_endpoint(struct wg_peer *, struct wg_endpoint *); 332744bfb21SJohn Baldwin static void wg_send_buf(struct wg_softc *, struct wg_endpoint *, uint8_t *, size_t); 333744bfb21SJohn Baldwin static void wg_send_keepalive(struct wg_peer *); 334744bfb21SJohn Baldwin static void wg_handshake(struct wg_softc *, struct wg_packet *); 335744bfb21SJohn Baldwin static void wg_encrypt(struct wg_softc *, struct wg_packet *); 336744bfb21SJohn Baldwin static void wg_decrypt(struct wg_softc *, struct wg_packet *); 337744bfb21SJohn Baldwin static void wg_softc_handshake_receive(struct wg_softc *); 338744bfb21SJohn Baldwin static void wg_softc_decrypt(struct wg_softc *); 339744bfb21SJohn Baldwin static void wg_softc_encrypt(struct wg_softc *); 340744bfb21SJohn Baldwin static void wg_encrypt_dispatch(struct wg_softc *); 341744bfb21SJohn Baldwin static void wg_decrypt_dispatch(struct wg_softc *); 342744bfb21SJohn Baldwin static void wg_deliver_out(struct wg_peer *); 343744bfb21SJohn Baldwin static void wg_deliver_in(struct wg_peer *); 344744bfb21SJohn Baldwin static struct wg_packet *wg_packet_alloc(struct mbuf *); 345744bfb21SJohn Baldwin static void wg_packet_free(struct wg_packet *); 346744bfb21SJohn Baldwin static void wg_queue_init(struct wg_queue *, const char *); 347744bfb21SJohn Baldwin static void wg_queue_deinit(struct wg_queue *); 348744bfb21SJohn Baldwin static size_t wg_queue_len(struct wg_queue *); 349744bfb21SJohn Baldwin static int wg_queue_enqueue_handshake(struct wg_queue *, struct wg_packet *); 350744bfb21SJohn Baldwin static struct wg_packet *wg_queue_dequeue_handshake(struct wg_queue *); 351744bfb21SJohn Baldwin static void wg_queue_push_staged(struct wg_queue *, struct wg_packet *); 352744bfb21SJohn Baldwin static void wg_queue_enlist_staged(struct wg_queue *, struct wg_packet_list *); 353744bfb21SJohn Baldwin static void wg_queue_delist_staged(struct wg_queue *, struct wg_packet_list *); 354744bfb21SJohn Baldwin static void wg_queue_purge(struct wg_queue *); 355744bfb21SJohn Baldwin static int wg_queue_both(struct wg_queue *, struct wg_queue *, struct wg_packet *); 356744bfb21SJohn Baldwin static struct wg_packet *wg_queue_dequeue_serial(struct wg_queue *); 357744bfb21SJohn Baldwin static struct wg_packet *wg_queue_dequeue_parallel(struct wg_queue *); 358744bfb21SJohn Baldwin static bool wg_input(struct mbuf *, int, struct inpcb *, const struct sockaddr *, void *); 359744bfb21SJohn Baldwin static void wg_peer_send_staged(struct wg_peer *); 360744bfb21SJohn Baldwin static int wg_clone_create(struct if_clone *, int, caddr_t); 361744bfb21SJohn Baldwin static void wg_qflush(struct ifnet *); 362744bfb21SJohn Baldwin static inline int determine_af_and_pullup(struct mbuf **m, sa_family_t *af); 363744bfb21SJohn Baldwin static int wg_xmit(struct ifnet *, struct mbuf *, sa_family_t, uint32_t); 364744bfb21SJohn Baldwin static int wg_transmit(struct ifnet *, struct mbuf *); 365744bfb21SJohn Baldwin static int wg_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *); 366744bfb21SJohn Baldwin static void wg_clone_destroy(struct ifnet *); 367744bfb21SJohn Baldwin static bool wgc_privileged(struct wg_softc *); 368744bfb21SJohn Baldwin static int wgc_get(struct wg_softc *, struct wg_data_io *); 369744bfb21SJohn Baldwin static int wgc_set(struct wg_softc *, struct wg_data_io *); 370744bfb21SJohn Baldwin static int wg_up(struct wg_softc *); 371744bfb21SJohn Baldwin static void wg_down(struct wg_softc *); 372744bfb21SJohn Baldwin static void wg_reassign(struct ifnet *, struct vnet *, char *unused); 373744bfb21SJohn Baldwin static void wg_init(void *); 374744bfb21SJohn Baldwin static int wg_ioctl(struct ifnet *, u_long, caddr_t); 375744bfb21SJohn Baldwin static void vnet_wg_init(const void *); 376744bfb21SJohn Baldwin static void vnet_wg_uninit(const void *); 377744bfb21SJohn Baldwin static int wg_module_init(void); 378744bfb21SJohn Baldwin static void wg_module_deinit(void); 379744bfb21SJohn Baldwin 380744bfb21SJohn Baldwin /* TODO Peer */ 381744bfb21SJohn Baldwin static struct wg_peer * 382744bfb21SJohn Baldwin wg_peer_alloc(struct wg_softc *sc, const uint8_t pub_key[WG_KEY_SIZE]) 383744bfb21SJohn Baldwin { 384744bfb21SJohn Baldwin struct wg_peer *peer; 385744bfb21SJohn Baldwin 386744bfb21SJohn Baldwin sx_assert(&sc->sc_lock, SX_XLOCKED); 387744bfb21SJohn Baldwin 388744bfb21SJohn Baldwin peer = malloc(sizeof(*peer), M_WG, M_WAITOK | M_ZERO); 389744bfb21SJohn Baldwin peer->p_remote = noise_remote_alloc(sc->sc_local, peer, pub_key); 390744bfb21SJohn Baldwin peer->p_tx_bytes = counter_u64_alloc(M_WAITOK); 391744bfb21SJohn Baldwin peer->p_rx_bytes = counter_u64_alloc(M_WAITOK); 392744bfb21SJohn Baldwin peer->p_id = peer_counter++; 393744bfb21SJohn Baldwin peer->p_sc = sc; 394744bfb21SJohn Baldwin 395744bfb21SJohn Baldwin cookie_maker_init(&peer->p_cookie, pub_key); 396744bfb21SJohn Baldwin 397744bfb21SJohn Baldwin rw_init(&peer->p_endpoint_lock, "wg_peer_endpoint"); 398744bfb21SJohn Baldwin 399744bfb21SJohn Baldwin wg_queue_init(&peer->p_stage_queue, "stageq"); 400744bfb21SJohn Baldwin wg_queue_init(&peer->p_encrypt_serial, "txq"); 401744bfb21SJohn Baldwin wg_queue_init(&peer->p_decrypt_serial, "rxq"); 402744bfb21SJohn Baldwin 403744bfb21SJohn Baldwin peer->p_enabled = false; 404744bfb21SJohn Baldwin peer->p_need_another_keepalive = false; 405744bfb21SJohn Baldwin peer->p_persistent_keepalive_interval = 0; 406744bfb21SJohn Baldwin callout_init(&peer->p_new_handshake, true); 407744bfb21SJohn Baldwin callout_init(&peer->p_send_keepalive, true); 408744bfb21SJohn Baldwin callout_init(&peer->p_retry_handshake, true); 409744bfb21SJohn Baldwin callout_init(&peer->p_persistent_keepalive, true); 410744bfb21SJohn Baldwin callout_init(&peer->p_zero_key_material, true); 411744bfb21SJohn Baldwin 412744bfb21SJohn Baldwin mtx_init(&peer->p_handshake_mtx, "peer handshake", NULL, MTX_DEF); 413744bfb21SJohn Baldwin bzero(&peer->p_handshake_complete, sizeof(peer->p_handshake_complete)); 414744bfb21SJohn Baldwin peer->p_handshake_retries = 0; 415744bfb21SJohn Baldwin 416744bfb21SJohn Baldwin GROUPTASK_INIT(&peer->p_send, 0, (gtask_fn_t *)wg_deliver_out, peer); 417744bfb21SJohn Baldwin taskqgroup_attach(qgroup_wg_tqg, &peer->p_send, peer, NULL, NULL, "wg send"); 418744bfb21SJohn Baldwin GROUPTASK_INIT(&peer->p_recv, 0, (gtask_fn_t *)wg_deliver_in, peer); 419744bfb21SJohn Baldwin taskqgroup_attach(qgroup_wg_tqg, &peer->p_recv, peer, NULL, NULL, "wg recv"); 420744bfb21SJohn Baldwin 421744bfb21SJohn Baldwin LIST_INIT(&peer->p_aips); 422744bfb21SJohn Baldwin peer->p_aips_num = 0; 423744bfb21SJohn Baldwin 424744bfb21SJohn Baldwin return (peer); 425744bfb21SJohn Baldwin } 426744bfb21SJohn Baldwin 427744bfb21SJohn Baldwin static void 428744bfb21SJohn Baldwin wg_peer_free_deferred(struct noise_remote *r) 429744bfb21SJohn Baldwin { 430744bfb21SJohn Baldwin struct wg_peer *peer = noise_remote_arg(r); 431744bfb21SJohn Baldwin 432744bfb21SJohn Baldwin /* While there are no references remaining, we may still have 433744bfb21SJohn Baldwin * p_{send,recv} executing (think empty queue, but wg_deliver_{in,out} 434744bfb21SJohn Baldwin * needs to check the queue. We should wait for them and then free. */ 435744bfb21SJohn Baldwin GROUPTASK_DRAIN(&peer->p_recv); 436744bfb21SJohn Baldwin GROUPTASK_DRAIN(&peer->p_send); 437744bfb21SJohn Baldwin taskqgroup_detach(qgroup_wg_tqg, &peer->p_recv); 438744bfb21SJohn Baldwin taskqgroup_detach(qgroup_wg_tqg, &peer->p_send); 439744bfb21SJohn Baldwin 440744bfb21SJohn Baldwin wg_queue_deinit(&peer->p_decrypt_serial); 441744bfb21SJohn Baldwin wg_queue_deinit(&peer->p_encrypt_serial); 442744bfb21SJohn Baldwin wg_queue_deinit(&peer->p_stage_queue); 443744bfb21SJohn Baldwin 444744bfb21SJohn Baldwin counter_u64_free(peer->p_tx_bytes); 445744bfb21SJohn Baldwin counter_u64_free(peer->p_rx_bytes); 446744bfb21SJohn Baldwin rw_destroy(&peer->p_endpoint_lock); 447744bfb21SJohn Baldwin mtx_destroy(&peer->p_handshake_mtx); 448744bfb21SJohn Baldwin 449744bfb21SJohn Baldwin cookie_maker_free(&peer->p_cookie); 450744bfb21SJohn Baldwin 451744bfb21SJohn Baldwin free(peer, M_WG); 452744bfb21SJohn Baldwin } 453744bfb21SJohn Baldwin 454744bfb21SJohn Baldwin static void 455744bfb21SJohn Baldwin wg_peer_destroy(struct wg_peer *peer) 456744bfb21SJohn Baldwin { 457744bfb21SJohn Baldwin struct wg_softc *sc = peer->p_sc; 458744bfb21SJohn Baldwin sx_assert(&sc->sc_lock, SX_XLOCKED); 459744bfb21SJohn Baldwin 460744bfb21SJohn Baldwin /* Disable remote and timers. This will prevent any new handshakes 461744bfb21SJohn Baldwin * occuring. */ 462744bfb21SJohn Baldwin noise_remote_disable(peer->p_remote); 463744bfb21SJohn Baldwin wg_timers_disable(peer); 464744bfb21SJohn Baldwin 465744bfb21SJohn Baldwin /* Now we can remove all allowed IPs so no more packets will be routed 466744bfb21SJohn Baldwin * to the peer. */ 467744bfb21SJohn Baldwin wg_aip_remove_all(sc, peer); 468744bfb21SJohn Baldwin 469744bfb21SJohn Baldwin /* Remove peer from the interface, then free. Some references may still 470744bfb21SJohn Baldwin * exist to p_remote, so noise_remote_free will wait until they're all 471744bfb21SJohn Baldwin * put to call wg_peer_free_deferred. */ 472744bfb21SJohn Baldwin sc->sc_peers_num--; 473744bfb21SJohn Baldwin TAILQ_REMOVE(&sc->sc_peers, peer, p_entry); 474744bfb21SJohn Baldwin DPRINTF(sc, "Peer %" PRIu64 " destroyed\n", peer->p_id); 475744bfb21SJohn Baldwin noise_remote_free(peer->p_remote, wg_peer_free_deferred); 476744bfb21SJohn Baldwin } 477744bfb21SJohn Baldwin 478744bfb21SJohn Baldwin static void 479744bfb21SJohn Baldwin wg_peer_destroy_all(struct wg_softc *sc) 480744bfb21SJohn Baldwin { 481744bfb21SJohn Baldwin struct wg_peer *peer, *tpeer; 482744bfb21SJohn Baldwin TAILQ_FOREACH_SAFE(peer, &sc->sc_peers, p_entry, tpeer) 483744bfb21SJohn Baldwin wg_peer_destroy(peer); 484744bfb21SJohn Baldwin } 485744bfb21SJohn Baldwin 486744bfb21SJohn Baldwin static void 487744bfb21SJohn Baldwin wg_peer_set_endpoint(struct wg_peer *peer, struct wg_endpoint *e) 488744bfb21SJohn Baldwin { 489744bfb21SJohn Baldwin MPASS(e->e_remote.r_sa.sa_family != 0); 490744bfb21SJohn Baldwin if (memcmp(e, &peer->p_endpoint, sizeof(*e)) == 0) 491744bfb21SJohn Baldwin return; 492744bfb21SJohn Baldwin 493744bfb21SJohn Baldwin rw_wlock(&peer->p_endpoint_lock); 494744bfb21SJohn Baldwin peer->p_endpoint = *e; 495744bfb21SJohn Baldwin rw_wunlock(&peer->p_endpoint_lock); 496744bfb21SJohn Baldwin } 497744bfb21SJohn Baldwin 498744bfb21SJohn Baldwin static void 499744bfb21SJohn Baldwin wg_peer_clear_src(struct wg_peer *peer) 500744bfb21SJohn Baldwin { 501744bfb21SJohn Baldwin rw_wlock(&peer->p_endpoint_lock); 502744bfb21SJohn Baldwin bzero(&peer->p_endpoint.e_local, sizeof(peer->p_endpoint.e_local)); 503744bfb21SJohn Baldwin rw_wunlock(&peer->p_endpoint_lock); 504744bfb21SJohn Baldwin } 505744bfb21SJohn Baldwin 506744bfb21SJohn Baldwin static void 507744bfb21SJohn Baldwin wg_peer_get_endpoint(struct wg_peer *peer, struct wg_endpoint *e) 508744bfb21SJohn Baldwin { 509744bfb21SJohn Baldwin rw_rlock(&peer->p_endpoint_lock); 510744bfb21SJohn Baldwin *e = peer->p_endpoint; 511744bfb21SJohn Baldwin rw_runlock(&peer->p_endpoint_lock); 512744bfb21SJohn Baldwin } 513744bfb21SJohn Baldwin 514744bfb21SJohn Baldwin /* Allowed IP */ 515744bfb21SJohn Baldwin static int 516744bfb21SJohn Baldwin wg_aip_add(struct wg_softc *sc, struct wg_peer *peer, sa_family_t af, const void *addr, uint8_t cidr) 517744bfb21SJohn Baldwin { 518744bfb21SJohn Baldwin struct radix_node_head *root; 519744bfb21SJohn Baldwin struct radix_node *node; 520744bfb21SJohn Baldwin struct wg_aip *aip; 521744bfb21SJohn Baldwin int ret = 0; 522744bfb21SJohn Baldwin 523744bfb21SJohn Baldwin aip = malloc(sizeof(*aip), M_WG, M_WAITOK | M_ZERO); 524744bfb21SJohn Baldwin aip->a_peer = peer; 525744bfb21SJohn Baldwin aip->a_af = af; 526744bfb21SJohn Baldwin 527744bfb21SJohn Baldwin switch (af) { 528744bfb21SJohn Baldwin #ifdef INET 529744bfb21SJohn Baldwin case AF_INET: 530744bfb21SJohn Baldwin if (cidr > 32) cidr = 32; 531744bfb21SJohn Baldwin root = sc->sc_aip4; 532744bfb21SJohn Baldwin aip->a_addr.in = *(const struct in_addr *)addr; 533744bfb21SJohn Baldwin aip->a_mask.ip = htonl(~((1LL << (32 - cidr)) - 1) & 0xffffffff); 534744bfb21SJohn Baldwin aip->a_addr.ip &= aip->a_mask.ip; 535744bfb21SJohn Baldwin aip->a_addr.length = aip->a_mask.length = offsetof(struct aip_addr, in) + sizeof(struct in_addr); 536744bfb21SJohn Baldwin break; 537744bfb21SJohn Baldwin #endif 538744bfb21SJohn Baldwin #ifdef INET6 539744bfb21SJohn Baldwin case AF_INET6: 540744bfb21SJohn Baldwin if (cidr > 128) cidr = 128; 541744bfb21SJohn Baldwin root = sc->sc_aip6; 542744bfb21SJohn Baldwin aip->a_addr.in6 = *(const struct in6_addr *)addr; 543744bfb21SJohn Baldwin in6_prefixlen2mask(&aip->a_mask.in6, cidr); 544744bfb21SJohn Baldwin for (int i = 0; i < 4; i++) 545744bfb21SJohn Baldwin aip->a_addr.ip6[i] &= aip->a_mask.ip6[i]; 546744bfb21SJohn Baldwin aip->a_addr.length = aip->a_mask.length = offsetof(struct aip_addr, in6) + sizeof(struct in6_addr); 547744bfb21SJohn Baldwin break; 548744bfb21SJohn Baldwin #endif 549744bfb21SJohn Baldwin default: 550744bfb21SJohn Baldwin free(aip, M_WG); 551744bfb21SJohn Baldwin return (EAFNOSUPPORT); 552744bfb21SJohn Baldwin } 553744bfb21SJohn Baldwin 554744bfb21SJohn Baldwin RADIX_NODE_HEAD_LOCK(root); 555744bfb21SJohn Baldwin node = root->rnh_addaddr(&aip->a_addr, &aip->a_mask, &root->rh, aip->a_nodes); 556744bfb21SJohn Baldwin if (node == aip->a_nodes) { 557744bfb21SJohn Baldwin LIST_INSERT_HEAD(&peer->p_aips, aip, a_entry); 558744bfb21SJohn Baldwin peer->p_aips_num++; 559744bfb21SJohn Baldwin } else if (!node) 560744bfb21SJohn Baldwin node = root->rnh_lookup(&aip->a_addr, &aip->a_mask, &root->rh); 561744bfb21SJohn Baldwin if (!node) { 562744bfb21SJohn Baldwin free(aip, M_WG); 563744bfb21SJohn Baldwin return (ENOMEM); 564744bfb21SJohn Baldwin } else if (node != aip->a_nodes) { 565744bfb21SJohn Baldwin free(aip, M_WG); 566744bfb21SJohn Baldwin aip = (struct wg_aip *)node; 567744bfb21SJohn Baldwin if (aip->a_peer != peer) { 568744bfb21SJohn Baldwin LIST_REMOVE(aip, a_entry); 569744bfb21SJohn Baldwin aip->a_peer->p_aips_num--; 570744bfb21SJohn Baldwin aip->a_peer = peer; 571744bfb21SJohn Baldwin LIST_INSERT_HEAD(&peer->p_aips, aip, a_entry); 572744bfb21SJohn Baldwin aip->a_peer->p_aips_num++; 573744bfb21SJohn Baldwin } 574744bfb21SJohn Baldwin } 575744bfb21SJohn Baldwin RADIX_NODE_HEAD_UNLOCK(root); 576744bfb21SJohn Baldwin return (ret); 577744bfb21SJohn Baldwin } 578744bfb21SJohn Baldwin 579744bfb21SJohn Baldwin static struct wg_peer * 580744bfb21SJohn Baldwin wg_aip_lookup(struct wg_softc *sc, sa_family_t af, void *a) 581744bfb21SJohn Baldwin { 582744bfb21SJohn Baldwin struct radix_node_head *root; 583744bfb21SJohn Baldwin struct radix_node *node; 584744bfb21SJohn Baldwin struct wg_peer *peer; 585744bfb21SJohn Baldwin struct aip_addr addr; 586744bfb21SJohn Baldwin RADIX_NODE_HEAD_RLOCK_TRACKER; 587744bfb21SJohn Baldwin 588744bfb21SJohn Baldwin switch (af) { 589744bfb21SJohn Baldwin case AF_INET: 590744bfb21SJohn Baldwin root = sc->sc_aip4; 591744bfb21SJohn Baldwin memcpy(&addr.in, a, sizeof(addr.in)); 592744bfb21SJohn Baldwin addr.length = offsetof(struct aip_addr, in) + sizeof(struct in_addr); 593744bfb21SJohn Baldwin break; 594744bfb21SJohn Baldwin case AF_INET6: 595744bfb21SJohn Baldwin root = sc->sc_aip6; 596744bfb21SJohn Baldwin memcpy(&addr.in6, a, sizeof(addr.in6)); 597744bfb21SJohn Baldwin addr.length = offsetof(struct aip_addr, in6) + sizeof(struct in6_addr); 598744bfb21SJohn Baldwin break; 599744bfb21SJohn Baldwin default: 600744bfb21SJohn Baldwin return NULL; 601744bfb21SJohn Baldwin } 602744bfb21SJohn Baldwin 603744bfb21SJohn Baldwin RADIX_NODE_HEAD_RLOCK(root); 604744bfb21SJohn Baldwin node = root->rnh_matchaddr(&addr, &root->rh); 605744bfb21SJohn Baldwin if (node != NULL) { 606744bfb21SJohn Baldwin peer = ((struct wg_aip *)node)->a_peer; 607744bfb21SJohn Baldwin noise_remote_ref(peer->p_remote); 608744bfb21SJohn Baldwin } else { 609744bfb21SJohn Baldwin peer = NULL; 610744bfb21SJohn Baldwin } 611744bfb21SJohn Baldwin RADIX_NODE_HEAD_RUNLOCK(root); 612744bfb21SJohn Baldwin 613744bfb21SJohn Baldwin return (peer); 614744bfb21SJohn Baldwin } 615744bfb21SJohn Baldwin 616744bfb21SJohn Baldwin static void 617744bfb21SJohn Baldwin wg_aip_remove_all(struct wg_softc *sc, struct wg_peer *peer) 618744bfb21SJohn Baldwin { 619744bfb21SJohn Baldwin struct wg_aip *aip, *taip; 620744bfb21SJohn Baldwin 621744bfb21SJohn Baldwin RADIX_NODE_HEAD_LOCK(sc->sc_aip4); 622744bfb21SJohn Baldwin LIST_FOREACH_SAFE(aip, &peer->p_aips, a_entry, taip) { 623744bfb21SJohn Baldwin if (aip->a_af == AF_INET) { 624744bfb21SJohn Baldwin if (sc->sc_aip4->rnh_deladdr(&aip->a_addr, &aip->a_mask, &sc->sc_aip4->rh) == NULL) 625744bfb21SJohn Baldwin panic("failed to delete aip %p", aip); 626744bfb21SJohn Baldwin LIST_REMOVE(aip, a_entry); 627744bfb21SJohn Baldwin peer->p_aips_num--; 628744bfb21SJohn Baldwin free(aip, M_WG); 629744bfb21SJohn Baldwin } 630744bfb21SJohn Baldwin } 631744bfb21SJohn Baldwin RADIX_NODE_HEAD_UNLOCK(sc->sc_aip4); 632744bfb21SJohn Baldwin 633744bfb21SJohn Baldwin RADIX_NODE_HEAD_LOCK(sc->sc_aip6); 634744bfb21SJohn Baldwin LIST_FOREACH_SAFE(aip, &peer->p_aips, a_entry, taip) { 635744bfb21SJohn Baldwin if (aip->a_af == AF_INET6) { 636744bfb21SJohn Baldwin if (sc->sc_aip6->rnh_deladdr(&aip->a_addr, &aip->a_mask, &sc->sc_aip6->rh) == NULL) 637744bfb21SJohn Baldwin panic("failed to delete aip %p", aip); 638744bfb21SJohn Baldwin LIST_REMOVE(aip, a_entry); 639744bfb21SJohn Baldwin peer->p_aips_num--; 640744bfb21SJohn Baldwin free(aip, M_WG); 641744bfb21SJohn Baldwin } 642744bfb21SJohn Baldwin } 643744bfb21SJohn Baldwin RADIX_NODE_HEAD_UNLOCK(sc->sc_aip6); 644744bfb21SJohn Baldwin 645744bfb21SJohn Baldwin if (!LIST_EMPTY(&peer->p_aips) || peer->p_aips_num != 0) 646744bfb21SJohn Baldwin panic("wg_aip_remove_all could not delete all %p", peer); 647744bfb21SJohn Baldwin } 648744bfb21SJohn Baldwin 649744bfb21SJohn Baldwin static int 650744bfb21SJohn Baldwin wg_socket_init(struct wg_softc *sc, in_port_t port) 651744bfb21SJohn Baldwin { 652744bfb21SJohn Baldwin struct ucred *cred = sc->sc_ucred; 653744bfb21SJohn Baldwin struct socket *so4 = NULL, *so6 = NULL; 654744bfb21SJohn Baldwin int rc; 655744bfb21SJohn Baldwin 656744bfb21SJohn Baldwin sx_assert(&sc->sc_lock, SX_XLOCKED); 657744bfb21SJohn Baldwin 658744bfb21SJohn Baldwin if (!cred) 659744bfb21SJohn Baldwin return (EBUSY); 660744bfb21SJohn Baldwin 661744bfb21SJohn Baldwin /* 662744bfb21SJohn Baldwin * For socket creation, we use the creds of the thread that created the 663744bfb21SJohn Baldwin * tunnel rather than the current thread to maintain the semantics that 664744bfb21SJohn Baldwin * WireGuard has on Linux with network namespaces -- that the sockets 665744bfb21SJohn Baldwin * are created in their home vnet so that they can be configured and 666744bfb21SJohn Baldwin * functionally attached to a foreign vnet as the jail's only interface 667744bfb21SJohn Baldwin * to the network. 668744bfb21SJohn Baldwin */ 669744bfb21SJohn Baldwin #ifdef INET 670744bfb21SJohn Baldwin rc = socreate(AF_INET, &so4, SOCK_DGRAM, IPPROTO_UDP, cred, curthread); 671744bfb21SJohn Baldwin if (rc) 672744bfb21SJohn Baldwin goto out; 673744bfb21SJohn Baldwin 674744bfb21SJohn Baldwin rc = udp_set_kernel_tunneling(so4, wg_input, NULL, sc); 675744bfb21SJohn Baldwin /* 676744bfb21SJohn Baldwin * udp_set_kernel_tunneling can only fail if there is already a tunneling function set. 677744bfb21SJohn Baldwin * This should never happen with a new socket. 678744bfb21SJohn Baldwin */ 679744bfb21SJohn Baldwin MPASS(rc == 0); 680744bfb21SJohn Baldwin #endif 681744bfb21SJohn Baldwin 682744bfb21SJohn Baldwin #ifdef INET6 683744bfb21SJohn Baldwin rc = socreate(AF_INET6, &so6, SOCK_DGRAM, IPPROTO_UDP, cred, curthread); 684744bfb21SJohn Baldwin if (rc) 685744bfb21SJohn Baldwin goto out; 686744bfb21SJohn Baldwin rc = udp_set_kernel_tunneling(so6, wg_input, NULL, sc); 687744bfb21SJohn Baldwin MPASS(rc == 0); 688744bfb21SJohn Baldwin #endif 689744bfb21SJohn Baldwin 690744bfb21SJohn Baldwin if (sc->sc_socket.so_user_cookie) { 691744bfb21SJohn Baldwin rc = wg_socket_set_sockopt(so4, so6, SO_USER_COOKIE, &sc->sc_socket.so_user_cookie, sizeof(sc->sc_socket.so_user_cookie)); 692744bfb21SJohn Baldwin if (rc) 693744bfb21SJohn Baldwin goto out; 694744bfb21SJohn Baldwin } 695744bfb21SJohn Baldwin rc = wg_socket_set_sockopt(so4, so6, SO_SETFIB, &sc->sc_socket.so_fibnum, sizeof(sc->sc_socket.so_fibnum)); 696744bfb21SJohn Baldwin if (rc) 697744bfb21SJohn Baldwin goto out; 698744bfb21SJohn Baldwin 699744bfb21SJohn Baldwin rc = wg_socket_bind(&so4, &so6, &port); 700744bfb21SJohn Baldwin if (!rc) { 701744bfb21SJohn Baldwin sc->sc_socket.so_port = port; 702744bfb21SJohn Baldwin wg_socket_set(sc, so4, so6); 703744bfb21SJohn Baldwin } 704744bfb21SJohn Baldwin out: 705744bfb21SJohn Baldwin if (rc) { 706744bfb21SJohn Baldwin if (so4 != NULL) 707744bfb21SJohn Baldwin soclose(so4); 708744bfb21SJohn Baldwin if (so6 != NULL) 709744bfb21SJohn Baldwin soclose(so6); 710744bfb21SJohn Baldwin } 711744bfb21SJohn Baldwin return (rc); 712744bfb21SJohn Baldwin } 713744bfb21SJohn Baldwin 714744bfb21SJohn Baldwin static int wg_socket_set_sockopt(struct socket *so4, struct socket *so6, int name, void *val, size_t len) 715744bfb21SJohn Baldwin { 716744bfb21SJohn Baldwin int ret4 = 0, ret6 = 0; 717744bfb21SJohn Baldwin struct sockopt sopt = { 718744bfb21SJohn Baldwin .sopt_dir = SOPT_SET, 719744bfb21SJohn Baldwin .sopt_level = SOL_SOCKET, 720744bfb21SJohn Baldwin .sopt_name = name, 721744bfb21SJohn Baldwin .sopt_val = val, 722744bfb21SJohn Baldwin .sopt_valsize = len 723744bfb21SJohn Baldwin }; 724744bfb21SJohn Baldwin 725744bfb21SJohn Baldwin if (so4) 726744bfb21SJohn Baldwin ret4 = sosetopt(so4, &sopt); 727744bfb21SJohn Baldwin if (so6) 728744bfb21SJohn Baldwin ret6 = sosetopt(so6, &sopt); 729744bfb21SJohn Baldwin return (ret4 ?: ret6); 730744bfb21SJohn Baldwin } 731744bfb21SJohn Baldwin 732744bfb21SJohn Baldwin static int wg_socket_set_cookie(struct wg_softc *sc, uint32_t user_cookie) 733744bfb21SJohn Baldwin { 734744bfb21SJohn Baldwin struct wg_socket *so = &sc->sc_socket; 735744bfb21SJohn Baldwin int ret; 736744bfb21SJohn Baldwin 737744bfb21SJohn Baldwin sx_assert(&sc->sc_lock, SX_XLOCKED); 738744bfb21SJohn Baldwin ret = wg_socket_set_sockopt(so->so_so4, so->so_so6, SO_USER_COOKIE, &user_cookie, sizeof(user_cookie)); 739744bfb21SJohn Baldwin if (!ret) 740744bfb21SJohn Baldwin so->so_user_cookie = user_cookie; 741744bfb21SJohn Baldwin return (ret); 742744bfb21SJohn Baldwin } 743744bfb21SJohn Baldwin 744744bfb21SJohn Baldwin static int wg_socket_set_fibnum(struct wg_softc *sc, int fibnum) 745744bfb21SJohn Baldwin { 746744bfb21SJohn Baldwin struct wg_socket *so = &sc->sc_socket; 747744bfb21SJohn Baldwin int ret; 748744bfb21SJohn Baldwin 749744bfb21SJohn Baldwin sx_assert(&sc->sc_lock, SX_XLOCKED); 750744bfb21SJohn Baldwin 751744bfb21SJohn Baldwin ret = wg_socket_set_sockopt(so->so_so4, so->so_so6, SO_SETFIB, &fibnum, sizeof(fibnum)); 752744bfb21SJohn Baldwin if (!ret) 753744bfb21SJohn Baldwin so->so_fibnum = fibnum; 754744bfb21SJohn Baldwin return (ret); 755744bfb21SJohn Baldwin } 756744bfb21SJohn Baldwin 757744bfb21SJohn Baldwin static void 758744bfb21SJohn Baldwin wg_socket_uninit(struct wg_softc *sc) 759744bfb21SJohn Baldwin { 760744bfb21SJohn Baldwin wg_socket_set(sc, NULL, NULL); 761744bfb21SJohn Baldwin } 762744bfb21SJohn Baldwin 763744bfb21SJohn Baldwin static void 764744bfb21SJohn Baldwin wg_socket_set(struct wg_softc *sc, struct socket *new_so4, struct socket *new_so6) 765744bfb21SJohn Baldwin { 766744bfb21SJohn Baldwin struct wg_socket *so = &sc->sc_socket; 767744bfb21SJohn Baldwin struct socket *so4, *so6; 768744bfb21SJohn Baldwin 769744bfb21SJohn Baldwin sx_assert(&sc->sc_lock, SX_XLOCKED); 770744bfb21SJohn Baldwin 771e32e1a16SJohn Baldwin so4 = atomic_load_ptr(&so->so_so4); 772e32e1a16SJohn Baldwin so6 = atomic_load_ptr(&so->so_so6); 773e32e1a16SJohn Baldwin atomic_store_ptr(&so->so_so4, new_so4); 774e32e1a16SJohn Baldwin atomic_store_ptr(&so->so_so6, new_so6); 775744bfb21SJohn Baldwin 776744bfb21SJohn Baldwin if (!so4 && !so6) 777744bfb21SJohn Baldwin return; 778744bfb21SJohn Baldwin NET_EPOCH_WAIT(); 779744bfb21SJohn Baldwin if (so4) 780744bfb21SJohn Baldwin soclose(so4); 781744bfb21SJohn Baldwin if (so6) 782744bfb21SJohn Baldwin soclose(so6); 783744bfb21SJohn Baldwin } 784744bfb21SJohn Baldwin 785744bfb21SJohn Baldwin static int 786744bfb21SJohn Baldwin wg_socket_bind(struct socket **in_so4, struct socket **in_so6, in_port_t *requested_port) 787744bfb21SJohn Baldwin { 788744bfb21SJohn Baldwin struct socket *so4 = *in_so4, *so6 = *in_so6; 789744bfb21SJohn Baldwin int ret4 = 0, ret6 = 0; 790744bfb21SJohn Baldwin in_port_t port = *requested_port; 791744bfb21SJohn Baldwin struct sockaddr_in sin = { 792744bfb21SJohn Baldwin .sin_len = sizeof(struct sockaddr_in), 793744bfb21SJohn Baldwin .sin_family = AF_INET, 794744bfb21SJohn Baldwin .sin_port = htons(port) 795744bfb21SJohn Baldwin }; 796744bfb21SJohn Baldwin struct sockaddr_in6 sin6 = { 797744bfb21SJohn Baldwin .sin6_len = sizeof(struct sockaddr_in6), 798744bfb21SJohn Baldwin .sin6_family = AF_INET6, 799744bfb21SJohn Baldwin .sin6_port = htons(port) 800744bfb21SJohn Baldwin }; 801744bfb21SJohn Baldwin 802744bfb21SJohn Baldwin if (so4) { 803744bfb21SJohn Baldwin ret4 = sobind(so4, (struct sockaddr *)&sin, curthread); 804744bfb21SJohn Baldwin if (ret4 && ret4 != EADDRNOTAVAIL) 805744bfb21SJohn Baldwin return (ret4); 806744bfb21SJohn Baldwin if (!ret4 && !sin.sin_port) { 807744bfb21SJohn Baldwin struct sockaddr_in *bound_sin; 808744bfb21SJohn Baldwin int ret = so4->so_proto->pr_sockaddr(so4, 809744bfb21SJohn Baldwin (struct sockaddr **)&bound_sin); 810744bfb21SJohn Baldwin if (ret) 811744bfb21SJohn Baldwin return (ret); 812744bfb21SJohn Baldwin port = ntohs(bound_sin->sin_port); 813744bfb21SJohn Baldwin sin6.sin6_port = bound_sin->sin_port; 814744bfb21SJohn Baldwin free(bound_sin, M_SONAME); 815744bfb21SJohn Baldwin } 816744bfb21SJohn Baldwin } 817744bfb21SJohn Baldwin 818744bfb21SJohn Baldwin if (so6) { 819744bfb21SJohn Baldwin ret6 = sobind(so6, (struct sockaddr *)&sin6, curthread); 820744bfb21SJohn Baldwin if (ret6 && ret6 != EADDRNOTAVAIL) 821744bfb21SJohn Baldwin return (ret6); 822744bfb21SJohn Baldwin if (!ret6 && !sin6.sin6_port) { 823744bfb21SJohn Baldwin struct sockaddr_in6 *bound_sin6; 824744bfb21SJohn Baldwin int ret = so6->so_proto->pr_sockaddr(so6, 825744bfb21SJohn Baldwin (struct sockaddr **)&bound_sin6); 826744bfb21SJohn Baldwin if (ret) 827744bfb21SJohn Baldwin return (ret); 828744bfb21SJohn Baldwin port = ntohs(bound_sin6->sin6_port); 829744bfb21SJohn Baldwin free(bound_sin6, M_SONAME); 830744bfb21SJohn Baldwin } 831744bfb21SJohn Baldwin } 832744bfb21SJohn Baldwin 833744bfb21SJohn Baldwin if (ret4 && ret6) 834744bfb21SJohn Baldwin return (ret4); 835744bfb21SJohn Baldwin *requested_port = port; 836744bfb21SJohn Baldwin if (ret4 && !ret6 && so4) { 837744bfb21SJohn Baldwin soclose(so4); 838744bfb21SJohn Baldwin *in_so4 = NULL; 839744bfb21SJohn Baldwin } else if (ret6 && !ret4 && so6) { 840744bfb21SJohn Baldwin soclose(so6); 841744bfb21SJohn Baldwin *in_so6 = NULL; 842744bfb21SJohn Baldwin } 843744bfb21SJohn Baldwin return (0); 844744bfb21SJohn Baldwin } 845744bfb21SJohn Baldwin 846744bfb21SJohn Baldwin static int 847744bfb21SJohn Baldwin wg_send(struct wg_softc *sc, struct wg_endpoint *e, struct mbuf *m) 848744bfb21SJohn Baldwin { 849744bfb21SJohn Baldwin struct epoch_tracker et; 850744bfb21SJohn Baldwin struct sockaddr *sa; 851744bfb21SJohn Baldwin struct wg_socket *so = &sc->sc_socket; 852744bfb21SJohn Baldwin struct socket *so4, *so6; 853744bfb21SJohn Baldwin struct mbuf *control = NULL; 854744bfb21SJohn Baldwin int ret = 0; 855744bfb21SJohn Baldwin size_t len = m->m_pkthdr.len; 856744bfb21SJohn Baldwin 857744bfb21SJohn Baldwin /* Get local control address before locking */ 858744bfb21SJohn Baldwin if (e->e_remote.r_sa.sa_family == AF_INET) { 859744bfb21SJohn Baldwin if (e->e_local.l_in.s_addr != INADDR_ANY) 860744bfb21SJohn Baldwin control = sbcreatecontrol((caddr_t)&e->e_local.l_in, 861744bfb21SJohn Baldwin sizeof(struct in_addr), IP_SENDSRCADDR, 862744bfb21SJohn Baldwin IPPROTO_IP, M_NOWAIT); 863744bfb21SJohn Baldwin #ifdef INET6 864744bfb21SJohn Baldwin } else if (e->e_remote.r_sa.sa_family == AF_INET6) { 865744bfb21SJohn Baldwin if (!IN6_IS_ADDR_UNSPECIFIED(&e->e_local.l_in6)) 866744bfb21SJohn Baldwin control = sbcreatecontrol((caddr_t)&e->e_local.l_pktinfo6, 867744bfb21SJohn Baldwin sizeof(struct in6_pktinfo), IPV6_PKTINFO, 868744bfb21SJohn Baldwin IPPROTO_IPV6, M_NOWAIT); 869744bfb21SJohn Baldwin #endif 870744bfb21SJohn Baldwin } else { 871744bfb21SJohn Baldwin m_freem(m); 872744bfb21SJohn Baldwin return (EAFNOSUPPORT); 873744bfb21SJohn Baldwin } 874744bfb21SJohn Baldwin 875744bfb21SJohn Baldwin /* Get remote address */ 876744bfb21SJohn Baldwin sa = &e->e_remote.r_sa; 877744bfb21SJohn Baldwin 878744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 879e32e1a16SJohn Baldwin so4 = atomic_load_ptr(&so->so_so4); 880e32e1a16SJohn Baldwin so6 = atomic_load_ptr(&so->so_so6); 881744bfb21SJohn Baldwin if (e->e_remote.r_sa.sa_family == AF_INET && so4 != NULL) 882744bfb21SJohn Baldwin ret = sosend(so4, sa, NULL, m, control, 0, curthread); 883744bfb21SJohn Baldwin else if (e->e_remote.r_sa.sa_family == AF_INET6 && so6 != NULL) 884744bfb21SJohn Baldwin ret = sosend(so6, sa, NULL, m, control, 0, curthread); 885744bfb21SJohn Baldwin else { 886744bfb21SJohn Baldwin ret = ENOTCONN; 887744bfb21SJohn Baldwin m_freem(control); 888744bfb21SJohn Baldwin m_freem(m); 889744bfb21SJohn Baldwin } 890744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 891744bfb21SJohn Baldwin if (ret == 0) { 892744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_OPACKETS, 1); 893744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_OBYTES, len); 894744bfb21SJohn Baldwin } 895744bfb21SJohn Baldwin return (ret); 896744bfb21SJohn Baldwin } 897744bfb21SJohn Baldwin 898744bfb21SJohn Baldwin static void 899744bfb21SJohn Baldwin wg_send_buf(struct wg_softc *sc, struct wg_endpoint *e, uint8_t *buf, size_t len) 900744bfb21SJohn Baldwin { 901744bfb21SJohn Baldwin struct mbuf *m; 902744bfb21SJohn Baldwin int ret = 0; 903744bfb21SJohn Baldwin bool retried = false; 904744bfb21SJohn Baldwin 905744bfb21SJohn Baldwin retry: 906744bfb21SJohn Baldwin m = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR); 907744bfb21SJohn Baldwin if (!m) { 908744bfb21SJohn Baldwin ret = ENOMEM; 909744bfb21SJohn Baldwin goto out; 910744bfb21SJohn Baldwin } 911744bfb21SJohn Baldwin m_copyback(m, 0, len, buf); 912744bfb21SJohn Baldwin 913744bfb21SJohn Baldwin if (ret == 0) { 914744bfb21SJohn Baldwin ret = wg_send(sc, e, m); 915744bfb21SJohn Baldwin /* Retry if we couldn't bind to e->e_local */ 916744bfb21SJohn Baldwin if (ret == EADDRNOTAVAIL && !retried) { 917744bfb21SJohn Baldwin bzero(&e->e_local, sizeof(e->e_local)); 918744bfb21SJohn Baldwin retried = true; 919744bfb21SJohn Baldwin goto retry; 920744bfb21SJohn Baldwin } 921744bfb21SJohn Baldwin } else { 922744bfb21SJohn Baldwin ret = wg_send(sc, e, m); 923744bfb21SJohn Baldwin } 924744bfb21SJohn Baldwin out: 925744bfb21SJohn Baldwin if (ret) 926744bfb21SJohn Baldwin DPRINTF(sc, "Unable to send packet: %d\n", ret); 927744bfb21SJohn Baldwin } 928744bfb21SJohn Baldwin 929744bfb21SJohn Baldwin /* Timers */ 930744bfb21SJohn Baldwin static void 931744bfb21SJohn Baldwin wg_timers_enable(struct wg_peer *peer) 932744bfb21SJohn Baldwin { 933e32e1a16SJohn Baldwin atomic_store_bool(&peer->p_enabled, true); 934744bfb21SJohn Baldwin wg_timers_run_persistent_keepalive(peer); 935744bfb21SJohn Baldwin } 936744bfb21SJohn Baldwin 937744bfb21SJohn Baldwin static void 938744bfb21SJohn Baldwin wg_timers_disable(struct wg_peer *peer) 939744bfb21SJohn Baldwin { 940744bfb21SJohn Baldwin /* By setting p_enabled = false, then calling NET_EPOCH_WAIT, we can be 941744bfb21SJohn Baldwin * sure no new handshakes are created after the wait. This is because 942744bfb21SJohn Baldwin * all callout_resets (scheduling the callout) are guarded by 943744bfb21SJohn Baldwin * p_enabled. We can be sure all sections that read p_enabled and then 944744bfb21SJohn Baldwin * optionally call callout_reset are finished as they are surrounded by 945744bfb21SJohn Baldwin * NET_EPOCH_{ENTER,EXIT}. 946744bfb21SJohn Baldwin * 947744bfb21SJohn Baldwin * However, as new callouts may be scheduled during NET_EPOCH_WAIT (but 948744bfb21SJohn Baldwin * not after), we stop all callouts leaving no callouts active. 949744bfb21SJohn Baldwin * 950744bfb21SJohn Baldwin * We should also pull NET_EPOCH_WAIT out of the FOREACH(peer) loops, but the 951744bfb21SJohn Baldwin * performance impact is acceptable for the time being. */ 952e32e1a16SJohn Baldwin atomic_store_bool(&peer->p_enabled, false); 953744bfb21SJohn Baldwin NET_EPOCH_WAIT(); 954e32e1a16SJohn Baldwin atomic_store_bool(&peer->p_need_another_keepalive, false); 955744bfb21SJohn Baldwin 956744bfb21SJohn Baldwin callout_stop(&peer->p_new_handshake); 957744bfb21SJohn Baldwin callout_stop(&peer->p_send_keepalive); 958744bfb21SJohn Baldwin callout_stop(&peer->p_retry_handshake); 959744bfb21SJohn Baldwin callout_stop(&peer->p_persistent_keepalive); 960744bfb21SJohn Baldwin callout_stop(&peer->p_zero_key_material); 961744bfb21SJohn Baldwin } 962744bfb21SJohn Baldwin 963744bfb21SJohn Baldwin static void 964744bfb21SJohn Baldwin wg_timers_set_persistent_keepalive(struct wg_peer *peer, uint16_t interval) 965744bfb21SJohn Baldwin { 966744bfb21SJohn Baldwin struct epoch_tracker et; 967744bfb21SJohn Baldwin if (interval != peer->p_persistent_keepalive_interval) { 968e32e1a16SJohn Baldwin atomic_store_16(&peer->p_persistent_keepalive_interval, interval); 969744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 970e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled)) 971744bfb21SJohn Baldwin wg_timers_run_persistent_keepalive(peer); 972744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 973744bfb21SJohn Baldwin } 974744bfb21SJohn Baldwin } 975744bfb21SJohn Baldwin 976744bfb21SJohn Baldwin static void 977744bfb21SJohn Baldwin wg_timers_get_last_handshake(struct wg_peer *peer, struct wg_timespec64 *time) 978744bfb21SJohn Baldwin { 979744bfb21SJohn Baldwin mtx_lock(&peer->p_handshake_mtx); 980744bfb21SJohn Baldwin time->tv_sec = peer->p_handshake_complete.tv_sec; 981744bfb21SJohn Baldwin time->tv_nsec = peer->p_handshake_complete.tv_nsec; 982744bfb21SJohn Baldwin mtx_unlock(&peer->p_handshake_mtx); 983744bfb21SJohn Baldwin } 984744bfb21SJohn Baldwin 985744bfb21SJohn Baldwin static void 986744bfb21SJohn Baldwin wg_timers_event_data_sent(struct wg_peer *peer) 987744bfb21SJohn Baldwin { 988744bfb21SJohn Baldwin struct epoch_tracker et; 989744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 990e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled) && 991e32e1a16SJohn Baldwin !callout_pending(&peer->p_new_handshake)) 992744bfb21SJohn Baldwin callout_reset(&peer->p_new_handshake, MSEC_2_TICKS( 993744bfb21SJohn Baldwin NEW_HANDSHAKE_TIMEOUT * 1000 + 994744bfb21SJohn Baldwin arc4random_uniform(REKEY_TIMEOUT_JITTER)), 995744bfb21SJohn Baldwin wg_timers_run_new_handshake, peer); 996744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 997744bfb21SJohn Baldwin } 998744bfb21SJohn Baldwin 999744bfb21SJohn Baldwin static void 1000744bfb21SJohn Baldwin wg_timers_event_data_received(struct wg_peer *peer) 1001744bfb21SJohn Baldwin { 1002744bfb21SJohn Baldwin struct epoch_tracker et; 1003744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1004e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled)) { 1005744bfb21SJohn Baldwin if (!callout_pending(&peer->p_send_keepalive)) 1006744bfb21SJohn Baldwin callout_reset(&peer->p_send_keepalive, 1007744bfb21SJohn Baldwin MSEC_2_TICKS(KEEPALIVE_TIMEOUT * 1000), 1008744bfb21SJohn Baldwin wg_timers_run_send_keepalive, peer); 1009744bfb21SJohn Baldwin else 1010e32e1a16SJohn Baldwin atomic_store_bool(&peer->p_need_another_keepalive, 1011e32e1a16SJohn Baldwin true); 1012744bfb21SJohn Baldwin } 1013744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1014744bfb21SJohn Baldwin } 1015744bfb21SJohn Baldwin 1016744bfb21SJohn Baldwin static void 1017744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_sent(struct wg_peer *peer) 1018744bfb21SJohn Baldwin { 1019744bfb21SJohn Baldwin callout_stop(&peer->p_send_keepalive); 1020744bfb21SJohn Baldwin } 1021744bfb21SJohn Baldwin 1022744bfb21SJohn Baldwin static void 1023744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_received(struct wg_peer *peer) 1024744bfb21SJohn Baldwin { 1025744bfb21SJohn Baldwin callout_stop(&peer->p_new_handshake); 1026744bfb21SJohn Baldwin } 1027744bfb21SJohn Baldwin 1028744bfb21SJohn Baldwin static void 1029744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_traversal(struct wg_peer *peer) 1030744bfb21SJohn Baldwin { 1031744bfb21SJohn Baldwin struct epoch_tracker et; 1032744bfb21SJohn Baldwin uint16_t interval; 1033744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1034e32e1a16SJohn Baldwin interval = atomic_load_16(&peer->p_persistent_keepalive_interval); 1035e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled) && interval > 0) 1036744bfb21SJohn Baldwin callout_reset(&peer->p_persistent_keepalive, 1037744bfb21SJohn Baldwin MSEC_2_TICKS(interval * 1000), 1038744bfb21SJohn Baldwin wg_timers_run_persistent_keepalive, peer); 1039744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1040744bfb21SJohn Baldwin } 1041744bfb21SJohn Baldwin 1042744bfb21SJohn Baldwin static void 1043744bfb21SJohn Baldwin wg_timers_event_handshake_initiated(struct wg_peer *peer) 1044744bfb21SJohn Baldwin { 1045744bfb21SJohn Baldwin struct epoch_tracker et; 1046744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1047e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled)) 1048744bfb21SJohn Baldwin callout_reset(&peer->p_retry_handshake, MSEC_2_TICKS( 1049744bfb21SJohn Baldwin REKEY_TIMEOUT * 1000 + 1050744bfb21SJohn Baldwin arc4random_uniform(REKEY_TIMEOUT_JITTER)), 1051744bfb21SJohn Baldwin wg_timers_run_retry_handshake, peer); 1052744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1053744bfb21SJohn Baldwin } 1054744bfb21SJohn Baldwin 1055744bfb21SJohn Baldwin static void 1056744bfb21SJohn Baldwin wg_timers_event_handshake_complete(struct wg_peer *peer) 1057744bfb21SJohn Baldwin { 1058744bfb21SJohn Baldwin struct epoch_tracker et; 1059744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1060e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled)) { 1061744bfb21SJohn Baldwin mtx_lock(&peer->p_handshake_mtx); 1062744bfb21SJohn Baldwin callout_stop(&peer->p_retry_handshake); 1063744bfb21SJohn Baldwin peer->p_handshake_retries = 0; 1064744bfb21SJohn Baldwin getnanotime(&peer->p_handshake_complete); 1065744bfb21SJohn Baldwin mtx_unlock(&peer->p_handshake_mtx); 1066744bfb21SJohn Baldwin wg_timers_run_send_keepalive(peer); 1067744bfb21SJohn Baldwin } 1068744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1069744bfb21SJohn Baldwin } 1070744bfb21SJohn Baldwin 1071744bfb21SJohn Baldwin static void 1072744bfb21SJohn Baldwin wg_timers_event_session_derived(struct wg_peer *peer) 1073744bfb21SJohn Baldwin { 1074744bfb21SJohn Baldwin struct epoch_tracker et; 1075744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1076e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled)) 1077744bfb21SJohn Baldwin callout_reset(&peer->p_zero_key_material, 1078744bfb21SJohn Baldwin MSEC_2_TICKS(REJECT_AFTER_TIME * 3 * 1000), 1079744bfb21SJohn Baldwin wg_timers_run_zero_key_material, peer); 1080744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1081744bfb21SJohn Baldwin } 1082744bfb21SJohn Baldwin 1083744bfb21SJohn Baldwin static void 1084744bfb21SJohn Baldwin wg_timers_event_want_initiation(struct wg_peer *peer) 1085744bfb21SJohn Baldwin { 1086744bfb21SJohn Baldwin struct epoch_tracker et; 1087744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1088e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled)) 1089744bfb21SJohn Baldwin wg_timers_run_send_initiation(peer, false); 1090744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1091744bfb21SJohn Baldwin } 1092744bfb21SJohn Baldwin 1093744bfb21SJohn Baldwin static void 1094744bfb21SJohn Baldwin wg_timers_run_send_initiation(struct wg_peer *peer, bool is_retry) 1095744bfb21SJohn Baldwin { 1096744bfb21SJohn Baldwin if (!is_retry) 1097744bfb21SJohn Baldwin peer->p_handshake_retries = 0; 1098744bfb21SJohn Baldwin if (noise_remote_initiation_expired(peer->p_remote) == ETIMEDOUT) 1099744bfb21SJohn Baldwin wg_send_initiation(peer); 1100744bfb21SJohn Baldwin } 1101744bfb21SJohn Baldwin 1102744bfb21SJohn Baldwin static void 1103744bfb21SJohn Baldwin wg_timers_run_retry_handshake(void *_peer) 1104744bfb21SJohn Baldwin { 1105744bfb21SJohn Baldwin struct epoch_tracker et; 1106744bfb21SJohn Baldwin struct wg_peer *peer = _peer; 1107744bfb21SJohn Baldwin 1108744bfb21SJohn Baldwin mtx_lock(&peer->p_handshake_mtx); 1109744bfb21SJohn Baldwin if (peer->p_handshake_retries <= MAX_TIMER_HANDSHAKES) { 1110744bfb21SJohn Baldwin peer->p_handshake_retries++; 1111744bfb21SJohn Baldwin mtx_unlock(&peer->p_handshake_mtx); 1112744bfb21SJohn Baldwin 1113744bfb21SJohn Baldwin DPRINTF(peer->p_sc, "Handshake for peer %" PRIu64 " did not complete " 1114744bfb21SJohn Baldwin "after %d seconds, retrying (try %d)\n", peer->p_id, 1115744bfb21SJohn Baldwin REKEY_TIMEOUT, peer->p_handshake_retries + 1); 1116744bfb21SJohn Baldwin wg_peer_clear_src(peer); 1117744bfb21SJohn Baldwin wg_timers_run_send_initiation(peer, true); 1118744bfb21SJohn Baldwin } else { 1119744bfb21SJohn Baldwin mtx_unlock(&peer->p_handshake_mtx); 1120744bfb21SJohn Baldwin 1121744bfb21SJohn Baldwin DPRINTF(peer->p_sc, "Handshake for peer %" PRIu64 " did not complete " 1122744bfb21SJohn Baldwin "after %d retries, giving up\n", peer->p_id, 1123744bfb21SJohn Baldwin MAX_TIMER_HANDSHAKES + 2); 1124744bfb21SJohn Baldwin 1125744bfb21SJohn Baldwin callout_stop(&peer->p_send_keepalive); 1126744bfb21SJohn Baldwin wg_queue_purge(&peer->p_stage_queue); 1127744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1128e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled) && 1129744bfb21SJohn Baldwin !callout_pending(&peer->p_zero_key_material)) 1130744bfb21SJohn Baldwin callout_reset(&peer->p_zero_key_material, 1131744bfb21SJohn Baldwin MSEC_2_TICKS(REJECT_AFTER_TIME * 3 * 1000), 1132744bfb21SJohn Baldwin wg_timers_run_zero_key_material, peer); 1133744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1134744bfb21SJohn Baldwin } 1135744bfb21SJohn Baldwin } 1136744bfb21SJohn Baldwin 1137744bfb21SJohn Baldwin static void 1138744bfb21SJohn Baldwin wg_timers_run_send_keepalive(void *_peer) 1139744bfb21SJohn Baldwin { 1140744bfb21SJohn Baldwin struct epoch_tracker et; 1141744bfb21SJohn Baldwin struct wg_peer *peer = _peer; 1142744bfb21SJohn Baldwin 1143744bfb21SJohn Baldwin wg_send_keepalive(peer); 1144744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1145e32e1a16SJohn Baldwin if (atomic_load_bool(&peer->p_enabled) && 1146e32e1a16SJohn Baldwin atomic_load_bool(&peer->p_need_another_keepalive)) { 1147e32e1a16SJohn Baldwin atomic_store_bool(&peer->p_need_another_keepalive, false); 1148744bfb21SJohn Baldwin callout_reset(&peer->p_send_keepalive, 1149744bfb21SJohn Baldwin MSEC_2_TICKS(KEEPALIVE_TIMEOUT * 1000), 1150744bfb21SJohn Baldwin wg_timers_run_send_keepalive, peer); 1151744bfb21SJohn Baldwin } 1152744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1153744bfb21SJohn Baldwin } 1154744bfb21SJohn Baldwin 1155744bfb21SJohn Baldwin static void 1156744bfb21SJohn Baldwin wg_timers_run_new_handshake(void *_peer) 1157744bfb21SJohn Baldwin { 1158744bfb21SJohn Baldwin struct wg_peer *peer = _peer; 1159744bfb21SJohn Baldwin 1160744bfb21SJohn Baldwin DPRINTF(peer->p_sc, "Retrying handshake with peer %" PRIu64 " because we " 1161744bfb21SJohn Baldwin "stopped hearing back after %d seconds\n", 1162744bfb21SJohn Baldwin peer->p_id, NEW_HANDSHAKE_TIMEOUT); 1163744bfb21SJohn Baldwin 1164744bfb21SJohn Baldwin wg_peer_clear_src(peer); 1165744bfb21SJohn Baldwin wg_timers_run_send_initiation(peer, false); 1166744bfb21SJohn Baldwin } 1167744bfb21SJohn Baldwin 1168744bfb21SJohn Baldwin static void 1169744bfb21SJohn Baldwin wg_timers_run_zero_key_material(void *_peer) 1170744bfb21SJohn Baldwin { 1171744bfb21SJohn Baldwin struct wg_peer *peer = _peer; 1172744bfb21SJohn Baldwin 1173744bfb21SJohn Baldwin DPRINTF(peer->p_sc, "Zeroing out keys for peer %" PRIu64 ", since we " 1174744bfb21SJohn Baldwin "haven't received a new one in %d seconds\n", 1175744bfb21SJohn Baldwin peer->p_id, REJECT_AFTER_TIME * 3); 1176744bfb21SJohn Baldwin noise_remote_keypairs_clear(peer->p_remote); 1177744bfb21SJohn Baldwin } 1178744bfb21SJohn Baldwin 1179744bfb21SJohn Baldwin static void 1180744bfb21SJohn Baldwin wg_timers_run_persistent_keepalive(void *_peer) 1181744bfb21SJohn Baldwin { 1182744bfb21SJohn Baldwin struct wg_peer *peer = _peer; 1183744bfb21SJohn Baldwin 1184e32e1a16SJohn Baldwin if (atomic_load_16(&peer->p_persistent_keepalive_interval) > 0) 1185744bfb21SJohn Baldwin wg_send_keepalive(peer); 1186744bfb21SJohn Baldwin } 1187744bfb21SJohn Baldwin 1188744bfb21SJohn Baldwin /* TODO Handshake */ 1189744bfb21SJohn Baldwin static void 1190744bfb21SJohn Baldwin wg_peer_send_buf(struct wg_peer *peer, uint8_t *buf, size_t len) 1191744bfb21SJohn Baldwin { 1192744bfb21SJohn Baldwin struct wg_endpoint endpoint; 1193744bfb21SJohn Baldwin 1194744bfb21SJohn Baldwin counter_u64_add(peer->p_tx_bytes, len); 1195744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_traversal(peer); 1196744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_sent(peer); 1197744bfb21SJohn Baldwin wg_peer_get_endpoint(peer, &endpoint); 1198744bfb21SJohn Baldwin wg_send_buf(peer->p_sc, &endpoint, buf, len); 1199744bfb21SJohn Baldwin } 1200744bfb21SJohn Baldwin 1201744bfb21SJohn Baldwin static void 1202744bfb21SJohn Baldwin wg_send_initiation(struct wg_peer *peer) 1203744bfb21SJohn Baldwin { 1204744bfb21SJohn Baldwin struct wg_pkt_initiation pkt; 1205744bfb21SJohn Baldwin 1206744bfb21SJohn Baldwin if (noise_create_initiation(peer->p_remote, &pkt.s_idx, pkt.ue, 1207744bfb21SJohn Baldwin pkt.es, pkt.ets) != 0) 1208744bfb21SJohn Baldwin return; 1209744bfb21SJohn Baldwin 1210744bfb21SJohn Baldwin DPRINTF(peer->p_sc, "Sending handshake initiation to peer %" PRIu64 "\n", peer->p_id); 1211744bfb21SJohn Baldwin 1212744bfb21SJohn Baldwin pkt.t = WG_PKT_INITIATION; 1213744bfb21SJohn Baldwin cookie_maker_mac(&peer->p_cookie, &pkt.m, &pkt, 1214744bfb21SJohn Baldwin sizeof(pkt) - sizeof(pkt.m)); 1215744bfb21SJohn Baldwin wg_peer_send_buf(peer, (uint8_t *)&pkt, sizeof(pkt)); 1216744bfb21SJohn Baldwin wg_timers_event_handshake_initiated(peer); 1217744bfb21SJohn Baldwin } 1218744bfb21SJohn Baldwin 1219744bfb21SJohn Baldwin static void 1220744bfb21SJohn Baldwin wg_send_response(struct wg_peer *peer) 1221744bfb21SJohn Baldwin { 1222744bfb21SJohn Baldwin struct wg_pkt_response pkt; 1223744bfb21SJohn Baldwin 1224744bfb21SJohn Baldwin if (noise_create_response(peer->p_remote, &pkt.s_idx, &pkt.r_idx, 1225744bfb21SJohn Baldwin pkt.ue, pkt.en) != 0) 1226744bfb21SJohn Baldwin return; 1227744bfb21SJohn Baldwin 1228744bfb21SJohn Baldwin DPRINTF(peer->p_sc, "Sending handshake response to peer %" PRIu64 "\n", peer->p_id); 1229744bfb21SJohn Baldwin 1230744bfb21SJohn Baldwin wg_timers_event_session_derived(peer); 1231744bfb21SJohn Baldwin pkt.t = WG_PKT_RESPONSE; 1232744bfb21SJohn Baldwin cookie_maker_mac(&peer->p_cookie, &pkt.m, &pkt, 1233744bfb21SJohn Baldwin sizeof(pkt)-sizeof(pkt.m)); 1234744bfb21SJohn Baldwin wg_peer_send_buf(peer, (uint8_t*)&pkt, sizeof(pkt)); 1235744bfb21SJohn Baldwin } 1236744bfb21SJohn Baldwin 1237744bfb21SJohn Baldwin static void 1238744bfb21SJohn Baldwin wg_send_cookie(struct wg_softc *sc, struct cookie_macs *cm, uint32_t idx, 1239744bfb21SJohn Baldwin struct wg_endpoint *e) 1240744bfb21SJohn Baldwin { 1241744bfb21SJohn Baldwin struct wg_pkt_cookie pkt; 1242744bfb21SJohn Baldwin 1243744bfb21SJohn Baldwin DPRINTF(sc, "Sending cookie response for denied handshake message\n"); 1244744bfb21SJohn Baldwin 1245744bfb21SJohn Baldwin pkt.t = WG_PKT_COOKIE; 1246744bfb21SJohn Baldwin pkt.r_idx = idx; 1247744bfb21SJohn Baldwin 1248744bfb21SJohn Baldwin cookie_checker_create_payload(&sc->sc_cookie, cm, pkt.nonce, 1249744bfb21SJohn Baldwin pkt.ec, &e->e_remote.r_sa); 1250744bfb21SJohn Baldwin wg_send_buf(sc, e, (uint8_t *)&pkt, sizeof(pkt)); 1251744bfb21SJohn Baldwin } 1252744bfb21SJohn Baldwin 1253744bfb21SJohn Baldwin static void 1254744bfb21SJohn Baldwin wg_send_keepalive(struct wg_peer *peer) 1255744bfb21SJohn Baldwin { 1256744bfb21SJohn Baldwin struct wg_packet *pkt; 1257744bfb21SJohn Baldwin struct mbuf *m; 1258744bfb21SJohn Baldwin 1259744bfb21SJohn Baldwin if (wg_queue_len(&peer->p_stage_queue) > 0) 1260744bfb21SJohn Baldwin goto send; 1261744bfb21SJohn Baldwin if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL) 1262744bfb21SJohn Baldwin return; 1263744bfb21SJohn Baldwin if ((pkt = wg_packet_alloc(m)) == NULL) { 1264744bfb21SJohn Baldwin m_freem(m); 1265744bfb21SJohn Baldwin return; 1266744bfb21SJohn Baldwin } 1267744bfb21SJohn Baldwin wg_queue_push_staged(&peer->p_stage_queue, pkt); 1268744bfb21SJohn Baldwin DPRINTF(peer->p_sc, "Sending keepalive packet to peer %" PRIu64 "\n", peer->p_id); 1269744bfb21SJohn Baldwin send: 1270744bfb21SJohn Baldwin wg_peer_send_staged(peer); 1271744bfb21SJohn Baldwin } 1272744bfb21SJohn Baldwin 1273744bfb21SJohn Baldwin static void 1274744bfb21SJohn Baldwin wg_handshake(struct wg_softc *sc, struct wg_packet *pkt) 1275744bfb21SJohn Baldwin { 1276744bfb21SJohn Baldwin struct wg_pkt_initiation *init; 1277744bfb21SJohn Baldwin struct wg_pkt_response *resp; 1278744bfb21SJohn Baldwin struct wg_pkt_cookie *cook; 1279744bfb21SJohn Baldwin struct wg_endpoint *e; 1280744bfb21SJohn Baldwin struct wg_peer *peer; 1281744bfb21SJohn Baldwin struct mbuf *m; 1282744bfb21SJohn Baldwin struct noise_remote *remote = NULL; 1283744bfb21SJohn Baldwin int res; 1284744bfb21SJohn Baldwin bool underload = false; 1285744bfb21SJohn Baldwin static sbintime_t wg_last_underload; /* sbinuptime */ 1286744bfb21SJohn Baldwin 1287744bfb21SJohn Baldwin underload = wg_queue_len(&sc->sc_handshake_queue) >= MAX_QUEUED_HANDSHAKES / 8; 1288744bfb21SJohn Baldwin if (underload) { 1289744bfb21SJohn Baldwin wg_last_underload = getsbinuptime(); 1290744bfb21SJohn Baldwin } else if (wg_last_underload) { 1291744bfb21SJohn Baldwin underload = wg_last_underload + UNDERLOAD_TIMEOUT * SBT_1S > getsbinuptime(); 1292744bfb21SJohn Baldwin if (!underload) 1293744bfb21SJohn Baldwin wg_last_underload = 0; 1294744bfb21SJohn Baldwin } 1295744bfb21SJohn Baldwin 1296744bfb21SJohn Baldwin m = pkt->p_mbuf; 1297744bfb21SJohn Baldwin e = &pkt->p_endpoint; 1298744bfb21SJohn Baldwin 1299744bfb21SJohn Baldwin if ((pkt->p_mbuf = m = m_pullup(m, m->m_pkthdr.len)) == NULL) 1300744bfb21SJohn Baldwin goto error; 1301744bfb21SJohn Baldwin 1302744bfb21SJohn Baldwin switch (*mtod(m, uint32_t *)) { 1303744bfb21SJohn Baldwin case WG_PKT_INITIATION: 1304744bfb21SJohn Baldwin init = mtod(m, struct wg_pkt_initiation *); 1305744bfb21SJohn Baldwin 1306744bfb21SJohn Baldwin res = cookie_checker_validate_macs(&sc->sc_cookie, &init->m, 1307744bfb21SJohn Baldwin init, sizeof(*init) - sizeof(init->m), 1308744bfb21SJohn Baldwin underload, &e->e_remote.r_sa, 1309744bfb21SJohn Baldwin sc->sc_ifp->if_vnet); 1310744bfb21SJohn Baldwin 1311744bfb21SJohn Baldwin if (res == EINVAL) { 1312744bfb21SJohn Baldwin DPRINTF(sc, "Invalid initiation MAC\n"); 1313744bfb21SJohn Baldwin goto error; 1314744bfb21SJohn Baldwin } else if (res == ECONNREFUSED) { 1315744bfb21SJohn Baldwin DPRINTF(sc, "Handshake ratelimited\n"); 1316744bfb21SJohn Baldwin goto error; 1317744bfb21SJohn Baldwin } else if (res == EAGAIN) { 1318744bfb21SJohn Baldwin wg_send_cookie(sc, &init->m, init->s_idx, e); 1319744bfb21SJohn Baldwin goto error; 1320744bfb21SJohn Baldwin } else if (res != 0) { 1321744bfb21SJohn Baldwin panic("unexpected response: %d\n", res); 1322744bfb21SJohn Baldwin } 1323744bfb21SJohn Baldwin 1324744bfb21SJohn Baldwin if (noise_consume_initiation(sc->sc_local, &remote, 1325744bfb21SJohn Baldwin init->s_idx, init->ue, init->es, init->ets) != 0) { 1326744bfb21SJohn Baldwin DPRINTF(sc, "Invalid handshake initiation\n"); 1327744bfb21SJohn Baldwin goto error; 1328744bfb21SJohn Baldwin } 1329744bfb21SJohn Baldwin 1330744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 1331744bfb21SJohn Baldwin 1332744bfb21SJohn Baldwin DPRINTF(sc, "Receiving handshake initiation from peer %" PRIu64 "\n", peer->p_id); 1333744bfb21SJohn Baldwin 1334744bfb21SJohn Baldwin wg_peer_set_endpoint(peer, e); 1335744bfb21SJohn Baldwin wg_send_response(peer); 1336744bfb21SJohn Baldwin break; 1337744bfb21SJohn Baldwin case WG_PKT_RESPONSE: 1338744bfb21SJohn Baldwin resp = mtod(m, struct wg_pkt_response *); 1339744bfb21SJohn Baldwin 1340744bfb21SJohn Baldwin res = cookie_checker_validate_macs(&sc->sc_cookie, &resp->m, 1341744bfb21SJohn Baldwin resp, sizeof(*resp) - sizeof(resp->m), 1342744bfb21SJohn Baldwin underload, &e->e_remote.r_sa, 1343744bfb21SJohn Baldwin sc->sc_ifp->if_vnet); 1344744bfb21SJohn Baldwin 1345744bfb21SJohn Baldwin if (res == EINVAL) { 1346744bfb21SJohn Baldwin DPRINTF(sc, "Invalid response MAC\n"); 1347744bfb21SJohn Baldwin goto error; 1348744bfb21SJohn Baldwin } else if (res == ECONNREFUSED) { 1349744bfb21SJohn Baldwin DPRINTF(sc, "Handshake ratelimited\n"); 1350744bfb21SJohn Baldwin goto error; 1351744bfb21SJohn Baldwin } else if (res == EAGAIN) { 1352744bfb21SJohn Baldwin wg_send_cookie(sc, &resp->m, resp->s_idx, e); 1353744bfb21SJohn Baldwin goto error; 1354744bfb21SJohn Baldwin } else if (res != 0) { 1355744bfb21SJohn Baldwin panic("unexpected response: %d\n", res); 1356744bfb21SJohn Baldwin } 1357744bfb21SJohn Baldwin 1358744bfb21SJohn Baldwin if (noise_consume_response(sc->sc_local, &remote, 1359744bfb21SJohn Baldwin resp->s_idx, resp->r_idx, resp->ue, resp->en) != 0) { 1360744bfb21SJohn Baldwin DPRINTF(sc, "Invalid handshake response\n"); 1361744bfb21SJohn Baldwin goto error; 1362744bfb21SJohn Baldwin } 1363744bfb21SJohn Baldwin 1364744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 1365744bfb21SJohn Baldwin DPRINTF(sc, "Receiving handshake response from peer %" PRIu64 "\n", peer->p_id); 1366744bfb21SJohn Baldwin 1367744bfb21SJohn Baldwin wg_peer_set_endpoint(peer, e); 1368744bfb21SJohn Baldwin wg_timers_event_session_derived(peer); 1369744bfb21SJohn Baldwin wg_timers_event_handshake_complete(peer); 1370744bfb21SJohn Baldwin break; 1371744bfb21SJohn Baldwin case WG_PKT_COOKIE: 1372744bfb21SJohn Baldwin cook = mtod(m, struct wg_pkt_cookie *); 1373744bfb21SJohn Baldwin 1374744bfb21SJohn Baldwin if ((remote = noise_remote_index(sc->sc_local, cook->r_idx)) == NULL) { 1375744bfb21SJohn Baldwin DPRINTF(sc, "Unknown cookie index\n"); 1376744bfb21SJohn Baldwin goto error; 1377744bfb21SJohn Baldwin } 1378744bfb21SJohn Baldwin 1379744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 1380744bfb21SJohn Baldwin 1381744bfb21SJohn Baldwin if (cookie_maker_consume_payload(&peer->p_cookie, 1382744bfb21SJohn Baldwin cook->nonce, cook->ec) == 0) { 1383744bfb21SJohn Baldwin DPRINTF(sc, "Receiving cookie response\n"); 1384744bfb21SJohn Baldwin } else { 1385744bfb21SJohn Baldwin DPRINTF(sc, "Could not decrypt cookie response\n"); 1386744bfb21SJohn Baldwin goto error; 1387744bfb21SJohn Baldwin } 1388744bfb21SJohn Baldwin 1389744bfb21SJohn Baldwin goto not_authenticated; 1390744bfb21SJohn Baldwin default: 1391744bfb21SJohn Baldwin panic("invalid packet in handshake queue"); 1392744bfb21SJohn Baldwin } 1393744bfb21SJohn Baldwin 1394744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_received(peer); 1395744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_traversal(peer); 1396744bfb21SJohn Baldwin 1397744bfb21SJohn Baldwin not_authenticated: 1398744bfb21SJohn Baldwin counter_u64_add(peer->p_rx_bytes, m->m_pkthdr.len); 1399744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); 1400744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 1401744bfb21SJohn Baldwin error: 1402744bfb21SJohn Baldwin if (remote != NULL) 1403744bfb21SJohn Baldwin noise_remote_put(remote); 1404744bfb21SJohn Baldwin wg_packet_free(pkt); 1405744bfb21SJohn Baldwin } 1406744bfb21SJohn Baldwin 1407744bfb21SJohn Baldwin static void 1408744bfb21SJohn Baldwin wg_softc_handshake_receive(struct wg_softc *sc) 1409744bfb21SJohn Baldwin { 1410744bfb21SJohn Baldwin struct wg_packet *pkt; 1411744bfb21SJohn Baldwin while ((pkt = wg_queue_dequeue_handshake(&sc->sc_handshake_queue)) != NULL) 1412744bfb21SJohn Baldwin wg_handshake(sc, pkt); 1413744bfb21SJohn Baldwin } 1414744bfb21SJohn Baldwin 1415744bfb21SJohn Baldwin static void 1416744bfb21SJohn Baldwin wg_mbuf_reset(struct mbuf *m) 1417744bfb21SJohn Baldwin { 1418744bfb21SJohn Baldwin 1419744bfb21SJohn Baldwin struct m_tag *t, *tmp; 1420744bfb21SJohn Baldwin 1421744bfb21SJohn Baldwin /* 1422744bfb21SJohn Baldwin * We want to reset the mbuf to a newly allocated state, containing 1423744bfb21SJohn Baldwin * just the packet contents. Unfortunately FreeBSD doesn't seem to 1424744bfb21SJohn Baldwin * offer this anywhere, so we have to make it up as we go. If we can 1425744bfb21SJohn Baldwin * get this in kern/kern_mbuf.c, that would be best. 1426744bfb21SJohn Baldwin * 1427744bfb21SJohn Baldwin * Notice: this may break things unexpectedly but it is better to fail 1428744bfb21SJohn Baldwin * closed in the extreme case than leak informtion in every 1429744bfb21SJohn Baldwin * case. 1430744bfb21SJohn Baldwin * 1431744bfb21SJohn Baldwin * With that said, all this attempts to do is remove any extraneous 1432744bfb21SJohn Baldwin * information that could be present. 1433744bfb21SJohn Baldwin */ 1434744bfb21SJohn Baldwin 1435744bfb21SJohn Baldwin M_ASSERTPKTHDR(m); 1436744bfb21SJohn Baldwin 1437744bfb21SJohn Baldwin m->m_flags &= ~(M_BCAST|M_MCAST|M_VLANTAG|M_PROMISC|M_PROTOFLAGS); 1438744bfb21SJohn Baldwin 1439744bfb21SJohn Baldwin M_HASHTYPE_CLEAR(m); 1440744bfb21SJohn Baldwin #ifdef NUMA 1441744bfb21SJohn Baldwin m->m_pkthdr.numa_domain = M_NODOM; 1442744bfb21SJohn Baldwin #endif 1443744bfb21SJohn Baldwin SLIST_FOREACH_SAFE(t, &m->m_pkthdr.tags, m_tag_link, tmp) { 1444744bfb21SJohn Baldwin if ((t->m_tag_id != 0 || t->m_tag_cookie != MTAG_WGLOOP) && 1445744bfb21SJohn Baldwin t->m_tag_id != PACKET_TAG_MACLABEL) 1446744bfb21SJohn Baldwin m_tag_delete(m, t); 1447744bfb21SJohn Baldwin } 1448744bfb21SJohn Baldwin 1449744bfb21SJohn Baldwin KASSERT((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0, 1450744bfb21SJohn Baldwin ("%s: mbuf %p has a send tag", __func__, m)); 1451744bfb21SJohn Baldwin 1452744bfb21SJohn Baldwin m->m_pkthdr.csum_flags = 0; 1453744bfb21SJohn Baldwin m->m_pkthdr.PH_per.sixtyfour[0] = 0; 1454744bfb21SJohn Baldwin m->m_pkthdr.PH_loc.sixtyfour[0] = 0; 1455744bfb21SJohn Baldwin } 1456744bfb21SJohn Baldwin 1457744bfb21SJohn Baldwin static inline unsigned int 1458744bfb21SJohn Baldwin calculate_padding(struct wg_packet *pkt) 1459744bfb21SJohn Baldwin { 1460744bfb21SJohn Baldwin unsigned int padded_size, last_unit = pkt->p_mbuf->m_pkthdr.len; 1461744bfb21SJohn Baldwin 1462744bfb21SJohn Baldwin if (__predict_false(!pkt->p_mtu)) 1463744bfb21SJohn Baldwin return (last_unit + (WG_PKT_PADDING - 1)) & ~(WG_PKT_PADDING - 1); 1464744bfb21SJohn Baldwin 1465744bfb21SJohn Baldwin if (__predict_false(last_unit > pkt->p_mtu)) 1466744bfb21SJohn Baldwin last_unit %= pkt->p_mtu; 1467744bfb21SJohn Baldwin 1468744bfb21SJohn Baldwin padded_size = (last_unit + (WG_PKT_PADDING - 1)) & ~(WG_PKT_PADDING - 1); 1469744bfb21SJohn Baldwin if (pkt->p_mtu < padded_size) 1470744bfb21SJohn Baldwin padded_size = pkt->p_mtu; 1471744bfb21SJohn Baldwin return padded_size - last_unit; 1472744bfb21SJohn Baldwin } 1473744bfb21SJohn Baldwin 1474744bfb21SJohn Baldwin static void 1475744bfb21SJohn Baldwin wg_encrypt(struct wg_softc *sc, struct wg_packet *pkt) 1476744bfb21SJohn Baldwin { 1477744bfb21SJohn Baldwin static const uint8_t padding[WG_PKT_PADDING] = { 0 }; 1478744bfb21SJohn Baldwin struct wg_pkt_data *data; 1479744bfb21SJohn Baldwin struct wg_peer *peer; 1480744bfb21SJohn Baldwin struct noise_remote *remote; 1481744bfb21SJohn Baldwin struct mbuf *m; 1482744bfb21SJohn Baldwin uint32_t idx; 1483744bfb21SJohn Baldwin unsigned int padlen; 1484744bfb21SJohn Baldwin enum wg_ring_state state = WG_PACKET_DEAD; 1485744bfb21SJohn Baldwin 1486744bfb21SJohn Baldwin remote = noise_keypair_remote(pkt->p_keypair); 1487744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 1488744bfb21SJohn Baldwin m = pkt->p_mbuf; 1489744bfb21SJohn Baldwin 1490744bfb21SJohn Baldwin /* Pad the packet */ 1491744bfb21SJohn Baldwin padlen = calculate_padding(pkt); 1492744bfb21SJohn Baldwin if (padlen != 0 && !m_append(m, padlen, padding)) 1493744bfb21SJohn Baldwin goto out; 1494744bfb21SJohn Baldwin 1495744bfb21SJohn Baldwin /* Do encryption */ 1496744bfb21SJohn Baldwin if (noise_keypair_encrypt(pkt->p_keypair, &idx, pkt->p_nonce, m) != 0) 1497744bfb21SJohn Baldwin goto out; 1498744bfb21SJohn Baldwin 1499744bfb21SJohn Baldwin /* Put header into packet */ 1500744bfb21SJohn Baldwin M_PREPEND(m, sizeof(struct wg_pkt_data), M_NOWAIT); 1501744bfb21SJohn Baldwin if (m == NULL) 1502744bfb21SJohn Baldwin goto out; 1503744bfb21SJohn Baldwin data = mtod(m, struct wg_pkt_data *); 1504744bfb21SJohn Baldwin data->t = WG_PKT_DATA; 1505744bfb21SJohn Baldwin data->r_idx = idx; 1506744bfb21SJohn Baldwin data->nonce = htole64(pkt->p_nonce); 1507744bfb21SJohn Baldwin 1508744bfb21SJohn Baldwin wg_mbuf_reset(m); 1509744bfb21SJohn Baldwin state = WG_PACKET_CRYPTED; 1510744bfb21SJohn Baldwin out: 1511744bfb21SJohn Baldwin pkt->p_mbuf = m; 1512744bfb21SJohn Baldwin wmb(); 1513744bfb21SJohn Baldwin pkt->p_state = state; 1514744bfb21SJohn Baldwin GROUPTASK_ENQUEUE(&peer->p_send); 1515744bfb21SJohn Baldwin noise_remote_put(remote); 1516744bfb21SJohn Baldwin } 1517744bfb21SJohn Baldwin 1518744bfb21SJohn Baldwin static void 1519744bfb21SJohn Baldwin wg_decrypt(struct wg_softc *sc, struct wg_packet *pkt) 1520744bfb21SJohn Baldwin { 1521744bfb21SJohn Baldwin struct wg_peer *peer, *allowed_peer; 1522744bfb21SJohn Baldwin struct noise_remote *remote; 1523744bfb21SJohn Baldwin struct mbuf *m; 1524744bfb21SJohn Baldwin int len; 1525744bfb21SJohn Baldwin enum wg_ring_state state = WG_PACKET_DEAD; 1526744bfb21SJohn Baldwin 1527744bfb21SJohn Baldwin remote = noise_keypair_remote(pkt->p_keypair); 1528744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 1529744bfb21SJohn Baldwin m = pkt->p_mbuf; 1530744bfb21SJohn Baldwin 1531744bfb21SJohn Baldwin /* Read nonce and then adjust to remove the header. */ 1532744bfb21SJohn Baldwin pkt->p_nonce = le64toh(mtod(m, struct wg_pkt_data *)->nonce); 1533744bfb21SJohn Baldwin m_adj(m, sizeof(struct wg_pkt_data)); 1534744bfb21SJohn Baldwin 1535744bfb21SJohn Baldwin if (noise_keypair_decrypt(pkt->p_keypair, pkt->p_nonce, m) != 0) 1536744bfb21SJohn Baldwin goto out; 1537744bfb21SJohn Baldwin 1538744bfb21SJohn Baldwin /* A packet with length 0 is a keepalive packet */ 1539744bfb21SJohn Baldwin if (__predict_false(m->m_pkthdr.len == 0)) { 1540744bfb21SJohn Baldwin DPRINTF(sc, "Receiving keepalive packet from peer " 1541744bfb21SJohn Baldwin "%" PRIu64 "\n", peer->p_id); 1542744bfb21SJohn Baldwin state = WG_PACKET_CRYPTED; 1543744bfb21SJohn Baldwin goto out; 1544744bfb21SJohn Baldwin } 1545744bfb21SJohn Baldwin 1546744bfb21SJohn Baldwin /* 1547744bfb21SJohn Baldwin * We can let the network stack handle the intricate validation of the 1548744bfb21SJohn Baldwin * IP header, we just worry about the sizeof and the version, so we can 1549744bfb21SJohn Baldwin * read the source address in wg_aip_lookup. 1550744bfb21SJohn Baldwin */ 1551744bfb21SJohn Baldwin 1552744bfb21SJohn Baldwin if (determine_af_and_pullup(&m, &pkt->p_af) == 0) { 1553744bfb21SJohn Baldwin if (pkt->p_af == AF_INET) { 1554744bfb21SJohn Baldwin struct ip *ip = mtod(m, struct ip *); 1555744bfb21SJohn Baldwin allowed_peer = wg_aip_lookup(sc, AF_INET, &ip->ip_src); 1556744bfb21SJohn Baldwin len = ntohs(ip->ip_len); 1557744bfb21SJohn Baldwin if (len >= sizeof(struct ip) && len < m->m_pkthdr.len) 1558744bfb21SJohn Baldwin m_adj(m, len - m->m_pkthdr.len); 1559744bfb21SJohn Baldwin } else if (pkt->p_af == AF_INET6) { 1560744bfb21SJohn Baldwin struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1561744bfb21SJohn Baldwin allowed_peer = wg_aip_lookup(sc, AF_INET6, &ip6->ip6_src); 1562744bfb21SJohn Baldwin len = ntohs(ip6->ip6_plen) + sizeof(struct ip6_hdr); 1563744bfb21SJohn Baldwin if (len < m->m_pkthdr.len) 1564744bfb21SJohn Baldwin m_adj(m, len - m->m_pkthdr.len); 1565744bfb21SJohn Baldwin } else 1566744bfb21SJohn Baldwin panic("determine_af_and_pullup returned unexpected value"); 1567744bfb21SJohn Baldwin } else { 1568744bfb21SJohn Baldwin DPRINTF(sc, "Packet is neither ipv4 nor ipv6 from peer %" PRIu64 "\n", peer->p_id); 1569744bfb21SJohn Baldwin goto out; 1570744bfb21SJohn Baldwin } 1571744bfb21SJohn Baldwin 1572744bfb21SJohn Baldwin /* We only want to compare the address, not dereference, so drop the ref. */ 1573744bfb21SJohn Baldwin if (allowed_peer != NULL) 1574744bfb21SJohn Baldwin noise_remote_put(allowed_peer->p_remote); 1575744bfb21SJohn Baldwin 1576744bfb21SJohn Baldwin if (__predict_false(peer != allowed_peer)) { 1577744bfb21SJohn Baldwin DPRINTF(sc, "Packet has unallowed src IP from peer %" PRIu64 "\n", peer->p_id); 1578744bfb21SJohn Baldwin goto out; 1579744bfb21SJohn Baldwin } 1580744bfb21SJohn Baldwin 1581744bfb21SJohn Baldwin wg_mbuf_reset(m); 1582744bfb21SJohn Baldwin state = WG_PACKET_CRYPTED; 1583744bfb21SJohn Baldwin out: 1584744bfb21SJohn Baldwin pkt->p_mbuf = m; 1585744bfb21SJohn Baldwin wmb(); 1586744bfb21SJohn Baldwin pkt->p_state = state; 1587744bfb21SJohn Baldwin GROUPTASK_ENQUEUE(&peer->p_recv); 1588744bfb21SJohn Baldwin noise_remote_put(remote); 1589744bfb21SJohn Baldwin } 1590744bfb21SJohn Baldwin 1591744bfb21SJohn Baldwin static void 1592744bfb21SJohn Baldwin wg_softc_decrypt(struct wg_softc *sc) 1593744bfb21SJohn Baldwin { 1594744bfb21SJohn Baldwin struct wg_packet *pkt; 1595744bfb21SJohn Baldwin 1596744bfb21SJohn Baldwin while ((pkt = wg_queue_dequeue_parallel(&sc->sc_decrypt_parallel)) != NULL) 1597744bfb21SJohn Baldwin wg_decrypt(sc, pkt); 1598744bfb21SJohn Baldwin } 1599744bfb21SJohn Baldwin 1600744bfb21SJohn Baldwin static void 1601744bfb21SJohn Baldwin wg_softc_encrypt(struct wg_softc *sc) 1602744bfb21SJohn Baldwin { 1603744bfb21SJohn Baldwin struct wg_packet *pkt; 1604744bfb21SJohn Baldwin 1605744bfb21SJohn Baldwin while ((pkt = wg_queue_dequeue_parallel(&sc->sc_encrypt_parallel)) != NULL) 1606744bfb21SJohn Baldwin wg_encrypt(sc, pkt); 1607744bfb21SJohn Baldwin } 1608744bfb21SJohn Baldwin 1609744bfb21SJohn Baldwin static void 1610744bfb21SJohn Baldwin wg_encrypt_dispatch(struct wg_softc *sc) 1611744bfb21SJohn Baldwin { 1612744bfb21SJohn Baldwin /* 1613744bfb21SJohn Baldwin * The update to encrypt_last_cpu is racey such that we may 1614744bfb21SJohn Baldwin * reschedule the task for the same CPU multiple times, but 1615744bfb21SJohn Baldwin * the race doesn't really matter. 1616744bfb21SJohn Baldwin */ 1617744bfb21SJohn Baldwin u_int cpu = (sc->sc_encrypt_last_cpu + 1) % mp_ncpus; 1618744bfb21SJohn Baldwin sc->sc_encrypt_last_cpu = cpu; 1619744bfb21SJohn Baldwin GROUPTASK_ENQUEUE(&sc->sc_encrypt[cpu]); 1620744bfb21SJohn Baldwin } 1621744bfb21SJohn Baldwin 1622744bfb21SJohn Baldwin static void 1623744bfb21SJohn Baldwin wg_decrypt_dispatch(struct wg_softc *sc) 1624744bfb21SJohn Baldwin { 1625744bfb21SJohn Baldwin u_int cpu = (sc->sc_decrypt_last_cpu + 1) % mp_ncpus; 1626744bfb21SJohn Baldwin sc->sc_decrypt_last_cpu = cpu; 1627744bfb21SJohn Baldwin GROUPTASK_ENQUEUE(&sc->sc_decrypt[cpu]); 1628744bfb21SJohn Baldwin } 1629744bfb21SJohn Baldwin 1630744bfb21SJohn Baldwin static void 1631744bfb21SJohn Baldwin wg_deliver_out(struct wg_peer *peer) 1632744bfb21SJohn Baldwin { 1633744bfb21SJohn Baldwin struct wg_endpoint endpoint; 1634744bfb21SJohn Baldwin struct wg_softc *sc = peer->p_sc; 1635744bfb21SJohn Baldwin struct wg_packet *pkt; 1636744bfb21SJohn Baldwin struct mbuf *m; 1637744bfb21SJohn Baldwin int rc, len; 1638744bfb21SJohn Baldwin 1639744bfb21SJohn Baldwin wg_peer_get_endpoint(peer, &endpoint); 1640744bfb21SJohn Baldwin 1641744bfb21SJohn Baldwin while ((pkt = wg_queue_dequeue_serial(&peer->p_encrypt_serial)) != NULL) { 1642744bfb21SJohn Baldwin if (pkt->p_state != WG_PACKET_CRYPTED) 1643744bfb21SJohn Baldwin goto error; 1644744bfb21SJohn Baldwin 1645744bfb21SJohn Baldwin m = pkt->p_mbuf; 1646744bfb21SJohn Baldwin pkt->p_mbuf = NULL; 1647744bfb21SJohn Baldwin 1648744bfb21SJohn Baldwin len = m->m_pkthdr.len; 1649744bfb21SJohn Baldwin 1650744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_traversal(peer); 1651744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_sent(peer); 1652744bfb21SJohn Baldwin rc = wg_send(sc, &endpoint, m); 1653744bfb21SJohn Baldwin if (rc == 0) { 1654744bfb21SJohn Baldwin if (len > (sizeof(struct wg_pkt_data) + NOISE_AUTHTAG_LEN)) 1655744bfb21SJohn Baldwin wg_timers_event_data_sent(peer); 1656744bfb21SJohn Baldwin counter_u64_add(peer->p_tx_bytes, len); 1657744bfb21SJohn Baldwin } else if (rc == EADDRNOTAVAIL) { 1658744bfb21SJohn Baldwin wg_peer_clear_src(peer); 1659744bfb21SJohn Baldwin wg_peer_get_endpoint(peer, &endpoint); 1660744bfb21SJohn Baldwin goto error; 1661744bfb21SJohn Baldwin } else { 1662744bfb21SJohn Baldwin goto error; 1663744bfb21SJohn Baldwin } 1664744bfb21SJohn Baldwin wg_packet_free(pkt); 1665744bfb21SJohn Baldwin if (noise_keep_key_fresh_send(peer->p_remote)) 1666744bfb21SJohn Baldwin wg_timers_event_want_initiation(peer); 1667744bfb21SJohn Baldwin continue; 1668744bfb21SJohn Baldwin error: 1669744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_OERRORS, 1); 1670744bfb21SJohn Baldwin wg_packet_free(pkt); 1671744bfb21SJohn Baldwin } 1672744bfb21SJohn Baldwin } 1673744bfb21SJohn Baldwin 1674744bfb21SJohn Baldwin static void 1675744bfb21SJohn Baldwin wg_deliver_in(struct wg_peer *peer) 1676744bfb21SJohn Baldwin { 1677744bfb21SJohn Baldwin struct wg_softc *sc = peer->p_sc; 1678744bfb21SJohn Baldwin struct ifnet *ifp = sc->sc_ifp; 1679744bfb21SJohn Baldwin struct wg_packet *pkt; 1680744bfb21SJohn Baldwin struct mbuf *m; 1681744bfb21SJohn Baldwin struct epoch_tracker et; 1682744bfb21SJohn Baldwin 1683744bfb21SJohn Baldwin while ((pkt = wg_queue_dequeue_serial(&peer->p_decrypt_serial)) != NULL) { 1684744bfb21SJohn Baldwin if (pkt->p_state != WG_PACKET_CRYPTED) 1685744bfb21SJohn Baldwin goto error; 1686744bfb21SJohn Baldwin 1687744bfb21SJohn Baldwin m = pkt->p_mbuf; 1688744bfb21SJohn Baldwin if (noise_keypair_nonce_check(pkt->p_keypair, pkt->p_nonce) != 0) 1689744bfb21SJohn Baldwin goto error; 1690744bfb21SJohn Baldwin 1691744bfb21SJohn Baldwin if (noise_keypair_received_with(pkt->p_keypair) == ECONNRESET) 1692744bfb21SJohn Baldwin wg_timers_event_handshake_complete(peer); 1693744bfb21SJohn Baldwin 1694744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_received(peer); 1695744bfb21SJohn Baldwin wg_timers_event_any_authenticated_packet_traversal(peer); 1696744bfb21SJohn Baldwin wg_peer_set_endpoint(peer, &pkt->p_endpoint); 1697744bfb21SJohn Baldwin 1698744bfb21SJohn Baldwin counter_u64_add(peer->p_rx_bytes, m->m_pkthdr.len + 1699744bfb21SJohn Baldwin sizeof(struct wg_pkt_data) + NOISE_AUTHTAG_LEN); 1700744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); 1701744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len + 1702744bfb21SJohn Baldwin sizeof(struct wg_pkt_data) + NOISE_AUTHTAG_LEN); 1703744bfb21SJohn Baldwin 1704744bfb21SJohn Baldwin if (m->m_pkthdr.len == 0) 1705744bfb21SJohn Baldwin goto done; 1706744bfb21SJohn Baldwin 1707744bfb21SJohn Baldwin MPASS(pkt->p_af == AF_INET || pkt->p_af == AF_INET6); 1708744bfb21SJohn Baldwin pkt->p_mbuf = NULL; 1709744bfb21SJohn Baldwin 1710744bfb21SJohn Baldwin m->m_pkthdr.rcvif = ifp; 1711744bfb21SJohn Baldwin 1712744bfb21SJohn Baldwin NET_EPOCH_ENTER(et); 1713744bfb21SJohn Baldwin BPF_MTAP2_AF(ifp, m, pkt->p_af); 1714744bfb21SJohn Baldwin 1715744bfb21SJohn Baldwin CURVNET_SET(ifp->if_vnet); 1716744bfb21SJohn Baldwin M_SETFIB(m, ifp->if_fib); 1717744bfb21SJohn Baldwin if (pkt->p_af == AF_INET) 1718744bfb21SJohn Baldwin netisr_dispatch(NETISR_IP, m); 1719744bfb21SJohn Baldwin if (pkt->p_af == AF_INET6) 1720744bfb21SJohn Baldwin netisr_dispatch(NETISR_IPV6, m); 1721744bfb21SJohn Baldwin CURVNET_RESTORE(); 1722744bfb21SJohn Baldwin NET_EPOCH_EXIT(et); 1723744bfb21SJohn Baldwin 1724744bfb21SJohn Baldwin wg_timers_event_data_received(peer); 1725744bfb21SJohn Baldwin 1726744bfb21SJohn Baldwin done: 1727744bfb21SJohn Baldwin if (noise_keep_key_fresh_recv(peer->p_remote)) 1728744bfb21SJohn Baldwin wg_timers_event_want_initiation(peer); 1729744bfb21SJohn Baldwin wg_packet_free(pkt); 1730744bfb21SJohn Baldwin continue; 1731744bfb21SJohn Baldwin error: 1732744bfb21SJohn Baldwin if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 1733744bfb21SJohn Baldwin wg_packet_free(pkt); 1734744bfb21SJohn Baldwin } 1735744bfb21SJohn Baldwin } 1736744bfb21SJohn Baldwin 1737744bfb21SJohn Baldwin static struct wg_packet * 1738744bfb21SJohn Baldwin wg_packet_alloc(struct mbuf *m) 1739744bfb21SJohn Baldwin { 1740744bfb21SJohn Baldwin struct wg_packet *pkt; 1741744bfb21SJohn Baldwin 1742744bfb21SJohn Baldwin if ((pkt = uma_zalloc(wg_packet_zone, M_NOWAIT | M_ZERO)) == NULL) 1743744bfb21SJohn Baldwin return (NULL); 1744744bfb21SJohn Baldwin pkt->p_mbuf = m; 1745744bfb21SJohn Baldwin return (pkt); 1746744bfb21SJohn Baldwin } 1747744bfb21SJohn Baldwin 1748744bfb21SJohn Baldwin static void 1749744bfb21SJohn Baldwin wg_packet_free(struct wg_packet *pkt) 1750744bfb21SJohn Baldwin { 1751744bfb21SJohn Baldwin if (pkt->p_keypair != NULL) 1752744bfb21SJohn Baldwin noise_keypair_put(pkt->p_keypair); 1753744bfb21SJohn Baldwin if (pkt->p_mbuf != NULL) 1754744bfb21SJohn Baldwin m_freem(pkt->p_mbuf); 1755744bfb21SJohn Baldwin uma_zfree(wg_packet_zone, pkt); 1756744bfb21SJohn Baldwin } 1757744bfb21SJohn Baldwin 1758744bfb21SJohn Baldwin static void 1759744bfb21SJohn Baldwin wg_queue_init(struct wg_queue *queue, const char *name) 1760744bfb21SJohn Baldwin { 1761744bfb21SJohn Baldwin mtx_init(&queue->q_mtx, name, NULL, MTX_DEF); 1762744bfb21SJohn Baldwin STAILQ_INIT(&queue->q_queue); 1763744bfb21SJohn Baldwin queue->q_len = 0; 1764744bfb21SJohn Baldwin } 1765744bfb21SJohn Baldwin 1766744bfb21SJohn Baldwin static void 1767744bfb21SJohn Baldwin wg_queue_deinit(struct wg_queue *queue) 1768744bfb21SJohn Baldwin { 1769744bfb21SJohn Baldwin wg_queue_purge(queue); 1770744bfb21SJohn Baldwin mtx_destroy(&queue->q_mtx); 1771744bfb21SJohn Baldwin } 1772744bfb21SJohn Baldwin 1773744bfb21SJohn Baldwin static size_t 1774744bfb21SJohn Baldwin wg_queue_len(struct wg_queue *queue) 1775744bfb21SJohn Baldwin { 1776744bfb21SJohn Baldwin return (queue->q_len); 1777744bfb21SJohn Baldwin } 1778744bfb21SJohn Baldwin 1779744bfb21SJohn Baldwin static int 1780744bfb21SJohn Baldwin wg_queue_enqueue_handshake(struct wg_queue *hs, struct wg_packet *pkt) 1781744bfb21SJohn Baldwin { 1782744bfb21SJohn Baldwin int ret = 0; 1783744bfb21SJohn Baldwin mtx_lock(&hs->q_mtx); 1784744bfb21SJohn Baldwin if (hs->q_len < MAX_QUEUED_HANDSHAKES) { 1785744bfb21SJohn Baldwin STAILQ_INSERT_TAIL(&hs->q_queue, pkt, p_parallel); 1786744bfb21SJohn Baldwin hs->q_len++; 1787744bfb21SJohn Baldwin } else { 1788744bfb21SJohn Baldwin ret = ENOBUFS; 1789744bfb21SJohn Baldwin } 1790744bfb21SJohn Baldwin mtx_unlock(&hs->q_mtx); 1791744bfb21SJohn Baldwin if (ret != 0) 1792744bfb21SJohn Baldwin wg_packet_free(pkt); 1793744bfb21SJohn Baldwin return (ret); 1794744bfb21SJohn Baldwin } 1795744bfb21SJohn Baldwin 1796744bfb21SJohn Baldwin static struct wg_packet * 1797744bfb21SJohn Baldwin wg_queue_dequeue_handshake(struct wg_queue *hs) 1798744bfb21SJohn Baldwin { 1799744bfb21SJohn Baldwin struct wg_packet *pkt; 1800744bfb21SJohn Baldwin mtx_lock(&hs->q_mtx); 1801744bfb21SJohn Baldwin if ((pkt = STAILQ_FIRST(&hs->q_queue)) != NULL) { 1802744bfb21SJohn Baldwin STAILQ_REMOVE_HEAD(&hs->q_queue, p_parallel); 1803744bfb21SJohn Baldwin hs->q_len--; 1804744bfb21SJohn Baldwin } 1805744bfb21SJohn Baldwin mtx_unlock(&hs->q_mtx); 1806744bfb21SJohn Baldwin return (pkt); 1807744bfb21SJohn Baldwin } 1808744bfb21SJohn Baldwin 1809744bfb21SJohn Baldwin static void 1810744bfb21SJohn Baldwin wg_queue_push_staged(struct wg_queue *staged, struct wg_packet *pkt) 1811744bfb21SJohn Baldwin { 1812744bfb21SJohn Baldwin struct wg_packet *old = NULL; 1813744bfb21SJohn Baldwin 1814744bfb21SJohn Baldwin mtx_lock(&staged->q_mtx); 1815744bfb21SJohn Baldwin if (staged->q_len >= MAX_STAGED_PKT) { 1816744bfb21SJohn Baldwin old = STAILQ_FIRST(&staged->q_queue); 1817744bfb21SJohn Baldwin STAILQ_REMOVE_HEAD(&staged->q_queue, p_parallel); 1818744bfb21SJohn Baldwin staged->q_len--; 1819744bfb21SJohn Baldwin } 1820744bfb21SJohn Baldwin STAILQ_INSERT_TAIL(&staged->q_queue, pkt, p_parallel); 1821744bfb21SJohn Baldwin staged->q_len++; 1822744bfb21SJohn Baldwin mtx_unlock(&staged->q_mtx); 1823744bfb21SJohn Baldwin 1824744bfb21SJohn Baldwin if (old != NULL) 1825744bfb21SJohn Baldwin wg_packet_free(old); 1826744bfb21SJohn Baldwin } 1827744bfb21SJohn Baldwin 1828744bfb21SJohn Baldwin static void 1829744bfb21SJohn Baldwin wg_queue_enlist_staged(struct wg_queue *staged, struct wg_packet_list *list) 1830744bfb21SJohn Baldwin { 1831744bfb21SJohn Baldwin struct wg_packet *pkt, *tpkt; 1832744bfb21SJohn Baldwin STAILQ_FOREACH_SAFE(pkt, list, p_parallel, tpkt) 1833744bfb21SJohn Baldwin wg_queue_push_staged(staged, pkt); 1834744bfb21SJohn Baldwin } 1835744bfb21SJohn Baldwin 1836744bfb21SJohn Baldwin static void 1837744bfb21SJohn Baldwin wg_queue_delist_staged(struct wg_queue *staged, struct wg_packet_list *list) 1838744bfb21SJohn Baldwin { 1839744bfb21SJohn Baldwin STAILQ_INIT(list); 1840744bfb21SJohn Baldwin mtx_lock(&staged->q_mtx); 1841744bfb21SJohn Baldwin STAILQ_CONCAT(list, &staged->q_queue); 1842744bfb21SJohn Baldwin staged->q_len = 0; 1843744bfb21SJohn Baldwin mtx_unlock(&staged->q_mtx); 1844744bfb21SJohn Baldwin } 1845744bfb21SJohn Baldwin 1846744bfb21SJohn Baldwin static void 1847744bfb21SJohn Baldwin wg_queue_purge(struct wg_queue *staged) 1848744bfb21SJohn Baldwin { 1849744bfb21SJohn Baldwin struct wg_packet_list list; 1850744bfb21SJohn Baldwin struct wg_packet *pkt, *tpkt; 1851744bfb21SJohn Baldwin wg_queue_delist_staged(staged, &list); 1852744bfb21SJohn Baldwin STAILQ_FOREACH_SAFE(pkt, &list, p_parallel, tpkt) 1853744bfb21SJohn Baldwin wg_packet_free(pkt); 1854744bfb21SJohn Baldwin } 1855744bfb21SJohn Baldwin 1856744bfb21SJohn Baldwin static int 1857744bfb21SJohn Baldwin wg_queue_both(struct wg_queue *parallel, struct wg_queue *serial, struct wg_packet *pkt) 1858744bfb21SJohn Baldwin { 1859744bfb21SJohn Baldwin pkt->p_state = WG_PACKET_UNCRYPTED; 1860744bfb21SJohn Baldwin 1861744bfb21SJohn Baldwin mtx_lock(&serial->q_mtx); 1862744bfb21SJohn Baldwin if (serial->q_len < MAX_QUEUED_PKT) { 1863744bfb21SJohn Baldwin serial->q_len++; 1864744bfb21SJohn Baldwin STAILQ_INSERT_TAIL(&serial->q_queue, pkt, p_serial); 1865744bfb21SJohn Baldwin } else { 1866744bfb21SJohn Baldwin mtx_unlock(&serial->q_mtx); 1867744bfb21SJohn Baldwin wg_packet_free(pkt); 1868744bfb21SJohn Baldwin return (ENOBUFS); 1869744bfb21SJohn Baldwin } 1870744bfb21SJohn Baldwin mtx_unlock(&serial->q_mtx); 1871744bfb21SJohn Baldwin 1872744bfb21SJohn Baldwin mtx_lock(¶llel->q_mtx); 1873744bfb21SJohn Baldwin if (parallel->q_len < MAX_QUEUED_PKT) { 1874744bfb21SJohn Baldwin parallel->q_len++; 1875744bfb21SJohn Baldwin STAILQ_INSERT_TAIL(¶llel->q_queue, pkt, p_parallel); 1876744bfb21SJohn Baldwin } else { 1877744bfb21SJohn Baldwin mtx_unlock(¶llel->q_mtx); 1878744bfb21SJohn Baldwin pkt->p_state = WG_PACKET_DEAD; 1879744bfb21SJohn Baldwin return (ENOBUFS); 1880744bfb21SJohn Baldwin } 1881744bfb21SJohn Baldwin mtx_unlock(¶llel->q_mtx); 1882744bfb21SJohn Baldwin 1883744bfb21SJohn Baldwin return (0); 1884744bfb21SJohn Baldwin } 1885744bfb21SJohn Baldwin 1886744bfb21SJohn Baldwin static struct wg_packet * 1887744bfb21SJohn Baldwin wg_queue_dequeue_serial(struct wg_queue *serial) 1888744bfb21SJohn Baldwin { 1889744bfb21SJohn Baldwin struct wg_packet *pkt = NULL; 1890744bfb21SJohn Baldwin mtx_lock(&serial->q_mtx); 1891744bfb21SJohn Baldwin if (serial->q_len > 0 && STAILQ_FIRST(&serial->q_queue)->p_state != WG_PACKET_UNCRYPTED) { 1892744bfb21SJohn Baldwin serial->q_len--; 1893744bfb21SJohn Baldwin pkt = STAILQ_FIRST(&serial->q_queue); 1894744bfb21SJohn Baldwin STAILQ_REMOVE_HEAD(&serial->q_queue, p_serial); 1895744bfb21SJohn Baldwin } 1896744bfb21SJohn Baldwin mtx_unlock(&serial->q_mtx); 1897744bfb21SJohn Baldwin return (pkt); 1898744bfb21SJohn Baldwin } 1899744bfb21SJohn Baldwin 1900744bfb21SJohn Baldwin static struct wg_packet * 1901744bfb21SJohn Baldwin wg_queue_dequeue_parallel(struct wg_queue *parallel) 1902744bfb21SJohn Baldwin { 1903744bfb21SJohn Baldwin struct wg_packet *pkt = NULL; 1904744bfb21SJohn Baldwin mtx_lock(¶llel->q_mtx); 1905744bfb21SJohn Baldwin if (parallel->q_len > 0) { 1906744bfb21SJohn Baldwin parallel->q_len--; 1907744bfb21SJohn Baldwin pkt = STAILQ_FIRST(¶llel->q_queue); 1908744bfb21SJohn Baldwin STAILQ_REMOVE_HEAD(¶llel->q_queue, p_parallel); 1909744bfb21SJohn Baldwin } 1910744bfb21SJohn Baldwin mtx_unlock(¶llel->q_mtx); 1911744bfb21SJohn Baldwin return (pkt); 1912744bfb21SJohn Baldwin } 1913744bfb21SJohn Baldwin 1914744bfb21SJohn Baldwin static bool 1915744bfb21SJohn Baldwin wg_input(struct mbuf *m, int offset, struct inpcb *inpcb, 1916744bfb21SJohn Baldwin const struct sockaddr *sa, void *_sc) 1917744bfb21SJohn Baldwin { 1918744bfb21SJohn Baldwin #ifdef INET 1919744bfb21SJohn Baldwin const struct sockaddr_in *sin; 1920744bfb21SJohn Baldwin #endif 1921744bfb21SJohn Baldwin #ifdef INET6 1922744bfb21SJohn Baldwin const struct sockaddr_in6 *sin6; 1923744bfb21SJohn Baldwin #endif 1924744bfb21SJohn Baldwin struct noise_remote *remote; 1925744bfb21SJohn Baldwin struct wg_pkt_data *data; 1926744bfb21SJohn Baldwin struct wg_packet *pkt; 1927744bfb21SJohn Baldwin struct wg_peer *peer; 1928744bfb21SJohn Baldwin struct wg_softc *sc = _sc; 1929744bfb21SJohn Baldwin struct mbuf *defragged; 1930744bfb21SJohn Baldwin 1931744bfb21SJohn Baldwin defragged = m_defrag(m, M_NOWAIT); 1932744bfb21SJohn Baldwin if (defragged) 1933744bfb21SJohn Baldwin m = defragged; 1934744bfb21SJohn Baldwin m = m_unshare(m, M_NOWAIT); 1935744bfb21SJohn Baldwin if (!m) { 1936744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); 1937744bfb21SJohn Baldwin return true; 1938744bfb21SJohn Baldwin } 1939744bfb21SJohn Baldwin 1940744bfb21SJohn Baldwin /* Caller provided us with `sa`, no need for this header. */ 1941744bfb21SJohn Baldwin m_adj(m, offset + sizeof(struct udphdr)); 1942744bfb21SJohn Baldwin 1943744bfb21SJohn Baldwin /* Pullup enough to read packet type */ 1944744bfb21SJohn Baldwin if ((m = m_pullup(m, sizeof(uint32_t))) == NULL) { 1945744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); 1946744bfb21SJohn Baldwin return true; 1947744bfb21SJohn Baldwin } 1948744bfb21SJohn Baldwin 1949744bfb21SJohn Baldwin if ((pkt = wg_packet_alloc(m)) == NULL) { 1950744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); 1951744bfb21SJohn Baldwin m_freem(m); 1952744bfb21SJohn Baldwin return true; 1953744bfb21SJohn Baldwin } 1954744bfb21SJohn Baldwin 1955744bfb21SJohn Baldwin /* Save send/recv address and port for later. */ 1956744bfb21SJohn Baldwin switch (sa->sa_family) { 1957744bfb21SJohn Baldwin #ifdef INET 1958744bfb21SJohn Baldwin case AF_INET: 1959744bfb21SJohn Baldwin sin = (const struct sockaddr_in *)sa; 1960744bfb21SJohn Baldwin pkt->p_endpoint.e_remote.r_sin = sin[0]; 1961744bfb21SJohn Baldwin pkt->p_endpoint.e_local.l_in = sin[1].sin_addr; 1962744bfb21SJohn Baldwin break; 1963744bfb21SJohn Baldwin #endif 1964744bfb21SJohn Baldwin #ifdef INET6 1965744bfb21SJohn Baldwin case AF_INET6: 1966744bfb21SJohn Baldwin sin6 = (const struct sockaddr_in6 *)sa; 1967744bfb21SJohn Baldwin pkt->p_endpoint.e_remote.r_sin6 = sin6[0]; 1968744bfb21SJohn Baldwin pkt->p_endpoint.e_local.l_in6 = sin6[1].sin6_addr; 1969744bfb21SJohn Baldwin break; 1970744bfb21SJohn Baldwin #endif 1971744bfb21SJohn Baldwin default: 1972744bfb21SJohn Baldwin goto error; 1973744bfb21SJohn Baldwin } 1974744bfb21SJohn Baldwin 1975744bfb21SJohn Baldwin if ((m->m_pkthdr.len == sizeof(struct wg_pkt_initiation) && 1976744bfb21SJohn Baldwin *mtod(m, uint32_t *) == WG_PKT_INITIATION) || 1977744bfb21SJohn Baldwin (m->m_pkthdr.len == sizeof(struct wg_pkt_response) && 1978744bfb21SJohn Baldwin *mtod(m, uint32_t *) == WG_PKT_RESPONSE) || 1979744bfb21SJohn Baldwin (m->m_pkthdr.len == sizeof(struct wg_pkt_cookie) && 1980744bfb21SJohn Baldwin *mtod(m, uint32_t *) == WG_PKT_COOKIE)) { 1981744bfb21SJohn Baldwin 1982744bfb21SJohn Baldwin if (wg_queue_enqueue_handshake(&sc->sc_handshake_queue, pkt) != 0) { 1983744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); 1984744bfb21SJohn Baldwin DPRINTF(sc, "Dropping handshake packet\n"); 1985744bfb21SJohn Baldwin } 1986744bfb21SJohn Baldwin GROUPTASK_ENQUEUE(&sc->sc_handshake); 1987744bfb21SJohn Baldwin } else if (m->m_pkthdr.len >= sizeof(struct wg_pkt_data) + 1988744bfb21SJohn Baldwin NOISE_AUTHTAG_LEN && *mtod(m, uint32_t *) == WG_PKT_DATA) { 1989744bfb21SJohn Baldwin 1990744bfb21SJohn Baldwin /* Pullup whole header to read r_idx below. */ 1991744bfb21SJohn Baldwin if ((pkt->p_mbuf = m_pullup(m, sizeof(struct wg_pkt_data))) == NULL) 1992744bfb21SJohn Baldwin goto error; 1993744bfb21SJohn Baldwin 1994744bfb21SJohn Baldwin data = mtod(pkt->p_mbuf, struct wg_pkt_data *); 1995744bfb21SJohn Baldwin if ((pkt->p_keypair = noise_keypair_lookup(sc->sc_local, data->r_idx)) == NULL) 1996744bfb21SJohn Baldwin goto error; 1997744bfb21SJohn Baldwin 1998744bfb21SJohn Baldwin remote = noise_keypair_remote(pkt->p_keypair); 1999744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 2000744bfb21SJohn Baldwin if (wg_queue_both(&sc->sc_decrypt_parallel, &peer->p_decrypt_serial, pkt) != 0) 2001744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IQDROPS, 1); 2002744bfb21SJohn Baldwin wg_decrypt_dispatch(sc); 2003744bfb21SJohn Baldwin noise_remote_put(remote); 2004744bfb21SJohn Baldwin } else { 2005744bfb21SJohn Baldwin goto error; 2006744bfb21SJohn Baldwin } 2007744bfb21SJohn Baldwin return true; 2008744bfb21SJohn Baldwin error: 2009744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1); 2010744bfb21SJohn Baldwin wg_packet_free(pkt); 2011744bfb21SJohn Baldwin return true; 2012744bfb21SJohn Baldwin } 2013744bfb21SJohn Baldwin 2014744bfb21SJohn Baldwin static void 2015744bfb21SJohn Baldwin wg_peer_send_staged(struct wg_peer *peer) 2016744bfb21SJohn Baldwin { 2017744bfb21SJohn Baldwin struct wg_packet_list list; 2018744bfb21SJohn Baldwin struct noise_keypair *keypair; 2019744bfb21SJohn Baldwin struct wg_packet *pkt, *tpkt; 2020744bfb21SJohn Baldwin struct wg_softc *sc = peer->p_sc; 2021744bfb21SJohn Baldwin 2022744bfb21SJohn Baldwin wg_queue_delist_staged(&peer->p_stage_queue, &list); 2023744bfb21SJohn Baldwin 2024744bfb21SJohn Baldwin if (STAILQ_EMPTY(&list)) 2025744bfb21SJohn Baldwin return; 2026744bfb21SJohn Baldwin 2027744bfb21SJohn Baldwin if ((keypair = noise_keypair_current(peer->p_remote)) == NULL) 2028744bfb21SJohn Baldwin goto error; 2029744bfb21SJohn Baldwin 2030744bfb21SJohn Baldwin STAILQ_FOREACH(pkt, &list, p_parallel) { 2031744bfb21SJohn Baldwin if (noise_keypair_nonce_next(keypair, &pkt->p_nonce) != 0) 2032744bfb21SJohn Baldwin goto error_keypair; 2033744bfb21SJohn Baldwin } 2034744bfb21SJohn Baldwin STAILQ_FOREACH_SAFE(pkt, &list, p_parallel, tpkt) { 2035744bfb21SJohn Baldwin pkt->p_keypair = noise_keypair_ref(keypair); 2036744bfb21SJohn Baldwin if (wg_queue_both(&sc->sc_encrypt_parallel, &peer->p_encrypt_serial, pkt) != 0) 2037744bfb21SJohn Baldwin if_inc_counter(sc->sc_ifp, IFCOUNTER_OQDROPS, 1); 2038744bfb21SJohn Baldwin } 2039744bfb21SJohn Baldwin wg_encrypt_dispatch(sc); 2040744bfb21SJohn Baldwin noise_keypair_put(keypair); 2041744bfb21SJohn Baldwin return; 2042744bfb21SJohn Baldwin 2043744bfb21SJohn Baldwin error_keypair: 2044744bfb21SJohn Baldwin noise_keypair_put(keypair); 2045744bfb21SJohn Baldwin error: 2046744bfb21SJohn Baldwin wg_queue_enlist_staged(&peer->p_stage_queue, &list); 2047744bfb21SJohn Baldwin wg_timers_event_want_initiation(peer); 2048744bfb21SJohn Baldwin } 2049744bfb21SJohn Baldwin 2050744bfb21SJohn Baldwin static inline void 2051744bfb21SJohn Baldwin xmit_err(struct ifnet *ifp, struct mbuf *m, struct wg_packet *pkt, sa_family_t af) 2052744bfb21SJohn Baldwin { 2053744bfb21SJohn Baldwin if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 2054744bfb21SJohn Baldwin switch (af) { 2055744bfb21SJohn Baldwin #ifdef INET 2056744bfb21SJohn Baldwin case AF_INET: 2057744bfb21SJohn Baldwin icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); 2058744bfb21SJohn Baldwin if (pkt) 2059744bfb21SJohn Baldwin pkt->p_mbuf = NULL; 2060744bfb21SJohn Baldwin m = NULL; 2061744bfb21SJohn Baldwin break; 2062744bfb21SJohn Baldwin #endif 2063744bfb21SJohn Baldwin #ifdef INET6 2064744bfb21SJohn Baldwin case AF_INET6: 2065744bfb21SJohn Baldwin icmp6_error(m, ICMP6_DST_UNREACH, 0, 0); 2066744bfb21SJohn Baldwin if (pkt) 2067744bfb21SJohn Baldwin pkt->p_mbuf = NULL; 2068744bfb21SJohn Baldwin m = NULL; 2069744bfb21SJohn Baldwin break; 2070744bfb21SJohn Baldwin #endif 2071744bfb21SJohn Baldwin } 2072744bfb21SJohn Baldwin if (pkt) 2073744bfb21SJohn Baldwin wg_packet_free(pkt); 2074744bfb21SJohn Baldwin else if (m) 2075744bfb21SJohn Baldwin m_freem(m); 2076744bfb21SJohn Baldwin } 2077744bfb21SJohn Baldwin 2078744bfb21SJohn Baldwin static int 2079744bfb21SJohn Baldwin wg_xmit(struct ifnet *ifp, struct mbuf *m, sa_family_t af, uint32_t mtu) 2080744bfb21SJohn Baldwin { 2081744bfb21SJohn Baldwin struct wg_packet *pkt = NULL; 2082744bfb21SJohn Baldwin struct wg_softc *sc = ifp->if_softc; 2083744bfb21SJohn Baldwin struct wg_peer *peer; 2084744bfb21SJohn Baldwin int rc = 0; 2085744bfb21SJohn Baldwin sa_family_t peer_af; 2086744bfb21SJohn Baldwin 2087744bfb21SJohn Baldwin /* Work around lifetime issue in the ipv6 mld code. */ 2088744bfb21SJohn Baldwin if (__predict_false((ifp->if_flags & IFF_DYING) || !sc)) { 2089744bfb21SJohn Baldwin rc = ENXIO; 2090744bfb21SJohn Baldwin goto err_xmit; 2091744bfb21SJohn Baldwin } 2092744bfb21SJohn Baldwin 2093744bfb21SJohn Baldwin if ((pkt = wg_packet_alloc(m)) == NULL) { 2094744bfb21SJohn Baldwin rc = ENOBUFS; 2095744bfb21SJohn Baldwin goto err_xmit; 2096744bfb21SJohn Baldwin } 2097744bfb21SJohn Baldwin pkt->p_mtu = mtu; 2098744bfb21SJohn Baldwin pkt->p_af = af; 2099744bfb21SJohn Baldwin 2100744bfb21SJohn Baldwin if (af == AF_INET) { 2101744bfb21SJohn Baldwin peer = wg_aip_lookup(sc, AF_INET, &mtod(m, struct ip *)->ip_dst); 2102744bfb21SJohn Baldwin } else if (af == AF_INET6) { 2103744bfb21SJohn Baldwin peer = wg_aip_lookup(sc, AF_INET6, &mtod(m, struct ip6_hdr *)->ip6_dst); 2104744bfb21SJohn Baldwin } else { 2105744bfb21SJohn Baldwin rc = EAFNOSUPPORT; 2106744bfb21SJohn Baldwin goto err_xmit; 2107744bfb21SJohn Baldwin } 2108744bfb21SJohn Baldwin 2109744bfb21SJohn Baldwin BPF_MTAP2_AF(ifp, m, pkt->p_af); 2110744bfb21SJohn Baldwin 2111744bfb21SJohn Baldwin if (__predict_false(peer == NULL)) { 2112744bfb21SJohn Baldwin rc = ENOKEY; 2113744bfb21SJohn Baldwin goto err_xmit; 2114744bfb21SJohn Baldwin } 2115744bfb21SJohn Baldwin 2116744bfb21SJohn Baldwin if (__predict_false(if_tunnel_check_nesting(ifp, m, MTAG_WGLOOP, MAX_LOOPS))) { 2117744bfb21SJohn Baldwin DPRINTF(sc, "Packet looped"); 2118744bfb21SJohn Baldwin rc = ELOOP; 2119744bfb21SJohn Baldwin goto err_peer; 2120744bfb21SJohn Baldwin } 2121744bfb21SJohn Baldwin 2122744bfb21SJohn Baldwin peer_af = peer->p_endpoint.e_remote.r_sa.sa_family; 2123744bfb21SJohn Baldwin if (__predict_false(peer_af != AF_INET && peer_af != AF_INET6)) { 2124744bfb21SJohn Baldwin DPRINTF(sc, "No valid endpoint has been configured or " 2125744bfb21SJohn Baldwin "discovered for peer %" PRIu64 "\n", peer->p_id); 2126744bfb21SJohn Baldwin rc = EHOSTUNREACH; 2127744bfb21SJohn Baldwin goto err_peer; 2128744bfb21SJohn Baldwin } 2129744bfb21SJohn Baldwin 2130744bfb21SJohn Baldwin wg_queue_push_staged(&peer->p_stage_queue, pkt); 2131744bfb21SJohn Baldwin wg_peer_send_staged(peer); 2132744bfb21SJohn Baldwin noise_remote_put(peer->p_remote); 2133744bfb21SJohn Baldwin return (0); 2134744bfb21SJohn Baldwin 2135744bfb21SJohn Baldwin err_peer: 2136744bfb21SJohn Baldwin noise_remote_put(peer->p_remote); 2137744bfb21SJohn Baldwin err_xmit: 2138744bfb21SJohn Baldwin xmit_err(ifp, m, pkt, af); 2139744bfb21SJohn Baldwin return (rc); 2140744bfb21SJohn Baldwin } 2141744bfb21SJohn Baldwin 2142744bfb21SJohn Baldwin static inline int 2143744bfb21SJohn Baldwin determine_af_and_pullup(struct mbuf **m, sa_family_t *af) 2144744bfb21SJohn Baldwin { 2145744bfb21SJohn Baldwin u_char ipv; 2146744bfb21SJohn Baldwin if ((*m)->m_pkthdr.len >= sizeof(struct ip6_hdr)) 2147744bfb21SJohn Baldwin *m = m_pullup(*m, sizeof(struct ip6_hdr)); 2148744bfb21SJohn Baldwin else if ((*m)->m_pkthdr.len >= sizeof(struct ip)) 2149744bfb21SJohn Baldwin *m = m_pullup(*m, sizeof(struct ip)); 2150744bfb21SJohn Baldwin else 2151744bfb21SJohn Baldwin return (EAFNOSUPPORT); 2152744bfb21SJohn Baldwin if (*m == NULL) 2153744bfb21SJohn Baldwin return (ENOBUFS); 2154744bfb21SJohn Baldwin ipv = mtod(*m, struct ip *)->ip_v; 2155744bfb21SJohn Baldwin if (ipv == 4) 2156744bfb21SJohn Baldwin *af = AF_INET; 2157744bfb21SJohn Baldwin else if (ipv == 6 && (*m)->m_pkthdr.len >= sizeof(struct ip6_hdr)) 2158744bfb21SJohn Baldwin *af = AF_INET6; 2159744bfb21SJohn Baldwin else 2160744bfb21SJohn Baldwin return (EAFNOSUPPORT); 2161744bfb21SJohn Baldwin return (0); 2162744bfb21SJohn Baldwin } 2163744bfb21SJohn Baldwin 2164744bfb21SJohn Baldwin static int 2165744bfb21SJohn Baldwin wg_transmit(struct ifnet *ifp, struct mbuf *m) 2166744bfb21SJohn Baldwin { 2167744bfb21SJohn Baldwin sa_family_t af; 2168744bfb21SJohn Baldwin int ret; 2169744bfb21SJohn Baldwin struct mbuf *defragged; 2170744bfb21SJohn Baldwin 2171744bfb21SJohn Baldwin defragged = m_defrag(m, M_NOWAIT); 2172744bfb21SJohn Baldwin if (defragged) 2173744bfb21SJohn Baldwin m = defragged; 2174744bfb21SJohn Baldwin m = m_unshare(m, M_NOWAIT); 2175744bfb21SJohn Baldwin if (!m) { 2176744bfb21SJohn Baldwin xmit_err(ifp, m, NULL, AF_UNSPEC); 2177744bfb21SJohn Baldwin return (ENOBUFS); 2178744bfb21SJohn Baldwin } 2179744bfb21SJohn Baldwin 2180744bfb21SJohn Baldwin ret = determine_af_and_pullup(&m, &af); 2181744bfb21SJohn Baldwin if (ret) { 2182744bfb21SJohn Baldwin xmit_err(ifp, m, NULL, AF_UNSPEC); 2183744bfb21SJohn Baldwin return (ret); 2184744bfb21SJohn Baldwin } 2185744bfb21SJohn Baldwin return (wg_xmit(ifp, m, af, ifp->if_mtu)); 2186744bfb21SJohn Baldwin } 2187744bfb21SJohn Baldwin 2188744bfb21SJohn Baldwin static int 2189744bfb21SJohn Baldwin wg_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro) 2190744bfb21SJohn Baldwin { 2191744bfb21SJohn Baldwin sa_family_t parsed_af; 2192744bfb21SJohn Baldwin uint32_t af, mtu; 2193744bfb21SJohn Baldwin int ret; 2194744bfb21SJohn Baldwin struct mbuf *defragged; 2195744bfb21SJohn Baldwin 2196744bfb21SJohn Baldwin if (dst->sa_family == AF_UNSPEC) 2197744bfb21SJohn Baldwin memcpy(&af, dst->sa_data, sizeof(af)); 2198744bfb21SJohn Baldwin else 2199744bfb21SJohn Baldwin af = dst->sa_family; 2200744bfb21SJohn Baldwin if (af == AF_UNSPEC) { 2201744bfb21SJohn Baldwin xmit_err(ifp, m, NULL, af); 2202744bfb21SJohn Baldwin return (EAFNOSUPPORT); 2203744bfb21SJohn Baldwin } 2204744bfb21SJohn Baldwin 2205744bfb21SJohn Baldwin defragged = m_defrag(m, M_NOWAIT); 2206744bfb21SJohn Baldwin if (defragged) 2207744bfb21SJohn Baldwin m = defragged; 2208744bfb21SJohn Baldwin m = m_unshare(m, M_NOWAIT); 2209744bfb21SJohn Baldwin if (!m) { 2210744bfb21SJohn Baldwin xmit_err(ifp, m, NULL, AF_UNSPEC); 2211744bfb21SJohn Baldwin return (ENOBUFS); 2212744bfb21SJohn Baldwin } 2213744bfb21SJohn Baldwin 2214744bfb21SJohn Baldwin ret = determine_af_and_pullup(&m, &parsed_af); 2215744bfb21SJohn Baldwin if (ret) { 2216744bfb21SJohn Baldwin xmit_err(ifp, m, NULL, AF_UNSPEC); 2217744bfb21SJohn Baldwin return (ret); 2218744bfb21SJohn Baldwin } 2219744bfb21SJohn Baldwin if (parsed_af != af) { 2220744bfb21SJohn Baldwin xmit_err(ifp, m, NULL, AF_UNSPEC); 2221744bfb21SJohn Baldwin return (EAFNOSUPPORT); 2222744bfb21SJohn Baldwin } 2223744bfb21SJohn Baldwin mtu = (ro != NULL && ro->ro_mtu > 0) ? ro->ro_mtu : ifp->if_mtu; 2224744bfb21SJohn Baldwin return (wg_xmit(ifp, m, parsed_af, mtu)); 2225744bfb21SJohn Baldwin } 2226744bfb21SJohn Baldwin 2227744bfb21SJohn Baldwin static int 2228744bfb21SJohn Baldwin wg_peer_add(struct wg_softc *sc, const nvlist_t *nvl) 2229744bfb21SJohn Baldwin { 2230744bfb21SJohn Baldwin uint8_t public[WG_KEY_SIZE]; 2231744bfb21SJohn Baldwin const void *pub_key, *preshared_key = NULL; 2232744bfb21SJohn Baldwin const struct sockaddr *endpoint; 2233744bfb21SJohn Baldwin int err; 2234744bfb21SJohn Baldwin size_t size; 2235744bfb21SJohn Baldwin struct noise_remote *remote; 2236744bfb21SJohn Baldwin struct wg_peer *peer = NULL; 2237744bfb21SJohn Baldwin bool need_insert = false; 2238744bfb21SJohn Baldwin 2239744bfb21SJohn Baldwin sx_assert(&sc->sc_lock, SX_XLOCKED); 2240744bfb21SJohn Baldwin 2241744bfb21SJohn Baldwin if (!nvlist_exists_binary(nvl, "public-key")) { 2242744bfb21SJohn Baldwin return (EINVAL); 2243744bfb21SJohn Baldwin } 2244744bfb21SJohn Baldwin pub_key = nvlist_get_binary(nvl, "public-key", &size); 2245744bfb21SJohn Baldwin if (size != WG_KEY_SIZE) { 2246744bfb21SJohn Baldwin return (EINVAL); 2247744bfb21SJohn Baldwin } 2248744bfb21SJohn Baldwin if (noise_local_keys(sc->sc_local, public, NULL) == 0 && 2249744bfb21SJohn Baldwin bcmp(public, pub_key, WG_KEY_SIZE) == 0) { 2250744bfb21SJohn Baldwin return (0); // Silently ignored; not actually a failure. 2251744bfb21SJohn Baldwin } 2252744bfb21SJohn Baldwin if ((remote = noise_remote_lookup(sc->sc_local, pub_key)) != NULL) 2253744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 2254744bfb21SJohn Baldwin if (nvlist_exists_bool(nvl, "remove") && 2255744bfb21SJohn Baldwin nvlist_get_bool(nvl, "remove")) { 2256744bfb21SJohn Baldwin if (remote != NULL) { 2257744bfb21SJohn Baldwin wg_peer_destroy(peer); 2258744bfb21SJohn Baldwin noise_remote_put(remote); 2259744bfb21SJohn Baldwin } 2260744bfb21SJohn Baldwin return (0); 2261744bfb21SJohn Baldwin } 2262744bfb21SJohn Baldwin if (nvlist_exists_bool(nvl, "replace-allowedips") && 2263744bfb21SJohn Baldwin nvlist_get_bool(nvl, "replace-allowedips") && 2264744bfb21SJohn Baldwin peer != NULL) { 2265744bfb21SJohn Baldwin 2266744bfb21SJohn Baldwin wg_aip_remove_all(sc, peer); 2267744bfb21SJohn Baldwin } 2268744bfb21SJohn Baldwin if (peer == NULL) { 2269744bfb21SJohn Baldwin peer = wg_peer_alloc(sc, pub_key); 2270744bfb21SJohn Baldwin need_insert = true; 2271744bfb21SJohn Baldwin } 2272744bfb21SJohn Baldwin if (nvlist_exists_binary(nvl, "endpoint")) { 2273744bfb21SJohn Baldwin endpoint = nvlist_get_binary(nvl, "endpoint", &size); 2274744bfb21SJohn Baldwin if (size > sizeof(peer->p_endpoint.e_remote)) { 2275744bfb21SJohn Baldwin err = EINVAL; 2276744bfb21SJohn Baldwin goto out; 2277744bfb21SJohn Baldwin } 2278744bfb21SJohn Baldwin memcpy(&peer->p_endpoint.e_remote, endpoint, size); 2279744bfb21SJohn Baldwin } 2280744bfb21SJohn Baldwin if (nvlist_exists_binary(nvl, "preshared-key")) { 2281744bfb21SJohn Baldwin preshared_key = nvlist_get_binary(nvl, "preshared-key", &size); 2282744bfb21SJohn Baldwin if (size != WG_KEY_SIZE) { 2283744bfb21SJohn Baldwin err = EINVAL; 2284744bfb21SJohn Baldwin goto out; 2285744bfb21SJohn Baldwin } 2286744bfb21SJohn Baldwin noise_remote_set_psk(peer->p_remote, preshared_key); 2287744bfb21SJohn Baldwin } 2288744bfb21SJohn Baldwin if (nvlist_exists_number(nvl, "persistent-keepalive-interval")) { 2289744bfb21SJohn Baldwin uint64_t pki = nvlist_get_number(nvl, "persistent-keepalive-interval"); 2290744bfb21SJohn Baldwin if (pki > UINT16_MAX) { 2291744bfb21SJohn Baldwin err = EINVAL; 2292744bfb21SJohn Baldwin goto out; 2293744bfb21SJohn Baldwin } 2294744bfb21SJohn Baldwin wg_timers_set_persistent_keepalive(peer, pki); 2295744bfb21SJohn Baldwin } 2296744bfb21SJohn Baldwin if (nvlist_exists_nvlist_array(nvl, "allowed-ips")) { 2297744bfb21SJohn Baldwin const void *addr; 2298744bfb21SJohn Baldwin uint64_t cidr; 2299744bfb21SJohn Baldwin const nvlist_t * const * aipl; 2300744bfb21SJohn Baldwin size_t allowedip_count; 2301744bfb21SJohn Baldwin 2302744bfb21SJohn Baldwin aipl = nvlist_get_nvlist_array(nvl, "allowed-ips", &allowedip_count); 2303744bfb21SJohn Baldwin for (size_t idx = 0; idx < allowedip_count; idx++) { 2304744bfb21SJohn Baldwin if (!nvlist_exists_number(aipl[idx], "cidr")) 2305744bfb21SJohn Baldwin continue; 2306744bfb21SJohn Baldwin cidr = nvlist_get_number(aipl[idx], "cidr"); 2307744bfb21SJohn Baldwin if (nvlist_exists_binary(aipl[idx], "ipv4")) { 2308744bfb21SJohn Baldwin addr = nvlist_get_binary(aipl[idx], "ipv4", &size); 2309744bfb21SJohn Baldwin if (addr == NULL || cidr > 32 || size != sizeof(struct in_addr)) { 2310744bfb21SJohn Baldwin err = EINVAL; 2311744bfb21SJohn Baldwin goto out; 2312744bfb21SJohn Baldwin } 2313744bfb21SJohn Baldwin if ((err = wg_aip_add(sc, peer, AF_INET, addr, cidr)) != 0) 2314744bfb21SJohn Baldwin goto out; 2315744bfb21SJohn Baldwin } else if (nvlist_exists_binary(aipl[idx], "ipv6")) { 2316744bfb21SJohn Baldwin addr = nvlist_get_binary(aipl[idx], "ipv6", &size); 2317744bfb21SJohn Baldwin if (addr == NULL || cidr > 128 || size != sizeof(struct in6_addr)) { 2318744bfb21SJohn Baldwin err = EINVAL; 2319744bfb21SJohn Baldwin goto out; 2320744bfb21SJohn Baldwin } 2321744bfb21SJohn Baldwin if ((err = wg_aip_add(sc, peer, AF_INET6, addr, cidr)) != 0) 2322744bfb21SJohn Baldwin goto out; 2323744bfb21SJohn Baldwin } else { 2324744bfb21SJohn Baldwin continue; 2325744bfb21SJohn Baldwin } 2326744bfb21SJohn Baldwin } 2327744bfb21SJohn Baldwin } 2328744bfb21SJohn Baldwin if (need_insert) { 2329744bfb21SJohn Baldwin if ((err = noise_remote_enable(peer->p_remote)) != 0) 2330744bfb21SJohn Baldwin goto out; 2331744bfb21SJohn Baldwin TAILQ_INSERT_TAIL(&sc->sc_peers, peer, p_entry); 2332744bfb21SJohn Baldwin sc->sc_peers_num++; 2333744bfb21SJohn Baldwin if (sc->sc_ifp->if_link_state == LINK_STATE_UP) 2334744bfb21SJohn Baldwin wg_timers_enable(peer); 2335744bfb21SJohn Baldwin } 2336744bfb21SJohn Baldwin if (remote != NULL) 2337744bfb21SJohn Baldwin noise_remote_put(remote); 2338744bfb21SJohn Baldwin return (0); 2339744bfb21SJohn Baldwin out: 2340744bfb21SJohn Baldwin if (need_insert) /* If we fail, only destroy if it was new. */ 2341744bfb21SJohn Baldwin wg_peer_destroy(peer); 2342744bfb21SJohn Baldwin if (remote != NULL) 2343744bfb21SJohn Baldwin noise_remote_put(remote); 2344744bfb21SJohn Baldwin return (err); 2345744bfb21SJohn Baldwin } 2346744bfb21SJohn Baldwin 2347744bfb21SJohn Baldwin static int 2348744bfb21SJohn Baldwin wgc_set(struct wg_softc *sc, struct wg_data_io *wgd) 2349744bfb21SJohn Baldwin { 2350744bfb21SJohn Baldwin uint8_t public[WG_KEY_SIZE], private[WG_KEY_SIZE]; 2351744bfb21SJohn Baldwin struct ifnet *ifp; 2352744bfb21SJohn Baldwin void *nvlpacked; 2353744bfb21SJohn Baldwin nvlist_t *nvl; 2354744bfb21SJohn Baldwin ssize_t size; 2355744bfb21SJohn Baldwin int err; 2356744bfb21SJohn Baldwin 2357744bfb21SJohn Baldwin ifp = sc->sc_ifp; 2358744bfb21SJohn Baldwin if (wgd->wgd_size == 0 || wgd->wgd_data == NULL) 2359744bfb21SJohn Baldwin return (EFAULT); 2360744bfb21SJohn Baldwin 2361744bfb21SJohn Baldwin /* Can nvlists be streamed in? It's not nice to impose arbitrary limits like that but 2362744bfb21SJohn Baldwin * there needs to be _some_ limitation. */ 2363744bfb21SJohn Baldwin if (wgd->wgd_size >= UINT32_MAX / 2) 2364744bfb21SJohn Baldwin return (E2BIG); 2365744bfb21SJohn Baldwin 2366744bfb21SJohn Baldwin nvlpacked = malloc(wgd->wgd_size, M_TEMP, M_WAITOK | M_ZERO); 2367744bfb21SJohn Baldwin 2368744bfb21SJohn Baldwin err = copyin(wgd->wgd_data, nvlpacked, wgd->wgd_size); 2369744bfb21SJohn Baldwin if (err) 2370744bfb21SJohn Baldwin goto out; 2371744bfb21SJohn Baldwin nvl = nvlist_unpack(nvlpacked, wgd->wgd_size, 0); 2372744bfb21SJohn Baldwin if (nvl == NULL) { 2373744bfb21SJohn Baldwin err = EBADMSG; 2374744bfb21SJohn Baldwin goto out; 2375744bfb21SJohn Baldwin } 2376744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2377744bfb21SJohn Baldwin if (nvlist_exists_bool(nvl, "replace-peers") && 2378744bfb21SJohn Baldwin nvlist_get_bool(nvl, "replace-peers")) 2379744bfb21SJohn Baldwin wg_peer_destroy_all(sc); 2380744bfb21SJohn Baldwin if (nvlist_exists_number(nvl, "listen-port")) { 2381744bfb21SJohn Baldwin uint64_t new_port = nvlist_get_number(nvl, "listen-port"); 2382744bfb21SJohn Baldwin if (new_port > UINT16_MAX) { 2383744bfb21SJohn Baldwin err = EINVAL; 2384744bfb21SJohn Baldwin goto out_locked; 2385744bfb21SJohn Baldwin } 2386744bfb21SJohn Baldwin if (new_port != sc->sc_socket.so_port) { 2387744bfb21SJohn Baldwin if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 2388744bfb21SJohn Baldwin if ((err = wg_socket_init(sc, new_port)) != 0) 2389744bfb21SJohn Baldwin goto out_locked; 2390744bfb21SJohn Baldwin } else 2391744bfb21SJohn Baldwin sc->sc_socket.so_port = new_port; 2392744bfb21SJohn Baldwin } 2393744bfb21SJohn Baldwin } 2394744bfb21SJohn Baldwin if (nvlist_exists_binary(nvl, "private-key")) { 2395744bfb21SJohn Baldwin const void *key = nvlist_get_binary(nvl, "private-key", &size); 2396744bfb21SJohn Baldwin if (size != WG_KEY_SIZE) { 2397744bfb21SJohn Baldwin err = EINVAL; 2398744bfb21SJohn Baldwin goto out_locked; 2399744bfb21SJohn Baldwin } 2400744bfb21SJohn Baldwin 2401744bfb21SJohn Baldwin if (noise_local_keys(sc->sc_local, NULL, private) != 0 || 2402744bfb21SJohn Baldwin timingsafe_bcmp(private, key, WG_KEY_SIZE) != 0) { 2403744bfb21SJohn Baldwin struct wg_peer *peer; 2404744bfb21SJohn Baldwin 2405744bfb21SJohn Baldwin if (curve25519_generate_public(public, key)) { 2406744bfb21SJohn Baldwin /* Peer conflict: remove conflicting peer. */ 2407744bfb21SJohn Baldwin struct noise_remote *remote; 2408744bfb21SJohn Baldwin if ((remote = noise_remote_lookup(sc->sc_local, 2409744bfb21SJohn Baldwin public)) != NULL) { 2410744bfb21SJohn Baldwin peer = noise_remote_arg(remote); 2411744bfb21SJohn Baldwin wg_peer_destroy(peer); 2412744bfb21SJohn Baldwin noise_remote_put(remote); 2413744bfb21SJohn Baldwin } 2414744bfb21SJohn Baldwin } 2415744bfb21SJohn Baldwin 2416744bfb21SJohn Baldwin /* 2417744bfb21SJohn Baldwin * Set the private key and invalidate all existing 2418744bfb21SJohn Baldwin * handshakes. 2419744bfb21SJohn Baldwin */ 2420744bfb21SJohn Baldwin /* Note: we might be removing the private key. */ 2421744bfb21SJohn Baldwin noise_local_private(sc->sc_local, key); 2422744bfb21SJohn Baldwin if (noise_local_keys(sc->sc_local, NULL, NULL) == 0) 2423744bfb21SJohn Baldwin cookie_checker_update(&sc->sc_cookie, public); 2424744bfb21SJohn Baldwin else 2425744bfb21SJohn Baldwin cookie_checker_update(&sc->sc_cookie, NULL); 2426744bfb21SJohn Baldwin } 2427744bfb21SJohn Baldwin } 2428744bfb21SJohn Baldwin if (nvlist_exists_number(nvl, "user-cookie")) { 2429744bfb21SJohn Baldwin uint64_t user_cookie = nvlist_get_number(nvl, "user-cookie"); 2430744bfb21SJohn Baldwin if (user_cookie > UINT32_MAX) { 2431744bfb21SJohn Baldwin err = EINVAL; 2432744bfb21SJohn Baldwin goto out_locked; 2433744bfb21SJohn Baldwin } 2434744bfb21SJohn Baldwin err = wg_socket_set_cookie(sc, user_cookie); 2435744bfb21SJohn Baldwin if (err) 2436744bfb21SJohn Baldwin goto out_locked; 2437744bfb21SJohn Baldwin } 2438744bfb21SJohn Baldwin if (nvlist_exists_nvlist_array(nvl, "peers")) { 2439744bfb21SJohn Baldwin size_t peercount; 2440744bfb21SJohn Baldwin const nvlist_t * const*nvl_peers; 2441744bfb21SJohn Baldwin 2442744bfb21SJohn Baldwin nvl_peers = nvlist_get_nvlist_array(nvl, "peers", &peercount); 2443744bfb21SJohn Baldwin for (int i = 0; i < peercount; i++) { 2444744bfb21SJohn Baldwin err = wg_peer_add(sc, nvl_peers[i]); 2445744bfb21SJohn Baldwin if (err != 0) 2446744bfb21SJohn Baldwin goto out_locked; 2447744bfb21SJohn Baldwin } 2448744bfb21SJohn Baldwin } 2449744bfb21SJohn Baldwin 2450744bfb21SJohn Baldwin out_locked: 2451744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2452744bfb21SJohn Baldwin nvlist_destroy(nvl); 2453744bfb21SJohn Baldwin out: 2454dcf581bbSJohn Baldwin zfree(nvlpacked, M_TEMP); 2455744bfb21SJohn Baldwin return (err); 2456744bfb21SJohn Baldwin } 2457744bfb21SJohn Baldwin 2458744bfb21SJohn Baldwin static int 2459744bfb21SJohn Baldwin wgc_get(struct wg_softc *sc, struct wg_data_io *wgd) 2460744bfb21SJohn Baldwin { 2461744bfb21SJohn Baldwin uint8_t public_key[WG_KEY_SIZE] = { 0 }; 2462744bfb21SJohn Baldwin uint8_t private_key[WG_KEY_SIZE] = { 0 }; 2463744bfb21SJohn Baldwin uint8_t preshared_key[NOISE_SYMMETRIC_KEY_LEN] = { 0 }; 2464744bfb21SJohn Baldwin nvlist_t *nvl, *nvl_peer, *nvl_aip, **nvl_peers, **nvl_aips; 2465744bfb21SJohn Baldwin size_t size, peer_count, aip_count, i, j; 2466744bfb21SJohn Baldwin struct wg_timespec64 ts64; 2467744bfb21SJohn Baldwin struct wg_peer *peer; 2468744bfb21SJohn Baldwin struct wg_aip *aip; 2469744bfb21SJohn Baldwin void *packed; 2470744bfb21SJohn Baldwin int err = 0; 2471744bfb21SJohn Baldwin 2472744bfb21SJohn Baldwin nvl = nvlist_create(0); 2473744bfb21SJohn Baldwin if (!nvl) 2474744bfb21SJohn Baldwin return (ENOMEM); 2475744bfb21SJohn Baldwin 2476744bfb21SJohn Baldwin sx_slock(&sc->sc_lock); 2477744bfb21SJohn Baldwin 2478744bfb21SJohn Baldwin if (sc->sc_socket.so_port != 0) 2479744bfb21SJohn Baldwin nvlist_add_number(nvl, "listen-port", sc->sc_socket.so_port); 2480744bfb21SJohn Baldwin if (sc->sc_socket.so_user_cookie != 0) 2481744bfb21SJohn Baldwin nvlist_add_number(nvl, "user-cookie", sc->sc_socket.so_user_cookie); 2482744bfb21SJohn Baldwin if (noise_local_keys(sc->sc_local, public_key, private_key) == 0) { 2483744bfb21SJohn Baldwin nvlist_add_binary(nvl, "public-key", public_key, WG_KEY_SIZE); 2484744bfb21SJohn Baldwin if (wgc_privileged(sc)) 2485744bfb21SJohn Baldwin nvlist_add_binary(nvl, "private-key", private_key, WG_KEY_SIZE); 2486744bfb21SJohn Baldwin explicit_bzero(private_key, sizeof(private_key)); 2487744bfb21SJohn Baldwin } 2488744bfb21SJohn Baldwin peer_count = sc->sc_peers_num; 2489744bfb21SJohn Baldwin if (peer_count) { 2490744bfb21SJohn Baldwin nvl_peers = mallocarray(peer_count, sizeof(void *), M_NVLIST, M_WAITOK | M_ZERO); 2491744bfb21SJohn Baldwin i = 0; 2492744bfb21SJohn Baldwin TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) { 2493744bfb21SJohn Baldwin if (i >= peer_count) 2494744bfb21SJohn Baldwin panic("peers changed from under us"); 2495744bfb21SJohn Baldwin 2496744bfb21SJohn Baldwin nvl_peers[i++] = nvl_peer = nvlist_create(0); 2497744bfb21SJohn Baldwin if (!nvl_peer) { 2498744bfb21SJohn Baldwin err = ENOMEM; 2499744bfb21SJohn Baldwin goto err_peer; 2500744bfb21SJohn Baldwin } 2501744bfb21SJohn Baldwin 2502744bfb21SJohn Baldwin (void)noise_remote_keys(peer->p_remote, public_key, preshared_key); 2503744bfb21SJohn Baldwin nvlist_add_binary(nvl_peer, "public-key", public_key, sizeof(public_key)); 2504744bfb21SJohn Baldwin if (wgc_privileged(sc)) 2505744bfb21SJohn Baldwin nvlist_add_binary(nvl_peer, "preshared-key", preshared_key, sizeof(preshared_key)); 2506744bfb21SJohn Baldwin explicit_bzero(preshared_key, sizeof(preshared_key)); 2507744bfb21SJohn Baldwin if (peer->p_endpoint.e_remote.r_sa.sa_family == AF_INET) 2508744bfb21SJohn Baldwin nvlist_add_binary(nvl_peer, "endpoint", &peer->p_endpoint.e_remote, sizeof(struct sockaddr_in)); 2509744bfb21SJohn Baldwin else if (peer->p_endpoint.e_remote.r_sa.sa_family == AF_INET6) 2510744bfb21SJohn Baldwin nvlist_add_binary(nvl_peer, "endpoint", &peer->p_endpoint.e_remote, sizeof(struct sockaddr_in6)); 2511744bfb21SJohn Baldwin wg_timers_get_last_handshake(peer, &ts64); 2512744bfb21SJohn Baldwin nvlist_add_binary(nvl_peer, "last-handshake-time", &ts64, sizeof(ts64)); 2513744bfb21SJohn Baldwin nvlist_add_number(nvl_peer, "persistent-keepalive-interval", peer->p_persistent_keepalive_interval); 2514744bfb21SJohn Baldwin nvlist_add_number(nvl_peer, "rx-bytes", counter_u64_fetch(peer->p_rx_bytes)); 2515744bfb21SJohn Baldwin nvlist_add_number(nvl_peer, "tx-bytes", counter_u64_fetch(peer->p_tx_bytes)); 2516744bfb21SJohn Baldwin 2517744bfb21SJohn Baldwin aip_count = peer->p_aips_num; 2518744bfb21SJohn Baldwin if (aip_count) { 2519744bfb21SJohn Baldwin nvl_aips = mallocarray(aip_count, sizeof(void *), M_NVLIST, M_WAITOK | M_ZERO); 2520744bfb21SJohn Baldwin j = 0; 2521744bfb21SJohn Baldwin LIST_FOREACH(aip, &peer->p_aips, a_entry) { 2522744bfb21SJohn Baldwin if (j >= aip_count) 2523744bfb21SJohn Baldwin panic("aips changed from under us"); 2524744bfb21SJohn Baldwin 2525744bfb21SJohn Baldwin nvl_aips[j++] = nvl_aip = nvlist_create(0); 2526744bfb21SJohn Baldwin if (!nvl_aip) { 2527744bfb21SJohn Baldwin err = ENOMEM; 2528744bfb21SJohn Baldwin goto err_aip; 2529744bfb21SJohn Baldwin } 2530744bfb21SJohn Baldwin if (aip->a_af == AF_INET) { 2531744bfb21SJohn Baldwin nvlist_add_binary(nvl_aip, "ipv4", &aip->a_addr.in, sizeof(aip->a_addr.in)); 2532744bfb21SJohn Baldwin nvlist_add_number(nvl_aip, "cidr", bitcount32(aip->a_mask.ip)); 2533744bfb21SJohn Baldwin } 2534744bfb21SJohn Baldwin #ifdef INET6 2535744bfb21SJohn Baldwin else if (aip->a_af == AF_INET6) { 2536744bfb21SJohn Baldwin nvlist_add_binary(nvl_aip, "ipv6", &aip->a_addr.in6, sizeof(aip->a_addr.in6)); 2537744bfb21SJohn Baldwin nvlist_add_number(nvl_aip, "cidr", in6_mask2len(&aip->a_mask.in6, NULL)); 2538744bfb21SJohn Baldwin } 2539744bfb21SJohn Baldwin #endif 2540744bfb21SJohn Baldwin } 2541744bfb21SJohn Baldwin nvlist_add_nvlist_array(nvl_peer, "allowed-ips", (const nvlist_t *const *)nvl_aips, aip_count); 2542744bfb21SJohn Baldwin err_aip: 2543744bfb21SJohn Baldwin for (j = 0; j < aip_count; ++j) 2544744bfb21SJohn Baldwin nvlist_destroy(nvl_aips[j]); 2545744bfb21SJohn Baldwin free(nvl_aips, M_NVLIST); 2546744bfb21SJohn Baldwin if (err) 2547744bfb21SJohn Baldwin goto err_peer; 2548744bfb21SJohn Baldwin } 2549744bfb21SJohn Baldwin } 2550744bfb21SJohn Baldwin nvlist_add_nvlist_array(nvl, "peers", (const nvlist_t * const *)nvl_peers, peer_count); 2551744bfb21SJohn Baldwin err_peer: 2552744bfb21SJohn Baldwin for (i = 0; i < peer_count; ++i) 2553744bfb21SJohn Baldwin nvlist_destroy(nvl_peers[i]); 2554744bfb21SJohn Baldwin free(nvl_peers, M_NVLIST); 2555744bfb21SJohn Baldwin if (err) { 2556744bfb21SJohn Baldwin sx_sunlock(&sc->sc_lock); 2557744bfb21SJohn Baldwin goto err; 2558744bfb21SJohn Baldwin } 2559744bfb21SJohn Baldwin } 2560744bfb21SJohn Baldwin sx_sunlock(&sc->sc_lock); 2561744bfb21SJohn Baldwin packed = nvlist_pack(nvl, &size); 2562744bfb21SJohn Baldwin if (!packed) { 2563744bfb21SJohn Baldwin err = ENOMEM; 2564744bfb21SJohn Baldwin goto err; 2565744bfb21SJohn Baldwin } 2566744bfb21SJohn Baldwin if (!wgd->wgd_size) { 2567744bfb21SJohn Baldwin wgd->wgd_size = size; 2568744bfb21SJohn Baldwin goto out; 2569744bfb21SJohn Baldwin } 2570744bfb21SJohn Baldwin if (wgd->wgd_size < size) { 2571744bfb21SJohn Baldwin err = ENOSPC; 2572744bfb21SJohn Baldwin goto out; 2573744bfb21SJohn Baldwin } 2574744bfb21SJohn Baldwin err = copyout(packed, wgd->wgd_data, size); 2575744bfb21SJohn Baldwin wgd->wgd_size = size; 2576744bfb21SJohn Baldwin 2577744bfb21SJohn Baldwin out: 2578dcf581bbSJohn Baldwin zfree(packed, M_NVLIST); 2579744bfb21SJohn Baldwin err: 2580744bfb21SJohn Baldwin nvlist_destroy(nvl); 2581744bfb21SJohn Baldwin return (err); 2582744bfb21SJohn Baldwin } 2583744bfb21SJohn Baldwin 2584744bfb21SJohn Baldwin static int 2585744bfb21SJohn Baldwin wg_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 2586744bfb21SJohn Baldwin { 2587744bfb21SJohn Baldwin struct wg_data_io *wgd = (struct wg_data_io *)data; 2588744bfb21SJohn Baldwin struct ifreq *ifr = (struct ifreq *)data; 2589744bfb21SJohn Baldwin struct wg_softc *sc; 2590744bfb21SJohn Baldwin int ret = 0; 2591744bfb21SJohn Baldwin 2592744bfb21SJohn Baldwin sx_slock(&wg_sx); 2593744bfb21SJohn Baldwin sc = ifp->if_softc; 2594744bfb21SJohn Baldwin if (!sc) { 2595744bfb21SJohn Baldwin ret = ENXIO; 2596744bfb21SJohn Baldwin goto out; 2597744bfb21SJohn Baldwin } 2598744bfb21SJohn Baldwin 2599744bfb21SJohn Baldwin switch (cmd) { 2600744bfb21SJohn Baldwin case SIOCSWG: 2601744bfb21SJohn Baldwin ret = priv_check(curthread, PRIV_NET_WG); 2602744bfb21SJohn Baldwin if (ret == 0) 2603744bfb21SJohn Baldwin ret = wgc_set(sc, wgd); 2604744bfb21SJohn Baldwin break; 2605744bfb21SJohn Baldwin case SIOCGWG: 2606744bfb21SJohn Baldwin ret = wgc_get(sc, wgd); 2607744bfb21SJohn Baldwin break; 2608744bfb21SJohn Baldwin /* Interface IOCTLs */ 2609744bfb21SJohn Baldwin case SIOCSIFADDR: 2610744bfb21SJohn Baldwin /* 2611744bfb21SJohn Baldwin * This differs from *BSD norms, but is more uniform with how 2612744bfb21SJohn Baldwin * WireGuard behaves elsewhere. 2613744bfb21SJohn Baldwin */ 2614744bfb21SJohn Baldwin break; 2615744bfb21SJohn Baldwin case SIOCSIFFLAGS: 2616744bfb21SJohn Baldwin if (ifp->if_flags & IFF_UP) 2617744bfb21SJohn Baldwin ret = wg_up(sc); 2618744bfb21SJohn Baldwin else 2619744bfb21SJohn Baldwin wg_down(sc); 2620744bfb21SJohn Baldwin break; 2621744bfb21SJohn Baldwin case SIOCSIFMTU: 2622744bfb21SJohn Baldwin if (ifr->ifr_mtu <= 0 || ifr->ifr_mtu > MAX_MTU) 2623744bfb21SJohn Baldwin ret = EINVAL; 2624744bfb21SJohn Baldwin else 2625744bfb21SJohn Baldwin ifp->if_mtu = ifr->ifr_mtu; 2626744bfb21SJohn Baldwin break; 2627744bfb21SJohn Baldwin case SIOCADDMULTI: 2628744bfb21SJohn Baldwin case SIOCDELMULTI: 2629744bfb21SJohn Baldwin break; 2630744bfb21SJohn Baldwin case SIOCGTUNFIB: 2631744bfb21SJohn Baldwin ifr->ifr_fib = sc->sc_socket.so_fibnum; 2632744bfb21SJohn Baldwin break; 2633744bfb21SJohn Baldwin case SIOCSTUNFIB: 2634744bfb21SJohn Baldwin ret = priv_check(curthread, PRIV_NET_WG); 2635744bfb21SJohn Baldwin if (ret) 2636744bfb21SJohn Baldwin break; 2637744bfb21SJohn Baldwin ret = priv_check(curthread, PRIV_NET_SETIFFIB); 2638744bfb21SJohn Baldwin if (ret) 2639744bfb21SJohn Baldwin break; 2640744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2641744bfb21SJohn Baldwin ret = wg_socket_set_fibnum(sc, ifr->ifr_fib); 2642744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2643744bfb21SJohn Baldwin break; 2644744bfb21SJohn Baldwin default: 2645744bfb21SJohn Baldwin ret = ENOTTY; 2646744bfb21SJohn Baldwin } 2647744bfb21SJohn Baldwin 2648744bfb21SJohn Baldwin out: 2649744bfb21SJohn Baldwin sx_sunlock(&wg_sx); 2650744bfb21SJohn Baldwin return (ret); 2651744bfb21SJohn Baldwin } 2652744bfb21SJohn Baldwin 2653744bfb21SJohn Baldwin static int 2654744bfb21SJohn Baldwin wg_up(struct wg_softc *sc) 2655744bfb21SJohn Baldwin { 2656744bfb21SJohn Baldwin struct ifnet *ifp = sc->sc_ifp; 2657744bfb21SJohn Baldwin struct wg_peer *peer; 2658744bfb21SJohn Baldwin int rc = EBUSY; 2659744bfb21SJohn Baldwin 2660744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2661744bfb21SJohn Baldwin /* Jail's being removed, no more wg_up(). */ 2662744bfb21SJohn Baldwin if ((sc->sc_flags & WGF_DYING) != 0) 2663744bfb21SJohn Baldwin goto out; 2664744bfb21SJohn Baldwin 2665744bfb21SJohn Baldwin /* Silent success if we're already running. */ 2666744bfb21SJohn Baldwin rc = 0; 2667744bfb21SJohn Baldwin if (ifp->if_drv_flags & IFF_DRV_RUNNING) 2668744bfb21SJohn Baldwin goto out; 2669744bfb21SJohn Baldwin ifp->if_drv_flags |= IFF_DRV_RUNNING; 2670744bfb21SJohn Baldwin 2671744bfb21SJohn Baldwin rc = wg_socket_init(sc, sc->sc_socket.so_port); 2672744bfb21SJohn Baldwin if (rc == 0) { 2673744bfb21SJohn Baldwin TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) 2674744bfb21SJohn Baldwin wg_timers_enable(peer); 2675744bfb21SJohn Baldwin if_link_state_change(sc->sc_ifp, LINK_STATE_UP); 2676744bfb21SJohn Baldwin } else { 2677744bfb21SJohn Baldwin ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2678744bfb21SJohn Baldwin DPRINTF(sc, "Unable to initialize sockets: %d\n", rc); 2679744bfb21SJohn Baldwin } 2680744bfb21SJohn Baldwin out: 2681744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2682744bfb21SJohn Baldwin return (rc); 2683744bfb21SJohn Baldwin } 2684744bfb21SJohn Baldwin 2685744bfb21SJohn Baldwin static void 2686744bfb21SJohn Baldwin wg_down(struct wg_softc *sc) 2687744bfb21SJohn Baldwin { 2688744bfb21SJohn Baldwin struct ifnet *ifp = sc->sc_ifp; 2689744bfb21SJohn Baldwin struct wg_peer *peer; 2690744bfb21SJohn Baldwin 2691744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2692744bfb21SJohn Baldwin if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2693744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2694744bfb21SJohn Baldwin return; 2695744bfb21SJohn Baldwin } 2696744bfb21SJohn Baldwin ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 2697744bfb21SJohn Baldwin 2698744bfb21SJohn Baldwin TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) { 2699744bfb21SJohn Baldwin wg_queue_purge(&peer->p_stage_queue); 2700744bfb21SJohn Baldwin wg_timers_disable(peer); 2701744bfb21SJohn Baldwin } 2702744bfb21SJohn Baldwin 2703744bfb21SJohn Baldwin wg_queue_purge(&sc->sc_handshake_queue); 2704744bfb21SJohn Baldwin 2705744bfb21SJohn Baldwin TAILQ_FOREACH(peer, &sc->sc_peers, p_entry) { 2706744bfb21SJohn Baldwin noise_remote_handshake_clear(peer->p_remote); 2707744bfb21SJohn Baldwin noise_remote_keypairs_clear(peer->p_remote); 2708744bfb21SJohn Baldwin } 2709744bfb21SJohn Baldwin 2710744bfb21SJohn Baldwin if_link_state_change(sc->sc_ifp, LINK_STATE_DOWN); 2711744bfb21SJohn Baldwin wg_socket_uninit(sc); 2712744bfb21SJohn Baldwin 2713744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2714744bfb21SJohn Baldwin } 2715744bfb21SJohn Baldwin 2716744bfb21SJohn Baldwin static int 2717744bfb21SJohn Baldwin wg_clone_create(struct if_clone *ifc, int unit, caddr_t params) 2718744bfb21SJohn Baldwin { 2719744bfb21SJohn Baldwin struct wg_softc *sc; 2720744bfb21SJohn Baldwin struct ifnet *ifp; 2721744bfb21SJohn Baldwin 2722744bfb21SJohn Baldwin sc = malloc(sizeof(*sc), M_WG, M_WAITOK | M_ZERO); 2723744bfb21SJohn Baldwin 2724744bfb21SJohn Baldwin sc->sc_local = noise_local_alloc(sc); 2725744bfb21SJohn Baldwin 2726744bfb21SJohn Baldwin sc->sc_encrypt = mallocarray(sizeof(struct grouptask), mp_ncpus, M_WG, M_WAITOK | M_ZERO); 2727744bfb21SJohn Baldwin 2728744bfb21SJohn Baldwin sc->sc_decrypt = mallocarray(sizeof(struct grouptask), mp_ncpus, M_WG, M_WAITOK | M_ZERO); 2729744bfb21SJohn Baldwin 2730744bfb21SJohn Baldwin if (!rn_inithead((void **)&sc->sc_aip4, offsetof(struct aip_addr, in) * NBBY)) 2731744bfb21SJohn Baldwin goto free_decrypt; 2732744bfb21SJohn Baldwin 2733744bfb21SJohn Baldwin if (!rn_inithead((void **)&sc->sc_aip6, offsetof(struct aip_addr, in6) * NBBY)) 2734744bfb21SJohn Baldwin goto free_aip4; 2735744bfb21SJohn Baldwin 2736744bfb21SJohn Baldwin atomic_add_int(&clone_count, 1); 2737744bfb21SJohn Baldwin ifp = sc->sc_ifp = if_alloc(IFT_WIREGUARD); 2738744bfb21SJohn Baldwin 2739744bfb21SJohn Baldwin sc->sc_ucred = crhold(curthread->td_ucred); 2740744bfb21SJohn Baldwin sc->sc_socket.so_fibnum = curthread->td_proc->p_fibnum; 2741744bfb21SJohn Baldwin sc->sc_socket.so_port = 0; 2742744bfb21SJohn Baldwin 2743744bfb21SJohn Baldwin TAILQ_INIT(&sc->sc_peers); 2744744bfb21SJohn Baldwin sc->sc_peers_num = 0; 2745744bfb21SJohn Baldwin 2746744bfb21SJohn Baldwin cookie_checker_init(&sc->sc_cookie); 2747744bfb21SJohn Baldwin 2748744bfb21SJohn Baldwin RADIX_NODE_HEAD_LOCK_INIT(sc->sc_aip4); 2749744bfb21SJohn Baldwin RADIX_NODE_HEAD_LOCK_INIT(sc->sc_aip6); 2750744bfb21SJohn Baldwin 2751744bfb21SJohn Baldwin GROUPTASK_INIT(&sc->sc_handshake, 0, (gtask_fn_t *)wg_softc_handshake_receive, sc); 2752744bfb21SJohn Baldwin taskqgroup_attach(qgroup_wg_tqg, &sc->sc_handshake, sc, NULL, NULL, "wg tx initiation"); 2753744bfb21SJohn Baldwin wg_queue_init(&sc->sc_handshake_queue, "hsq"); 2754744bfb21SJohn Baldwin 2755744bfb21SJohn Baldwin for (int i = 0; i < mp_ncpus; i++) { 2756744bfb21SJohn Baldwin GROUPTASK_INIT(&sc->sc_encrypt[i], 0, 2757744bfb21SJohn Baldwin (gtask_fn_t *)wg_softc_encrypt, sc); 2758744bfb21SJohn Baldwin taskqgroup_attach_cpu(qgroup_wg_tqg, &sc->sc_encrypt[i], sc, i, NULL, NULL, "wg encrypt"); 2759744bfb21SJohn Baldwin GROUPTASK_INIT(&sc->sc_decrypt[i], 0, 2760744bfb21SJohn Baldwin (gtask_fn_t *)wg_softc_decrypt, sc); 2761744bfb21SJohn Baldwin taskqgroup_attach_cpu(qgroup_wg_tqg, &sc->sc_decrypt[i], sc, i, NULL, NULL, "wg decrypt"); 2762744bfb21SJohn Baldwin } 2763744bfb21SJohn Baldwin 2764744bfb21SJohn Baldwin wg_queue_init(&sc->sc_encrypt_parallel, "encp"); 2765744bfb21SJohn Baldwin wg_queue_init(&sc->sc_decrypt_parallel, "decp"); 2766744bfb21SJohn Baldwin 2767744bfb21SJohn Baldwin sx_init(&sc->sc_lock, "wg softc lock"); 2768744bfb21SJohn Baldwin 2769744bfb21SJohn Baldwin ifp->if_softc = sc; 2770744bfb21SJohn Baldwin ifp->if_capabilities = ifp->if_capenable = WG_CAPS; 2771744bfb21SJohn Baldwin if_initname(ifp, wgname, unit); 2772744bfb21SJohn Baldwin 2773744bfb21SJohn Baldwin if_setmtu(ifp, DEFAULT_MTU); 2774744bfb21SJohn Baldwin ifp->if_flags = IFF_NOARP | IFF_MULTICAST; 2775744bfb21SJohn Baldwin ifp->if_init = wg_init; 2776744bfb21SJohn Baldwin ifp->if_reassign = wg_reassign; 2777744bfb21SJohn Baldwin ifp->if_qflush = wg_qflush; 2778744bfb21SJohn Baldwin ifp->if_transmit = wg_transmit; 2779744bfb21SJohn Baldwin ifp->if_output = wg_output; 2780744bfb21SJohn Baldwin ifp->if_ioctl = wg_ioctl; 2781744bfb21SJohn Baldwin if_attach(ifp); 2782744bfb21SJohn Baldwin bpfattach(ifp, DLT_NULL, sizeof(uint32_t)); 2783744bfb21SJohn Baldwin #ifdef INET6 2784744bfb21SJohn Baldwin ND_IFINFO(ifp)->flags &= ~ND6_IFF_AUTO_LINKLOCAL; 2785744bfb21SJohn Baldwin ND_IFINFO(ifp)->flags |= ND6_IFF_NO_DAD; 2786744bfb21SJohn Baldwin #endif 2787744bfb21SJohn Baldwin sx_xlock(&wg_sx); 2788744bfb21SJohn Baldwin LIST_INSERT_HEAD(&wg_list, sc, sc_entry); 2789744bfb21SJohn Baldwin sx_xunlock(&wg_sx); 2790744bfb21SJohn Baldwin return (0); 2791744bfb21SJohn Baldwin free_aip4: 2792744bfb21SJohn Baldwin RADIX_NODE_HEAD_DESTROY(sc->sc_aip4); 2793744bfb21SJohn Baldwin free(sc->sc_aip4, M_RTABLE); 2794744bfb21SJohn Baldwin free_decrypt: 2795744bfb21SJohn Baldwin free(sc->sc_decrypt, M_WG); 2796744bfb21SJohn Baldwin free(sc->sc_encrypt, M_WG); 2797744bfb21SJohn Baldwin noise_local_free(sc->sc_local, NULL); 2798744bfb21SJohn Baldwin free(sc, M_WG); 2799744bfb21SJohn Baldwin return (ENOMEM); 2800744bfb21SJohn Baldwin } 2801744bfb21SJohn Baldwin 2802744bfb21SJohn Baldwin static void 2803744bfb21SJohn Baldwin wg_clone_deferred_free(struct noise_local *l) 2804744bfb21SJohn Baldwin { 2805744bfb21SJohn Baldwin struct wg_softc *sc = noise_local_arg(l); 2806744bfb21SJohn Baldwin 2807744bfb21SJohn Baldwin free(sc, M_WG); 2808744bfb21SJohn Baldwin atomic_add_int(&clone_count, -1); 2809744bfb21SJohn Baldwin } 2810744bfb21SJohn Baldwin 2811744bfb21SJohn Baldwin static void 2812744bfb21SJohn Baldwin wg_clone_destroy(struct ifnet *ifp) 2813744bfb21SJohn Baldwin { 2814744bfb21SJohn Baldwin struct wg_softc *sc = ifp->if_softc; 2815744bfb21SJohn Baldwin struct ucred *cred; 2816744bfb21SJohn Baldwin 2817744bfb21SJohn Baldwin sx_xlock(&wg_sx); 2818744bfb21SJohn Baldwin ifp->if_softc = NULL; 2819744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2820744bfb21SJohn Baldwin sc->sc_flags |= WGF_DYING; 2821744bfb21SJohn Baldwin cred = sc->sc_ucred; 2822744bfb21SJohn Baldwin sc->sc_ucred = NULL; 2823744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2824744bfb21SJohn Baldwin LIST_REMOVE(sc, sc_entry); 2825744bfb21SJohn Baldwin sx_xunlock(&wg_sx); 2826744bfb21SJohn Baldwin 2827744bfb21SJohn Baldwin if_link_state_change(sc->sc_ifp, LINK_STATE_DOWN); 2828744bfb21SJohn Baldwin CURVNET_SET(sc->sc_ifp->if_vnet); 2829744bfb21SJohn Baldwin if_purgeaddrs(sc->sc_ifp); 2830744bfb21SJohn Baldwin CURVNET_RESTORE(); 2831744bfb21SJohn Baldwin 2832744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2833744bfb21SJohn Baldwin wg_socket_uninit(sc); 2834744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2835744bfb21SJohn Baldwin 2836744bfb21SJohn Baldwin /* 2837744bfb21SJohn Baldwin * No guarantees that all traffic have passed until the epoch has 2838744bfb21SJohn Baldwin * elapsed with the socket closed. 2839744bfb21SJohn Baldwin */ 2840744bfb21SJohn Baldwin NET_EPOCH_WAIT(); 2841744bfb21SJohn Baldwin 2842744bfb21SJohn Baldwin taskqgroup_drain_all(qgroup_wg_tqg); 2843744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2844744bfb21SJohn Baldwin wg_peer_destroy_all(sc); 2845*f948cb71SZhenlei Huang NET_EPOCH_DRAIN_CALLBACKS(); 2846744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2847744bfb21SJohn Baldwin sx_destroy(&sc->sc_lock); 2848744bfb21SJohn Baldwin taskqgroup_detach(qgroup_wg_tqg, &sc->sc_handshake); 2849744bfb21SJohn Baldwin for (int i = 0; i < mp_ncpus; i++) { 2850744bfb21SJohn Baldwin taskqgroup_detach(qgroup_wg_tqg, &sc->sc_encrypt[i]); 2851744bfb21SJohn Baldwin taskqgroup_detach(qgroup_wg_tqg, &sc->sc_decrypt[i]); 2852744bfb21SJohn Baldwin } 2853744bfb21SJohn Baldwin free(sc->sc_encrypt, M_WG); 2854744bfb21SJohn Baldwin free(sc->sc_decrypt, M_WG); 2855744bfb21SJohn Baldwin wg_queue_deinit(&sc->sc_handshake_queue); 2856744bfb21SJohn Baldwin wg_queue_deinit(&sc->sc_encrypt_parallel); 2857744bfb21SJohn Baldwin wg_queue_deinit(&sc->sc_decrypt_parallel); 2858744bfb21SJohn Baldwin 2859744bfb21SJohn Baldwin RADIX_NODE_HEAD_DESTROY(sc->sc_aip4); 2860744bfb21SJohn Baldwin RADIX_NODE_HEAD_DESTROY(sc->sc_aip6); 2861744bfb21SJohn Baldwin rn_detachhead((void **)&sc->sc_aip4); 2862744bfb21SJohn Baldwin rn_detachhead((void **)&sc->sc_aip6); 2863744bfb21SJohn Baldwin 2864744bfb21SJohn Baldwin cookie_checker_free(&sc->sc_cookie); 2865744bfb21SJohn Baldwin 2866744bfb21SJohn Baldwin if (cred != NULL) 2867744bfb21SJohn Baldwin crfree(cred); 2868744bfb21SJohn Baldwin if_detach(sc->sc_ifp); 2869744bfb21SJohn Baldwin if_free(sc->sc_ifp); 2870744bfb21SJohn Baldwin 2871744bfb21SJohn Baldwin noise_local_free(sc->sc_local, wg_clone_deferred_free); 2872744bfb21SJohn Baldwin } 2873744bfb21SJohn Baldwin 2874744bfb21SJohn Baldwin static void 2875744bfb21SJohn Baldwin wg_qflush(struct ifnet *ifp __unused) 2876744bfb21SJohn Baldwin { 2877744bfb21SJohn Baldwin } 2878744bfb21SJohn Baldwin 2879744bfb21SJohn Baldwin /* 2880744bfb21SJohn Baldwin * Privileged information (private-key, preshared-key) are only exported for 2881744bfb21SJohn Baldwin * root and jailed root by default. 2882744bfb21SJohn Baldwin */ 2883744bfb21SJohn Baldwin static bool 2884744bfb21SJohn Baldwin wgc_privileged(struct wg_softc *sc) 2885744bfb21SJohn Baldwin { 2886744bfb21SJohn Baldwin struct thread *td; 2887744bfb21SJohn Baldwin 2888744bfb21SJohn Baldwin td = curthread; 2889744bfb21SJohn Baldwin return (priv_check(td, PRIV_NET_WG) == 0); 2890744bfb21SJohn Baldwin } 2891744bfb21SJohn Baldwin 2892744bfb21SJohn Baldwin static void 2893744bfb21SJohn Baldwin wg_reassign(struct ifnet *ifp, struct vnet *new_vnet __unused, 2894744bfb21SJohn Baldwin char *unused __unused) 2895744bfb21SJohn Baldwin { 2896744bfb21SJohn Baldwin struct wg_softc *sc; 2897744bfb21SJohn Baldwin 2898744bfb21SJohn Baldwin sc = ifp->if_softc; 2899744bfb21SJohn Baldwin wg_down(sc); 2900744bfb21SJohn Baldwin } 2901744bfb21SJohn Baldwin 2902744bfb21SJohn Baldwin static void 2903744bfb21SJohn Baldwin wg_init(void *xsc) 2904744bfb21SJohn Baldwin { 2905744bfb21SJohn Baldwin struct wg_softc *sc; 2906744bfb21SJohn Baldwin 2907744bfb21SJohn Baldwin sc = xsc; 2908744bfb21SJohn Baldwin wg_up(sc); 2909744bfb21SJohn Baldwin } 2910744bfb21SJohn Baldwin 2911744bfb21SJohn Baldwin static void 2912744bfb21SJohn Baldwin vnet_wg_init(const void *unused __unused) 2913744bfb21SJohn Baldwin { 2914744bfb21SJohn Baldwin V_wg_cloner = if_clone_simple(wgname, wg_clone_create, wg_clone_destroy, 2915744bfb21SJohn Baldwin 0); 2916744bfb21SJohn Baldwin } 2917744bfb21SJohn Baldwin VNET_SYSINIT(vnet_wg_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 2918744bfb21SJohn Baldwin vnet_wg_init, NULL); 2919744bfb21SJohn Baldwin 2920744bfb21SJohn Baldwin static void 2921744bfb21SJohn Baldwin vnet_wg_uninit(const void *unused __unused) 2922744bfb21SJohn Baldwin { 2923744bfb21SJohn Baldwin if (V_wg_cloner) 2924744bfb21SJohn Baldwin if_clone_detach(V_wg_cloner); 2925744bfb21SJohn Baldwin } 2926744bfb21SJohn Baldwin VNET_SYSUNINIT(vnet_wg_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, 2927744bfb21SJohn Baldwin vnet_wg_uninit, NULL); 2928744bfb21SJohn Baldwin 2929744bfb21SJohn Baldwin static int 2930744bfb21SJohn Baldwin wg_prison_remove(void *obj, void *data __unused) 2931744bfb21SJohn Baldwin { 2932744bfb21SJohn Baldwin const struct prison *pr = obj; 2933744bfb21SJohn Baldwin struct wg_softc *sc; 2934744bfb21SJohn Baldwin 2935744bfb21SJohn Baldwin /* 2936744bfb21SJohn Baldwin * Do a pass through all if_wg interfaces and release creds on any from 2937744bfb21SJohn Baldwin * the jail that are supposed to be going away. This will, in turn, let 2938744bfb21SJohn Baldwin * the jail die so that we don't end up with Schrödinger's jail. 2939744bfb21SJohn Baldwin */ 2940744bfb21SJohn Baldwin sx_slock(&wg_sx); 2941744bfb21SJohn Baldwin LIST_FOREACH(sc, &wg_list, sc_entry) { 2942744bfb21SJohn Baldwin sx_xlock(&sc->sc_lock); 2943744bfb21SJohn Baldwin if (!(sc->sc_flags & WGF_DYING) && sc->sc_ucred && sc->sc_ucred->cr_prison == pr) { 2944744bfb21SJohn Baldwin struct ucred *cred = sc->sc_ucred; 2945744bfb21SJohn Baldwin DPRINTF(sc, "Creating jail exiting\n"); 2946744bfb21SJohn Baldwin if_link_state_change(sc->sc_ifp, LINK_STATE_DOWN); 2947744bfb21SJohn Baldwin wg_socket_uninit(sc); 2948744bfb21SJohn Baldwin sc->sc_ucred = NULL; 2949744bfb21SJohn Baldwin crfree(cred); 2950744bfb21SJohn Baldwin sc->sc_flags |= WGF_DYING; 2951744bfb21SJohn Baldwin } 2952744bfb21SJohn Baldwin sx_xunlock(&sc->sc_lock); 2953744bfb21SJohn Baldwin } 2954744bfb21SJohn Baldwin sx_sunlock(&wg_sx); 2955744bfb21SJohn Baldwin 2956744bfb21SJohn Baldwin return (0); 2957744bfb21SJohn Baldwin } 2958744bfb21SJohn Baldwin 2959744bfb21SJohn Baldwin #ifdef SELFTESTS 2960744bfb21SJohn Baldwin #include "selftest/allowedips.c" 2961744bfb21SJohn Baldwin static bool wg_run_selftests(void) 2962744bfb21SJohn Baldwin { 2963744bfb21SJohn Baldwin bool ret = true; 2964744bfb21SJohn Baldwin ret &= wg_allowedips_selftest(); 2965744bfb21SJohn Baldwin ret &= noise_counter_selftest(); 2966744bfb21SJohn Baldwin ret &= cookie_selftest(); 2967744bfb21SJohn Baldwin return ret; 2968744bfb21SJohn Baldwin } 2969744bfb21SJohn Baldwin #else 2970744bfb21SJohn Baldwin static inline bool wg_run_selftests(void) { return true; } 2971744bfb21SJohn Baldwin #endif 2972744bfb21SJohn Baldwin 2973744bfb21SJohn Baldwin static int 2974744bfb21SJohn Baldwin wg_module_init(void) 2975744bfb21SJohn Baldwin { 2976744bfb21SJohn Baldwin int ret = ENOMEM; 2977744bfb21SJohn Baldwin 2978744bfb21SJohn Baldwin osd_method_t methods[PR_MAXMETHOD] = { 2979744bfb21SJohn Baldwin [PR_METHOD_REMOVE] = wg_prison_remove, 2980744bfb21SJohn Baldwin }; 2981744bfb21SJohn Baldwin 2982744bfb21SJohn Baldwin if ((wg_packet_zone = uma_zcreate("wg packet", sizeof(struct wg_packet), 2983744bfb21SJohn Baldwin NULL, NULL, NULL, NULL, 0, 0)) == NULL) 2984744bfb21SJohn Baldwin goto free_none; 2985744bfb21SJohn Baldwin ret = crypto_init(); 2986744bfb21SJohn Baldwin if (ret != 0) 2987744bfb21SJohn Baldwin goto free_zone; 2988744bfb21SJohn Baldwin if (cookie_init() != 0) 2989744bfb21SJohn Baldwin goto free_crypto; 2990744bfb21SJohn Baldwin 2991744bfb21SJohn Baldwin wg_osd_jail_slot = osd_jail_register(NULL, methods); 2992744bfb21SJohn Baldwin 2993744bfb21SJohn Baldwin ret = ENOTRECOVERABLE; 2994744bfb21SJohn Baldwin if (!wg_run_selftests()) 2995744bfb21SJohn Baldwin goto free_all; 2996744bfb21SJohn Baldwin 2997744bfb21SJohn Baldwin return (0); 2998744bfb21SJohn Baldwin 2999744bfb21SJohn Baldwin free_all: 3000744bfb21SJohn Baldwin osd_jail_deregister(wg_osd_jail_slot); 3001744bfb21SJohn Baldwin cookie_deinit(); 3002744bfb21SJohn Baldwin free_crypto: 3003744bfb21SJohn Baldwin crypto_deinit(); 3004744bfb21SJohn Baldwin free_zone: 3005744bfb21SJohn Baldwin uma_zdestroy(wg_packet_zone); 3006744bfb21SJohn Baldwin free_none: 3007744bfb21SJohn Baldwin return (ret); 3008744bfb21SJohn Baldwin } 3009744bfb21SJohn Baldwin 3010744bfb21SJohn Baldwin static void 3011744bfb21SJohn Baldwin wg_module_deinit(void) 3012744bfb21SJohn Baldwin { 3013744bfb21SJohn Baldwin VNET_ITERATOR_DECL(vnet_iter); 3014744bfb21SJohn Baldwin VNET_LIST_RLOCK(); 3015744bfb21SJohn Baldwin VNET_FOREACH(vnet_iter) { 3016744bfb21SJohn Baldwin struct if_clone *clone = VNET_VNET(vnet_iter, wg_cloner); 3017744bfb21SJohn Baldwin if (clone) { 3018744bfb21SJohn Baldwin if_clone_detach(clone); 3019744bfb21SJohn Baldwin VNET_VNET(vnet_iter, wg_cloner) = NULL; 3020744bfb21SJohn Baldwin } 3021744bfb21SJohn Baldwin } 3022744bfb21SJohn Baldwin VNET_LIST_RUNLOCK(); 3023744bfb21SJohn Baldwin NET_EPOCH_WAIT(); 3024744bfb21SJohn Baldwin MPASS(LIST_EMPTY(&wg_list)); 3025744bfb21SJohn Baldwin osd_jail_deregister(wg_osd_jail_slot); 3026744bfb21SJohn Baldwin cookie_deinit(); 3027744bfb21SJohn Baldwin crypto_deinit(); 3028744bfb21SJohn Baldwin uma_zdestroy(wg_packet_zone); 3029744bfb21SJohn Baldwin } 3030744bfb21SJohn Baldwin 3031744bfb21SJohn Baldwin static int 3032744bfb21SJohn Baldwin wg_module_event_handler(module_t mod, int what, void *arg) 3033744bfb21SJohn Baldwin { 3034744bfb21SJohn Baldwin switch (what) { 3035744bfb21SJohn Baldwin case MOD_LOAD: 3036744bfb21SJohn Baldwin return wg_module_init(); 3037744bfb21SJohn Baldwin case MOD_UNLOAD: 3038744bfb21SJohn Baldwin wg_module_deinit(); 3039744bfb21SJohn Baldwin break; 3040744bfb21SJohn Baldwin default: 3041744bfb21SJohn Baldwin return (EOPNOTSUPP); 3042744bfb21SJohn Baldwin } 3043744bfb21SJohn Baldwin return (0); 3044744bfb21SJohn Baldwin } 3045744bfb21SJohn Baldwin 3046744bfb21SJohn Baldwin static moduledata_t wg_moduledata = { 3047744bfb21SJohn Baldwin wgname, 3048744bfb21SJohn Baldwin wg_module_event_handler, 3049744bfb21SJohn Baldwin NULL 3050744bfb21SJohn Baldwin }; 3051744bfb21SJohn Baldwin 3052744bfb21SJohn Baldwin DECLARE_MODULE(wg, wg_moduledata, SI_SUB_PSEUDO, SI_ORDER_ANY); 3053744bfb21SJohn Baldwin MODULE_VERSION(wg, WIREGUARD_VERSION); 3054744bfb21SJohn Baldwin MODULE_DEPEND(wg, crypto, 1, 1, 1); 3055