| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_wg.c,v 1.48 2020/08/31 20:31:43 riastradh Exp $ */ | | 1 | /* $NetBSD: if_wg.c,v 1.49 2020/08/31 20:33:58 riastradh Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (C) Ryota Ozaki <ozaki.ryota@gmail.com> | | 4 | * Copyright (C) Ryota Ozaki <ozaki.ryota@gmail.com> |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -31,27 +31,27 @@ | | | @@ -31,27 +31,27 @@ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * This network interface aims to implement the WireGuard protocol. | | 33 | * This network interface aims to implement the WireGuard protocol. |
34 | * The implementation is based on the paper of WireGuard as of | | 34 | * The implementation is based on the paper of WireGuard as of |
35 | * 2018-06-30 [1]. The paper is referred in the source code with label | | 35 | * 2018-06-30 [1]. The paper is referred in the source code with label |
36 | * [W]. Also the specification of the Noise protocol framework as of | | 36 | * [W]. Also the specification of the Noise protocol framework as of |
37 | * 2018-07-11 [2] is referred with label [N]. | | 37 | * 2018-07-11 [2] is referred with label [N]. |
38 | * | | 38 | * |
39 | * [1] https://www.wireguard.com/papers/wireguard.pdf | | 39 | * [1] https://www.wireguard.com/papers/wireguard.pdf |
40 | * [2] http://noiseprotocol.org/noise.pdf | | 40 | * [2] http://noiseprotocol.org/noise.pdf |
41 | */ | | 41 | */ |
42 | | | 42 | |
43 | #include <sys/cdefs.h> | | 43 | #include <sys/cdefs.h> |
44 | __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.48 2020/08/31 20:31:43 riastradh Exp $"); | | 44 | __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.49 2020/08/31 20:33:58 riastradh Exp $"); |
45 | | | 45 | |
46 | #ifdef _KERNEL_OPT | | 46 | #ifdef _KERNEL_OPT |
47 | #include "opt_inet.h" | | 47 | #include "opt_inet.h" |
48 | #endif | | 48 | #endif |
49 | | | 49 | |
50 | #include <sys/param.h> | | 50 | #include <sys/param.h> |
51 | #include <sys/types.h> | | 51 | #include <sys/types.h> |
52 | | | 52 | |
53 | #include <sys/atomic.h> | | 53 | #include <sys/atomic.h> |
54 | #include <sys/callout.h> | | 54 | #include <sys/callout.h> |
55 | #include <sys/cprng.h> | | 55 | #include <sys/cprng.h> |
56 | #include <sys/cpu.h> | | 56 | #include <sys/cpu.h> |
57 | #include <sys/device.h> | | 57 | #include <sys/device.h> |
| @@ -127,53 +127,50 @@ __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1. | | | @@ -127,53 +127,50 @@ __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1. |
127 | * - It has a softint that is used to send packets over an wg interface | | 127 | * - It has a softint that is used to send packets over an wg interface |
128 | * to a peer | | 128 | * to a peer |
129 | * - It has a pair of session instances (struct wg_session) | | 129 | * - It has a pair of session instances (struct wg_session) |
130 | * - It has a pair of endpoint instances (struct wg_sockaddr) | | 130 | * - It has a pair of endpoint instances (struct wg_sockaddr) |
131 | * - Normally one endpoint is used and the second one is used only on | | 131 | * - Normally one endpoint is used and the second one is used only on |
132 | * a peer migration (a change of peer's IP address) | | 132 | * a peer migration (a change of peer's IP address) |
133 | * - It has a list of IP addresses and sub networks called allowedips | | 133 | * - It has a list of IP addresses and sub networks called allowedips |
134 | * (struct wg_allowedip) | | 134 | * (struct wg_allowedip) |
135 | * - A packets sent over a session is allowed if its destination matches | | 135 | * - A packets sent over a session is allowed if its destination matches |
136 | * any IP addresses or sub networks of the list | | 136 | * any IP addresses or sub networks of the list |
137 | * - struct wg_session represents a session of a secure tunnel with a peer | | 137 | * - struct wg_session represents a session of a secure tunnel with a peer |
138 | * - Two instances of sessions belong to a peer; a stable session and a | | 138 | * - Two instances of sessions belong to a peer; a stable session and a |
139 | * unstable session | | 139 | * unstable session |
140 | * - A handshake process of a session always starts with a unstable instace | | 140 | * - A handshake process of a session always starts with a unstable instance |
141 | * - Once a session is established, its instance becomes stable and the | | 141 | * - Once a session is established, its instance becomes stable and the |
142 | * other becomes unstable instead | | 142 | * other becomes unstable instead |
143 | * - Data messages are always sent via a stable session | | 143 | * - Data messages are always sent via a stable session |
144 | * | | 144 | * |
145 | * Locking notes: | | 145 | * Locking notes: |
146 | * - wg interfaces (struct wg_softc, wg) is listed in wg_softcs.list and | | 146 | * - wg interfaces (struct wg_softc, wg) is listed in wg_softcs.list and |
147 | * protected by wg_softcs.lock | | 147 | * protected by wg_softcs.lock |
148 | * - Each wg has a mutex(9) and a rwlock(9) | | 148 | * - Each wg has a mutex(9) wg_lock, and a rwlock(9) wg_rwlock |
149 | * - The mutex (wg_lock) protects its peer list (wg_peers) | | 149 | * - Changes to the peer list are serialized by wg_lock |
150 | * - A peer on the list is also protected by pserialize(9) or psref(9) | | 150 | * - The peer list may be read with pserialize(9) and psref(9) |
151 | * - The rwlock (wg_rwlock) protects the routing tables (wg_rtable_ipv[46]) | | 151 | * - The rwlock (wg_rwlock) protects the routing tables (wg_rtable_ipv[46]) |
152 | * - Each peer (struct wg_peer, wgp) has a mutex | | 152 | * => XXX replace by pserialize when routing table is psz-safe |
153 | * - The mutex (wgp_lock) protects wgp_session_unstable and wgp_state | | 153 | * - Each peer (struct wg_peer, wgp) has a mutex wgp_lock, which can be taken |
154 | * - Each session (struct wg_session, wgs) has a mutex | | 154 | * only in thread context and serializes: |
155 | * - The mutex (wgs_lock) protects its state (wgs_state) and its handshake | | 155 | * - the stable and unstable session pointers |
156 | * states | | 156 | * - all unstable session state |
157 | * - wgs_state of a unstable session can be changed while it never be | | 157 | * - Packet processing may be done in softint context: |
158 | * changed on a stable session, so once get a session instace via | | 158 | * - The stable session can be read under pserialize(9) or psref(9) |
159 | * wgp_session_stable we can safely access wgs_state without | | 159 | * - The stable session is always ESTABLISHED |
160 | * holding wgs_lock | | | |
161 | * - A session is protected by pserialize or psref like wgp | | | |
162 | * - On a session swap, we must wait for all readers to release a | | 160 | * - On a session swap, we must wait for all readers to release a |
163 | * reference to a stable session before changing wgs_state and | | 161 | * reference to a stable session before changing wgs_state and |
164 | * session states | | 162 | * session states |
165 | * | | 163 | * - Lock order: wg_lock -> wgp_lock |
166 | * Lock order: wg_lock -> wgp_lock -> wgs_lock | | | |
167 | */ | | 164 | */ |
168 | | | 165 | |
169 | | | 166 | |
170 | #define WGLOG(level, fmt, args...) \ | | 167 | #define WGLOG(level, fmt, args...) \ |
171 | log(level, "%s: " fmt, __func__, ##args) | | 168 | log(level, "%s: " fmt, __func__, ##args) |
172 | | | 169 | |
173 | /* Debug options */ | | 170 | /* Debug options */ |
174 | #ifdef WG_DEBUG | | 171 | #ifdef WG_DEBUG |
175 | /* Output debug logs */ | | 172 | /* Output debug logs */ |
176 | #ifndef WG_DEBUG_LOG | | 173 | #ifndef WG_DEBUG_LOG |
177 | #define WG_DEBUG_LOG | | 174 | #define WG_DEBUG_LOG |
178 | #endif | | 175 | #endif |
179 | /* Output trace logs */ | | 176 | /* Output trace logs */ |
| @@ -434,41 +431,40 @@ struct wg_worker { | | | @@ -434,41 +431,40 @@ struct wg_worker { |
434 | bool wgw_todie; | | 431 | bool wgw_todie; |
435 | struct socket *wgw_so4; | | 432 | struct socket *wgw_so4; |
436 | struct socket *wgw_so6; | | 433 | struct socket *wgw_so6; |
437 | int wgw_wakeup_reasons; | | 434 | int wgw_wakeup_reasons; |
438 | #define WG_WAKEUP_REASON_RECEIVE_PACKETS_IPV4 __BIT(0) | | 435 | #define WG_WAKEUP_REASON_RECEIVE_PACKETS_IPV4 __BIT(0) |
439 | #define WG_WAKEUP_REASON_RECEIVE_PACKETS_IPV6 __BIT(1) | | 436 | #define WG_WAKEUP_REASON_RECEIVE_PACKETS_IPV6 __BIT(1) |
440 | #define WG_WAKEUP_REASON_PEER __BIT(2) | | 437 | #define WG_WAKEUP_REASON_PEER __BIT(2) |
441 | }; | | 438 | }; |
442 | | | 439 | |
443 | struct wg_session { | | 440 | struct wg_session { |
444 | struct wg_peer *wgs_peer; | | 441 | struct wg_peer *wgs_peer; |
445 | struct psref_target | | 442 | struct psref_target |
446 | wgs_psref; | | 443 | wgs_psref; |
447 | kmutex_t *wgs_lock; | | | |
448 | | | 444 | |
449 | int wgs_state; | | 445 | int wgs_state; |
450 | #define WGS_STATE_UNKNOWN 0 | | 446 | #define WGS_STATE_UNKNOWN 0 |
451 | #define WGS_STATE_INIT_ACTIVE 1 | | 447 | #define WGS_STATE_INIT_ACTIVE 1 |
452 | #define WGS_STATE_INIT_PASSIVE 2 | | 448 | #define WGS_STATE_INIT_PASSIVE 2 |
453 | #define WGS_STATE_ESTABLISHED 3 | | 449 | #define WGS_STATE_ESTABLISHED 3 |
454 | #define WGS_STATE_DESTROYING 4 | | 450 | #define WGS_STATE_DESTROYING 4 |
455 | | | 451 | |
456 | time_t wgs_time_established; | | 452 | time_t wgs_time_established; |
457 | time_t wgs_time_last_data_sent; | | 453 | time_t wgs_time_last_data_sent; |
458 | bool wgs_is_initiator; | | 454 | bool wgs_is_initiator; |
459 | | | 455 | |
460 | uint32_t wgs_sender_index; | | 456 | uint32_t wgs_local_index; |
461 | uint32_t wgs_receiver_index; | | 457 | uint32_t wgs_remote_index; |
462 | #ifdef __HAVE_ATOMIC64_LOADSTORE | | 458 | #ifdef __HAVE_ATOMIC64_LOADSTORE |
463 | volatile uint64_t | | 459 | volatile uint64_t |
464 | wgs_send_counter; | | 460 | wgs_send_counter; |
465 | #else | | 461 | #else |
466 | kmutex_t wgs_send_counter_lock; | | 462 | kmutex_t wgs_send_counter_lock; |
467 | uint64_t wgs_send_counter; | | 463 | uint64_t wgs_send_counter; |
468 | #endif | | 464 | #endif |
469 | | | 465 | |
470 | struct { | | 466 | struct { |
471 | kmutex_t lock; | | 467 | kmutex_t lock; |
472 | struct sliwin window; | | 468 | struct sliwin window; |
473 | } *wgs_recvwin; | | 469 | } *wgs_recvwin; |
474 | | | 470 | |
| @@ -527,38 +523,32 @@ struct wg_ppsratecheck { | | | @@ -527,38 +523,32 @@ struct wg_ppsratecheck { |
527 | | | 523 | |
528 | struct wg_softc; | | 524 | struct wg_softc; |
529 | struct wg_peer { | | 525 | struct wg_peer { |
530 | struct wg_softc *wgp_sc; | | 526 | struct wg_softc *wgp_sc; |
531 | char wgp_name[WG_PEER_NAME_MAXLEN + 1]; | | 527 | char wgp_name[WG_PEER_NAME_MAXLEN + 1]; |
532 | struct pslist_entry wgp_peerlist_entry; | | 528 | struct pslist_entry wgp_peerlist_entry; |
533 | pserialize_t wgp_psz; | | 529 | pserialize_t wgp_psz; |
534 | struct psref_target wgp_psref; | | 530 | struct psref_target wgp_psref; |
535 | kmutex_t *wgp_lock; | | 531 | kmutex_t *wgp_lock; |
536 | | | 532 | |
537 | uint8_t wgp_pubkey[WG_STATIC_KEY_LEN]; | | 533 | uint8_t wgp_pubkey[WG_STATIC_KEY_LEN]; |
538 | struct wg_sockaddr *wgp_endpoint; | | 534 | struct wg_sockaddr *wgp_endpoint; |
539 | struct wg_sockaddr *wgp_endpoint0; | | 535 | struct wg_sockaddr *wgp_endpoint0; |
540 | bool wgp_endpoint_changing; | | 536 | volatile unsigned wgp_endpoint_changing; |
541 | bool wgp_endpoint_available; | | 537 | bool wgp_endpoint_available; |
542 | | | 538 | |
543 | /* The preshared key (optional) */ | | 539 | /* The preshared key (optional) */ |
544 | uint8_t wgp_psk[WG_PRESHARED_KEY_LEN]; | | 540 | uint8_t wgp_psk[WG_PRESHARED_KEY_LEN]; |
545 | | | 541 | |
546 | int wgp_state; | | | |
547 | #define WGP_STATE_INIT 0 | | | |
548 | #define WGP_STATE_ESTABLISHED 1 | | | |
549 | #define WGP_STATE_GIVEUP 2 | | | |
550 | #define WGP_STATE_DESTROYING 3 | | | |
551 | | | | |
552 | void *wgp_si; | | 542 | void *wgp_si; |
553 | pcq_t *wgp_q; | | 543 | pcq_t *wgp_q; |
554 | | | 544 | |
555 | struct wg_session *wgp_session_stable; | | 545 | struct wg_session *wgp_session_stable; |
556 | struct wg_session *wgp_session_unstable; | | 546 | struct wg_session *wgp_session_unstable; |
557 | | | 547 | |
558 | /* timestamp in big-endian */ | | 548 | /* timestamp in big-endian */ |
559 | wg_timestamp_t wgp_timestamp_latest_init; | | 549 | wg_timestamp_t wgp_timestamp_latest_init; |
560 | | | 550 | |
561 | struct timespec wgp_last_handshake_time; | | 551 | struct timespec wgp_last_handshake_time; |
562 | | | 552 | |
563 | callout_t wgp_rekey_timer; | | 553 | callout_t wgp_rekey_timer; |
564 | callout_t wgp_handshake_timeout_timer; | | 554 | callout_t wgp_handshake_timeout_timer; |
| @@ -575,29 +565,31 @@ struct wg_peer { | | | @@ -575,29 +565,31 @@ struct wg_peer { |
575 | bool wgp_last_sent_mac1_valid; | | 565 | bool wgp_last_sent_mac1_valid; |
576 | uint8_t wgp_last_sent_cookie[WG_COOKIE_LEN]; | | 566 | uint8_t wgp_last_sent_cookie[WG_COOKIE_LEN]; |
577 | bool wgp_last_sent_cookie_valid; | | 567 | bool wgp_last_sent_cookie_valid; |
578 | | | 568 | |
579 | time_t wgp_last_msg_received_time[WG_MSG_TYPE_MAX]; | | 569 | time_t wgp_last_msg_received_time[WG_MSG_TYPE_MAX]; |
580 | | | 570 | |
581 | time_t wgp_last_genrandval_time; | | 571 | time_t wgp_last_genrandval_time; |
582 | uint32_t wgp_randval; | | 572 | uint32_t wgp_randval; |
583 | | | 573 | |
584 | struct wg_ppsratecheck wgp_ppsratecheck; | | 574 | struct wg_ppsratecheck wgp_ppsratecheck; |
585 | | | 575 | |
586 | volatile unsigned int wgp_tasks; | | 576 | volatile unsigned int wgp_tasks; |
587 | #define WGP_TASK_SEND_INIT_MESSAGE __BIT(0) | | 577 | #define WGP_TASK_SEND_INIT_MESSAGE __BIT(0) |
588 | #define WGP_TASK_ENDPOINT_CHANGED __BIT(1) | | 578 | #define WGP_TASK_RETRY_HANDSHAKE __BIT(1) |
589 | #define WGP_TASK_SEND_KEEPALIVE_MESSAGE __BIT(2) | | 579 | #define WGP_TASK_ESTABLISH_SESSION __BIT(2) |
590 | #define WGP_TASK_DESTROY_PREV_SESSION __BIT(3) | | 580 | #define WGP_TASK_ENDPOINT_CHANGED __BIT(3) |
| | | 581 | #define WGP_TASK_SEND_KEEPALIVE_MESSAGE __BIT(4) |
| | | 582 | #define WGP_TASK_DESTROY_PREV_SESSION __BIT(5) |
591 | }; | | 583 | }; |
592 | | | 584 | |
593 | struct wg_ops; | | 585 | struct wg_ops; |
594 | | | 586 | |
595 | struct wg_softc { | | 587 | struct wg_softc { |
596 | struct ifnet wg_if; | | 588 | struct ifnet wg_if; |
597 | LIST_ENTRY(wg_softc) wg_list; | | 589 | LIST_ENTRY(wg_softc) wg_list; |
598 | kmutex_t *wg_lock; | | 590 | kmutex_t *wg_lock; |
599 | krwlock_t *wg_rwlock; | | 591 | krwlock_t *wg_rwlock; |
600 | | | 592 | |
601 | uint8_t wg_privkey[WG_STATIC_KEY_LEN]; | | 593 | uint8_t wg_privkey[WG_STATIC_KEY_LEN]; |
602 | uint8_t wg_pubkey[WG_STATIC_KEY_LEN]; | | 594 | uint8_t wg_pubkey[WG_STATIC_KEY_LEN]; |
603 | | | 595 | |
| @@ -642,28 +634,28 @@ static unsigned wg_reject_after_time = W | | | @@ -642,28 +634,28 @@ static unsigned wg_reject_after_time = W |
642 | static unsigned wg_rekey_attempt_time = WG_REKEY_ATTEMPT_TIME; | | 634 | static unsigned wg_rekey_attempt_time = WG_REKEY_ATTEMPT_TIME; |
643 | static unsigned wg_rekey_timeout = WG_REKEY_TIMEOUT; | | 635 | static unsigned wg_rekey_timeout = WG_REKEY_TIMEOUT; |
644 | static unsigned wg_keepalive_timeout = WG_KEEPALIVE_TIMEOUT; | | 636 | static unsigned wg_keepalive_timeout = WG_KEEPALIVE_TIMEOUT; |
645 | | | 637 | |
646 | static struct mbuf * | | 638 | static struct mbuf * |
647 | wg_get_mbuf(size_t, size_t); | | 639 | wg_get_mbuf(size_t, size_t); |
648 | | | 640 | |
649 | static void wg_wakeup_worker(struct wg_worker *, int); | | 641 | static void wg_wakeup_worker(struct wg_worker *, int); |
650 | | | 642 | |
651 | static int wg_send_data_msg(struct wg_peer *, struct wg_session *, | | 643 | static int wg_send_data_msg(struct wg_peer *, struct wg_session *, |
652 | struct mbuf *); | | 644 | struct mbuf *); |
653 | static int wg_send_cookie_msg(struct wg_softc *, struct wg_peer *, | | 645 | static int wg_send_cookie_msg(struct wg_softc *, struct wg_peer *, |
654 | const uint32_t, const uint8_t [], const struct sockaddr *); | | 646 | const uint32_t, const uint8_t [], const struct sockaddr *); |
655 | static int wg_send_handshake_msg_resp(struct wg_softc *, | | 647 | static int wg_send_handshake_msg_resp(struct wg_softc *, struct wg_peer *, |
656 | struct wg_peer *, const struct wg_msg_init *); | | 648 | struct wg_session *, const struct wg_msg_init *); |
657 | static void wg_send_keepalive_msg(struct wg_peer *, struct wg_session *); | | 649 | static void wg_send_keepalive_msg(struct wg_peer *, struct wg_session *); |
658 | | | 650 | |
659 | static struct wg_peer * | | 651 | static struct wg_peer * |
660 | wg_pick_peer_by_sa(struct wg_softc *, const struct sockaddr *, | | 652 | wg_pick_peer_by_sa(struct wg_softc *, const struct sockaddr *, |
661 | struct psref *); | | 653 | struct psref *); |
662 | static struct wg_peer * | | 654 | static struct wg_peer * |
663 | wg_lookup_peer_by_pubkey(struct wg_softc *, | | 655 | wg_lookup_peer_by_pubkey(struct wg_softc *, |
664 | const uint8_t [], struct psref *); | | 656 | const uint8_t [], struct psref *); |
665 | | | 657 | |
666 | static struct wg_session * | | 658 | static struct wg_session * |
667 | wg_lookup_session_by_index(struct wg_softc *, | | 659 | wg_lookup_session_by_index(struct wg_softc *, |
668 | const uint32_t, struct psref *); | | 660 | const uint32_t, struct psref *); |
669 | | | 661 | |
| @@ -681,26 +673,28 @@ static void wg_clear_states(struct wg_se | | | @@ -681,26 +673,28 @@ static void wg_clear_states(struct wg_se |
681 | static void wg_get_peer(struct wg_peer *, struct psref *); | | 673 | static void wg_get_peer(struct wg_peer *, struct psref *); |
682 | static void wg_put_peer(struct wg_peer *, struct psref *); | | 674 | static void wg_put_peer(struct wg_peer *, struct psref *); |
683 | | | 675 | |
684 | static int wg_send_so(struct wg_peer *, struct mbuf *); | | 676 | static int wg_send_so(struct wg_peer *, struct mbuf *); |
685 | static int wg_send_udp(struct wg_peer *, struct mbuf *); | | 677 | static int wg_send_udp(struct wg_peer *, struct mbuf *); |
686 | static int wg_output(struct ifnet *, struct mbuf *, | | 678 | static int wg_output(struct ifnet *, struct mbuf *, |
687 | const struct sockaddr *, const struct rtentry *); | | 679 | const struct sockaddr *, const struct rtentry *); |
688 | static void wg_input(struct ifnet *, struct mbuf *, const int); | | 680 | static void wg_input(struct ifnet *, struct mbuf *, const int); |
689 | static int wg_ioctl(struct ifnet *, u_long, void *); | | 681 | static int wg_ioctl(struct ifnet *, u_long, void *); |
690 | static int wg_bind_port(struct wg_softc *, const uint16_t); | | 682 | static int wg_bind_port(struct wg_softc *, const uint16_t); |
691 | static int wg_init(struct ifnet *); | | 683 | static int wg_init(struct ifnet *); |
692 | static void wg_stop(struct ifnet *, int); | | 684 | static void wg_stop(struct ifnet *, int); |
693 | | | 685 | |
| | | 686 | static void wg_purge_pending_packets(struct wg_peer *); |
| | | 687 | |
694 | static int wg_clone_create(struct if_clone *, int); | | 688 | static int wg_clone_create(struct if_clone *, int); |
695 | static int wg_clone_destroy(struct ifnet *); | | 689 | static int wg_clone_destroy(struct ifnet *); |
696 | | | 690 | |
697 | struct wg_ops { | | 691 | struct wg_ops { |
698 | int (*send_hs_msg)(struct wg_peer *, struct mbuf *); | | 692 | int (*send_hs_msg)(struct wg_peer *, struct mbuf *); |
699 | int (*send_data_msg)(struct wg_peer *, struct mbuf *); | | 693 | int (*send_data_msg)(struct wg_peer *, struct mbuf *); |
700 | void (*input)(struct ifnet *, struct mbuf *, const int); | | 694 | void (*input)(struct ifnet *, struct mbuf *, const int); |
701 | int (*bind_port)(struct wg_softc *, const uint16_t); | | 695 | int (*bind_port)(struct wg_softc *, const uint16_t); |
702 | }; | | 696 | }; |
703 | | | 697 | |
704 | struct wg_ops wg_ops_rumpkernel = { | | 698 | struct wg_ops wg_ops_rumpkernel = { |
705 | .send_hs_msg = wg_send_so, | | 699 | .send_hs_msg = wg_send_so, |
706 | .send_data_msg = wg_send_udp, | | 700 | .send_data_msg = wg_send_udp, |
| @@ -1090,131 +1084,142 @@ wg_algo_tai64n(wg_timestamp_t timestamp) | | | @@ -1090,131 +1084,142 @@ wg_algo_tai64n(wg_timestamp_t timestamp) |
1090 | { | | 1084 | { |
1091 | struct timespec ts; | | 1085 | struct timespec ts; |
1092 | | | 1086 | |
1093 | /* FIXME strict TAI64N (https://cr.yp.to/libtai/tai64.html) */ | | 1087 | /* FIXME strict TAI64N (https://cr.yp.to/libtai/tai64.html) */ |
1094 | getnanotime(&ts); | | 1088 | getnanotime(&ts); |
1095 | /* TAI64 label in external TAI64 format */ | | 1089 | /* TAI64 label in external TAI64 format */ |
1096 | be32enc(timestamp, 0x40000000UL + (ts.tv_sec >> 32)); | | 1090 | be32enc(timestamp, 0x40000000UL + (ts.tv_sec >> 32)); |
1097 | /* second beginning from 1970 TAI */ | | 1091 | /* second beginning from 1970 TAI */ |
1098 | be32enc(timestamp + 4, ts.tv_sec & 0xffffffffU); | | 1092 | be32enc(timestamp + 4, ts.tv_sec & 0xffffffffU); |
1099 | /* nanosecond in big-endian format */ | | 1093 | /* nanosecond in big-endian format */ |
1100 | be32enc(timestamp + 8, ts.tv_nsec); | | 1094 | be32enc(timestamp + 8, ts.tv_nsec); |
1101 | } | | 1095 | } |
1102 | | | 1096 | |
1103 | static struct wg_session * | | 1097 | /* |
1104 | wg_get_unstable_session(struct wg_peer *wgp, struct psref *psref) | | 1098 | * wg_get_stable_session(wgp, psref) |
1105 | { | | 1099 | * |
1106 | int s; | | 1100 | * Get a passive reference to the current stable session, or |
1107 | struct wg_session *wgs; | | 1101 | * return NULL if there is no current stable session. |
1108 | | | 1102 | * |
1109 | s = pserialize_read_enter(); | | 1103 | * The pointer is always there but the session is not necessarily |
1110 | wgs = wgp->wgp_session_unstable; | | 1104 | * ESTABLISHED; if it is not ESTABLISHED, return NULL. However, |
1111 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); | | 1105 | * the session may transition from ESTABLISHED to DESTROYING while |
1112 | pserialize_read_exit(s); | | 1106 | * holding the passive reference. |
1113 | return wgs; | | 1107 | */ |
1114 | } | | | |
1115 | | | | |
1116 | static struct wg_session * | | 1108 | static struct wg_session * |
1117 | wg_get_stable_session(struct wg_peer *wgp, struct psref *psref) | | 1109 | wg_get_stable_session(struct wg_peer *wgp, struct psref *psref) |
1118 | { | | 1110 | { |
1119 | int s; | | 1111 | int s; |
1120 | struct wg_session *wgs; | | 1112 | struct wg_session *wgs; |
1121 | | | 1113 | |
1122 | s = pserialize_read_enter(); | | 1114 | s = pserialize_read_enter(); |
1123 | wgs = wgp->wgp_session_stable; | | 1115 | wgs = atomic_load_consume(&wgp->wgp_session_stable); |
1124 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); | | 1116 | if (__predict_false(wgs->wgs_state != WGS_STATE_ESTABLISHED)) |
| | | 1117 | wgs = NULL; |
| | | 1118 | else |
| | | 1119 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); |
1125 | pserialize_read_exit(s); | | 1120 | pserialize_read_exit(s); |
1126 | return wgs; | | | |
1127 | } | | | |
1128 | | | | |
1129 | static void | | | |
1130 | wg_get_session(struct wg_session *wgs, struct psref *psref) | | | |
1131 | { | | | |
1132 | | | 1121 | |
1133 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); | | 1122 | return wgs; |
1134 | } | | 1123 | } |
1135 | | | 1124 | |
1136 | static void | | 1125 | static void |
1137 | wg_put_session(struct wg_session *wgs, struct psref *psref) | | 1126 | wg_put_session(struct wg_session *wgs, struct psref *psref) |
1138 | { | | 1127 | { |
1139 | | | 1128 | |
1140 | psref_release(psref, &wgs->wgs_psref, wg_psref_class); | | 1129 | psref_release(psref, &wgs->wgs_psref, wg_psref_class); |
1141 | } | | 1130 | } |
1142 | | | 1131 | |
1143 | static struct wg_session * | | 1132 | static void |
1144 | wg_lock_unstable_session(struct wg_peer *wgp) | | 1133 | wg_destroy_session(struct wg_softc *wg, struct wg_session *wgs) |
1145 | { | | 1134 | { |
1146 | struct wg_session *wgs; | | 1135 | struct wg_peer *wgp = wgs->wgs_peer; |
| | | 1136 | struct wg_session *wgs0 __diagused; |
| | | 1137 | void *garbage; |
1147 | | | 1138 | |
1148 | mutex_enter(wgp->wgp_lock); | | 1139 | KASSERT(mutex_owned(wgp->wgp_lock)); |
1149 | wgs = wgp->wgp_session_unstable; | | 1140 | KASSERT(wgs->wgs_state != WGS_STATE_UNKNOWN); |
1150 | mutex_enter(wgs->wgs_lock); | | | |
1151 | mutex_exit(wgp->wgp_lock); | | | |
1152 | return wgs; | | | |
1153 | } | | | |
1154 | | | 1141 | |
1155 | #if 0 | | 1142 | /* Remove the session from the table. */ |
1156 | static void | | 1143 | wgs0 = thmap_del(wg->wg_sessions_byindex, |
1157 | wg_unlock_session(struct wg_peer *wgp, struct wg_session *wgs) | | 1144 | &wgs->wgs_local_index, sizeof(wgs->wgs_local_index)); |
1158 | { | | 1145 | KASSERT(wgs0 == wgs); |
| | | 1146 | garbage = thmap_stage_gc(wg->wg_sessions_byindex); |
| | | 1147 | |
| | | 1148 | /* Wait for passive references to drain. */ |
| | | 1149 | pserialize_perform(wgp->wgp_psz); |
| | | 1150 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); |
1159 | | | 1151 | |
1160 | mutex_exit(wgs->wgs_lock); | | 1152 | /* Free memory, zero state, and transition to UNKNOWN. */ |
| | | 1153 | thmap_gc(wg->wg_sessions_byindex, garbage); |
| | | 1154 | wg_clear_states(wgs); |
| | | 1155 | wgs->wgs_state = WGS_STATE_UNKNOWN; |
1161 | } | | 1156 | } |
1162 | #endif | | | |
1163 | | | 1157 | |
1164 | static uint32_t | | 1158 | /* |
1165 | wg_assign_sender_index(struct wg_softc *wg, struct wg_session *wgs) | | 1159 | * wg_get_session_index(wg, wgs) |
| | | 1160 | * |
| | | 1161 | * Choose a session index for wgs->wgs_local_index, and store it |
| | | 1162 | * in wg's table of sessions by index. |
| | | 1163 | * |
| | | 1164 | * wgs must be the unstable session of its peer, and must be |
| | | 1165 | * transitioning out of the UNKNOWN state. |
| | | 1166 | */ |
| | | 1167 | static void |
| | | 1168 | wg_get_session_index(struct wg_softc *wg, struct wg_session *wgs) |
1166 | { | | 1169 | { |
1167 | struct wg_peer *wgp = wgs->wgs_peer; | | 1170 | struct wg_peer *wgp __diagused = wgs->wgs_peer; |
1168 | struct wg_session *wgs0; | | 1171 | struct wg_session *wgs0; |
1169 | uint32_t index; | | 1172 | uint32_t index; |
1170 | void *garbage; | | | |
1171 | | | 1173 | |
1172 | mutex_enter(wgs->wgs_lock); | | 1174 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 1175 | KASSERT(wgs == wgp->wgp_session_unstable); |
| | | 1176 | KASSERT(wgs->wgs_state == WGS_STATE_UNKNOWN); |
1173 | | | 1177 | |
1174 | /* Release the current index, if there is one. */ | | 1178 | do { |
1175 | while ((index = wgs->wgs_sender_index) != 0) { | | 1179 | /* Pick a uniform random index. */ |
1176 | /* Remove the session by index. */ | | 1180 | index = cprng_strong32(); |
1177 | thmap_del(wg->wg_sessions_byindex, &index, sizeof index); | | 1181 | |
1178 | wgs->wgs_sender_index = 0; | | 1182 | /* Try to take it. */ |
1179 | mutex_exit(wgs->wgs_lock); | | 1183 | wgs->wgs_local_index = index; |
1180 | | | 1184 | wgs0 = thmap_put(wg->wg_sessions_byindex, |
1181 | /* Wait for all thmap_gets to complete, and GC. */ | | 1185 | &wgs->wgs_local_index, sizeof wgs->wgs_local_index, wgs); |
1182 | garbage = thmap_stage_gc(wg->wg_sessions_byindex); | | | |
1183 | mutex_enter(wgs->wgs_peer->wgp_lock); | | | |
1184 | pserialize_perform(wgp->wgp_psz); | | | |
1185 | mutex_exit(wgs->wgs_peer->wgp_lock); | | | |
1186 | thmap_gc(wg->wg_sessions_byindex, garbage); | | | |
1187 | | | 1186 | |
1188 | mutex_enter(wgs->wgs_lock); | | 1187 | /* If someone else beat us, start over. */ |
1189 | } | | 1188 | } while (__predict_false(wgs0 != wgs)); |
| | | 1189 | } |
1190 | | | 1190 | |
1191 | restart: | | 1191 | /* |
1192 | /* Pick a uniform random nonzero index. */ | | 1192 | * wg_put_session_index(wg, wgs) |
1193 | while (__predict_false((index = cprng_strong32()) == 0)) | | 1193 | * |
1194 | continue; | | 1194 | * Remove wgs from the table of sessions by index, wait for any |
1195 | | | 1195 | * passive references to drain, and transition the session to the |
1196 | /* Try to take it. */ | | 1196 | * UNKNOWN state. |
1197 | wgs->wgs_sender_index = index; | | 1197 | * |
1198 | wgs0 = thmap_put(wg->wg_sessions_byindex, | | 1198 | * wgs must be the unstable session of its peer, and must not be |
1199 | &wgs->wgs_sender_index, sizeof wgs->wgs_sender_index, wgs); | | 1199 | * UNKNOWN or ESTABLISHED. |
1200 | | | 1200 | */ |
1201 | /* If someone else beat us, start over. */ | | 1201 | static void |
1202 | if (__predict_false(wgs0 != wgs)) | | 1202 | wg_put_session_index(struct wg_softc *wg, struct wg_session *wgs) |
1203 | goto restart; | | 1203 | { |
| | | 1204 | struct wg_peer *wgp = wgs->wgs_peer; |
1204 | | | 1205 | |
1205 | mutex_exit(wgs->wgs_lock); | | 1206 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 1207 | KASSERT(wgs == wgp->wgp_session_unstable); |
| | | 1208 | KASSERT(wgs->wgs_state != WGS_STATE_UNKNOWN); |
| | | 1209 | KASSERT(wgs->wgs_state != WGS_STATE_ESTABLISHED); |
1206 | | | 1210 | |
1207 | return index; | | 1211 | wg_destroy_session(wg, wgs); |
| | | 1212 | psref_target_init(&wgs->wgs_psref, wg_psref_class); |
1208 | } | | 1213 | } |
1209 | | | 1214 | |
1210 | /* | | 1215 | /* |
1211 | * Handshake patterns | | 1216 | * Handshake patterns |
1212 | * | | 1217 | * |
1213 | * [W] 5: "These messages use the "IK" pattern from Noise" | | 1218 | * [W] 5: "These messages use the "IK" pattern from Noise" |
1214 | * [N] 7.5. Interactive handshake patterns (fundamental) | | 1219 | * [N] 7.5. Interactive handshake patterns (fundamental) |
1215 | * "The first character refers to the initiator’s static key:" | | 1220 | * "The first character refers to the initiator’s static key:" |
1216 | * "I = Static key for initiator Immediately transmitted to responder, | | 1221 | * "I = Static key for initiator Immediately transmitted to responder, |
1217 | * despite reduced or absent identity hiding" | | 1222 | * despite reduced or absent identity hiding" |
1218 | * "The second character refers to the responder’s static key:" | | 1223 | * "The second character refers to the responder’s static key:" |
1219 | * "K = Static key for responder Known to initiator" | | 1224 | * "K = Static key for responder Known to initiator" |
1220 | * "IK: | | 1225 | * "IK: |
| @@ -1229,28 +1234,32 @@ restart: | | | @@ -1229,28 +1234,32 @@ restart: |
1229 | * -> e, es, s, ss | | 1234 | * -> e, es, s, ss |
1230 | * <- e, ee, se, psk" | | 1235 | * <- e, ee, se, psk" |
1231 | */ | | 1236 | */ |
1232 | static void | | 1237 | static void |
1233 | wg_fill_msg_init(struct wg_softc *wg, struct wg_peer *wgp, | | 1238 | wg_fill_msg_init(struct wg_softc *wg, struct wg_peer *wgp, |
1234 | struct wg_session *wgs, struct wg_msg_init *wgmi) | | 1239 | struct wg_session *wgs, struct wg_msg_init *wgmi) |
1235 | { | | 1240 | { |
1236 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ | | 1241 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ |
1237 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ | | 1242 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ |
1238 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; | | 1243 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; |
1239 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; | | 1244 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; |
1240 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; | | 1245 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; |
1241 | | | 1246 | |
| | | 1247 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 1248 | KASSERT(wgs == wgp->wgp_session_unstable); |
| | | 1249 | KASSERT(wgs->wgs_state == WGS_STATE_INIT_ACTIVE); |
| | | 1250 | |
1242 | wgmi->wgmi_type = htole32(WG_MSG_TYPE_INIT); | | 1251 | wgmi->wgmi_type = htole32(WG_MSG_TYPE_INIT); |
1243 | wgmi->wgmi_sender = wg_assign_sender_index(wg, wgs); | | 1252 | wgmi->wgmi_sender = wgs->wgs_local_index; |
1244 | | | 1253 | |
1245 | /* [W] 5.4.2: First Message: Initiator to Responder */ | | 1254 | /* [W] 5.4.2: First Message: Initiator to Responder */ |
1246 | | | 1255 | |
1247 | /* Ci := HASH(CONSTRUCTION) */ | | 1256 | /* Ci := HASH(CONSTRUCTION) */ |
1248 | /* Hi := HASH(Ci || IDENTIFIER) */ | | 1257 | /* Hi := HASH(Ci || IDENTIFIER) */ |
1249 | wg_init_key_and_hash(ckey, hash); | | 1258 | wg_init_key_and_hash(ckey, hash); |
1250 | /* Hi := HASH(Hi || Sr^pub) */ | | 1259 | /* Hi := HASH(Hi || Sr^pub) */ |
1251 | wg_algo_hash(hash, wgp->wgp_pubkey, sizeof(wgp->wgp_pubkey)); | | 1260 | wg_algo_hash(hash, wgp->wgp_pubkey, sizeof(wgp->wgp_pubkey)); |
1252 | | | 1261 | |
1253 | WG_DUMP_HASH("hash", hash); | | 1262 | WG_DUMP_HASH("hash", hash); |
1254 | | | 1263 | |
1255 | /* [N] 2.2: "e" */ | | 1264 | /* [N] 2.2: "e" */ |
1256 | /* Ei^priv, Ei^pub := DH-GENERATE() */ | | 1265 | /* Ei^priv, Ei^pub := DH-GENERATE() */ |
| @@ -1305,42 +1314,41 @@ wg_fill_msg_init(struct wg_softc *wg, st | | | @@ -1305,42 +1314,41 @@ wg_fill_msg_init(struct wg_softc *wg, st |
1305 | memset(wgmi->wgmi_mac2, 0, sizeof(wgmi->wgmi_mac2)); | | 1314 | memset(wgmi->wgmi_mac2, 0, sizeof(wgmi->wgmi_mac2)); |
1306 | else { | | 1315 | else { |
1307 | wg_algo_mac(wgmi->wgmi_mac2, sizeof(wgmi->wgmi_mac2), | | 1316 | wg_algo_mac(wgmi->wgmi_mac2, sizeof(wgmi->wgmi_mac2), |
1308 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, | | 1317 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, |
1309 | (const uint8_t *)wgmi, | | 1318 | (const uint8_t *)wgmi, |
1310 | offsetof(struct wg_msg_init, wgmi_mac2), | | 1319 | offsetof(struct wg_msg_init, wgmi_mac2), |
1311 | NULL, 0); | | 1320 | NULL, 0); |
1312 | } | | 1321 | } |
1313 | | | 1322 | |
1314 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); | | 1323 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); |
1315 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); | | 1324 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); |
1316 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); | | 1325 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); |
1317 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); | | 1326 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); |
1318 | WG_DLOG("%s: sender=%x\n", __func__, wgs->wgs_sender_index); | | 1327 | WG_DLOG("%s: sender=%x\n", __func__, wgs->wgs_local_index); |
1319 | } | | 1328 | } |
1320 | | | 1329 | |
1321 | static void | | 1330 | static void |
1322 | wg_handle_msg_init(struct wg_softc *wg, const struct wg_msg_init *wgmi, | | 1331 | wg_handle_msg_init(struct wg_softc *wg, const struct wg_msg_init *wgmi, |
1323 | const struct sockaddr *src) | | 1332 | const struct sockaddr *src) |
1324 | { | | 1333 | { |
1325 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ | | 1334 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ |
1326 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ | | 1335 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ |
1327 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; | | 1336 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; |
1328 | uint8_t peer_pubkey[WG_STATIC_KEY_LEN]; | | 1337 | uint8_t peer_pubkey[WG_STATIC_KEY_LEN]; |
1329 | struct wg_peer *wgp; | | 1338 | struct wg_peer *wgp; |
1330 | struct wg_session *wgs; | | 1339 | struct wg_session *wgs; |
1331 | int error, ret; | | 1340 | int error, ret; |
1332 | struct psref psref_peer; | | 1341 | struct psref psref_peer; |
1333 | struct psref psref_session; | | | |
1334 | uint8_t mac1[WG_MAC_LEN]; | | 1342 | uint8_t mac1[WG_MAC_LEN]; |
1335 | | | 1343 | |
1336 | WG_TRACE("init msg received"); | | 1344 | WG_TRACE("init msg received"); |
1337 | | | 1345 | |
1338 | wg_algo_mac_mac1(mac1, sizeof(mac1), | | 1346 | wg_algo_mac_mac1(mac1, sizeof(mac1), |
1339 | wg->wg_pubkey, sizeof(wg->wg_pubkey), | | 1347 | wg->wg_pubkey, sizeof(wg->wg_pubkey), |
1340 | (const uint8_t *)wgmi, offsetof(struct wg_msg_init, wgmi_mac1)); | | 1348 | (const uint8_t *)wgmi, offsetof(struct wg_msg_init, wgmi_mac1)); |
1341 | | | 1349 | |
1342 | /* | | 1350 | /* |
1343 | * [W] 5.3: Denial of Service Mitigation & Cookies | | 1351 | * [W] 5.3: Denial of Service Mitigation & Cookies |
1344 | * "the responder, ..., must always reject messages with an invalid | | 1352 | * "the responder, ..., must always reject messages with an invalid |
1345 | * msg.mac1" | | 1353 | * msg.mac1" |
1346 | */ | | 1354 | */ |
| @@ -1388,153 +1396,145 @@ wg_handle_msg_init(struct wg_softc *wg, | | | @@ -1388,153 +1396,145 @@ wg_handle_msg_init(struct wg_softc *wg, |
1388 | WG_LOG_RATECHECK(&wg->wg_ppsratecheck, LOG_DEBUG, | | 1396 | WG_LOG_RATECHECK(&wg->wg_ppsratecheck, LOG_DEBUG, |
1389 | "wg_algo_aead_dec for secret key failed\n"); | | 1397 | "wg_algo_aead_dec for secret key failed\n"); |
1390 | return; | | 1398 | return; |
1391 | } | | 1399 | } |
1392 | /* Hi := HASH(Hi || msg.static) */ | | 1400 | /* Hi := HASH(Hi || msg.static) */ |
1393 | wg_algo_hash(hash, wgmi->wgmi_static, sizeof(wgmi->wgmi_static)); | | 1401 | wg_algo_hash(hash, wgmi->wgmi_static, sizeof(wgmi->wgmi_static)); |
1394 | | | 1402 | |
1395 | wgp = wg_lookup_peer_by_pubkey(wg, peer_pubkey, &psref_peer); | | 1403 | wgp = wg_lookup_peer_by_pubkey(wg, peer_pubkey, &psref_peer); |
1396 | if (wgp == NULL) { | | 1404 | if (wgp == NULL) { |
1397 | WG_DLOG("peer not found\n"); | | 1405 | WG_DLOG("peer not found\n"); |
1398 | return; | | 1406 | return; |
1399 | } | | 1407 | } |
1400 | | | 1408 | |
| | | 1409 | /* |
| | | 1410 | * Lock the peer to serialize access to cookie state. |
| | | 1411 | * |
| | | 1412 | * XXX Can we safely avoid holding the lock across DH? Take it |
| | | 1413 | * just to verify mac2 and then unlock/DH/lock? |
| | | 1414 | */ |
| | | 1415 | mutex_enter(wgp->wgp_lock); |
| | | 1416 | |
1401 | if (__predict_false(wg_is_underload(wg, wgp, WG_MSG_TYPE_INIT))) { | | 1417 | if (__predict_false(wg_is_underload(wg, wgp, WG_MSG_TYPE_INIT))) { |
1402 | WG_TRACE("under load"); | | 1418 | WG_TRACE("under load"); |
1403 | /* | | 1419 | /* |
1404 | * [W] 5.3: Denial of Service Mitigation & Cookies | | 1420 | * [W] 5.3: Denial of Service Mitigation & Cookies |
1405 | * "the responder, ..., and when under load may reject messages | | 1421 | * "the responder, ..., and when under load may reject messages |
1406 | * with an invalid msg.mac2. If the responder receives a | | 1422 | * with an invalid msg.mac2. If the responder receives a |
1407 | * message with a valid msg.mac1 yet with an invalid msg.mac2, | | 1423 | * message with a valid msg.mac1 yet with an invalid msg.mac2, |
1408 | * and is under load, it may respond with a cookie reply | | 1424 | * and is under load, it may respond with a cookie reply |
1409 | * message" | | 1425 | * message" |
1410 | */ | | 1426 | */ |
1411 | uint8_t zero[WG_MAC_LEN] = {0}; | | 1427 | uint8_t zero[WG_MAC_LEN] = {0}; |
1412 | if (consttime_memequal(wgmi->wgmi_mac2, zero, sizeof(zero))) { | | 1428 | if (consttime_memequal(wgmi->wgmi_mac2, zero, sizeof(zero))) { |
1413 | WG_TRACE("sending a cookie message: no cookie included"); | | 1429 | WG_TRACE("sending a cookie message: no cookie included"); |
1414 | (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender, | | 1430 | (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender, |
1415 | wgmi->wgmi_mac1, src); | | 1431 | wgmi->wgmi_mac1, src); |
1416 | goto out_wgp; | | 1432 | goto out; |
1417 | } | | 1433 | } |
1418 | if (!wgp->wgp_last_sent_cookie_valid) { | | 1434 | if (!wgp->wgp_last_sent_cookie_valid) { |
1419 | WG_TRACE("sending a cookie message: no cookie sent ever"); | | 1435 | WG_TRACE("sending a cookie message: no cookie sent ever"); |
1420 | (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender, | | 1436 | (void)wg_send_cookie_msg(wg, wgp, wgmi->wgmi_sender, |
1421 | wgmi->wgmi_mac1, src); | | 1437 | wgmi->wgmi_mac1, src); |
1422 | goto out_wgp; | | 1438 | goto out; |
1423 | } | | 1439 | } |
1424 | uint8_t mac2[WG_MAC_LEN]; | | 1440 | uint8_t mac2[WG_MAC_LEN]; |
1425 | wg_algo_mac(mac2, sizeof(mac2), wgp->wgp_last_sent_cookie, | | 1441 | wg_algo_mac(mac2, sizeof(mac2), wgp->wgp_last_sent_cookie, |
1426 | WG_COOKIE_LEN, (const uint8_t *)wgmi, | | 1442 | WG_COOKIE_LEN, (const uint8_t *)wgmi, |
1427 | offsetof(struct wg_msg_init, wgmi_mac2), NULL, 0); | | 1443 | offsetof(struct wg_msg_init, wgmi_mac2), NULL, 0); |
1428 | if (!consttime_memequal(mac2, wgmi->wgmi_mac2, sizeof(mac2))) { | | 1444 | if (!consttime_memequal(mac2, wgmi->wgmi_mac2, sizeof(mac2))) { |
1429 | WG_DLOG("mac2 is invalid\n"); | | 1445 | WG_DLOG("mac2 is invalid\n"); |
1430 | goto out_wgp; | | 1446 | goto out; |
1431 | } | | 1447 | } |
1432 | WG_TRACE("under load, but continue to sending"); | | 1448 | WG_TRACE("under load, but continue to sending"); |
1433 | } | | 1449 | } |
1434 | | | 1450 | |
1435 | /* [N] 2.2: "ss" */ | | 1451 | /* [N] 2.2: "ss" */ |
1436 | /* Ci, k := KDF2(Ci, DH(Si^priv, Sr^pub)) */ | | 1452 | /* Ci, k := KDF2(Ci, DH(Si^priv, Sr^pub)) */ |
1437 | wg_algo_dh_kdf(ckey, cipher_key, wg->wg_privkey, wgp->wgp_pubkey); | | 1453 | wg_algo_dh_kdf(ckey, cipher_key, wg->wg_privkey, wgp->wgp_pubkey); |
1438 | | | 1454 | |
1439 | /* msg.timestamp := AEAD(k, TIMESTAMP(), Hi) */ | | 1455 | /* msg.timestamp := AEAD(k, TIMESTAMP(), Hi) */ |
1440 | wg_timestamp_t timestamp; | | 1456 | wg_timestamp_t timestamp; |
1441 | error = wg_algo_aead_dec(timestamp, sizeof(timestamp), cipher_key, 0, | | 1457 | error = wg_algo_aead_dec(timestamp, sizeof(timestamp), cipher_key, 0, |
1442 | wgmi->wgmi_timestamp, sizeof(wgmi->wgmi_timestamp), | | 1458 | wgmi->wgmi_timestamp, sizeof(wgmi->wgmi_timestamp), |
1443 | hash, sizeof(hash)); | | 1459 | hash, sizeof(hash)); |
1444 | if (error != 0) { | | 1460 | if (error != 0) { |
1445 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 1461 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
1446 | "wg_algo_aead_dec for timestamp failed\n"); | | 1462 | "wg_algo_aead_dec for timestamp failed\n"); |
1447 | goto out_wgp; | | 1463 | goto out; |
1448 | } | | 1464 | } |
1449 | /* Hi := HASH(Hi || msg.timestamp) */ | | 1465 | /* Hi := HASH(Hi || msg.timestamp) */ |
1450 | wg_algo_hash(hash, wgmi->wgmi_timestamp, sizeof(wgmi->wgmi_timestamp)); | | 1466 | wg_algo_hash(hash, wgmi->wgmi_timestamp, sizeof(wgmi->wgmi_timestamp)); |
1451 | | | 1467 | |
1452 | wgs = wg_lock_unstable_session(wgp); | | | |
1453 | if (wgs->wgs_state == WGS_STATE_DESTROYING) { | | | |
1454 | /* | | | |
1455 | * We can assume that the peer doesn't have an | | | |
1456 | * established session, so clear it now. If the timer | | | |
1457 | * fired, tough -- it won't have any effect unless we | | | |
1458 | * manage to transition back to WGS_STATE_DESTROYING. | | | |
1459 | */ | | | |
1460 | WG_TRACE("Session destroying, but force to clear"); | | | |
1461 | callout_stop(&wgp->wgp_session_dtor_timer); | | | |
1462 | wg_clear_states(wgs); | | | |
1463 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | | |
1464 | } | | | |
1465 | if (wgs->wgs_state == WGS_STATE_INIT_ACTIVE) { | | | |
1466 | WG_TRACE("Sesssion already initializing, ignoring the message"); | | | |
1467 | mutex_exit(wgs->wgs_lock); | | | |
1468 | goto out_wgp; | | | |
1469 | } | | | |
1470 | if (wgs->wgs_state == WGS_STATE_INIT_PASSIVE) { | | | |
1471 | WG_TRACE("Sesssion already initializing, destroying old states"); | | | |
1472 | wg_clear_states(wgs); | | | |
1473 | } | | | |
1474 | wgs->wgs_state = WGS_STATE_INIT_PASSIVE; | | | |
1475 | wg_get_session(wgs, &psref_session); | | | |
1476 | mutex_exit(wgs->wgs_lock); | | | |
1477 | | | | |
1478 | /* | | 1468 | /* |
1479 | * [W] 5.1 "The responder keeps track of the greatest timestamp | | 1469 | * [W] 5.1 "The responder keeps track of the greatest timestamp |
1480 | * received per peer and discards packets containing | | 1470 | * received per peer and discards packets containing |
1481 | * timestamps less than or equal to it." | | 1471 | * timestamps less than or equal to it." |
1482 | */ | | 1472 | */ |
1483 | ret = memcmp(timestamp, wgp->wgp_timestamp_latest_init, | | 1473 | ret = memcmp(timestamp, wgp->wgp_timestamp_latest_init, |
1484 | sizeof(timestamp)); | | 1474 | sizeof(timestamp)); |
1485 | if (ret <= 0) { | | 1475 | if (ret <= 0) { |
1486 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 1476 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
1487 | "invalid init msg: timestamp is old\n"); | | 1477 | "invalid init msg: timestamp is old\n"); |
1488 | goto out; | | 1478 | goto out; |
1489 | } | | 1479 | } |
1490 | memcpy(wgp->wgp_timestamp_latest_init, timestamp, sizeof(timestamp)); | | 1480 | memcpy(wgp->wgp_timestamp_latest_init, timestamp, sizeof(timestamp)); |
1491 | | | 1481 | |
| | | 1482 | /* |
| | | 1483 | * Message is good -- we're committing to handle it now, unless |
| | | 1484 | * we were already initiating a session. |
| | | 1485 | */ |
| | | 1486 | wgs = wgp->wgp_session_unstable; |
| | | 1487 | switch (wgs->wgs_state) { |
| | | 1488 | case WGS_STATE_UNKNOWN: /* new session initiated by peer */ |
| | | 1489 | wg_get_session_index(wg, wgs); |
| | | 1490 | break; |
| | | 1491 | case WGS_STATE_INIT_ACTIVE: /* we're already initiating, drop */ |
| | | 1492 | WG_TRACE("Session already initializing, ignoring the message"); |
| | | 1493 | goto out; |
| | | 1494 | case WGS_STATE_INIT_PASSIVE: /* peer is retrying, start over */ |
| | | 1495 | WG_TRACE("Session already initializing, destroying old states"); |
| | | 1496 | wg_clear_states(wgs); |
| | | 1497 | /* keep session index */ |
| | | 1498 | break; |
| | | 1499 | case WGS_STATE_ESTABLISHED: /* can't happen */ |
| | | 1500 | panic("unstable session can't be established"); |
| | | 1501 | break; |
| | | 1502 | case WGS_STATE_DESTROYING: /* rekey initiated by peer */ |
| | | 1503 | WG_TRACE("Session destroying, but force to clear"); |
| | | 1504 | callout_stop(&wgp->wgp_session_dtor_timer); |
| | | 1505 | wg_clear_states(wgs); |
| | | 1506 | /* keep session index */ |
| | | 1507 | break; |
| | | 1508 | default: |
| | | 1509 | panic("invalid session state: %d", wgs->wgs_state); |
| | | 1510 | } |
| | | 1511 | wgs->wgs_state = WGS_STATE_INIT_PASSIVE; |
| | | 1512 | |
1492 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); | | 1513 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); |
1493 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); | | 1514 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); |
1494 | memcpy(wgs->wgs_ephemeral_key_peer, wgmi->wgmi_ephemeral, | | 1515 | memcpy(wgs->wgs_ephemeral_key_peer, wgmi->wgmi_ephemeral, |
1495 | sizeof(wgmi->wgmi_ephemeral)); | | 1516 | sizeof(wgmi->wgmi_ephemeral)); |
1496 | | | 1517 | |
1497 | wg_update_endpoint_if_necessary(wgp, src); | | 1518 | wg_update_endpoint_if_necessary(wgp, src); |
1498 | | | 1519 | |
1499 | (void)wg_send_handshake_msg_resp(wg, wgp, wgmi); | | 1520 | (void)wg_send_handshake_msg_resp(wg, wgp, wgs, wgmi); |
1500 | | | 1521 | |
1501 | wg_calculate_keys(wgs, false); | | 1522 | wg_calculate_keys(wgs, false); |
1502 | wg_clear_states(wgs); | | 1523 | wg_clear_states(wgs); |
1503 | | | 1524 | |
1504 | wg_put_session(wgs, &psref_session); | | | |
1505 | wg_put_peer(wgp, &psref_peer); | | | |
1506 | return; | | | |
1507 | | | | |
1508 | out: | | 1525 | out: |
1509 | mutex_enter(wgs->wgs_lock); | | | |
1510 | KASSERT(wgs->wgs_state == WGS_STATE_INIT_PASSIVE); | | | |
1511 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | | |
1512 | mutex_exit(wgs->wgs_lock); | | | |
1513 | wg_put_session(wgs, &psref_session); | | | |
1514 | out_wgp: | | | |
1515 | wg_put_peer(wgp, &psref_peer); | | | |
1516 | } | | | |
1517 | | | | |
1518 | static void | | | |
1519 | wg_schedule_handshake_timeout_timer(struct wg_peer *wgp) | | | |
1520 | { | | | |
1521 | | | | |
1522 | mutex_enter(wgp->wgp_lock); | | | |
1523 | if (__predict_true(wgp->wgp_state != WGP_STATE_DESTROYING)) { | | | |
1524 | callout_schedule(&wgp->wgp_handshake_timeout_timer, | | | |
1525 | MIN(wg_rekey_timeout, INT_MAX/hz) * hz); | | | |
1526 | } | | | |
1527 | mutex_exit(wgp->wgp_lock); | | 1526 | mutex_exit(wgp->wgp_lock); |
| | | 1527 | wg_put_peer(wgp, &psref_peer); |
1528 | } | | 1528 | } |
1529 | | | 1529 | |
1530 | static struct socket * | | 1530 | static struct socket * |
1531 | wg_get_so_by_af(struct wg_worker *wgw, const int af) | | 1531 | wg_get_so_by_af(struct wg_worker *wgw, const int af) |
1532 | { | | 1532 | { |
1533 | | | 1533 | |
1534 | return (af == AF_INET) ? wgw->wgw_so4 : wgw->wgw_so6; | | 1534 | return (af == AF_INET) ? wgw->wgw_so4 : wgw->wgw_so6; |
1535 | } | | 1535 | } |
1536 | | | 1536 | |
1537 | static struct socket * | | 1537 | static struct socket * |
1538 | wg_get_so_by_peer(struct wg_peer *wgp, struct wg_sockaddr *wgsa) | | 1538 | wg_get_so_by_peer(struct wg_peer *wgp, struct wg_sockaddr *wgsa) |
1539 | { | | 1539 | { |
1540 | | | 1540 | |
| @@ -1575,89 +1575,93 @@ wg_send_so(struct wg_peer *wgp, struct m | | | @@ -1575,89 +1575,93 @@ wg_send_so(struct wg_peer *wgp, struct m |
1575 | error = sosend(so, wgsatosa(wgsa), NULL, m, NULL, 0, curlwp); | | 1575 | error = sosend(so, wgsatosa(wgsa), NULL, m, NULL, 0, curlwp); |
1576 | wg_put_sa(wgp, wgsa, &psref); | | 1576 | wg_put_sa(wgp, wgsa, &psref); |
1577 | | | 1577 | |
1578 | return error; | | 1578 | return error; |
1579 | } | | 1579 | } |
1580 | | | 1580 | |
1581 | static int | | 1581 | static int |
1582 | wg_send_handshake_msg_init(struct wg_softc *wg, struct wg_peer *wgp) | | 1582 | wg_send_handshake_msg_init(struct wg_softc *wg, struct wg_peer *wgp) |
1583 | { | | 1583 | { |
1584 | int error; | | 1584 | int error; |
1585 | struct mbuf *m; | | 1585 | struct mbuf *m; |
1586 | struct wg_msg_init *wgmi; | | 1586 | struct wg_msg_init *wgmi; |
1587 | struct wg_session *wgs; | | 1587 | struct wg_session *wgs; |
1588 | struct psref psref; | | | |
1589 | | | 1588 | |
1590 | wgs = wg_lock_unstable_session(wgp); | | 1589 | KASSERT(mutex_owned(wgp->wgp_lock)); |
1591 | if (wgs->wgs_state == WGS_STATE_DESTROYING) { | | 1590 | |
| | | 1591 | wgs = wgp->wgp_session_unstable; |
| | | 1592 | /* XXX pull dispatch out into wg_task_send_init_message */ |
| | | 1593 | switch (wgs->wgs_state) { |
| | | 1594 | case WGS_STATE_UNKNOWN: /* new session initiated by us */ |
| | | 1595 | wg_get_session_index(wg, wgs); |
| | | 1596 | break; |
| | | 1597 | case WGS_STATE_INIT_ACTIVE: /* we're already initiating, stop */ |
| | | 1598 | WG_TRACE("Session already initializing, skip starting new one"); |
| | | 1599 | return EBUSY; |
| | | 1600 | case WGS_STATE_INIT_PASSIVE: /* peer was trying -- XXX what now? */ |
| | | 1601 | WG_TRACE("Session already initializing, destroying old states"); |
| | | 1602 | wg_clear_states(wgs); |
| | | 1603 | /* keep session index */ |
| | | 1604 | break; |
| | | 1605 | case WGS_STATE_ESTABLISHED: /* can't happen */ |
| | | 1606 | panic("unstable session can't be established"); |
| | | 1607 | break; |
| | | 1608 | case WGS_STATE_DESTROYING: /* rekey initiated by us too early */ |
1592 | WG_TRACE("Session destroying"); | | 1609 | WG_TRACE("Session destroying"); |
1593 | mutex_exit(wgs->wgs_lock); | | | |
1594 | /* XXX should wait? */ | | 1610 | /* XXX should wait? */ |
1595 | return EBUSY; | | 1611 | return EBUSY; |
1596 | } | | 1612 | } |
1597 | if (wgs->wgs_state == WGS_STATE_INIT_ACTIVE) { | | | |
1598 | WG_TRACE("Sesssion already initializing, skip starting a new one"); | | | |
1599 | mutex_exit(wgs->wgs_lock); | | | |
1600 | return EBUSY; | | | |
1601 | } | | | |
1602 | if (wgs->wgs_state == WGS_STATE_INIT_PASSIVE) { | | | |
1603 | WG_TRACE("Sesssion already initializing, destroying old states"); | | | |
1604 | wg_clear_states(wgs); | | | |
1605 | } | | | |
1606 | wgs->wgs_state = WGS_STATE_INIT_ACTIVE; | | 1613 | wgs->wgs_state = WGS_STATE_INIT_ACTIVE; |
1607 | wg_get_session(wgs, &psref); | | | |
1608 | mutex_exit(wgs->wgs_lock); | | | |
1609 | | | 1614 | |
1610 | m = m_gethdr(M_WAIT, MT_DATA); | | 1615 | m = m_gethdr(M_WAIT, MT_DATA); |
1611 | m->m_pkthdr.len = m->m_len = sizeof(*wgmi); | | 1616 | m->m_pkthdr.len = m->m_len = sizeof(*wgmi); |
1612 | wgmi = mtod(m, struct wg_msg_init *); | | 1617 | wgmi = mtod(m, struct wg_msg_init *); |
1613 | wg_fill_msg_init(wg, wgp, wgs, wgmi); | | 1618 | wg_fill_msg_init(wg, wgp, wgs, wgmi); |
1614 | | | 1619 | |
1615 | error = wg->wg_ops->send_hs_msg(wgp, m); | | 1620 | error = wg->wg_ops->send_hs_msg(wgp, m); |
1616 | if (error == 0) { | | 1621 | if (error == 0) { |
1617 | WG_TRACE("init msg sent"); | | 1622 | WG_TRACE("init msg sent"); |
1618 | | | 1623 | |
1619 | if (wgp->wgp_handshake_start_time == 0) | | 1624 | if (wgp->wgp_handshake_start_time == 0) |
1620 | wgp->wgp_handshake_start_time = time_uptime; | | 1625 | wgp->wgp_handshake_start_time = time_uptime; |
1621 | wg_schedule_handshake_timeout_timer(wgp); | | 1626 | callout_schedule(&wgp->wgp_handshake_timeout_timer, |
| | | 1627 | MIN(wg_rekey_timeout, INT_MAX/hz) * hz); |
1622 | } else { | | 1628 | } else { |
1623 | mutex_enter(wgs->wgs_lock); | | 1629 | wg_put_session_index(wg, wgs); |
1624 | KASSERT(wgs->wgs_state == WGS_STATE_INIT_ACTIVE); | | | |
1625 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | | |
1626 | mutex_exit(wgs->wgs_lock); | | | |
1627 | } | | 1630 | } |
1628 | wg_put_session(wgs, &psref); | | | |
1629 | | | 1631 | |
1630 | return error; | | 1632 | return error; |
1631 | } | | 1633 | } |
1632 | | | 1634 | |
1633 | static void | | 1635 | static void |
1634 | wg_fill_msg_resp(struct wg_softc *wg, struct wg_peer *wgp, | | 1636 | wg_fill_msg_resp(struct wg_softc *wg, struct wg_peer *wgp, |
1635 | struct wg_msg_resp *wgmr, const struct wg_msg_init *wgmi) | | 1637 | struct wg_session *wgs, struct wg_msg_resp *wgmr, |
| | | 1638 | const struct wg_msg_init *wgmi) |
1636 | { | | 1639 | { |
1637 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */ | | 1640 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */ |
1638 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Hr */ | | 1641 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Hr */ |
1639 | uint8_t cipher_key[WG_KDF_OUTPUT_LEN]; | | 1642 | uint8_t cipher_key[WG_KDF_OUTPUT_LEN]; |
1640 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; | | 1643 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; |
1641 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; | | 1644 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; |
1642 | struct wg_session *wgs; | | | |
1643 | struct psref psref; | | | |
1644 | | | 1645 | |
1645 | wgs = wg_get_unstable_session(wgp, &psref); | | 1646 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 1647 | KASSERT(wgs == wgp->wgp_session_unstable); |
| | | 1648 | KASSERT(wgs->wgs_state == WGS_STATE_INIT_PASSIVE); |
| | | 1649 | |
1646 | memcpy(hash, wgs->wgs_handshake_hash, sizeof(hash)); | | 1650 | memcpy(hash, wgs->wgs_handshake_hash, sizeof(hash)); |
1647 | memcpy(ckey, wgs->wgs_chaining_key, sizeof(ckey)); | | 1651 | memcpy(ckey, wgs->wgs_chaining_key, sizeof(ckey)); |
1648 | | | 1652 | |
1649 | wgmr->wgmr_type = htole32(WG_MSG_TYPE_RESP); | | 1653 | wgmr->wgmr_type = htole32(WG_MSG_TYPE_RESP); |
1650 | wgmr->wgmr_sender = wg_assign_sender_index(wg, wgs); | | 1654 | wgmr->wgmr_sender = wgs->wgs_local_index; |
1651 | wgmr->wgmr_receiver = wgmi->wgmi_sender; | | 1655 | wgmr->wgmr_receiver = wgmi->wgmi_sender; |
1652 | | | 1656 | |
1653 | /* [W] 5.4.3 Second Message: Responder to Initiator */ | | 1657 | /* [W] 5.4.3 Second Message: Responder to Initiator */ |
1654 | | | 1658 | |
1655 | /* [N] 2.2: "e" */ | | 1659 | /* [N] 2.2: "e" */ |
1656 | /* Er^priv, Er^pub := DH-GENERATE() */ | | 1660 | /* Er^priv, Er^pub := DH-GENERATE() */ |
1657 | wg_algo_generate_keypair(pubkey, privkey); | | 1661 | wg_algo_generate_keypair(pubkey, privkey); |
1658 | /* Cr := KDF1(Cr, Er^pub) */ | | 1662 | /* Cr := KDF1(Cr, Er^pub) */ |
1659 | wg_algo_kdf(ckey, NULL, NULL, ckey, pubkey, sizeof(pubkey)); | | 1663 | wg_algo_kdf(ckey, NULL, NULL, ckey, pubkey, sizeof(pubkey)); |
1660 | /* msg.ephemeral := Er^pub */ | | 1664 | /* msg.ephemeral := Er^pub */ |
1661 | memcpy(wgmr->wgmr_ephemeral, pubkey, sizeof(wgmr->wgmr_ephemeral)); | | 1665 | memcpy(wgmr->wgmr_ephemeral, pubkey, sizeof(wgmr->wgmr_ephemeral)); |
1662 | /* Hr := HASH(Hr || msg.ephemeral) */ | | 1666 | /* Hr := HASH(Hr || msg.ephemeral) */ |
1663 | wg_algo_hash(hash, pubkey, sizeof(pubkey)); | | 1667 | wg_algo_hash(hash, pubkey, sizeof(pubkey)); |
| @@ -1708,41 +1712,46 @@ wg_fill_msg_resp(struct wg_softc *wg, st | | | @@ -1708,41 +1712,46 @@ wg_fill_msg_resp(struct wg_softc *wg, st |
1708 | else { | | 1712 | else { |
1709 | /* msg.mac2 := MAC(Lm, msg_b) */ | | 1713 | /* msg.mac2 := MAC(Lm, msg_b) */ |
1710 | wg_algo_mac(wgmr->wgmr_mac2, sizeof(wgmi->wgmi_mac2), | | 1714 | wg_algo_mac(wgmr->wgmr_mac2, sizeof(wgmi->wgmi_mac2), |
1711 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, | | 1715 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, |
1712 | (const uint8_t *)wgmr, | | 1716 | (const uint8_t *)wgmr, |
1713 | offsetof(struct wg_msg_resp, wgmr_mac2), | | 1717 | offsetof(struct wg_msg_resp, wgmr_mac2), |
1714 | NULL, 0); | | 1718 | NULL, 0); |
1715 | } | | 1719 | } |
1716 | | | 1720 | |
1717 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); | | 1721 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); |
1718 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); | | 1722 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); |
1719 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); | | 1723 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); |
1720 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); | | 1724 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); |
1721 | wgs->wgs_receiver_index = wgmi->wgmi_sender; | | 1725 | wgs->wgs_remote_index = wgmi->wgmi_sender; |
1722 | WG_DLOG("sender=%x\n", wgs->wgs_sender_index); | | 1726 | WG_DLOG("sender=%x\n", wgs->wgs_local_index); |
1723 | WG_DLOG("receiver=%x\n", wgs->wgs_receiver_index); | | 1727 | WG_DLOG("receiver=%x\n", wgs->wgs_remote_index); |
1724 | wg_put_session(wgs, &psref); | | | |
1725 | } | | 1728 | } |
1726 | | | 1729 | |
1727 | static void | | 1730 | static void |
1728 | wg_swap_sessions(struct wg_peer *wgp) | | 1731 | wg_swap_sessions(struct wg_peer *wgp) |
1729 | { | | 1732 | { |
| | | 1733 | struct wg_session *wgs, *wgs_prev; |
1730 | | | 1734 | |
1731 | KASSERT(mutex_owned(wgp->wgp_lock)); | | 1735 | KASSERT(mutex_owned(wgp->wgp_lock)); |
1732 | | | 1736 | |
1733 | wgp->wgp_session_unstable = atomic_swap_ptr(&wgp->wgp_session_stable, | | 1737 | wgs = wgp->wgp_session_unstable; |
1734 | wgp->wgp_session_unstable); | | 1738 | KASSERT(wgs->wgs_state == WGS_STATE_ESTABLISHED); |
1735 | KASSERT(wgp->wgp_session_stable->wgs_state == WGS_STATE_ESTABLISHED); | | 1739 | |
| | | 1740 | wgs_prev = wgp->wgp_session_stable; |
| | | 1741 | KASSERT(wgs_prev->wgs_state == WGS_STATE_ESTABLISHED || |
| | | 1742 | wgs_prev->wgs_state == WGS_STATE_UNKNOWN); |
| | | 1743 | atomic_store_release(&wgp->wgp_session_stable, wgs); |
| | | 1744 | wgp->wgp_session_unstable = wgs_prev; |
1736 | } | | 1745 | } |
1737 | | | 1746 | |
1738 | static void | | 1747 | static void |
1739 | wg_handle_msg_resp(struct wg_softc *wg, const struct wg_msg_resp *wgmr, | | 1748 | wg_handle_msg_resp(struct wg_softc *wg, const struct wg_msg_resp *wgmr, |
1740 | const struct sockaddr *src) | | 1749 | const struct sockaddr *src) |
1741 | { | | 1750 | { |
1742 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */ | | 1751 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */ |
1743 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Kr */ | | 1752 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Kr */ |
1744 | uint8_t cipher_key[WG_KDF_OUTPUT_LEN]; | | 1753 | uint8_t cipher_key[WG_KDF_OUTPUT_LEN]; |
1745 | struct wg_peer *wgp; | | 1754 | struct wg_peer *wgp; |
1746 | struct wg_session *wgs; | | 1755 | struct wg_session *wgs; |
1747 | struct psref psref; | | 1756 | struct psref psref; |
1748 | int error; | | 1757 | int error; |
| @@ -1762,26 +1771,34 @@ wg_handle_msg_resp(struct wg_softc *wg, | | | @@ -1762,26 +1771,34 @@ wg_handle_msg_resp(struct wg_softc *wg, |
1762 | WG_DLOG("mac1 is invalid\n"); | | 1771 | WG_DLOG("mac1 is invalid\n"); |
1763 | return; | | 1772 | return; |
1764 | } | | 1773 | } |
1765 | | | 1774 | |
1766 | WG_TRACE("resp msg received"); | | 1775 | WG_TRACE("resp msg received"); |
1767 | wgs = wg_lookup_session_by_index(wg, wgmr->wgmr_receiver, &psref); | | 1776 | wgs = wg_lookup_session_by_index(wg, wgmr->wgmr_receiver, &psref); |
1768 | if (wgs == NULL) { | | 1777 | if (wgs == NULL) { |
1769 | WG_TRACE("No session found"); | | 1778 | WG_TRACE("No session found"); |
1770 | return; | | 1779 | return; |
1771 | } | | 1780 | } |
1772 | | | 1781 | |
1773 | wgp = wgs->wgs_peer; | | 1782 | wgp = wgs->wgs_peer; |
1774 | | | 1783 | |
| | | 1784 | mutex_enter(wgp->wgp_lock); |
| | | 1785 | |
| | | 1786 | /* If we weren't waiting for a handshake response, drop it. */ |
| | | 1787 | if (wgs->wgs_state != WGS_STATE_INIT_ACTIVE) { |
| | | 1788 | WG_TRACE("peer sent spurious handshake response, ignoring"); |
| | | 1789 | goto out; |
| | | 1790 | } |
| | | 1791 | |
1775 | if (__predict_false(wg_is_underload(wg, wgp, WG_MSG_TYPE_RESP))) { | | 1792 | if (__predict_false(wg_is_underload(wg, wgp, WG_MSG_TYPE_RESP))) { |
1776 | WG_TRACE("under load"); | | 1793 | WG_TRACE("under load"); |
1777 | /* | | 1794 | /* |
1778 | * [W] 5.3: Denial of Service Mitigation & Cookies | | 1795 | * [W] 5.3: Denial of Service Mitigation & Cookies |
1779 | * "the responder, ..., and when under load may reject messages | | 1796 | * "the responder, ..., and when under load may reject messages |
1780 | * with an invalid msg.mac2. If the responder receives a | | 1797 | * with an invalid msg.mac2. If the responder receives a |
1781 | * message with a valid msg.mac1 yet with an invalid msg.mac2, | | 1798 | * message with a valid msg.mac1 yet with an invalid msg.mac2, |
1782 | * and is under load, it may respond with a cookie reply | | 1799 | * and is under load, it may respond with a cookie reply |
1783 | * message" | | 1800 | * message" |
1784 | */ | | 1801 | */ |
1785 | uint8_t zero[WG_MAC_LEN] = {0}; | | 1802 | uint8_t zero[WG_MAC_LEN] = {0}; |
1786 | if (consttime_memequal(wgmr->wgmr_mac2, zero, sizeof(zero))) { | | 1803 | if (consttime_memequal(wgmr->wgmr_mac2, zero, sizeof(zero))) { |
1787 | WG_TRACE("sending a cookie message: no cookie included"); | | 1804 | WG_TRACE("sending a cookie message: no cookie included"); |
| @@ -1855,90 +1872,100 @@ wg_handle_msg_resp(struct wg_softc *wg, | | | @@ -1855,90 +1872,100 @@ wg_handle_msg_resp(struct wg_softc *wg, |
1855 | sizeof(wgmr->wgmr_empty), hash, sizeof(hash)); | | 1872 | sizeof(wgmr->wgmr_empty), hash, sizeof(hash)); |
1856 | WG_DUMP_HASH("wgmr_empty", wgmr->wgmr_empty); | | 1873 | WG_DUMP_HASH("wgmr_empty", wgmr->wgmr_empty); |
1857 | if (error != 0) { | | 1874 | if (error != 0) { |
1858 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 1875 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
1859 | "wg_algo_aead_dec for empty message failed\n"); | | 1876 | "wg_algo_aead_dec for empty message failed\n"); |
1860 | goto out; | | 1877 | goto out; |
1861 | } | | 1878 | } |
1862 | /* Hr := HASH(Hr || msg.empty) */ | | 1879 | /* Hr := HASH(Hr || msg.empty) */ |
1863 | wg_algo_hash(hash, wgmr->wgmr_empty, sizeof(wgmr->wgmr_empty)); | | 1880 | wg_algo_hash(hash, wgmr->wgmr_empty, sizeof(wgmr->wgmr_empty)); |
1864 | } | | 1881 | } |
1865 | | | 1882 | |
1866 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(wgs->wgs_handshake_hash)); | | 1883 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(wgs->wgs_handshake_hash)); |
1867 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(wgs->wgs_chaining_key)); | | 1884 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(wgs->wgs_chaining_key)); |
1868 | wgs->wgs_receiver_index = wgmr->wgmr_sender; | | 1885 | wgs->wgs_remote_index = wgmr->wgmr_sender; |
1869 | WG_DLOG("receiver=%x\n", wgs->wgs_receiver_index); | | 1886 | WG_DLOG("receiver=%x\n", wgs->wgs_remote_index); |
1870 | | | 1887 | |
| | | 1888 | KASSERT(wgs->wgs_state == WGS_STATE_INIT_ACTIVE); |
1871 | wgs->wgs_state = WGS_STATE_ESTABLISHED; | | 1889 | wgs->wgs_state = WGS_STATE_ESTABLISHED; |
1872 | wgs->wgs_time_established = time_uptime; | | 1890 | wgs->wgs_time_established = time_uptime; |
1873 | wgs->wgs_time_last_data_sent = 0; | | 1891 | wgs->wgs_time_last_data_sent = 0; |
1874 | wgs->wgs_is_initiator = true; | | 1892 | wgs->wgs_is_initiator = true; |
1875 | wg_calculate_keys(wgs, true); | | 1893 | wg_calculate_keys(wgs, true); |
1876 | wg_clear_states(wgs); | | 1894 | wg_clear_states(wgs); |
1877 | WG_TRACE("WGS_STATE_ESTABLISHED"); | | 1895 | WG_TRACE("WGS_STATE_ESTABLISHED"); |
1878 | | | 1896 | |
1879 | callout_halt(&wgp->wgp_handshake_timeout_timer, NULL); | | 1897 | callout_stop(&wgp->wgp_handshake_timeout_timer); |
1880 | | | 1898 | |
1881 | mutex_enter(wgp->wgp_lock); | | | |
1882 | wg_swap_sessions(wgp); | | 1899 | wg_swap_sessions(wgp); |
| | | 1900 | KASSERT(wgs == wgp->wgp_session_stable); |
1883 | wgs_prev = wgp->wgp_session_unstable; | | 1901 | wgs_prev = wgp->wgp_session_unstable; |
1884 | mutex_enter(wgs_prev->wgs_lock); | | | |
1885 | | | | |
1886 | getnanotime(&wgp->wgp_last_handshake_time); | | 1902 | getnanotime(&wgp->wgp_last_handshake_time); |
1887 | wgp->wgp_handshake_start_time = 0; | | 1903 | wgp->wgp_handshake_start_time = 0; |
1888 | wgp->wgp_last_sent_mac1_valid = false; | | 1904 | wgp->wgp_last_sent_mac1_valid = false; |
1889 | wgp->wgp_last_sent_cookie_valid = false; | | 1905 | wgp->wgp_last_sent_cookie_valid = false; |
1890 | mutex_exit(wgp->wgp_lock); | | | |
1891 | | | 1906 | |
1892 | wg_schedule_rekey_timer(wgp); | | 1907 | wg_schedule_rekey_timer(wgp); |
1893 | | | 1908 | |
1894 | wg_update_endpoint_if_necessary(wgp, src); | | 1909 | wg_update_endpoint_if_necessary(wgp, src); |
1895 | | | 1910 | |
1896 | /* | | 1911 | /* |
1897 | * Send something immediately (same as the official implementation) | | 1912 | * Send something immediately (same as the official implementation) |
1898 | * XXX if there are pending data packets, we don't need to send | | 1913 | * XXX if there are pending data packets, we don't need to send |
1899 | * a keepalive message. | | 1914 | * a keepalive message. |
1900 | */ | | 1915 | */ |
1901 | wg_send_keepalive_msg(wgp, wgs); | | 1916 | wg_send_keepalive_msg(wgp, wgs); |
1902 | | | 1917 | |
1903 | /* Anyway run a softint to flush pending packets */ | | 1918 | /* Anyway run a softint to flush pending packets */ |
1904 | kpreempt_disable(); | | 1919 | kpreempt_disable(); |
1905 | softint_schedule(wgp->wgp_si); | | 1920 | softint_schedule(wgp->wgp_si); |
1906 | kpreempt_enable(); | | 1921 | kpreempt_enable(); |
1907 | WG_TRACE("softint scheduled"); | | 1922 | WG_TRACE("softint scheduled"); |
1908 | | | 1923 | |
1909 | if (wgs_prev->wgs_state == WGS_STATE_ESTABLISHED) { | | 1924 | if (wgs_prev->wgs_state == WGS_STATE_ESTABLISHED) { |
| | | 1925 | /* Wait for wg_get_stable_session to drain. */ |
| | | 1926 | pserialize_perform(wgp->wgp_psz); |
| | | 1927 | |
| | | 1928 | /* Transition ESTABLISHED->DESTROYING. */ |
1910 | wgs_prev->wgs_state = WGS_STATE_DESTROYING; | | 1929 | wgs_prev->wgs_state = WGS_STATE_DESTROYING; |
| | | 1930 | |
1911 | /* We can't destroy the old session immediately */ | | 1931 | /* We can't destroy the old session immediately */ |
1912 | wg_schedule_session_dtor_timer(wgp); | | 1932 | wg_schedule_session_dtor_timer(wgp); |
| | | 1933 | } else { |
| | | 1934 | KASSERTMSG(wgs_prev->wgs_state == WGS_STATE_UNKNOWN, |
| | | 1935 | "state=%d", wgs_prev->wgs_state); |
1913 | } | | 1936 | } |
1914 | mutex_exit(wgs_prev->wgs_lock); | | | |
1915 | | | 1937 | |
1916 | out: | | 1938 | out: |
| | | 1939 | mutex_exit(wgp->wgp_lock); |
1917 | wg_put_session(wgs, &psref); | | 1940 | wg_put_session(wgs, &psref); |
1918 | } | | 1941 | } |
1919 | | | 1942 | |
1920 | static int | | 1943 | static int |
1921 | wg_send_handshake_msg_resp(struct wg_softc *wg, struct wg_peer *wgp, | | 1944 | wg_send_handshake_msg_resp(struct wg_softc *wg, struct wg_peer *wgp, |
1922 | const struct wg_msg_init *wgmi) | | 1945 | struct wg_session *wgs, const struct wg_msg_init *wgmi) |
1923 | { | | 1946 | { |
1924 | int error; | | 1947 | int error; |
1925 | struct mbuf *m; | | 1948 | struct mbuf *m; |
1926 | struct wg_msg_resp *wgmr; | | 1949 | struct wg_msg_resp *wgmr; |
1927 | | | 1950 | |
| | | 1951 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 1952 | KASSERT(wgs == wgp->wgp_session_unstable); |
| | | 1953 | KASSERT(wgs->wgs_state == WGS_STATE_INIT_PASSIVE); |
| | | 1954 | |
1928 | m = m_gethdr(M_WAIT, MT_DATA); | | 1955 | m = m_gethdr(M_WAIT, MT_DATA); |
1929 | m->m_pkthdr.len = m->m_len = sizeof(*wgmr); | | 1956 | m->m_pkthdr.len = m->m_len = sizeof(*wgmr); |
1930 | wgmr = mtod(m, struct wg_msg_resp *); | | 1957 | wgmr = mtod(m, struct wg_msg_resp *); |
1931 | wg_fill_msg_resp(wg, wgp, wgmr, wgmi); | | 1958 | wg_fill_msg_resp(wg, wgp, wgs, wgmr, wgmi); |
1932 | | | 1959 | |
1933 | error = wg->wg_ops->send_hs_msg(wgp, m); | | 1960 | error = wg->wg_ops->send_hs_msg(wgp, m); |
1934 | if (error == 0) | | 1961 | if (error == 0) |
1935 | WG_TRACE("resp msg sent"); | | 1962 | WG_TRACE("resp msg sent"); |
1936 | return error; | | 1963 | return error; |
1937 | } | | 1964 | } |
1938 | | | 1965 | |
1939 | static struct wg_peer * | | 1966 | static struct wg_peer * |
1940 | wg_lookup_peer_by_pubkey(struct wg_softc *wg, | | 1967 | wg_lookup_peer_by_pubkey(struct wg_softc *wg, |
1941 | const uint8_t pubkey[WG_STATIC_KEY_LEN], struct psref *psref) | | 1968 | const uint8_t pubkey[WG_STATIC_KEY_LEN], struct psref *psref) |
1942 | { | | 1969 | { |
1943 | struct wg_peer *wgp; | | 1970 | struct wg_peer *wgp; |
1944 | | | 1971 | |
| @@ -1952,26 +1979,28 @@ wg_lookup_peer_by_pubkey(struct wg_softc | | | @@ -1952,26 +1979,28 @@ wg_lookup_peer_by_pubkey(struct wg_softc |
1952 | } | | 1979 | } |
1953 | | | 1980 | |
1954 | static void | | 1981 | static void |
1955 | wg_fill_msg_cookie(struct wg_softc *wg, struct wg_peer *wgp, | | 1982 | wg_fill_msg_cookie(struct wg_softc *wg, struct wg_peer *wgp, |
1956 | struct wg_msg_cookie *wgmc, const uint32_t sender, | | 1983 | struct wg_msg_cookie *wgmc, const uint32_t sender, |
1957 | const uint8_t mac1[WG_MAC_LEN], const struct sockaddr *src) | | 1984 | const uint8_t mac1[WG_MAC_LEN], const struct sockaddr *src) |
1958 | { | | 1985 | { |
1959 | uint8_t cookie[WG_COOKIE_LEN]; | | 1986 | uint8_t cookie[WG_COOKIE_LEN]; |
1960 | uint8_t key[WG_HASH_LEN]; | | 1987 | uint8_t key[WG_HASH_LEN]; |
1961 | uint8_t addr[sizeof(struct in6_addr)]; | | 1988 | uint8_t addr[sizeof(struct in6_addr)]; |
1962 | size_t addrlen; | | 1989 | size_t addrlen; |
1963 | uint16_t uh_sport; /* be */ | | 1990 | uint16_t uh_sport; /* be */ |
1964 | | | 1991 | |
| | | 1992 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 1993 | |
1965 | wgmc->wgmc_type = htole32(WG_MSG_TYPE_COOKIE); | | 1994 | wgmc->wgmc_type = htole32(WG_MSG_TYPE_COOKIE); |
1966 | wgmc->wgmc_receiver = sender; | | 1995 | wgmc->wgmc_receiver = sender; |
1967 | cprng_fast(wgmc->wgmc_salt, sizeof(wgmc->wgmc_salt)); | | 1996 | cprng_fast(wgmc->wgmc_salt, sizeof(wgmc->wgmc_salt)); |
1968 | | | 1997 | |
1969 | /* | | 1998 | /* |
1970 | * [W] 5.4.7: Under Load: Cookie Reply Message | | 1999 | * [W] 5.4.7: Under Load: Cookie Reply Message |
1971 | * "The secret variable, Rm, changes every two minutes to a | | 2000 | * "The secret variable, Rm, changes every two minutes to a |
1972 | * random value" | | 2001 | * random value" |
1973 | */ | | 2002 | */ |
1974 | if ((time_uptime - wgp->wgp_last_genrandval_time) > WG_RANDVAL_TIME) { | | 2003 | if ((time_uptime - wgp->wgp_last_genrandval_time) > WG_RANDVAL_TIME) { |
1975 | wgp->wgp_randval = cprng_strong32(); | | 2004 | wgp->wgp_randval = cprng_strong32(); |
1976 | wgp->wgp_last_genrandval_time = time_uptime; | | 2005 | wgp->wgp_last_genrandval_time = time_uptime; |
1977 | } | | 2006 | } |
| @@ -2009,26 +2038,28 @@ wg_fill_msg_cookie(struct wg_softc *wg, | | | @@ -2009,26 +2038,28 @@ wg_fill_msg_cookie(struct wg_softc *wg, |
2009 | memcpy(wgp->wgp_last_sent_cookie, cookie, sizeof(cookie)); | | 2038 | memcpy(wgp->wgp_last_sent_cookie, cookie, sizeof(cookie)); |
2010 | wgp->wgp_last_sent_cookie_valid = true; | | 2039 | wgp->wgp_last_sent_cookie_valid = true; |
2011 | } | | 2040 | } |
2012 | | | 2041 | |
2013 | static int | | 2042 | static int |
2014 | wg_send_cookie_msg(struct wg_softc *wg, struct wg_peer *wgp, | | 2043 | wg_send_cookie_msg(struct wg_softc *wg, struct wg_peer *wgp, |
2015 | const uint32_t sender, const uint8_t mac1[WG_MAC_LEN], | | 2044 | const uint32_t sender, const uint8_t mac1[WG_MAC_LEN], |
2016 | const struct sockaddr *src) | | 2045 | const struct sockaddr *src) |
2017 | { | | 2046 | { |
2018 | int error; | | 2047 | int error; |
2019 | struct mbuf *m; | | 2048 | struct mbuf *m; |
2020 | struct wg_msg_cookie *wgmc; | | 2049 | struct wg_msg_cookie *wgmc; |
2021 | | | 2050 | |
| | | 2051 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 2052 | |
2022 | m = m_gethdr(M_WAIT, MT_DATA); | | 2053 | m = m_gethdr(M_WAIT, MT_DATA); |
2023 | m->m_pkthdr.len = m->m_len = sizeof(*wgmc); | | 2054 | m->m_pkthdr.len = m->m_len = sizeof(*wgmc); |
2024 | wgmc = mtod(m, struct wg_msg_cookie *); | | 2055 | wgmc = mtod(m, struct wg_msg_cookie *); |
2025 | wg_fill_msg_cookie(wg, wgp, wgmc, sender, mac1, src); | | 2056 | wg_fill_msg_cookie(wg, wgp, wgmc, sender, mac1, src); |
2026 | | | 2057 | |
2027 | error = wg->wg_ops->send_hs_msg(wgp, m); | | 2058 | error = wg->wg_ops->send_hs_msg(wgp, m); |
2028 | if (error == 0) | | 2059 | if (error == 0) |
2029 | WG_TRACE("cookie msg sent"); | | 2060 | WG_TRACE("cookie msg sent"); |
2030 | return error; | | 2061 | return error; |
2031 | } | | 2062 | } |
2032 | | | 2063 | |
2033 | static bool | | 2064 | static bool |
2034 | wg_is_underload(struct wg_softc *wg, struct wg_peer *wgp, int msgtype) | | 2065 | wg_is_underload(struct wg_softc *wg, struct wg_peer *wgp, int msgtype) |
| @@ -2043,26 +2074,28 @@ wg_is_underload(struct wg_softc *wg, str | | | @@ -2043,26 +2074,28 @@ wg_is_underload(struct wg_softc *wg, str |
2043 | * the mechanism is a DoS mitigation, so we consider frequent handshake | | 2074 | * the mechanism is a DoS mitigation, so we consider frequent handshake |
2044 | * messages as (a kind of) load; if a message of the same type comes | | 2075 | * messages as (a kind of) load; if a message of the same type comes |
2045 | * to a peer within 1 second, we consider we are under load. | | 2076 | * to a peer within 1 second, we consider we are under load. |
2046 | */ | | 2077 | */ |
2047 | time_t last = wgp->wgp_last_msg_received_time[msgtype]; | | 2078 | time_t last = wgp->wgp_last_msg_received_time[msgtype]; |
2048 | wgp->wgp_last_msg_received_time[msgtype] = time_uptime; | | 2079 | wgp->wgp_last_msg_received_time[msgtype] = time_uptime; |
2049 | return (time_uptime - last) == 0; | | 2080 | return (time_uptime - last) == 0; |
2050 | } | | 2081 | } |
2051 | | | 2082 | |
2052 | static void | | 2083 | static void |
2053 | wg_calculate_keys(struct wg_session *wgs, const bool initiator) | | 2084 | wg_calculate_keys(struct wg_session *wgs, const bool initiator) |
2054 | { | | 2085 | { |
2055 | | | 2086 | |
| | | 2087 | KASSERT(mutex_owned(wgs->wgs_peer->wgp_lock)); |
| | | 2088 | |
2056 | /* | | 2089 | /* |
2057 | * [W] 5.4.5: Ti^send = Tr^recv, Ti^recv = Tr^send := KDF2(Ci = Cr, e) | | 2090 | * [W] 5.4.5: Ti^send = Tr^recv, Ti^recv = Tr^send := KDF2(Ci = Cr, e) |
2058 | */ | | 2091 | */ |
2059 | if (initiator) { | | 2092 | if (initiator) { |
2060 | wg_algo_kdf(wgs->wgs_tkey_send, wgs->wgs_tkey_recv, NULL, | | 2093 | wg_algo_kdf(wgs->wgs_tkey_send, wgs->wgs_tkey_recv, NULL, |
2061 | wgs->wgs_chaining_key, NULL, 0); | | 2094 | wgs->wgs_chaining_key, NULL, 0); |
2062 | } else { | | 2095 | } else { |
2063 | wg_algo_kdf(wgs->wgs_tkey_recv, wgs->wgs_tkey_send, NULL, | | 2096 | wg_algo_kdf(wgs->wgs_tkey_recv, wgs->wgs_tkey_send, NULL, |
2064 | wgs->wgs_chaining_key, NULL, 0); | | 2097 | wgs->wgs_chaining_key, NULL, 0); |
2065 | } | | 2098 | } |
2066 | WG_DUMP_HASH("wgs_tkey_send", wgs->wgs_tkey_send); | | 2099 | WG_DUMP_HASH("wgs_tkey_send", wgs->wgs_tkey_send); |
2067 | WG_DUMP_HASH("wgs_tkey_recv", wgs->wgs_tkey_recv); | | 2100 | WG_DUMP_HASH("wgs_tkey_recv", wgs->wgs_tkey_recv); |
2068 | } | | 2101 | } |
| @@ -2093,48 +2126,53 @@ wg_session_inc_send_counter(struct wg_se | | | @@ -2093,48 +2126,53 @@ wg_session_inc_send_counter(struct wg_se |
2093 | | | 2126 | |
2094 | mutex_enter(&wgs->wgs_send_counter_lock); | | 2127 | mutex_enter(&wgs->wgs_send_counter_lock); |
2095 | send_counter = wgs->wgs_send_counter++; | | 2128 | send_counter = wgs->wgs_send_counter++; |
2096 | mutex_exit(&wgs->wgs_send_counter_lock); | | 2129 | mutex_exit(&wgs->wgs_send_counter_lock); |
2097 | | | 2130 | |
2098 | return send_counter; | | 2131 | return send_counter; |
2099 | #endif | | 2132 | #endif |
2100 | } | | 2133 | } |
2101 | | | 2134 | |
2102 | static void | | 2135 | static void |
2103 | wg_clear_states(struct wg_session *wgs) | | 2136 | wg_clear_states(struct wg_session *wgs) |
2104 | { | | 2137 | { |
2105 | | | 2138 | |
| | | 2139 | KASSERT(mutex_owned(wgs->wgs_peer->wgp_lock)); |
| | | 2140 | |
2106 | wgs->wgs_send_counter = 0; | | 2141 | wgs->wgs_send_counter = 0; |
2107 | sliwin_reset(&wgs->wgs_recvwin->window); | | 2142 | sliwin_reset(&wgs->wgs_recvwin->window); |
2108 | | | 2143 | |
2109 | #define wgs_clear(v) explicit_memset(wgs->wgs_##v, 0, sizeof(wgs->wgs_##v)) | | 2144 | #define wgs_clear(v) explicit_memset(wgs->wgs_##v, 0, sizeof(wgs->wgs_##v)) |
2110 | wgs_clear(handshake_hash); | | 2145 | wgs_clear(handshake_hash); |
2111 | wgs_clear(chaining_key); | | 2146 | wgs_clear(chaining_key); |
2112 | wgs_clear(ephemeral_key_pub); | | 2147 | wgs_clear(ephemeral_key_pub); |
2113 | wgs_clear(ephemeral_key_priv); | | 2148 | wgs_clear(ephemeral_key_priv); |
2114 | wgs_clear(ephemeral_key_peer); | | 2149 | wgs_clear(ephemeral_key_peer); |
2115 | #undef wgs_clear | | 2150 | #undef wgs_clear |
2116 | } | | 2151 | } |
2117 | | | 2152 | |
2118 | static struct wg_session * | | 2153 | static struct wg_session * |
2119 | wg_lookup_session_by_index(struct wg_softc *wg, const uint32_t index, | | 2154 | wg_lookup_session_by_index(struct wg_softc *wg, const uint32_t index, |
2120 | struct psref *psref) | | 2155 | struct psref *psref) |
2121 | { | | 2156 | { |
2122 | struct wg_session *wgs; | | 2157 | struct wg_session *wgs; |
2123 | | | 2158 | |
2124 | int s = pserialize_read_enter(); | | 2159 | int s = pserialize_read_enter(); |
2125 | wgs = thmap_get(wg->wg_sessions_byindex, &index, sizeof index); | | 2160 | wgs = thmap_get(wg->wg_sessions_byindex, &index, sizeof index); |
2126 | if (wgs != NULL) | | 2161 | if (wgs != NULL) { |
| | | 2162 | KASSERT(atomic_load_relaxed(&wgs->wgs_state) != |
| | | 2163 | WGS_STATE_UNKNOWN); |
2127 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); | | 2164 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); |
| | | 2165 | } |
2128 | pserialize_read_exit(s); | | 2166 | pserialize_read_exit(s); |
2129 | | | 2167 | |
2130 | return wgs; | | 2168 | return wgs; |
2131 | } | | 2169 | } |
2132 | | | 2170 | |
2133 | static void | | 2171 | static void |
2134 | wg_schedule_rekey_timer(struct wg_peer *wgp) | | 2172 | wg_schedule_rekey_timer(struct wg_peer *wgp) |
2135 | { | | 2173 | { |
2136 | int timeout = MIN(wg_rekey_after_time, INT_MAX/hz); | | 2174 | int timeout = MIN(wg_rekey_after_time, INT_MAX/hz); |
2137 | | | 2175 | |
2138 | callout_schedule(&wgp->wgp_rekey_timer, timeout * hz); | | 2176 | callout_schedule(&wgp->wgp_rekey_timer, timeout * hz); |
2139 | } | | 2177 | } |
2140 | | | 2178 | |
| @@ -2171,39 +2209,36 @@ wg_need_to_send_init_message(struct wg_s | | | @@ -2171,39 +2209,36 @@ wg_need_to_send_init_message(struct wg_s |
2171 | | | 2209 | |
2172 | static void | | 2210 | static void |
2173 | wg_schedule_peer_task(struct wg_peer *wgp, int task) | | 2211 | wg_schedule_peer_task(struct wg_peer *wgp, int task) |
2174 | { | | 2212 | { |
2175 | | | 2213 | |
2176 | atomic_or_uint(&wgp->wgp_tasks, task); | | 2214 | atomic_or_uint(&wgp->wgp_tasks, task); |
2177 | WG_DLOG("tasks=%d, task=%d\n", wgp->wgp_tasks, task); | | 2215 | WG_DLOG("tasks=%d, task=%d\n", wgp->wgp_tasks, task); |
2178 | wg_wakeup_worker(wgp->wgp_sc->wg_worker, WG_WAKEUP_REASON_PEER); | | 2216 | wg_wakeup_worker(wgp->wgp_sc->wg_worker, WG_WAKEUP_REASON_PEER); |
2179 | } | | 2217 | } |
2180 | | | 2218 | |
2181 | static void | | 2219 | static void |
2182 | wg_change_endpoint(struct wg_peer *wgp, const struct sockaddr *new) | | 2220 | wg_change_endpoint(struct wg_peer *wgp, const struct sockaddr *new) |
2183 | { | | 2221 | { |
2184 | | | 2222 | struct wg_sockaddr *wgsa_prev; |
2185 | KASSERT(mutex_owned(wgp->wgp_lock)); | | | |
2186 | | | 2223 | |
2187 | WG_TRACE("Changing endpoint"); | | 2224 | WG_TRACE("Changing endpoint"); |
2188 | | | 2225 | |
2189 | memcpy(wgp->wgp_endpoint0, new, new->sa_len); | | 2226 | memcpy(wgp->wgp_endpoint0, new, new->sa_len); |
2190 | #ifndef __HAVE_ATOMIC_AS_MEMBAR /* store-release */ | | 2227 | wgsa_prev = wgp->wgp_endpoint; |
2191 | membar_exit(); | | 2228 | atomic_store_release(&wgp->wgp_endpoint, wgp->wgp_endpoint0); |
2192 | #endif | | 2229 | wgp->wgp_endpoint0 = wgsa_prev; |
2193 | wgp->wgp_endpoint0 = atomic_swap_ptr(&wgp->wgp_endpoint, | | 2230 | atomic_store_release(&wgp->wgp_endpoint_available, true); |
2194 | wgp->wgp_endpoint0); | | 2231 | |
2195 | wgp->wgp_endpoint_available = true; | | | |
2196 | wgp->wgp_endpoint_changing = true; | | | |
2197 | wg_schedule_peer_task(wgp, WGP_TASK_ENDPOINT_CHANGED); | | 2232 | wg_schedule_peer_task(wgp, WGP_TASK_ENDPOINT_CHANGED); |
2198 | } | | 2233 | } |
2199 | | | 2234 | |
2200 | static bool | | 2235 | static bool |
2201 | wg_validate_inner_packet(const char *packet, size_t decrypted_len, int *af) | | 2236 | wg_validate_inner_packet(const char *packet, size_t decrypted_len, int *af) |
2202 | { | | 2237 | { |
2203 | uint16_t packet_len; | | 2238 | uint16_t packet_len; |
2204 | const struct ip *ip; | | 2239 | const struct ip *ip; |
2205 | | | 2240 | |
2206 | if (__predict_false(decrypted_len < sizeof(struct ip))) | | 2241 | if (__predict_false(decrypted_len < sizeof(struct ip))) |
2207 | return false; | | 2242 | return false; |
2208 | | | 2243 | |
2209 | ip = (const struct ip *)packet; | | 2244 | ip = (const struct ip *)packet; |
| @@ -2271,33 +2306,26 @@ wg_validate_route(struct wg_softc *wg, s | | | @@ -2271,33 +2306,26 @@ wg_validate_route(struct wg_softc *wg, s |
2271 | if (wgp != NULL) | | 2306 | if (wgp != NULL) |
2272 | wg_put_peer(wgp, &psref); | | 2307 | wg_put_peer(wgp, &psref); |
2273 | | | 2308 | |
2274 | return ok; | | 2309 | return ok; |
2275 | } | | 2310 | } |
2276 | | | 2311 | |
2277 | static void | | 2312 | static void |
2278 | wg_session_dtor_timer(void *arg) | | 2313 | wg_session_dtor_timer(void *arg) |
2279 | { | | 2314 | { |
2280 | struct wg_peer *wgp = arg; | | 2315 | struct wg_peer *wgp = arg; |
2281 | | | 2316 | |
2282 | WG_TRACE("enter"); | | 2317 | WG_TRACE("enter"); |
2283 | | | 2318 | |
2284 | mutex_enter(wgp->wgp_lock); | | | |
2285 | if (__predict_false(wgp->wgp_state == WGP_STATE_DESTROYING)) { | | | |
2286 | mutex_exit(wgp->wgp_lock); | | | |
2287 | return; | | | |
2288 | } | | | |
2289 | mutex_exit(wgp->wgp_lock); | | | |
2290 | | | | |
2291 | wg_schedule_peer_task(wgp, WGP_TASK_DESTROY_PREV_SESSION); | | 2319 | wg_schedule_peer_task(wgp, WGP_TASK_DESTROY_PREV_SESSION); |
2292 | } | | 2320 | } |
2293 | | | 2321 | |
2294 | static void | | 2322 | static void |
2295 | wg_schedule_session_dtor_timer(struct wg_peer *wgp) | | 2323 | wg_schedule_session_dtor_timer(struct wg_peer *wgp) |
2296 | { | | 2324 | { |
2297 | | | 2325 | |
2298 | /* 1 second grace period */ | | 2326 | /* 1 second grace period */ |
2299 | callout_schedule(&wgp->wgp_session_dtor_timer, hz); | | 2327 | callout_schedule(&wgp->wgp_session_dtor_timer, hz); |
2300 | } | | 2328 | } |
2301 | | | 2329 | |
2302 | static bool | | 2330 | static bool |
2303 | sockaddr_port_match(const struct sockaddr *sa1, const struct sockaddr *sa2) | | 2331 | sockaddr_port_match(const struct sockaddr *sa1, const struct sockaddr *sa2) |
| @@ -2327,200 +2355,218 @@ wg_update_endpoint_if_necessary(struct w | | | @@ -2327,200 +2355,218 @@ wg_update_endpoint_if_necessary(struct w |
2327 | #ifdef WG_DEBUG_LOG | | 2355 | #ifdef WG_DEBUG_LOG |
2328 | char oldaddr[128], newaddr[128]; | | 2356 | char oldaddr[128], newaddr[128]; |
2329 | sockaddr_format(wgsatosa(wgsa), oldaddr, sizeof(oldaddr)); | | 2357 | sockaddr_format(wgsatosa(wgsa), oldaddr, sizeof(oldaddr)); |
2330 | sockaddr_format(src, newaddr, sizeof(newaddr)); | | 2358 | sockaddr_format(src, newaddr, sizeof(newaddr)); |
2331 | WG_DLOG("old=%s, new=%s\n", oldaddr, newaddr); | | 2359 | WG_DLOG("old=%s, new=%s\n", oldaddr, newaddr); |
2332 | #endif | | 2360 | #endif |
2333 | | | 2361 | |
2334 | /* | | 2362 | /* |
2335 | * III: "Since the packet has authenticated correctly, the source IP of | | 2363 | * III: "Since the packet has authenticated correctly, the source IP of |
2336 | * the outer UDP/IP packet is used to update the endpoint for peer..." | | 2364 | * the outer UDP/IP packet is used to update the endpoint for peer..." |
2337 | */ | | 2365 | */ |
2338 | if (__predict_false(sockaddr_cmp(src, wgsatosa(wgsa)) != 0 || | | 2366 | if (__predict_false(sockaddr_cmp(src, wgsatosa(wgsa)) != 0 || |
2339 | !sockaddr_port_match(src, wgsatosa(wgsa)))) { | | 2367 | !sockaddr_port_match(src, wgsatosa(wgsa)))) { |
2340 | mutex_enter(wgp->wgp_lock); | | | |
2341 | /* XXX We can't change the endpoint twice in a short period */ | | 2368 | /* XXX We can't change the endpoint twice in a short period */ |
2342 | if (!wgp->wgp_endpoint_changing) { | | 2369 | if (atomic_swap_uint(&wgp->wgp_endpoint_changing, 1) == 0) { |
2343 | wg_change_endpoint(wgp, src); | | 2370 | wg_change_endpoint(wgp, src); |
2344 | } | | 2371 | } |
2345 | mutex_exit(wgp->wgp_lock); | | | |
2346 | } | | 2372 | } |
2347 | | | 2373 | |
2348 | wg_put_sa(wgp, wgsa, &psref); | | 2374 | wg_put_sa(wgp, wgsa, &psref); |
2349 | } | | 2375 | } |
2350 | | | 2376 | |
2351 | static void | | 2377 | static void |
2352 | wg_handle_msg_data(struct wg_softc *wg, struct mbuf *m, | | 2378 | wg_handle_msg_data(struct wg_softc *wg, struct mbuf *m, |
2353 | const struct sockaddr *src) | | 2379 | const struct sockaddr *src) |
2354 | { | | 2380 | { |
2355 | struct wg_msg_data *wgmd; | | 2381 | struct wg_msg_data *wgmd; |
2356 | char *encrypted_buf = NULL, *decrypted_buf; | | 2382 | char *encrypted_buf = NULL, *decrypted_buf; |
2357 | size_t encrypted_len, decrypted_len; | | 2383 | size_t encrypted_len, decrypted_len; |
2358 | struct wg_session *wgs; | | 2384 | struct wg_session *wgs; |
2359 | struct wg_peer *wgp; | | 2385 | struct wg_peer *wgp; |
| | | 2386 | int state; |
2360 | size_t mlen; | | 2387 | size_t mlen; |
2361 | struct psref psref; | | 2388 | struct psref psref; |
2362 | int error, af; | | 2389 | int error, af; |
2363 | bool success, free_encrypted_buf = false, ok; | | 2390 | bool success, free_encrypted_buf = false, ok; |
2364 | struct mbuf *n; | | 2391 | struct mbuf *n; |
2365 | | | 2392 | |
2366 | KASSERT(m->m_len >= sizeof(struct wg_msg_data)); | | 2393 | KASSERT(m->m_len >= sizeof(struct wg_msg_data)); |
2367 | wgmd = mtod(m, struct wg_msg_data *); | | 2394 | wgmd = mtod(m, struct wg_msg_data *); |
2368 | | | 2395 | |
2369 | KASSERT(wgmd->wgmd_type == htole32(WG_MSG_TYPE_DATA)); | | 2396 | KASSERT(wgmd->wgmd_type == htole32(WG_MSG_TYPE_DATA)); |
2370 | WG_TRACE("data"); | | 2397 | WG_TRACE("data"); |
2371 | | | 2398 | |
| | | 2399 | /* Find the putative session, or drop. */ |
2372 | wgs = wg_lookup_session_by_index(wg, wgmd->wgmd_receiver, &psref); | | 2400 | wgs = wg_lookup_session_by_index(wg, wgmd->wgmd_receiver, &psref); |
2373 | if (wgs == NULL) { | | 2401 | if (wgs == NULL) { |
2374 | WG_TRACE("No session found"); | | 2402 | WG_TRACE("No session found"); |
2375 | m_freem(m); | | 2403 | m_freem(m); |
2376 | return; | | 2404 | return; |
2377 | } | | 2405 | } |
| | | 2406 | |
| | | 2407 | /* |
| | | 2408 | * We are only ready to handle data when in INIT_PASSIVE, |
| | | 2409 | * ESTABLISHED, or DESTROYING. All transitions out of that |
| | | 2410 | * state dissociate the session index and drain psrefs. |
| | | 2411 | */ |
| | | 2412 | state = atomic_load_relaxed(&wgs->wgs_state); |
| | | 2413 | switch (state) { |
| | | 2414 | case WGS_STATE_UNKNOWN: |
| | | 2415 | panic("wg session %p in unknown state has session index %u", |
| | | 2416 | wgs, wgmd->wgmd_receiver); |
| | | 2417 | case WGS_STATE_INIT_ACTIVE: |
| | | 2418 | WG_TRACE("not yet ready for data"); |
| | | 2419 | goto out; |
| | | 2420 | case WGS_STATE_INIT_PASSIVE: |
| | | 2421 | case WGS_STATE_ESTABLISHED: |
| | | 2422 | case WGS_STATE_DESTROYING: |
| | | 2423 | break; |
| | | 2424 | } |
| | | 2425 | |
| | | 2426 | /* |
| | | 2427 | * Get the peer, for rate-limited logs (XXX MPSAFE, dtrace) and |
| | | 2428 | * to update the endpoint if authentication succeeds. |
| | | 2429 | */ |
2378 | wgp = wgs->wgs_peer; | | 2430 | wgp = wgs->wgs_peer; |
2379 | | | 2431 | |
| | | 2432 | /* |
| | | 2433 | * Reject outrageously wrong sequence numbers before doing any |
| | | 2434 | * crypto work or taking any locks. |
| | | 2435 | */ |
2380 | error = sliwin_check_fast(&wgs->wgs_recvwin->window, | | 2436 | error = sliwin_check_fast(&wgs->wgs_recvwin->window, |
2381 | le64toh(wgmd->wgmd_counter)); | | 2437 | le64toh(wgmd->wgmd_counter)); |
2382 | if (error) { | | 2438 | if (error) { |
2383 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 2439 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
2384 | "out-of-window packet: %"PRIu64"\n", | | 2440 | "out-of-window packet: %"PRIu64"\n", |
2385 | le64toh(wgmd->wgmd_counter)); | | 2441 | le64toh(wgmd->wgmd_counter)); |
2386 | goto out; | | 2442 | goto out; |
2387 | } | | 2443 | } |
2388 | | | 2444 | |
| | | 2445 | /* Ensure the payload and authenticator are contiguous. */ |
2389 | mlen = m_length(m); | | 2446 | mlen = m_length(m); |
2390 | encrypted_len = mlen - sizeof(*wgmd); | | 2447 | encrypted_len = mlen - sizeof(*wgmd); |
2391 | | | | |
2392 | if (encrypted_len < WG_AUTHTAG_LEN) { | | 2448 | if (encrypted_len < WG_AUTHTAG_LEN) { |
2393 | WG_DLOG("Short encrypted_len: %lu\n", encrypted_len); | | 2449 | WG_DLOG("Short encrypted_len: %lu\n", encrypted_len); |
2394 | goto out; | | 2450 | goto out; |
2395 | } | | 2451 | } |
2396 | | | | |
2397 | success = m_ensure_contig(&m, sizeof(*wgmd) + encrypted_len); | | 2452 | success = m_ensure_contig(&m, sizeof(*wgmd) + encrypted_len); |
2398 | if (success) { | | 2453 | if (success) { |
2399 | encrypted_buf = mtod(m, char *) + sizeof(*wgmd); | | 2454 | encrypted_buf = mtod(m, char *) + sizeof(*wgmd); |
2400 | } else { | | 2455 | } else { |
2401 | encrypted_buf = kmem_intr_alloc(encrypted_len, KM_NOSLEEP); | | 2456 | encrypted_buf = kmem_intr_alloc(encrypted_len, KM_NOSLEEP); |
2402 | if (encrypted_buf == NULL) { | | 2457 | if (encrypted_buf == NULL) { |
2403 | WG_DLOG("failed to allocate encrypted_buf\n"); | | 2458 | WG_DLOG("failed to allocate encrypted_buf\n"); |
2404 | goto out; | | 2459 | goto out; |
2405 | } | | 2460 | } |
2406 | m_copydata(m, sizeof(*wgmd), encrypted_len, encrypted_buf); | | 2461 | m_copydata(m, sizeof(*wgmd), encrypted_len, encrypted_buf); |
2407 | free_encrypted_buf = true; | | 2462 | free_encrypted_buf = true; |
2408 | } | | 2463 | } |
2409 | /* m_ensure_contig may change m regardless of its result */ | | 2464 | /* m_ensure_contig may change m regardless of its result */ |
2410 | KASSERT(m->m_len >= sizeof(*wgmd)); | | 2465 | KASSERT(m->m_len >= sizeof(*wgmd)); |
2411 | wgmd = mtod(m, struct wg_msg_data *); | | 2466 | wgmd = mtod(m, struct wg_msg_data *); |
2412 | | | 2467 | |
| | | 2468 | /* |
| | | 2469 | * Get a buffer for the plaintext. Add WG_AUTHTAG_LEN to avoid |
| | | 2470 | * a zero-length buffer (XXX). Drop if plaintext is longer |
| | | 2471 | * than MCLBYTES (XXX). |
| | | 2472 | */ |
2413 | decrypted_len = encrypted_len - WG_AUTHTAG_LEN; | | 2473 | decrypted_len = encrypted_len - WG_AUTHTAG_LEN; |
2414 | if (decrypted_len > MCLBYTES) { | | 2474 | if (decrypted_len > MCLBYTES) { |
2415 | /* FIXME handle larger data than MCLBYTES */ | | 2475 | /* FIXME handle larger data than MCLBYTES */ |
2416 | WG_DLOG("couldn't handle larger data than MCLBYTES\n"); | | 2476 | WG_DLOG("couldn't handle larger data than MCLBYTES\n"); |
2417 | goto out; | | 2477 | goto out; |
2418 | } | | 2478 | } |
2419 | | | | |
2420 | /* To avoid zero length */ | | | |
2421 | n = wg_get_mbuf(0, decrypted_len + WG_AUTHTAG_LEN); | | 2479 | n = wg_get_mbuf(0, decrypted_len + WG_AUTHTAG_LEN); |
2422 | if (n == NULL) { | | 2480 | if (n == NULL) { |
2423 | WG_DLOG("wg_get_mbuf failed\n"); | | 2481 | WG_DLOG("wg_get_mbuf failed\n"); |
2424 | goto out; | | 2482 | goto out; |
2425 | } | | 2483 | } |
2426 | decrypted_buf = mtod(n, char *); | | 2484 | decrypted_buf = mtod(n, char *); |
2427 | | | 2485 | |
| | | 2486 | /* Decrypt and verify the packet. */ |
2428 | WG_DLOG("mlen=%lu, encrypted_len=%lu\n", mlen, encrypted_len); | | 2487 | WG_DLOG("mlen=%lu, encrypted_len=%lu\n", mlen, encrypted_len); |
2429 | error = wg_algo_aead_dec(decrypted_buf, | | 2488 | error = wg_algo_aead_dec(decrypted_buf, |
2430 | encrypted_len - WG_AUTHTAG_LEN /* can be 0 */, | | 2489 | encrypted_len - WG_AUTHTAG_LEN /* can be 0 */, |
2431 | wgs->wgs_tkey_recv, le64toh(wgmd->wgmd_counter), encrypted_buf, | | 2490 | wgs->wgs_tkey_recv, le64toh(wgmd->wgmd_counter), encrypted_buf, |
2432 | encrypted_len, NULL, 0); | | 2491 | encrypted_len, NULL, 0); |
2433 | if (error != 0) { | | 2492 | if (error != 0) { |
2434 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 2493 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
2435 | "failed to wg_algo_aead_dec\n"); | | 2494 | "failed to wg_algo_aead_dec\n"); |
2436 | m_freem(n); | | 2495 | m_freem(n); |
2437 | goto out; | | 2496 | goto out; |
2438 | } | | 2497 | } |
2439 | WG_DLOG("outsize=%u\n", (u_int)decrypted_len); | | 2498 | WG_DLOG("outsize=%u\n", (u_int)decrypted_len); |
2440 | | | 2499 | |
| | | 2500 | /* Packet is genuine. Reject it if a replay or just too old. */ |
2441 | mutex_enter(&wgs->wgs_recvwin->lock); | | 2501 | mutex_enter(&wgs->wgs_recvwin->lock); |
2442 | error = sliwin_update(&wgs->wgs_recvwin->window, | | 2502 | error = sliwin_update(&wgs->wgs_recvwin->window, |
2443 | le64toh(wgmd->wgmd_counter)); | | 2503 | le64toh(wgmd->wgmd_counter)); |
2444 | mutex_exit(&wgs->wgs_recvwin->lock); | | 2504 | mutex_exit(&wgs->wgs_recvwin->lock); |
2445 | if (error) { | | 2505 | if (error) { |
2446 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 2506 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
2447 | "replay or out-of-window packet: %"PRIu64"\n", | | 2507 | "replay or out-of-window packet: %"PRIu64"\n", |
2448 | le64toh(wgmd->wgmd_counter)); | | 2508 | le64toh(wgmd->wgmd_counter)); |
2449 | m_freem(n); | | 2509 | m_freem(n); |
2450 | goto out; | | 2510 | goto out; |
2451 | } | | 2511 | } |
2452 | | | 2512 | |
| | | 2513 | /* We're done with m now; free it and chuck the pointers. */ |
2453 | m_freem(m); | | 2514 | m_freem(m); |
2454 | m = NULL; | | 2515 | m = NULL; |
2455 | wgmd = NULL; | | 2516 | wgmd = NULL; |
2456 | | | 2517 | |
| | | 2518 | /* |
| | | 2519 | * Validate the encapsulated packet header and get the address |
| | | 2520 | * family, or drop. |
| | | 2521 | */ |
2457 | ok = wg_validate_inner_packet(decrypted_buf, decrypted_len, &af); | | 2522 | ok = wg_validate_inner_packet(decrypted_buf, decrypted_len, &af); |
2458 | if (!ok) { | | 2523 | if (!ok) { |
2459 | /* something wrong... */ | | | |
2460 | m_freem(n); | | 2524 | m_freem(n); |
2461 | goto out; | | 2525 | goto out; |
2462 | } | | 2526 | } |
2463 | | | 2527 | |
| | | 2528 | /* |
| | | 2529 | * The packet is genuine. Update the peer's endpoint if the |
| | | 2530 | * source address changed. |
| | | 2531 | * |
| | | 2532 | * XXX How to prevent DoS by replaying genuine packets from the |
| | | 2533 | * wrong source address? |
| | | 2534 | */ |
2464 | wg_update_endpoint_if_necessary(wgp, src); | | 2535 | wg_update_endpoint_if_necessary(wgp, src); |
2465 | | | 2536 | |
| | | 2537 | /* Submit it into our network stack if routable. */ |
2466 | ok = wg_validate_route(wg, wgp, af, decrypted_buf); | | 2538 | ok = wg_validate_route(wg, wgp, af, decrypted_buf); |
2467 | if (ok) { | | 2539 | if (ok) { |
2468 | wg->wg_ops->input(&wg->wg_if, n, af); | | 2540 | wg->wg_ops->input(&wg->wg_if, n, af); |
2469 | } else { | | 2541 | } else { |
2470 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 2542 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
2471 | "invalid source address\n"); | | 2543 | "invalid source address\n"); |
2472 | m_freem(n); | | 2544 | m_freem(n); |
2473 | /* | | 2545 | /* |
2474 | * The inner address is invalid however the session is valid | | 2546 | * The inner address is invalid however the session is valid |
2475 | * so continue the session processing below. | | 2547 | * so continue the session processing below. |
2476 | */ | | 2548 | */ |
2477 | } | | 2549 | } |
2478 | n = NULL; | | 2550 | n = NULL; |
2479 | | | 2551 | |
2480 | if (wgs->wgs_state == WGS_STATE_INIT_PASSIVE) { | | 2552 | /* Update the state machine if necessary. */ |
2481 | struct wg_session *wgs_prev; | | 2553 | if (__predict_false(state == WGS_STATE_INIT_PASSIVE)) { |
2482 | | | 2554 | /* |
2483 | KASSERT(wgs == wgp->wgp_session_unstable); | | 2555 | * We were waiting for the initiator to send their |
2484 | wgs->wgs_state = WGS_STATE_ESTABLISHED; | | 2556 | * first data transport message, and that has happened. |
2485 | wgs->wgs_time_established = time_uptime; | | 2557 | * Schedule a task to establish this session. |
2486 | wgs->wgs_time_last_data_sent = 0; | | 2558 | */ |
2487 | wgs->wgs_is_initiator = false; | | 2559 | wg_schedule_peer_task(wgp, WGP_TASK_ESTABLISH_SESSION); |
2488 | WG_TRACE("WGS_STATE_ESTABLISHED"); | | | |
2489 | | | | |
2490 | mutex_enter(wgp->wgp_lock); | | | |
2491 | wg_swap_sessions(wgp); | | | |
2492 | wgs_prev = wgp->wgp_session_unstable; | | | |
2493 | mutex_enter(wgs_prev->wgs_lock); | | | |
2494 | getnanotime(&wgp->wgp_last_handshake_time); | | | |
2495 | wgp->wgp_handshake_start_time = 0; | | | |
2496 | wgp->wgp_last_sent_mac1_valid = false; | | | |
2497 | wgp->wgp_last_sent_cookie_valid = false; | | | |
2498 | mutex_exit(wgp->wgp_lock); | | | |
2499 | | | | |
2500 | if (wgs_prev->wgs_state == WGS_STATE_ESTABLISHED) { | | | |
2501 | wgs_prev->wgs_state = WGS_STATE_DESTROYING; | | | |
2502 | /* We can't destroy the old session immediately */ | | | |
2503 | wg_schedule_session_dtor_timer(wgp); | | | |
2504 | } else { | | | |
2505 | wg_clear_states(wgs_prev); | | | |
2506 | wgs_prev->wgs_state = WGS_STATE_UNKNOWN; | | | |
2507 | } | | | |
2508 | mutex_exit(wgs_prev->wgs_lock); | | | |
2509 | | | | |
2510 | /* Anyway run a softint to flush pending packets */ | | | |
2511 | kpreempt_disable(); | | | |
2512 | softint_schedule(wgp->wgp_si); | | | |
2513 | kpreempt_enable(); | | | |
2514 | } else { | | 2560 | } else { |
2515 | if (__predict_false(wg_need_to_send_init_message(wgs))) { | | 2561 | if (__predict_false(wg_need_to_send_init_message(wgs))) { |
2516 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); | | 2562 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); |
2517 | } | | 2563 | } |
2518 | /* | | 2564 | /* |
2519 | * [W] 6.5 Passive Keepalive | | 2565 | * [W] 6.5 Passive Keepalive |
2520 | * "If a peer has received a validly-authenticated transport | | 2566 | * "If a peer has received a validly-authenticated transport |
2521 | * data message (section 5.4.6), but does not have any packets | | 2567 | * data message (section 5.4.6), but does not have any packets |
2522 | * itself to send back for KEEPALIVE-TIMEOUT seconds, it sends | | 2568 | * itself to send back for KEEPALIVE-TIMEOUT seconds, it sends |
2523 | * a keepalive message." | | 2569 | * a keepalive message." |
2524 | */ | | 2570 | */ |
2525 | WG_DLOG("time_uptime=%lu wgs_time_last_data_sent=%lu\n", | | 2571 | WG_DLOG("time_uptime=%lu wgs_time_last_data_sent=%lu\n", |
2526 | time_uptime, wgs->wgs_time_last_data_sent); | | 2572 | time_uptime, wgs->wgs_time_last_data_sent); |
| @@ -2545,58 +2591,65 @@ out: | | | @@ -2545,58 +2591,65 @@ out: |
2545 | } | | 2591 | } |
2546 | | | 2592 | |
2547 | static void | | 2593 | static void |
2548 | wg_handle_msg_cookie(struct wg_softc *wg, const struct wg_msg_cookie *wgmc) | | 2594 | wg_handle_msg_cookie(struct wg_softc *wg, const struct wg_msg_cookie *wgmc) |
2549 | { | | 2595 | { |
2550 | struct wg_session *wgs; | | 2596 | struct wg_session *wgs; |
2551 | struct wg_peer *wgp; | | 2597 | struct wg_peer *wgp; |
2552 | struct psref psref; | | 2598 | struct psref psref; |
2553 | int error; | | 2599 | int error; |
2554 | uint8_t key[WG_HASH_LEN]; | | 2600 | uint8_t key[WG_HASH_LEN]; |
2555 | uint8_t cookie[WG_COOKIE_LEN]; | | 2601 | uint8_t cookie[WG_COOKIE_LEN]; |
2556 | | | 2602 | |
2557 | WG_TRACE("cookie msg received"); | | 2603 | WG_TRACE("cookie msg received"); |
| | | 2604 | |
| | | 2605 | /* Find the putative session. */ |
2558 | wgs = wg_lookup_session_by_index(wg, wgmc->wgmc_receiver, &psref); | | 2606 | wgs = wg_lookup_session_by_index(wg, wgmc->wgmc_receiver, &psref); |
2559 | if (wgs == NULL) { | | 2607 | if (wgs == NULL) { |
2560 | WG_TRACE("No session found"); | | 2608 | WG_TRACE("No session found"); |
2561 | return; | | 2609 | return; |
2562 | } | | 2610 | } |
| | | 2611 | |
| | | 2612 | /* Lock the peer so we can update the cookie state. */ |
2563 | wgp = wgs->wgs_peer; | | 2613 | wgp = wgs->wgs_peer; |
| | | 2614 | mutex_enter(wgp->wgp_lock); |
2564 | | | 2615 | |
2565 | if (!wgp->wgp_last_sent_mac1_valid) { | | 2616 | if (!wgp->wgp_last_sent_mac1_valid) { |
2566 | WG_TRACE("No valid mac1 sent (or expired)"); | | 2617 | WG_TRACE("No valid mac1 sent (or expired)"); |
2567 | goto out; | | 2618 | goto out; |
2568 | } | | 2619 | } |
2569 | | | 2620 | |
| | | 2621 | /* Decrypt the cookie and store it for later handshake retry. */ |
2570 | wg_algo_mac_cookie(key, sizeof(key), wgp->wgp_pubkey, | | 2622 | wg_algo_mac_cookie(key, sizeof(key), wgp->wgp_pubkey, |
2571 | sizeof(wgp->wgp_pubkey)); | | 2623 | sizeof(wgp->wgp_pubkey)); |
2572 | error = wg_algo_xaead_dec(cookie, sizeof(cookie), key, | | 2624 | error = wg_algo_xaead_dec(cookie, sizeof(cookie), key, |
2573 | wgmc->wgmc_cookie, sizeof(wgmc->wgmc_cookie), | | 2625 | wgmc->wgmc_cookie, sizeof(wgmc->wgmc_cookie), |
2574 | wgp->wgp_last_sent_mac1, sizeof(wgp->wgp_last_sent_mac1), | | 2626 | wgp->wgp_last_sent_mac1, sizeof(wgp->wgp_last_sent_mac1), |
2575 | wgmc->wgmc_salt); | | 2627 | wgmc->wgmc_salt); |
2576 | if (error != 0) { | | 2628 | if (error != 0) { |
2577 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, | | 2629 | WG_LOG_RATECHECK(&wgp->wgp_ppsratecheck, LOG_DEBUG, |
2578 | "wg_algo_aead_dec for cookie failed: error=%d\n", error); | | 2630 | "wg_algo_aead_dec for cookie failed: error=%d\n", error); |
2579 | goto out; | | 2631 | goto out; |
2580 | } | | 2632 | } |
2581 | /* | | 2633 | /* |
2582 | * [W] 6.6: Interaction with Cookie Reply System | | 2634 | * [W] 6.6: Interaction with Cookie Reply System |
2583 | * "it should simply store the decrypted cookie value from the cookie | | 2635 | * "it should simply store the decrypted cookie value from the cookie |
2584 | * reply message, and wait for the expiration of the REKEY-TIMEOUT | | 2636 | * reply message, and wait for the expiration of the REKEY-TIMEOUT |
2585 | * timer for retrying a handshake initiation message." | | 2637 | * timer for retrying a handshake initiation message." |
2586 | */ | | 2638 | */ |
2587 | wgp->wgp_latest_cookie_time = time_uptime; | | 2639 | wgp->wgp_latest_cookie_time = time_uptime; |
2588 | memcpy(wgp->wgp_latest_cookie, cookie, sizeof(wgp->wgp_latest_cookie)); | | 2640 | memcpy(wgp->wgp_latest_cookie, cookie, sizeof(wgp->wgp_latest_cookie)); |
2589 | out: | | 2641 | out: |
| | | 2642 | mutex_exit(wgp->wgp_lock); |
2590 | wg_put_session(wgs, &psref); | | 2643 | wg_put_session(wgs, &psref); |
2591 | } | | 2644 | } |
2592 | | | 2645 | |
2593 | static struct mbuf * | | 2646 | static struct mbuf * |
2594 | wg_validate_msg_header(struct wg_softc *wg, struct mbuf *m) | | 2647 | wg_validate_msg_header(struct wg_softc *wg, struct mbuf *m) |
2595 | { | | 2648 | { |
2596 | struct wg_msg wgm; | | 2649 | struct wg_msg wgm; |
2597 | size_t mbuflen; | | 2650 | size_t mbuflen; |
2598 | size_t msglen; | | 2651 | size_t msglen; |
2599 | | | 2652 | |
2600 | /* | | 2653 | /* |
2601 | * Get the mbuf chain length. It is already guaranteed, by | | 2654 | * Get the mbuf chain length. It is already guaranteed, by |
2602 | * wg_overudp_cb, to be large enough for a struct wg_msg. | | 2655 | * wg_overudp_cb, to be large enough for a struct wg_msg. |
| @@ -2720,135 +2773,224 @@ wg_get_peer(struct wg_peer *wgp, struct | | | @@ -2720,135 +2773,224 @@ wg_get_peer(struct wg_peer *wgp, struct |
2720 | psref_acquire(psref, &wgp->wgp_psref, wg_psref_class); | | 2773 | psref_acquire(psref, &wgp->wgp_psref, wg_psref_class); |
2721 | } | | 2774 | } |
2722 | | | 2775 | |
2723 | static void | | 2776 | static void |
2724 | wg_put_peer(struct wg_peer *wgp, struct psref *psref) | | 2777 | wg_put_peer(struct wg_peer *wgp, struct psref *psref) |
2725 | { | | 2778 | { |
2726 | | | 2779 | |
2727 | psref_release(psref, &wgp->wgp_psref, wg_psref_class); | | 2780 | psref_release(psref, &wgp->wgp_psref, wg_psref_class); |
2728 | } | | 2781 | } |
2729 | | | 2782 | |
2730 | static void | | 2783 | static void |
2731 | wg_task_send_init_message(struct wg_softc *wg, struct wg_peer *wgp) | | 2784 | wg_task_send_init_message(struct wg_softc *wg, struct wg_peer *wgp) |
2732 | { | | 2785 | { |
2733 | struct psref psref; | | | |
2734 | struct wg_session *wgs; | | 2786 | struct wg_session *wgs; |
2735 | | | 2787 | |
2736 | WG_TRACE("WGP_TASK_SEND_INIT_MESSAGE"); | | 2788 | WG_TRACE("WGP_TASK_SEND_INIT_MESSAGE"); |
2737 | | | 2789 | |
2738 | if (!wgp->wgp_endpoint_available) { | | 2790 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 2791 | |
| | | 2792 | if (!atomic_load_acquire(&wgp->wgp_endpoint_available)) { |
2739 | WGLOG(LOG_DEBUG, "No endpoint available\n"); | | 2793 | WGLOG(LOG_DEBUG, "No endpoint available\n"); |
2740 | /* XXX should do something? */ | | 2794 | /* XXX should do something? */ |
2741 | return; | | 2795 | return; |
2742 | } | | 2796 | } |
2743 | | | 2797 | |
2744 | wgs = wg_get_stable_session(wgp, &psref); | | 2798 | wgs = wgp->wgp_session_stable; |
2745 | if (wgs->wgs_state == WGS_STATE_UNKNOWN) { | | 2799 | if (wgs->wgs_state == WGS_STATE_UNKNOWN) { |
2746 | wg_put_session(wgs, &psref); | | 2800 | /* XXX What if the unstable session is already INIT_ACTIVE? */ |
2747 | wg_send_handshake_msg_init(wg, wgp); | | 2801 | wg_send_handshake_msg_init(wg, wgp); |
2748 | } else { | | 2802 | } else { |
2749 | wg_put_session(wgs, &psref); | | | |
2750 | /* rekey */ | | 2803 | /* rekey */ |
2751 | wgs = wg_get_unstable_session(wgp, &psref); | | 2804 | wgs = wgp->wgp_session_unstable; |
2752 | if (wgs->wgs_state != WGS_STATE_INIT_ACTIVE) | | 2805 | if (wgs->wgs_state != WGS_STATE_INIT_ACTIVE) |
2753 | wg_send_handshake_msg_init(wg, wgp); | | 2806 | wg_send_handshake_msg_init(wg, wgp); |
2754 | wg_put_session(wgs, &psref); | | | |
2755 | } | | 2807 | } |
2756 | } | | 2808 | } |
2757 | | | 2809 | |
2758 | static void | | 2810 | static void |
| | | 2811 | wg_task_retry_handshake(struct wg_softc *wg, struct wg_peer *wgp) |
| | | 2812 | { |
| | | 2813 | struct wg_session *wgs; |
| | | 2814 | |
| | | 2815 | WG_TRACE("WGP_TASK_RETRY_HANDSHAKE"); |
| | | 2816 | |
| | | 2817 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 2818 | KASSERT(wgp->wgp_handshake_start_time != 0); |
| | | 2819 | |
| | | 2820 | wgs = wgp->wgp_session_unstable; |
| | | 2821 | if (wgs->wgs_state != WGS_STATE_INIT_ACTIVE) |
| | | 2822 | return; |
| | | 2823 | |
| | | 2824 | /* |
| | | 2825 | * XXX no real need to assign a new index here, but we do need |
| | | 2826 | * to transition to UNKNOWN temporarily |
| | | 2827 | */ |
| | | 2828 | wg_put_session_index(wg, wgs); |
| | | 2829 | |
| | | 2830 | /* [W] 6.4 Handshake Initiation Retransmission */ |
| | | 2831 | if ((time_uptime - wgp->wgp_handshake_start_time) > |
| | | 2832 | wg_rekey_attempt_time) { |
| | | 2833 | /* Give up handshaking */ |
| | | 2834 | wgp->wgp_handshake_start_time = 0; |
| | | 2835 | WG_TRACE("give up"); |
| | | 2836 | |
| | | 2837 | /* |
| | | 2838 | * If a new data packet comes, handshaking will be retried |
| | | 2839 | * and a new session would be established at that time, |
| | | 2840 | * however we don't want to send pending packets then. |
| | | 2841 | */ |
| | | 2842 | wg_purge_pending_packets(wgp); |
| | | 2843 | return; |
| | | 2844 | } |
| | | 2845 | |
| | | 2846 | wg_task_send_init_message(wg, wgp); |
| | | 2847 | } |
| | | 2848 | |
| | | 2849 | static void |
| | | 2850 | wg_task_establish_session(struct wg_softc *wg, struct wg_peer *wgp) |
| | | 2851 | { |
| | | 2852 | struct wg_session *wgs, *wgs_prev; |
| | | 2853 | |
| | | 2854 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 2855 | |
| | | 2856 | wgs = wgp->wgp_session_unstable; |
| | | 2857 | if (wgs->wgs_state != WGS_STATE_INIT_PASSIVE) |
| | | 2858 | /* XXX Can this happen? */ |
| | | 2859 | return; |
| | | 2860 | |
| | | 2861 | wgs->wgs_state = WGS_STATE_ESTABLISHED; |
| | | 2862 | wgs->wgs_time_established = time_uptime; |
| | | 2863 | wgs->wgs_time_last_data_sent = 0; |
| | | 2864 | wgs->wgs_is_initiator = false; |
| | | 2865 | WG_TRACE("WGS_STATE_ESTABLISHED"); |
| | | 2866 | |
| | | 2867 | wg_swap_sessions(wgp); |
| | | 2868 | KASSERT(wgs == wgp->wgp_session_stable); |
| | | 2869 | wgs_prev = wgp->wgp_session_unstable; |
| | | 2870 | getnanotime(&wgp->wgp_last_handshake_time); |
| | | 2871 | wgp->wgp_handshake_start_time = 0; |
| | | 2872 | wgp->wgp_last_sent_mac1_valid = false; |
| | | 2873 | wgp->wgp_last_sent_cookie_valid = false; |
| | | 2874 | |
| | | 2875 | if (wgs_prev->wgs_state == WGS_STATE_ESTABLISHED) { |
| | | 2876 | /* Wait for wg_get_stable_session to drain. */ |
| | | 2877 | pserialize_perform(wgp->wgp_psz); |
| | | 2878 | |
| | | 2879 | /* Transition ESTABLISHED->DESTROYING. */ |
| | | 2880 | wgs_prev->wgs_state = WGS_STATE_DESTROYING; |
| | | 2881 | |
| | | 2882 | /* We can't destroy the old session immediately */ |
| | | 2883 | wg_schedule_session_dtor_timer(wgp); |
| | | 2884 | } else { |
| | | 2885 | KASSERTMSG(wgs_prev->wgs_state == WGS_STATE_UNKNOWN, |
| | | 2886 | "state=%d", wgs_prev->wgs_state); |
| | | 2887 | wg_clear_states(wgs_prev); |
| | | 2888 | wgs_prev->wgs_state = WGS_STATE_UNKNOWN; |
| | | 2889 | } |
| | | 2890 | |
| | | 2891 | /* Anyway run a softint to flush pending packets */ |
| | | 2892 | kpreempt_disable(); |
| | | 2893 | softint_schedule(wgp->wgp_si); |
| | | 2894 | kpreempt_enable(); |
| | | 2895 | } |
| | | 2896 | |
| | | 2897 | static void |
2759 | wg_task_endpoint_changed(struct wg_softc *wg, struct wg_peer *wgp) | | 2898 | wg_task_endpoint_changed(struct wg_softc *wg, struct wg_peer *wgp) |
2760 | { | | 2899 | { |
2761 | | | 2900 | |
2762 | WG_TRACE("WGP_TASK_ENDPOINT_CHANGED"); | | 2901 | WG_TRACE("WGP_TASK_ENDPOINT_CHANGED"); |
2763 | | | 2902 | |
2764 | mutex_enter(wgp->wgp_lock); | | 2903 | KASSERT(mutex_owned(wgp->wgp_lock)); |
2765 | if (wgp->wgp_endpoint_changing) { | | 2904 | |
| | | 2905 | if (atomic_load_relaxed(&wgp->wgp_endpoint_changing)) { |
2766 | pserialize_perform(wgp->wgp_psz); | | 2906 | pserialize_perform(wgp->wgp_psz); |
2767 | psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, | | 2907 | psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, |
2768 | wg_psref_class); | | 2908 | wg_psref_class); |
2769 | psref_target_init(&wgp->wgp_endpoint0->wgsa_psref, | | 2909 | psref_target_init(&wgp->wgp_endpoint0->wgsa_psref, |
2770 | wg_psref_class); | | 2910 | wg_psref_class); |
2771 | wgp->wgp_endpoint_changing = false; | | 2911 | atomic_store_release(&wgp->wgp_endpoint_changing, 0); |
2772 | } | | 2912 | } |
2773 | mutex_exit(wgp->wgp_lock); | | | |
2774 | } | | 2913 | } |
2775 | | | 2914 | |
2776 | static void | | 2915 | static void |
2777 | wg_task_send_keepalive_message(struct wg_softc *wg, struct wg_peer *wgp) | | 2916 | wg_task_send_keepalive_message(struct wg_softc *wg, struct wg_peer *wgp) |
2778 | { | | 2917 | { |
2779 | struct psref psref; | | | |
2780 | struct wg_session *wgs; | | 2918 | struct wg_session *wgs; |
2781 | | | 2919 | |
2782 | WG_TRACE("WGP_TASK_SEND_KEEPALIVE_MESSAGE"); | | 2920 | WG_TRACE("WGP_TASK_SEND_KEEPALIVE_MESSAGE"); |
2783 | | | 2921 | |
2784 | wgs = wg_get_stable_session(wgp, &psref); | | 2922 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 2923 | |
| | | 2924 | wgs = wgp->wgp_session_stable; |
| | | 2925 | if (wgs->wgs_state != WGS_STATE_ESTABLISHED) |
| | | 2926 | return; |
| | | 2927 | |
2785 | wg_send_keepalive_msg(wgp, wgs); | | 2928 | wg_send_keepalive_msg(wgp, wgs); |
2786 | wg_put_session(wgs, &psref); | | | |
2787 | } | | 2929 | } |
2788 | | | 2930 | |
2789 | static void | | 2931 | static void |
2790 | wg_task_destroy_prev_session(struct wg_softc *wg, struct wg_peer *wgp) | | 2932 | wg_task_destroy_prev_session(struct wg_softc *wg, struct wg_peer *wgp) |
2791 | { | | 2933 | { |
2792 | struct wg_session *wgs; | | 2934 | struct wg_session *wgs; |
2793 | | | 2935 | |
2794 | WG_TRACE("WGP_TASK_DESTROY_PREV_SESSION"); | | 2936 | WG_TRACE("WGP_TASK_DESTROY_PREV_SESSION"); |
2795 | | | 2937 | |
2796 | mutex_enter(wgp->wgp_lock); | | 2938 | KASSERT(mutex_owned(wgp->wgp_lock)); |
| | | 2939 | |
2797 | wgs = wgp->wgp_session_unstable; | | 2940 | wgs = wgp->wgp_session_unstable; |
2798 | mutex_enter(wgs->wgs_lock); | | | |
2799 | if (wgs->wgs_state == WGS_STATE_DESTROYING) { | | 2941 | if (wgs->wgs_state == WGS_STATE_DESTROYING) { |
2800 | pserialize_perform(wgp->wgp_psz); | | 2942 | wg_put_session_index(wg, wgs); |
2801 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); | | | |
2802 | psref_target_init(&wgs->wgs_psref, wg_psref_class); | | | |
2803 | wg_clear_states(wgs); | | | |
2804 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | | |
2805 | } | | 2943 | } |
2806 | mutex_exit(wgs->wgs_lock); | | | |
2807 | mutex_exit(wgp->wgp_lock); | | | |
2808 | } | | 2944 | } |
2809 | | | 2945 | |
2810 | static void | | 2946 | static void |
2811 | wg_process_peer_tasks(struct wg_softc *wg) | | 2947 | wg_process_peer_tasks(struct wg_softc *wg) |
2812 | { | | 2948 | { |
2813 | struct wg_peer *wgp; | | 2949 | struct wg_peer *wgp; |
2814 | int s; | | 2950 | int s; |
2815 | | | 2951 | |
2816 | /* XXX should avoid checking all peers */ | | 2952 | /* XXX should avoid checking all peers */ |
2817 | s = pserialize_read_enter(); | | 2953 | s = pserialize_read_enter(); |
2818 | WG_PEER_READER_FOREACH(wgp, wg) { | | 2954 | WG_PEER_READER_FOREACH(wgp, wg) { |
2819 | struct psref psref; | | 2955 | struct psref psref; |
2820 | unsigned int tasks; | | 2956 | unsigned int tasks; |
2821 | | | 2957 | |
2822 | if (wgp->wgp_tasks == 0) | | 2958 | if (wgp->wgp_tasks == 0) |
2823 | continue; | | 2959 | continue; |
2824 | | | 2960 | |
2825 | wg_get_peer(wgp, &psref); | | 2961 | wg_get_peer(wgp, &psref); |
2826 | pserialize_read_exit(s); | | 2962 | pserialize_read_exit(s); |
2827 | | | 2963 | |
2828 | restart: | | 2964 | restart: |
2829 | tasks = atomic_swap_uint(&wgp->wgp_tasks, 0); | | 2965 | tasks = atomic_swap_uint(&wgp->wgp_tasks, 0); |
2830 | KASSERT(tasks != 0); | | 2966 | KASSERT(tasks != 0); |
2831 | | | 2967 | |
2832 | WG_DLOG("tasks=%x\n", tasks); | | 2968 | WG_DLOG("tasks=%x\n", tasks); |
2833 | | | 2969 | |
| | | 2970 | mutex_enter(wgp->wgp_lock); |
2834 | if (ISSET(tasks, WGP_TASK_SEND_INIT_MESSAGE)) | | 2971 | if (ISSET(tasks, WGP_TASK_SEND_INIT_MESSAGE)) |
2835 | wg_task_send_init_message(wg, wgp); | | 2972 | wg_task_send_init_message(wg, wgp); |
| | | 2973 | if (ISSET(tasks, WGP_TASK_RETRY_HANDSHAKE)) |
| | | 2974 | wg_task_retry_handshake(wg, wgp); |
| | | 2975 | if (ISSET(tasks, WGP_TASK_ESTABLISH_SESSION)) |
| | | 2976 | wg_task_establish_session(wg, wgp); |
2836 | if (ISSET(tasks, WGP_TASK_ENDPOINT_CHANGED)) | | 2977 | if (ISSET(tasks, WGP_TASK_ENDPOINT_CHANGED)) |
2837 | wg_task_endpoint_changed(wg, wgp); | | 2978 | wg_task_endpoint_changed(wg, wgp); |
2838 | if (ISSET(tasks, WGP_TASK_SEND_KEEPALIVE_MESSAGE)) | | 2979 | if (ISSET(tasks, WGP_TASK_SEND_KEEPALIVE_MESSAGE)) |
2839 | wg_task_send_keepalive_message(wg, wgp); | | 2980 | wg_task_send_keepalive_message(wg, wgp); |
2840 | if (ISSET(tasks, WGP_TASK_DESTROY_PREV_SESSION)) | | 2981 | if (ISSET(tasks, WGP_TASK_DESTROY_PREV_SESSION)) |
2841 | wg_task_destroy_prev_session(wg, wgp); | | 2982 | wg_task_destroy_prev_session(wg, wgp); |
| | | 2983 | mutex_exit(wgp->wgp_lock); |
2842 | | | 2984 | |
2843 | /* New tasks may be scheduled during processing tasks */ | | 2985 | /* New tasks may be scheduled during processing tasks */ |
2844 | WG_DLOG("wgp_tasks=%d\n", wgp->wgp_tasks); | | 2986 | WG_DLOG("wgp_tasks=%d\n", wgp->wgp_tasks); |
2845 | if (wgp->wgp_tasks != 0) | | 2987 | if (wgp->wgp_tasks != 0) |
2846 | goto restart; | | 2988 | goto restart; |
2847 | | | 2989 | |
2848 | s = pserialize_read_enter(); | | 2990 | s = pserialize_read_enter(); |
2849 | wg_put_peer(wgp, &psref); | | 2991 | wg_put_peer(wgp, &psref); |
2850 | } | | 2992 | } |
2851 | pserialize_read_exit(s); | | 2993 | pserialize_read_exit(s); |
2852 | } | | 2994 | } |
2853 | | | 2995 | |
2854 | static void | | 2996 | static void |
| @@ -3026,27 +3168,27 @@ wg_worker_socreate(struct wg_softc *wg, | | | @@ -3026,27 +3168,27 @@ wg_worker_socreate(struct wg_softc *wg, |
3026 | return 0; | | 3168 | return 0; |
3027 | } | | 3169 | } |
3028 | | | 3170 | |
3029 | static int | | 3171 | static int |
3030 | wg_worker_init(struct wg_softc *wg) | | 3172 | wg_worker_init(struct wg_softc *wg) |
3031 | { | | 3173 | { |
3032 | int error; | | 3174 | int error; |
3033 | struct wg_worker *wgw; | | 3175 | struct wg_worker *wgw; |
3034 | const char *ifname = wg->wg_if.if_xname; | | 3176 | const char *ifname = wg->wg_if.if_xname; |
3035 | struct socket *so; | | 3177 | struct socket *so; |
3036 | | | 3178 | |
3037 | wgw = kmem_zalloc(sizeof(struct wg_worker), KM_SLEEP); | | 3179 | wgw = kmem_zalloc(sizeof(struct wg_worker), KM_SLEEP); |
3038 | | | 3180 | |
3039 | mutex_init(&wgw->wgw_lock, MUTEX_DEFAULT, IPL_NONE); | | 3181 | mutex_init(&wgw->wgw_lock, MUTEX_DEFAULT, IPL_SOFTNET); |
3040 | cv_init(&wgw->wgw_cv, ifname); | | 3182 | cv_init(&wgw->wgw_cv, ifname); |
3041 | wgw->wgw_todie = false; | | 3183 | wgw->wgw_todie = false; |
3042 | wgw->wgw_wakeup_reasons = 0; | | 3184 | wgw->wgw_wakeup_reasons = 0; |
3043 | | | 3185 | |
3044 | error = wg_worker_socreate(wg, wgw, AF_INET, &so); | | 3186 | error = wg_worker_socreate(wg, wgw, AF_INET, &so); |
3045 | if (error != 0) | | 3187 | if (error != 0) |
3046 | goto error; | | 3188 | goto error; |
3047 | wgw->wgw_so4 = so; | | 3189 | wgw->wgw_so4 = so; |
3048 | #ifdef INET6 | | 3190 | #ifdef INET6 |
3049 | error = wg_worker_socreate(wg, wgw, AF_INET6, &so); | | 3191 | error = wg_worker_socreate(wg, wgw, AF_INET6, &so); |
3050 | if (error != 0) | | 3192 | if (error != 0) |
3051 | goto error; | | 3193 | goto error; |
3052 | wgw->wgw_so6 = so; | | 3194 | wgw->wgw_so6 = so; |
| @@ -3119,123 +3261,80 @@ wg_session_hit_limits(struct wg_session | | | @@ -3119,123 +3261,80 @@ wg_session_hit_limits(struct wg_session |
3119 | } | | 3261 | } |
3120 | | | 3262 | |
3121 | return false; | | 3263 | return false; |
3122 | } | | 3264 | } |
3123 | | | 3265 | |
3124 | static void | | 3266 | static void |
3125 | wg_peer_softint(void *arg) | | 3267 | wg_peer_softint(void *arg) |
3126 | { | | 3268 | { |
3127 | struct wg_peer *wgp = arg; | | 3269 | struct wg_peer *wgp = arg; |
3128 | struct wg_session *wgs; | | 3270 | struct wg_session *wgs; |
3129 | struct mbuf *m; | | 3271 | struct mbuf *m; |
3130 | struct psref psref; | | 3272 | struct psref psref; |
3131 | | | 3273 | |
3132 | wgs = wg_get_stable_session(wgp, &psref); | | 3274 | if ((wgs = wg_get_stable_session(wgp, &psref)) == NULL) { |
3133 | if (wgs->wgs_state != WGS_STATE_ESTABLISHED) { | | | |
3134 | /* XXX how to treat? */ | | 3275 | /* XXX how to treat? */ |
3135 | WG_TRACE("skipped"); | | 3276 | WG_TRACE("skipped"); |
3136 | goto out; | | 3277 | return; |
3137 | } | | 3278 | } |
3138 | if (wg_session_hit_limits(wgs)) { | | 3279 | if (wg_session_hit_limits(wgs)) { |
3139 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); | | 3280 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); |
3140 | goto out; | | 3281 | goto out; |
3141 | } | | 3282 | } |
3142 | WG_TRACE("running"); | | 3283 | WG_TRACE("running"); |
3143 | | | 3284 | |
3144 | while ((m = pcq_get(wgp->wgp_q)) != NULL) { | | 3285 | while ((m = pcq_get(wgp->wgp_q)) != NULL) { |
3145 | wg_send_data_msg(wgp, wgs, m); | | 3286 | wg_send_data_msg(wgp, wgs, m); |
3146 | } | | 3287 | } |
3147 | out: | | 3288 | out: |
3148 | wg_put_session(wgs, &psref); | | 3289 | wg_put_session(wgs, &psref); |
3149 | } | | 3290 | } |
3150 | | | 3291 | |
3151 | static void | | 3292 | static void |
3152 | wg_rekey_timer(void *arg) | | 3293 | wg_rekey_timer(void *arg) |
3153 | { | | 3294 | { |
3154 | struct wg_peer *wgp = arg; | | 3295 | struct wg_peer *wgp = arg; |
3155 | | | 3296 | |
3156 | mutex_enter(wgp->wgp_lock); | | 3297 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); |
3157 | if (__predict_true(wgp->wgp_state != WGP_STATE_DESTROYING)) { | | | |
3158 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); | | | |
3159 | } | | | |
3160 | mutex_exit(wgp->wgp_lock); | | | |
3161 | } | | 3298 | } |
3162 | | | 3299 | |
3163 | static void | | 3300 | static void |
3164 | wg_purge_pending_packets(struct wg_peer *wgp) | | 3301 | wg_purge_pending_packets(struct wg_peer *wgp) |
3165 | { | | 3302 | { |
3166 | struct mbuf *m; | | 3303 | struct mbuf *m; |
3167 | | | 3304 | |
3168 | while ((m = pcq_get(wgp->wgp_q)) != NULL) { | | 3305 | while ((m = pcq_get(wgp->wgp_q)) != NULL) { |
3169 | m_freem(m); | | 3306 | m_freem(m); |
3170 | } | | 3307 | } |
3171 | } | | 3308 | } |
3172 | | | 3309 | |
3173 | static void | | 3310 | static void |
3174 | wg_handshake_timeout_timer(void *arg) | | 3311 | wg_handshake_timeout_timer(void *arg) |
3175 | { | | 3312 | { |
3176 | struct wg_peer *wgp = arg; | | 3313 | struct wg_peer *wgp = arg; |
3177 | struct wg_session *wgs; | | | |
3178 | struct psref psref; | | | |
3179 | | | 3314 | |
3180 | WG_TRACE("enter"); | | 3315 | WG_TRACE("enter"); |
3181 | | | 3316 | |
3182 | mutex_enter(wgp->wgp_lock); | | 3317 | wg_schedule_peer_task(wgp, WGP_TASK_RETRY_HANDSHAKE); |
3183 | if (__predict_false(wgp->wgp_state == WGP_STATE_DESTROYING)) { | | | |
3184 | mutex_exit(wgp->wgp_lock); | | | |
3185 | return; | | | |
3186 | } | | | |
3187 | mutex_exit(wgp->wgp_lock); | | | |
3188 | | | | |
3189 | KASSERT(wgp->wgp_handshake_start_time != 0); | | | |
3190 | wgs = wg_get_unstable_session(wgp, &psref); | | | |
3191 | KASSERT(wgs->wgs_state == WGS_STATE_INIT_ACTIVE); | | | |
3192 | | | | |
3193 | /* [W] 6.4 Handshake Initiation Retransmission */ | | | |
3194 | if ((time_uptime - wgp->wgp_handshake_start_time) > | | | |
3195 | wg_rekey_attempt_time) { | | | |
3196 | /* Give up handshaking */ | | | |
3197 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | | |
3198 | wg_clear_states(wgs); | | | |
3199 | wgp->wgp_state = WGP_STATE_GIVEUP; | | | |
3200 | wgp->wgp_handshake_start_time = 0; | | | |
3201 | wg_put_session(wgs, &psref); | | | |
3202 | WG_TRACE("give up"); | | | |
3203 | /* | | | |
3204 | * If a new data packet comes, handshaking will be retried | | | |
3205 | * and a new session would be established at that time, | | | |
3206 | * however we don't want to send pending packets then. | | | |
3207 | */ | | | |
3208 | wg_purge_pending_packets(wgp); | | | |
3209 | return; | | | |
3210 | } | | | |
3211 | | | | |
3212 | /* No response for an initiation message sent, retry handshaking */ | | | |
3213 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | | |
3214 | wg_clear_states(wgs); | | | |
3215 | wg_put_session(wgs, &psref); | | | |
3216 | | | | |
3217 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); | | | |
3218 | } | | 3318 | } |
3219 | | | 3319 | |
3220 | static struct wg_peer * | | 3320 | static struct wg_peer * |
3221 | wg_alloc_peer(struct wg_softc *wg) | | 3321 | wg_alloc_peer(struct wg_softc *wg) |
3222 | { | | 3322 | { |
3223 | struct wg_peer *wgp; | | 3323 | struct wg_peer *wgp; |
3224 | | | 3324 | |
3225 | wgp = kmem_zalloc(sizeof(*wgp), KM_SLEEP); | | 3325 | wgp = kmem_zalloc(sizeof(*wgp), KM_SLEEP); |
3226 | | | 3326 | |
3227 | wgp->wgp_sc = wg; | | 3327 | wgp->wgp_sc = wg; |
3228 | wgp->wgp_state = WGP_STATE_INIT; | | | |
3229 | wgp->wgp_q = pcq_create(1024, KM_SLEEP); | | 3328 | wgp->wgp_q = pcq_create(1024, KM_SLEEP); |
3230 | wgp->wgp_si = softint_establish(SOFTINT_NET, wg_peer_softint, wgp); | | 3329 | wgp->wgp_si = softint_establish(SOFTINT_NET, wg_peer_softint, wgp); |
3231 | callout_init(&wgp->wgp_rekey_timer, CALLOUT_MPSAFE); | | 3330 | callout_init(&wgp->wgp_rekey_timer, CALLOUT_MPSAFE); |
3232 | callout_setfunc(&wgp->wgp_rekey_timer, wg_rekey_timer, wgp); | | 3331 | callout_setfunc(&wgp->wgp_rekey_timer, wg_rekey_timer, wgp); |
3233 | callout_init(&wgp->wgp_handshake_timeout_timer, CALLOUT_MPSAFE); | | 3332 | callout_init(&wgp->wgp_handshake_timeout_timer, CALLOUT_MPSAFE); |
3234 | callout_setfunc(&wgp->wgp_handshake_timeout_timer, | | 3333 | callout_setfunc(&wgp->wgp_handshake_timeout_timer, |
3235 | wg_handshake_timeout_timer, wgp); | | 3334 | wg_handshake_timeout_timer, wgp); |
3236 | callout_init(&wgp->wgp_session_dtor_timer, CALLOUT_MPSAFE); | | 3335 | callout_init(&wgp->wgp_session_dtor_timer, CALLOUT_MPSAFE); |
3237 | callout_setfunc(&wgp->wgp_session_dtor_timer, | | 3336 | callout_setfunc(&wgp->wgp_session_dtor_timer, |
3238 | wg_session_dtor_timer, wgp); | | 3337 | wg_session_dtor_timer, wgp); |
3239 | PSLIST_ENTRY_INIT(wgp, wgp_peerlist_entry); | | 3338 | PSLIST_ENTRY_INIT(wgp, wgp_peerlist_entry); |
3240 | wgp->wgp_endpoint_changing = false; | | 3339 | wgp->wgp_endpoint_changing = false; |
3241 | wgp->wgp_endpoint_available = false; | | 3340 | wgp->wgp_endpoint_available = false; |
| @@ -3247,54 +3346,50 @@ wg_alloc_peer(struct wg_softc *wg) | | | @@ -3247,54 +3346,50 @@ wg_alloc_peer(struct wg_softc *wg) |
3247 | wgp->wgp_endpoint0 = kmem_zalloc(sizeof(*wgp->wgp_endpoint0), KM_SLEEP); | | 3346 | wgp->wgp_endpoint0 = kmem_zalloc(sizeof(*wgp->wgp_endpoint0), KM_SLEEP); |
3248 | psref_target_init(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class); | | 3347 | psref_target_init(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class); |
3249 | psref_target_init(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class); | | 3348 | psref_target_init(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class); |
3250 | | | 3349 | |
3251 | struct wg_session *wgs; | | 3350 | struct wg_session *wgs; |
3252 | wgp->wgp_session_stable = | | 3351 | wgp->wgp_session_stable = |
3253 | kmem_zalloc(sizeof(*wgp->wgp_session_stable), KM_SLEEP); | | 3352 | kmem_zalloc(sizeof(*wgp->wgp_session_stable), KM_SLEEP); |
3254 | wgp->wgp_session_unstable = | | 3353 | wgp->wgp_session_unstable = |
3255 | kmem_zalloc(sizeof(*wgp->wgp_session_unstable), KM_SLEEP); | | 3354 | kmem_zalloc(sizeof(*wgp->wgp_session_unstable), KM_SLEEP); |
3256 | wgs = wgp->wgp_session_stable; | | 3355 | wgs = wgp->wgp_session_stable; |
3257 | wgs->wgs_peer = wgp; | | 3356 | wgs->wgs_peer = wgp; |
3258 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | 3357 | wgs->wgs_state = WGS_STATE_UNKNOWN; |
3259 | psref_target_init(&wgs->wgs_psref, wg_psref_class); | | 3358 | psref_target_init(&wgs->wgs_psref, wg_psref_class); |
3260 | wgs->wgs_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); | | | |
3261 | #ifndef __HAVE_ATOMIC64_LOADSTORE | | 3359 | #ifndef __HAVE_ATOMIC64_LOADSTORE |
3262 | mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET); | | 3360 | mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET); |
3263 | #endif | | 3361 | #endif |
3264 | wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP); | | 3362 | wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP); |
3265 | mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_NONE); | | 3363 | mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_SOFTNET); |
3266 | | | 3364 | |
3267 | wgs = wgp->wgp_session_unstable; | | 3365 | wgs = wgp->wgp_session_unstable; |
3268 | wgs->wgs_peer = wgp; | | 3366 | wgs->wgs_peer = wgp; |
3269 | wgs->wgs_state = WGS_STATE_UNKNOWN; | | 3367 | wgs->wgs_state = WGS_STATE_UNKNOWN; |
3270 | psref_target_init(&wgs->wgs_psref, wg_psref_class); | | 3368 | psref_target_init(&wgs->wgs_psref, wg_psref_class); |
3271 | wgs->wgs_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); | | | |
3272 | #ifndef __HAVE_ATOMIC64_LOADSTORE | | 3369 | #ifndef __HAVE_ATOMIC64_LOADSTORE |
3273 | mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET); | | 3370 | mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET); |
3274 | #endif | | 3371 | #endif |
3275 | wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP); | | 3372 | wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP); |
3276 | mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_NONE); | | 3373 | mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_SOFTNET); |
3277 | | | 3374 | |
3278 | return wgp; | | 3375 | return wgp; |
3279 | } | | 3376 | } |
3280 | | | 3377 | |
3281 | static void | | 3378 | static void |
3282 | wg_destroy_peer(struct wg_peer *wgp) | | 3379 | wg_destroy_peer(struct wg_peer *wgp) |
3283 | { | | 3380 | { |
3284 | struct wg_session *wgs; | | 3381 | struct wg_session *wgs; |
3285 | struct wg_softc *wg = wgp->wgp_sc; | | 3382 | struct wg_softc *wg = wgp->wgp_sc; |
3286 | uint32_t index; | | | |
3287 | void *garbage; | | | |
3288 | | | 3383 | |
3289 | /* Prevent new packets from this peer on any source address. */ | | 3384 | /* Prevent new packets from this peer on any source address. */ |
3290 | rw_enter(wg->wg_rwlock, RW_WRITER); | | 3385 | rw_enter(wg->wg_rwlock, RW_WRITER); |
3291 | for (int i = 0; i < wgp->wgp_n_allowedips; i++) { | | 3386 | for (int i = 0; i < wgp->wgp_n_allowedips; i++) { |
3292 | struct wg_allowedip *wga = &wgp->wgp_allowedips[i]; | | 3387 | struct wg_allowedip *wga = &wgp->wgp_allowedips[i]; |
3293 | struct radix_node_head *rnh = wg_rnh(wg, wga->wga_family); | | 3388 | struct radix_node_head *rnh = wg_rnh(wg, wga->wga_family); |
3294 | struct radix_node *rn; | | 3389 | struct radix_node *rn; |
3295 | | | 3390 | |
3296 | KASSERT(rnh != NULL); | | 3391 | KASSERT(rnh != NULL); |
3297 | rn = rnh->rnh_deladdr(&wga->wga_sa_addr, | | 3392 | rn = rnh->rnh_deladdr(&wga->wga_sa_addr, |
3298 | &wga->wga_sa_mask, rnh); | | 3393 | &wga->wga_sa_mask, rnh); |
3299 | if (rn == NULL) { | | 3394 | if (rn == NULL) { |
3300 | char addrstr[128]; | | 3395 | char addrstr[128]; |
| @@ -3304,56 +3399,45 @@ wg_destroy_peer(struct wg_peer *wgp) | | | @@ -3304,56 +3399,45 @@ wg_destroy_peer(struct wg_peer *wgp) |
3304 | } | | 3399 | } |
3305 | } | | 3400 | } |
3306 | rw_exit(wg->wg_rwlock); | | 3401 | rw_exit(wg->wg_rwlock); |
3307 | | | 3402 | |
3308 | /* Purge pending packets. */ | | 3403 | /* Purge pending packets. */ |
3309 | wg_purge_pending_packets(wgp); | | 3404 | wg_purge_pending_packets(wgp); |
3310 | | | 3405 | |
3311 | /* Halt all packet processing and timeouts. */ | | 3406 | /* Halt all packet processing and timeouts. */ |
3312 | softint_disestablish(wgp->wgp_si); | | 3407 | softint_disestablish(wgp->wgp_si); |
3313 | callout_halt(&wgp->wgp_rekey_timer, NULL); | | 3408 | callout_halt(&wgp->wgp_rekey_timer, NULL); |
3314 | callout_halt(&wgp->wgp_handshake_timeout_timer, NULL); | | 3409 | callout_halt(&wgp->wgp_handshake_timeout_timer, NULL); |
3315 | callout_halt(&wgp->wgp_session_dtor_timer, NULL); | | 3410 | callout_halt(&wgp->wgp_session_dtor_timer, NULL); |
3316 | | | 3411 | |
3317 | /* Remove the sessions by index. */ | | | |
3318 | if ((index = wgp->wgp_session_stable->wgs_sender_index) != 0) { | | | |
3319 | thmap_del(wg->wg_sessions_byindex, &index, sizeof index); | | | |
3320 | wgp->wgp_session_stable->wgs_sender_index = 0; | | | |
3321 | } | | | |
3322 | if ((index = wgp->wgp_session_unstable->wgs_sender_index) != 0) { | | | |
3323 | thmap_del(wg->wg_sessions_byindex, &index, sizeof index); | | | |
3324 | wgp->wgp_session_unstable->wgs_sender_index = 0; | | | |
3325 | } | | | |
3326 | | | | |
3327 | /* Wait for all thmap_gets to complete, and GC. */ | | | |
3328 | garbage = thmap_stage_gc(wg->wg_sessions_byindex); | | | |
3329 | mutex_enter(wgp->wgp_lock); | | | |
3330 | pserialize_perform(wgp->wgp_psz); | | | |
3331 | mutex_exit(wgp->wgp_lock); | | | |
3332 | thmap_gc(wg->wg_sessions_byindex, garbage); | | | |
3333 | | | | |
3334 | wgs = wgp->wgp_session_unstable; | | 3412 | wgs = wgp->wgp_session_unstable; |
3335 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); | | 3413 | if (wgs->wgs_state != WGS_STATE_UNKNOWN) { |
3336 | mutex_obj_free(wgs->wgs_lock); | | 3414 | mutex_enter(wgp->wgp_lock); |
| | | 3415 | wg_destroy_session(wg, wgs); |
| | | 3416 | mutex_exit(wgp->wgp_lock); |
| | | 3417 | } |
3337 | mutex_destroy(&wgs->wgs_recvwin->lock); | | 3418 | mutex_destroy(&wgs->wgs_recvwin->lock); |
3338 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); | | 3419 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); |
3339 | #ifndef __HAVE_ATOMIC64_LOADSTORE | | 3420 | #ifndef __HAVE_ATOMIC64_LOADSTORE |
3340 | mutex_destroy(&wgs->wgs_send_counter_lock); | | 3421 | mutex_destroy(&wgs->wgs_send_counter_lock); |
3341 | #endif | | 3422 | #endif |
3342 | kmem_free(wgs, sizeof(*wgs)); | | 3423 | kmem_free(wgs, sizeof(*wgs)); |
3343 | | | 3424 | |
3344 | wgs = wgp->wgp_session_stable; | | 3425 | wgs = wgp->wgp_session_stable; |
3345 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); | | 3426 | if (wgs->wgs_state != WGS_STATE_UNKNOWN) { |
3346 | mutex_obj_free(wgs->wgs_lock); | | 3427 | mutex_enter(wgp->wgp_lock); |
| | | 3428 | wg_destroy_session(wg, wgs); |
| | | 3429 | mutex_exit(wgp->wgp_lock); |
| | | 3430 | } |
3347 | mutex_destroy(&wgs->wgs_recvwin->lock); | | 3431 | mutex_destroy(&wgs->wgs_recvwin->lock); |
3348 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); | | 3432 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); |
3349 | #ifndef __HAVE_ATOMIC64_LOADSTORE | | 3433 | #ifndef __HAVE_ATOMIC64_LOADSTORE |
3350 | mutex_destroy(&wgs->wgs_send_counter_lock); | | 3434 | mutex_destroy(&wgs->wgs_send_counter_lock); |
3351 | #endif | | 3435 | #endif |
3352 | kmem_free(wgs, sizeof(*wgs)); | | 3436 | kmem_free(wgs, sizeof(*wgs)); |
3353 | | | 3437 | |
3354 | psref_target_destroy(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class); | | 3438 | psref_target_destroy(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class); |
3355 | psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class); | | 3439 | psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class); |
3356 | kmem_free(wgp->wgp_endpoint, sizeof(*wgp->wgp_endpoint)); | | 3440 | kmem_free(wgp->wgp_endpoint, sizeof(*wgp->wgp_endpoint)); |
3357 | kmem_free(wgp->wgp_endpoint0, sizeof(*wgp->wgp_endpoint0)); | | 3441 | kmem_free(wgp->wgp_endpoint0, sizeof(*wgp->wgp_endpoint0)); |
3358 | | | 3442 | |
3359 | pserialize_destroy(wgp->wgp_psz); | | 3443 | pserialize_destroy(wgp->wgp_psz); |
| @@ -3376,27 +3460,26 @@ restart: | | | @@ -3376,27 +3460,26 @@ restart: |
3376 | if (wgp->wgp_name[0]) { | | 3460 | if (wgp->wgp_name[0]) { |
3377 | wgp0 = thmap_del(wg->wg_peers_byname, wgp->wgp_name, | | 3461 | wgp0 = thmap_del(wg->wg_peers_byname, wgp->wgp_name, |
3378 | strlen(wgp->wgp_name)); | | 3462 | strlen(wgp->wgp_name)); |
3379 | KASSERT(wgp0 == wgp); | | 3463 | KASSERT(wgp0 == wgp); |
3380 | garbage_byname = thmap_stage_gc(wg->wg_peers_byname); | | 3464 | garbage_byname = thmap_stage_gc(wg->wg_peers_byname); |
3381 | } | | 3465 | } |
3382 | wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey, | | 3466 | wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey, |
3383 | sizeof(wgp->wgp_pubkey)); | | 3467 | sizeof(wgp->wgp_pubkey)); |
3384 | KASSERT(wgp0 == wgp); | | 3468 | KASSERT(wgp0 == wgp); |
3385 | garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey); | | 3469 | garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey); |
3386 | WG_PEER_WRITER_REMOVE(wgp); | | 3470 | WG_PEER_WRITER_REMOVE(wgp); |
3387 | wg->wg_npeers--; | | 3471 | wg->wg_npeers--; |
3388 | mutex_enter(wgp->wgp_lock); | | 3472 | mutex_enter(wgp->wgp_lock); |
3389 | wgp->wgp_state = WGP_STATE_DESTROYING; | | | |
3390 | pserialize_perform(wgp->wgp_psz); | | 3473 | pserialize_perform(wgp->wgp_psz); |
3391 | mutex_exit(wgp->wgp_lock); | | 3474 | mutex_exit(wgp->wgp_lock); |
3392 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); | | 3475 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); |
3393 | break; | | 3476 | break; |
3394 | } | | 3477 | } |
3395 | mutex_exit(wg->wg_lock); | | 3478 | mutex_exit(wg->wg_lock); |
3396 | | | 3479 | |
3397 | if (wgp == NULL) | | 3480 | if (wgp == NULL) |
3398 | return; | | 3481 | return; |
3399 | | | 3482 | |
3400 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); | | 3483 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); |
3401 | | | 3484 | |
3402 | wg_destroy_peer(wgp); | | 3485 | wg_destroy_peer(wgp); |
| @@ -3413,27 +3496,26 @@ wg_destroy_peer_name(struct wg_softc *wg | | | @@ -3413,27 +3496,26 @@ wg_destroy_peer_name(struct wg_softc *wg |
3413 | void *garbage_byname, *garbage_bypubkey; | | 3496 | void *garbage_byname, *garbage_bypubkey; |
3414 | | | 3497 | |
3415 | mutex_enter(wg->wg_lock); | | 3498 | mutex_enter(wg->wg_lock); |
3416 | wgp = thmap_del(wg->wg_peers_byname, name, strlen(name)); | | 3499 | wgp = thmap_del(wg->wg_peers_byname, name, strlen(name)); |
3417 | if (wgp != NULL) { | | 3500 | if (wgp != NULL) { |
3418 | wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey, | | 3501 | wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey, |
3419 | sizeof(wgp->wgp_pubkey)); | | 3502 | sizeof(wgp->wgp_pubkey)); |
3420 | KASSERT(wgp0 == wgp); | | 3503 | KASSERT(wgp0 == wgp); |
3421 | garbage_byname = thmap_stage_gc(wg->wg_peers_byname); | | 3504 | garbage_byname = thmap_stage_gc(wg->wg_peers_byname); |
3422 | garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey); | | 3505 | garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey); |
3423 | WG_PEER_WRITER_REMOVE(wgp); | | 3506 | WG_PEER_WRITER_REMOVE(wgp); |
3424 | wg->wg_npeers--; | | 3507 | wg->wg_npeers--; |
3425 | mutex_enter(wgp->wgp_lock); | | 3508 | mutex_enter(wgp->wgp_lock); |
3426 | wgp->wgp_state = WGP_STATE_DESTROYING; | | | |
3427 | pserialize_perform(wgp->wgp_psz); | | 3509 | pserialize_perform(wgp->wgp_psz); |
3428 | mutex_exit(wgp->wgp_lock); | | 3510 | mutex_exit(wgp->wgp_lock); |
3429 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); | | 3511 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); |
3430 | } | | 3512 | } |
3431 | mutex_exit(wg->wg_lock); | | 3513 | mutex_exit(wg->wg_lock); |
3432 | | | 3514 | |
3433 | if (wgp == NULL) | | 3515 | if (wgp == NULL) |
3434 | return ENOENT; | | 3516 | return ENOENT; |
3435 | | | 3517 | |
3436 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); | | 3518 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); |
3437 | | | 3519 | |
3438 | wg_destroy_peer(wgp); | | 3520 | wg_destroy_peer(wgp); |
3439 | thmap_gc(wg->wg_peers_byname, garbage_byname); | | 3521 | thmap_gc(wg->wg_peers_byname, garbage_byname); |
| @@ -3597,95 +3679,93 @@ wg_pick_peer_by_sa(struct wg_softc *wg, | | | @@ -3597,95 +3679,93 @@ wg_pick_peer_by_sa(struct wg_softc *wg, |
3597 | | | 3679 | |
3598 | out: | | 3680 | out: |
3599 | rw_exit(wg->wg_rwlock); | | 3681 | rw_exit(wg->wg_rwlock); |
3600 | return wgp; | | 3682 | return wgp; |
3601 | } | | 3683 | } |
3602 | | | 3684 | |
3603 | static void | | 3685 | static void |
3604 | wg_fill_msg_data(struct wg_softc *wg, struct wg_peer *wgp, | | 3686 | wg_fill_msg_data(struct wg_softc *wg, struct wg_peer *wgp, |
3605 | struct wg_session *wgs, struct wg_msg_data *wgmd) | | 3687 | struct wg_session *wgs, struct wg_msg_data *wgmd) |
3606 | { | | 3688 | { |
3607 | | | 3689 | |
3608 | memset(wgmd, 0, sizeof(*wgmd)); | | 3690 | memset(wgmd, 0, sizeof(*wgmd)); |
3609 | wgmd->wgmd_type = htole32(WG_MSG_TYPE_DATA); | | 3691 | wgmd->wgmd_type = htole32(WG_MSG_TYPE_DATA); |
3610 | wgmd->wgmd_receiver = wgs->wgs_receiver_index; | | 3692 | wgmd->wgmd_receiver = wgs->wgs_remote_index; |
3611 | /* [W] 5.4.6: msg.counter := Nm^send */ | | 3693 | /* [W] 5.4.6: msg.counter := Nm^send */ |
3612 | /* [W] 5.4.6: Nm^send := Nm^send + 1 */ | | 3694 | /* [W] 5.4.6: Nm^send := Nm^send + 1 */ |
3613 | wgmd->wgmd_counter = htole64(wg_session_inc_send_counter(wgs)); | | 3695 | wgmd->wgmd_counter = htole64(wg_session_inc_send_counter(wgs)); |
3614 | WG_DLOG("counter=%"PRIu64"\n", le64toh(wgmd->wgmd_counter)); | | 3696 | WG_DLOG("counter=%"PRIu64"\n", le64toh(wgmd->wgmd_counter)); |
3615 | } | | 3697 | } |
3616 | | | 3698 | |
3617 | static int | | 3699 | static int |
3618 | wg_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, | | 3700 | wg_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, |
3619 | const struct rtentry *rt) | | 3701 | const struct rtentry *rt) |
3620 | { | | 3702 | { |
3621 | struct wg_softc *wg = ifp->if_softc; | | 3703 | struct wg_softc *wg = ifp->if_softc; |
3622 | int error = 0; | | 3704 | struct wg_peer *wgp = NULL; |
| | | 3705 | struct wg_session *wgs = NULL; |
| | | 3706 | struct psref wgp_psref, wgs_psref; |
3623 | int bound; | | 3707 | int bound; |
3624 | struct psref psref; | | 3708 | int error; |
| | | 3709 | |
| | | 3710 | bound = curlwp_bind(); |
3625 | | | 3711 | |
3626 | /* TODO make the nest limit configurable via sysctl */ | | 3712 | /* TODO make the nest limit configurable via sysctl */ |
3627 | error = if_tunnel_check_nesting(ifp, m, 1); | | 3713 | error = if_tunnel_check_nesting(ifp, m, 1); |
3628 | if (error != 0) { | | 3714 | if (error) { |
3629 | m_freem(m); | | | |
3630 | WGLOG(LOG_ERR, "tunneling loop detected and packet dropped\n"); | | 3715 | WGLOG(LOG_ERR, "tunneling loop detected and packet dropped\n"); |
3631 | return error; | | 3716 | goto out; |
3632 | } | | 3717 | } |
3633 | | | 3718 | |
3634 | bound = curlwp_bind(); | | | |
3635 | | | | |
3636 | IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); | | 3719 | IFQ_CLASSIFY(&ifp->if_snd, m, dst->sa_family); |
3637 | | | 3720 | |
3638 | bpf_mtap_af(ifp, dst->sa_family, m, BPF_D_OUT); | | 3721 | bpf_mtap_af(ifp, dst->sa_family, m, BPF_D_OUT); |
3639 | | | 3722 | |
3640 | m->m_flags &= ~(M_BCAST|M_MCAST); | | 3723 | m->m_flags &= ~(M_BCAST|M_MCAST); |
3641 | | | 3724 | |
3642 | struct wg_peer *wgp = wg_pick_peer_by_sa(wg, dst, &psref); | | 3725 | wgp = wg_pick_peer_by_sa(wg, dst, &wgp_psref); |
3643 | if (wgp == NULL) { | | 3726 | if (wgp == NULL) { |
3644 | WG_TRACE("peer not found"); | | 3727 | WG_TRACE("peer not found"); |
3645 | error = EHOSTUNREACH; | | 3728 | error = EHOSTUNREACH; |
3646 | goto error; | | 3729 | goto out; |
3647 | } | | 3730 | } |
3648 | | | 3731 | |
3649 | /* Clear checksum-offload flags. */ | | 3732 | /* Clear checksum-offload flags. */ |
3650 | m->m_pkthdr.csum_flags = 0; | | 3733 | m->m_pkthdr.csum_flags = 0; |
3651 | m->m_pkthdr.csum_data = 0; | | 3734 | m->m_pkthdr.csum_data = 0; |
3652 | | | 3735 | |
3653 | if (!pcq_put(wgp->wgp_q, m)) { | | 3736 | if (!pcq_put(wgp->wgp_q, m)) { |
3654 | error = ENOBUFS; | | 3737 | error = ENOBUFS; |
3655 | goto error; | | 3738 | goto out; |
3656 | } | | 3739 | } |
| | | 3740 | m = NULL; /* consumed */ |
3657 | | | 3741 | |
3658 | struct psref psref_wgs; | | 3742 | wgs = wg_get_stable_session(wgp, &wgs_psref); |
3659 | struct wg_session *wgs; | | 3743 | if (wgs != NULL && !wg_session_hit_limits(wgs)) { |
3660 | wgs = wg_get_stable_session(wgp, &psref_wgs); | | | |
3661 | if (wgs->wgs_state == WGS_STATE_ESTABLISHED && | | | |
3662 | !wg_session_hit_limits(wgs)) { | | | |
3663 | kpreempt_disable(); | | 3744 | kpreempt_disable(); |
3664 | softint_schedule(wgp->wgp_si); | | 3745 | softint_schedule(wgp->wgp_si); |
3665 | kpreempt_enable(); | | 3746 | kpreempt_enable(); |
3666 | WG_TRACE("softint scheduled"); | | 3747 | WG_TRACE("softint scheduled"); |
3667 | } else { | | 3748 | } else { |
3668 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); | | 3749 | wg_schedule_peer_task(wgp, WGP_TASK_SEND_INIT_MESSAGE); |
3669 | WG_TRACE("softint NOT scheduled"); | | 3750 | WG_TRACE("softint NOT scheduled"); |
3670 | } | | 3751 | } |
3671 | wg_put_session(wgs, &psref_wgs); | | 3752 | error = 0; |
3672 | wg_put_peer(wgp, &psref); | | | |
3673 | | | | |
3674 | return 0; | | | |
3675 | | | 3753 | |
3676 | error: | | 3754 | out: |
| | | 3755 | if (wgs != NULL) |
| | | 3756 | wg_put_session(wgs, &wgs_psref); |
3677 | if (wgp != NULL) | | 3757 | if (wgp != NULL) |
3678 | wg_put_peer(wgp, &psref); | | 3758 | wg_put_peer(wgp, &wgp_psref); |
3679 | if (m != NULL) | | 3759 | if (m != NULL) |
3680 | m_freem(m); | | 3760 | m_freem(m); |
3681 | curlwp_bindx(bound); | | 3761 | curlwp_bindx(bound); |
3682 | return error; | | 3762 | return error; |
3683 | } | | 3763 | } |
3684 | | | 3764 | |
3685 | static int | | 3765 | static int |
3686 | wg_send_udp(struct wg_peer *wgp, struct mbuf *m) | | 3766 | wg_send_udp(struct wg_peer *wgp, struct mbuf *m) |
3687 | { | | 3767 | { |
3688 | struct psref psref; | | 3768 | struct psref psref; |
3689 | struct wg_sockaddr *wgsa; | | 3769 | struct wg_sockaddr *wgsa; |
3690 | int error; | | 3770 | int error; |
3691 | struct socket *so; | | 3771 | struct socket *so; |