| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_wg.c,v 1.36 2020/08/31 20:21:30 riastradh Exp $ */ | | 1 | /* $NetBSD: if_wg.c,v 1.37 2020/08/31 20:23:56 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.36 2020/08/31 20:21:30 riastradh Exp $"); | | 44 | __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1.37 2020/08/31 20:23:56 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> |
| @@ -67,26 +67,27 @@ __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1. | | | @@ -67,26 +67,27 @@ __KERNEL_RCSID(0, "$NetBSD: if_wg.c,v 1. |
67 | #include <sys/mutex.h> | | 67 | #include <sys/mutex.h> |
68 | #include <sys/pcq.h> | | 68 | #include <sys/pcq.h> |
69 | #include <sys/percpu.h> | | 69 | #include <sys/percpu.h> |
70 | #include <sys/pserialize.h> | | 70 | #include <sys/pserialize.h> |
71 | #include <sys/psref.h> | | 71 | #include <sys/psref.h> |
72 | #include <sys/queue.h> | | 72 | #include <sys/queue.h> |
73 | #include <sys/rwlock.h> | | 73 | #include <sys/rwlock.h> |
74 | #include <sys/socket.h> | | 74 | #include <sys/socket.h> |
75 | #include <sys/socketvar.h> | | 75 | #include <sys/socketvar.h> |
76 | #include <sys/sockio.h> | | 76 | #include <sys/sockio.h> |
77 | #include <sys/sysctl.h> | | 77 | #include <sys/sysctl.h> |
78 | #include <sys/syslog.h> | | 78 | #include <sys/syslog.h> |
79 | #include <sys/systm.h> | | 79 | #include <sys/systm.h> |
| | | 80 | #include <sys/thmap.h> |
80 | #include <sys/time.h> | | 81 | #include <sys/time.h> |
81 | #include <sys/timespec.h> | | 82 | #include <sys/timespec.h> |
82 | | | 83 | |
83 | #include <net/bpf.h> | | 84 | #include <net/bpf.h> |
84 | #include <net/if.h> | | 85 | #include <net/if.h> |
85 | #include <net/if_types.h> | | 86 | #include <net/if_types.h> |
86 | #include <net/if_wg.h> | | 87 | #include <net/if_wg.h> |
87 | #include <net/route.h> | | 88 | #include <net/route.h> |
88 | | | 89 | |
89 | #include <netinet/in.h> | | 90 | #include <netinet/in.h> |
90 | #include <netinet/in_pcb.h> | | 91 | #include <netinet/in_pcb.h> |
91 | #include <netinet/in_var.h> | | 92 | #include <netinet/in_var.h> |
92 | #include <netinet/ip.h> | | 93 | #include <netinet/ip.h> |
| @@ -593,26 +594,29 @@ struct wg_peer { | | | @@ -593,26 +594,29 @@ struct wg_peer { |
593 | struct wg_ops; | | 594 | struct wg_ops; |
594 | | | 595 | |
595 | struct wg_softc { | | 596 | struct wg_softc { |
596 | struct ifnet wg_if; | | 597 | struct ifnet wg_if; |
597 | LIST_ENTRY(wg_softc) wg_list; | | 598 | LIST_ENTRY(wg_softc) wg_list; |
598 | kmutex_t *wg_lock; | | 599 | kmutex_t *wg_lock; |
599 | krwlock_t *wg_rwlock; | | 600 | krwlock_t *wg_rwlock; |
600 | | | 601 | |
601 | uint8_t wg_privkey[WG_STATIC_KEY_LEN]; | | 602 | uint8_t wg_privkey[WG_STATIC_KEY_LEN]; |
602 | uint8_t wg_pubkey[WG_STATIC_KEY_LEN]; | | 603 | uint8_t wg_pubkey[WG_STATIC_KEY_LEN]; |
603 | | | 604 | |
604 | int wg_npeers; | | 605 | int wg_npeers; |
605 | struct pslist_head wg_peers; | | 606 | struct pslist_head wg_peers; |
| | | 607 | struct thmap *wg_peers_bypubkey; |
| | | 608 | struct thmap *wg_peers_byname; |
| | | 609 | struct thmap *wg_sessions_byindex; |
606 | uint16_t wg_listen_port; | | 610 | uint16_t wg_listen_port; |
607 | | | 611 | |
608 | struct wg_worker *wg_worker; | | 612 | struct wg_worker *wg_worker; |
609 | lwp_t *wg_worker_lwp; | | 613 | lwp_t *wg_worker_lwp; |
610 | | | 614 | |
611 | struct radix_node_head *wg_rtable_ipv4; | | 615 | struct radix_node_head *wg_rtable_ipv4; |
612 | struct radix_node_head *wg_rtable_ipv6; | | 616 | struct radix_node_head *wg_rtable_ipv6; |
613 | | | 617 | |
614 | struct wg_ppsratecheck wg_ppsratecheck; | | 618 | struct wg_ppsratecheck wg_ppsratecheck; |
615 | | | 619 | |
616 | struct wg_ops *wg_ops; | | 620 | struct wg_ops *wg_ops; |
617 | | | 621 | |
618 | #ifdef WG_RUMPKERNEL | | 622 | #ifdef WG_RUMPKERNEL |
| @@ -1149,26 +1153,72 @@ wg_lock_unstable_session(struct wg_peer | | | @@ -1149,26 +1153,72 @@ wg_lock_unstable_session(struct wg_peer |
1149 | mutex_exit(wgp->wgp_lock); | | 1153 | mutex_exit(wgp->wgp_lock); |
1150 | return wgs; | | 1154 | return wgs; |
1151 | } | | 1155 | } |
1152 | | | 1156 | |
1153 | #if 0 | | 1157 | #if 0 |
1154 | static void | | 1158 | static void |
1155 | wg_unlock_session(struct wg_peer *wgp, struct wg_session *wgs) | | 1159 | wg_unlock_session(struct wg_peer *wgp, struct wg_session *wgs) |
1156 | { | | 1160 | { |
1157 | | | 1161 | |
1158 | mutex_exit(wgs->wgs_lock); | | 1162 | mutex_exit(wgs->wgs_lock); |
1159 | } | | 1163 | } |
1160 | #endif | | 1164 | #endif |
1161 | | | 1165 | |
| | | 1166 | static uint32_t |
| | | 1167 | wg_assign_sender_index(struct wg_softc *wg, struct wg_session *wgs) |
| | | 1168 | { |
| | | 1169 | struct wg_peer *wgp = wgs->wgs_peer; |
| | | 1170 | struct wg_session *wgs0; |
| | | 1171 | uint32_t index; |
| | | 1172 | void *garbage; |
| | | 1173 | |
| | | 1174 | mutex_enter(wgs->wgs_lock); |
| | | 1175 | |
| | | 1176 | /* Release the current index, if there is one. */ |
| | | 1177 | while ((index = wgs->wgs_sender_index) != 0) { |
| | | 1178 | /* Remove the session by index. */ |
| | | 1179 | thmap_del(wg->wg_sessions_byindex, &index, sizeof index); |
| | | 1180 | wgs->wgs_sender_index = 0; |
| | | 1181 | mutex_exit(wgs->wgs_lock); |
| | | 1182 | |
| | | 1183 | /* Wait for all thmap_gets to complete, and GC. */ |
| | | 1184 | garbage = thmap_stage_gc(wg->wg_sessions_byindex); |
| | | 1185 | mutex_enter(wgs->wgs_peer->wgp_lock); |
| | | 1186 | pserialize_perform(wgp->wgp_psz); |
| | | 1187 | mutex_exit(wgs->wgs_peer->wgp_lock); |
| | | 1188 | thmap_gc(wg->wg_sessions_byindex, garbage); |
| | | 1189 | |
| | | 1190 | mutex_enter(wgs->wgs_lock); |
| | | 1191 | } |
| | | 1192 | |
| | | 1193 | restart: |
| | | 1194 | /* Pick a uniform random nonzero index. */ |
| | | 1195 | while (__predict_false((index = cprng_strong32()) == 0)) |
| | | 1196 | continue; |
| | | 1197 | |
| | | 1198 | /* Try to take it. */ |
| | | 1199 | wgs->wgs_sender_index = index; |
| | | 1200 | wgs0 = thmap_put(wg->wg_sessions_byindex, |
| | | 1201 | &wgs->wgs_sender_index, sizeof wgs->wgs_sender_index, wgs); |
| | | 1202 | |
| | | 1203 | /* If someone else beat us, start over. */ |
| | | 1204 | if (__predict_false(wgs0 != wgs)) |
| | | 1205 | goto restart; |
| | | 1206 | |
| | | 1207 | mutex_exit(wgs->wgs_lock); |
| | | 1208 | |
| | | 1209 | return index; |
| | | 1210 | } |
| | | 1211 | |
1162 | /* | | 1212 | /* |
1163 | * Handshake patterns | | 1213 | * Handshake patterns |
1164 | * | | 1214 | * |
1165 | * [W] 5: "These messages use the "IK" pattern from Noise" | | 1215 | * [W] 5: "These messages use the "IK" pattern from Noise" |
1166 | * [N] 7.5. Interactive handshake patterns (fundamental) | | 1216 | * [N] 7.5. Interactive handshake patterns (fundamental) |
1167 | * "The first character refers to the initiator’s static key:" | | 1217 | * "The first character refers to the initiator’s static key:" |
1168 | * "I = Static key for initiator Immediately transmitted to responder, | | 1218 | * "I = Static key for initiator Immediately transmitted to responder, |
1169 | * despite reduced or absent identity hiding" | | 1219 | * despite reduced or absent identity hiding" |
1170 | * "The second character refers to the responder’s static key:" | | 1220 | * "The second character refers to the responder’s static key:" |
1171 | * "K = Static key for responder Known to initiator" | | 1221 | * "K = Static key for responder Known to initiator" |
1172 | * "IK: | | 1222 | * "IK: |
1173 | * <- s | | 1223 | * <- s |
1174 | * ... | | 1224 | * ... |
| @@ -1182,27 +1232,27 @@ wg_unlock_session(struct wg_peer *wgp, s | | | @@ -1182,27 +1232,27 @@ wg_unlock_session(struct wg_peer *wgp, s |
1182 | * <- e, ee, se, psk" | | 1232 | * <- e, ee, se, psk" |
1183 | */ | | 1233 | */ |
1184 | static void | | 1234 | static void |
1185 | wg_fill_msg_init(struct wg_softc *wg, struct wg_peer *wgp, | | 1235 | wg_fill_msg_init(struct wg_softc *wg, struct wg_peer *wgp, |
1186 | struct wg_session *wgs, struct wg_msg_init *wgmi) | | 1236 | struct wg_session *wgs, struct wg_msg_init *wgmi) |
1187 | { | | 1237 | { |
1188 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ | | 1238 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ |
1189 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ | | 1239 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ |
1190 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; | | 1240 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; |
1191 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; | | 1241 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; |
1192 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; | | 1242 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; |
1193 | | | 1243 | |
1194 | wgmi->wgmi_type = WG_MSG_TYPE_INIT; | | 1244 | wgmi->wgmi_type = WG_MSG_TYPE_INIT; |
1195 | wgmi->wgmi_sender = cprng_strong32(); | | 1245 | wgmi->wgmi_sender = wg_assign_sender_index(wg, wgs); |
1196 | | | 1246 | |
1197 | /* [W] 5.4.2: First Message: Initiator to Responder */ | | 1247 | /* [W] 5.4.2: First Message: Initiator to Responder */ |
1198 | | | 1248 | |
1199 | /* Ci := HASH(CONSTRUCTION) */ | | 1249 | /* Ci := HASH(CONSTRUCTION) */ |
1200 | /* Hi := HASH(Ci || IDENTIFIER) */ | | 1250 | /* Hi := HASH(Ci || IDENTIFIER) */ |
1201 | wg_init_key_and_hash(ckey, hash); | | 1251 | wg_init_key_and_hash(ckey, hash); |
1202 | /* Hi := HASH(Hi || Sr^pub) */ | | 1252 | /* Hi := HASH(Hi || Sr^pub) */ |
1203 | wg_algo_hash(hash, wgp->wgp_pubkey, sizeof(wgp->wgp_pubkey)); | | 1253 | wg_algo_hash(hash, wgp->wgp_pubkey, sizeof(wgp->wgp_pubkey)); |
1204 | | | 1254 | |
1205 | WG_DUMP_HASH("hash", hash); | | 1255 | WG_DUMP_HASH("hash", hash); |
1206 | | | 1256 | |
1207 | /* [N] 2.2: "e" */ | | 1257 | /* [N] 2.2: "e" */ |
1208 | /* Ei^priv, Ei^pub := DH-GENERATE() */ | | 1258 | /* Ei^priv, Ei^pub := DH-GENERATE() */ |
| @@ -1257,27 +1307,26 @@ wg_fill_msg_init(struct wg_softc *wg, st | | | @@ -1257,27 +1307,26 @@ wg_fill_msg_init(struct wg_softc *wg, st |
1257 | memset(wgmi->wgmi_mac2, 0, sizeof(wgmi->wgmi_mac2)); | | 1307 | memset(wgmi->wgmi_mac2, 0, sizeof(wgmi->wgmi_mac2)); |
1258 | else { | | 1308 | else { |
1259 | wg_algo_mac(wgmi->wgmi_mac2, sizeof(wgmi->wgmi_mac2), | | 1309 | wg_algo_mac(wgmi->wgmi_mac2, sizeof(wgmi->wgmi_mac2), |
1260 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, | | 1310 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, |
1261 | (const uint8_t *)wgmi, | | 1311 | (const uint8_t *)wgmi, |
1262 | offsetof(struct wg_msg_init, wgmi_mac2), | | 1312 | offsetof(struct wg_msg_init, wgmi_mac2), |
1263 | NULL, 0); | | 1313 | NULL, 0); |
1264 | } | | 1314 | } |
1265 | | | 1315 | |
1266 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); | | 1316 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); |
1267 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); | | 1317 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); |
1268 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); | | 1318 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); |
1269 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); | | 1319 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); |
1270 | wgs->wgs_sender_index = wgmi->wgmi_sender; | | | |
1271 | WG_DLOG("%s: sender=%x\n", __func__, wgs->wgs_sender_index); | | 1320 | WG_DLOG("%s: sender=%x\n", __func__, wgs->wgs_sender_index); |
1272 | } | | 1321 | } |
1273 | | | 1322 | |
1274 | static void | | 1323 | static void |
1275 | wg_handle_msg_init(struct wg_softc *wg, const struct wg_msg_init *wgmi, | | 1324 | wg_handle_msg_init(struct wg_softc *wg, const struct wg_msg_init *wgmi, |
1276 | const struct sockaddr *src) | | 1325 | const struct sockaddr *src) |
1277 | { | | 1326 | { |
1278 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ | | 1327 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.2: Ci */ |
1279 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ | | 1328 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.2: Hi */ |
1280 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; | | 1329 | uint8_t cipher_key[WG_CIPHER_KEY_LEN]; |
1281 | uint8_t peer_pubkey[WG_STATIC_KEY_LEN]; | | 1330 | uint8_t peer_pubkey[WG_STATIC_KEY_LEN]; |
1282 | struct wg_peer *wgp; | | 1331 | struct wg_peer *wgp; |
1283 | struct wg_session *wgs; | | 1332 | struct wg_session *wgs; |
| @@ -1599,27 +1648,27 @@ wg_fill_msg_resp(struct wg_softc *wg, st | | | @@ -1599,27 +1648,27 @@ wg_fill_msg_resp(struct wg_softc *wg, st |
1599 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */ | | 1648 | uint8_t ckey[WG_CHAINING_KEY_LEN]; /* [W] 5.4.3: Cr */ |
1600 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Hr */ | | 1649 | uint8_t hash[WG_HASH_LEN]; /* [W] 5.4.3: Hr */ |
1601 | uint8_t cipher_key[WG_KDF_OUTPUT_LEN]; | | 1650 | uint8_t cipher_key[WG_KDF_OUTPUT_LEN]; |
1602 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; | | 1651 | uint8_t pubkey[WG_EPHEMERAL_KEY_LEN]; |
1603 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; | | 1652 | uint8_t privkey[WG_EPHEMERAL_KEY_LEN]; |
1604 | struct wg_session *wgs; | | 1653 | struct wg_session *wgs; |
1605 | struct psref psref; | | 1654 | struct psref psref; |
1606 | | | 1655 | |
1607 | wgs = wg_get_unstable_session(wgp, &psref); | | 1656 | wgs = wg_get_unstable_session(wgp, &psref); |
1608 | memcpy(hash, wgs->wgs_handshake_hash, sizeof(hash)); | | 1657 | memcpy(hash, wgs->wgs_handshake_hash, sizeof(hash)); |
1609 | memcpy(ckey, wgs->wgs_chaining_key, sizeof(ckey)); | | 1658 | memcpy(ckey, wgs->wgs_chaining_key, sizeof(ckey)); |
1610 | | | 1659 | |
1611 | wgmr->wgmr_type = WG_MSG_TYPE_RESP; | | 1660 | wgmr->wgmr_type = WG_MSG_TYPE_RESP; |
1612 | wgmr->wgmr_sender = cprng_strong32(); | | 1661 | wgmr->wgmr_sender = wg_assign_sender_index(wg, wgs); |
1613 | wgmr->wgmr_receiver = wgmi->wgmi_sender; | | 1662 | wgmr->wgmr_receiver = wgmi->wgmi_sender; |
1614 | | | 1663 | |
1615 | /* [W] 5.4.3 Second Message: Responder to Initiator */ | | 1664 | /* [W] 5.4.3 Second Message: Responder to Initiator */ |
1616 | | | 1665 | |
1617 | /* [N] 2.2: "e" */ | | 1666 | /* [N] 2.2: "e" */ |
1618 | /* Er^priv, Er^pub := DH-GENERATE() */ | | 1667 | /* Er^priv, Er^pub := DH-GENERATE() */ |
1619 | wg_algo_generate_keypair(pubkey, privkey); | | 1668 | wg_algo_generate_keypair(pubkey, privkey); |
1620 | /* Cr := KDF1(Cr, Er^pub) */ | | 1669 | /* Cr := KDF1(Cr, Er^pub) */ |
1621 | wg_algo_kdf(ckey, NULL, NULL, ckey, pubkey, sizeof(pubkey)); | | 1670 | wg_algo_kdf(ckey, NULL, NULL, ckey, pubkey, sizeof(pubkey)); |
1622 | /* msg.ephemeral := Er^pub */ | | 1671 | /* msg.ephemeral := Er^pub */ |
1623 | memcpy(wgmr->wgmr_ephemeral, pubkey, sizeof(wgmr->wgmr_ephemeral)); | | 1672 | memcpy(wgmr->wgmr_ephemeral, pubkey, sizeof(wgmr->wgmr_ephemeral)); |
1624 | /* Hr := HASH(Hr || msg.ephemeral) */ | | 1673 | /* Hr := HASH(Hr || msg.ephemeral) */ |
1625 | wg_algo_hash(hash, pubkey, sizeof(pubkey)); | | 1674 | wg_algo_hash(hash, pubkey, sizeof(pubkey)); |
| @@ -1670,27 +1719,26 @@ wg_fill_msg_resp(struct wg_softc *wg, st | | | @@ -1670,27 +1719,26 @@ wg_fill_msg_resp(struct wg_softc *wg, st |
1670 | else { | | 1719 | else { |
1671 | /* msg.mac2 := MAC(Lm, msg_b) */ | | 1720 | /* msg.mac2 := MAC(Lm, msg_b) */ |
1672 | wg_algo_mac(wgmr->wgmr_mac2, sizeof(wgmi->wgmi_mac2), | | 1721 | wg_algo_mac(wgmr->wgmr_mac2, sizeof(wgmi->wgmi_mac2), |
1673 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, | | 1722 | wgp->wgp_latest_cookie, WG_COOKIE_LEN, |
1674 | (const uint8_t *)wgmr, | | 1723 | (const uint8_t *)wgmr, |
1675 | offsetof(struct wg_msg_resp, wgmr_mac2), | | 1724 | offsetof(struct wg_msg_resp, wgmr_mac2), |
1676 | NULL, 0); | | 1725 | NULL, 0); |
1677 | } | | 1726 | } |
1678 | | | 1727 | |
1679 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); | | 1728 | memcpy(wgs->wgs_handshake_hash, hash, sizeof(hash)); |
1680 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); | | 1729 | memcpy(wgs->wgs_chaining_key, ckey, sizeof(ckey)); |
1681 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); | | 1730 | memcpy(wgs->wgs_ephemeral_key_pub, pubkey, sizeof(pubkey)); |
1682 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); | | 1731 | memcpy(wgs->wgs_ephemeral_key_priv, privkey, sizeof(privkey)); |
1683 | wgs->wgs_sender_index = wgmr->wgmr_sender; | | | |
1684 | wgs->wgs_receiver_index = wgmi->wgmi_sender; | | 1732 | wgs->wgs_receiver_index = wgmi->wgmi_sender; |
1685 | WG_DLOG("sender=%x\n", wgs->wgs_sender_index); | | 1733 | WG_DLOG("sender=%x\n", wgs->wgs_sender_index); |
1686 | WG_DLOG("receiver=%x\n", wgs->wgs_receiver_index); | | 1734 | WG_DLOG("receiver=%x\n", wgs->wgs_receiver_index); |
1687 | wg_put_session(wgs, &psref); | | 1735 | wg_put_session(wgs, &psref); |
1688 | } | | 1736 | } |
1689 | | | 1737 | |
1690 | static void | | 1738 | static void |
1691 | wg_swap_sessions(struct wg_peer *wgp) | | 1739 | wg_swap_sessions(struct wg_peer *wgp) |
1692 | { | | 1740 | { |
1693 | | | 1741 | |
1694 | KASSERT(mutex_owned(wgp->wgp_lock)); | | 1742 | KASSERT(mutex_owned(wgp->wgp_lock)); |
1695 | | | 1743 | |
1696 | wgp->wgp_session_unstable = atomic_swap_ptr(&wgp->wgp_session_stable, | | 1744 | wgp->wgp_session_unstable = atomic_swap_ptr(&wgp->wgp_session_stable, |
| @@ -1896,32 +1944,27 @@ wg_send_handshake_msg_resp(struct wg_sof | | | @@ -1896,32 +1944,27 @@ wg_send_handshake_msg_resp(struct wg_sof |
1896 | error = wg->wg_ops->send_hs_msg(wgp, m); | | 1944 | error = wg->wg_ops->send_hs_msg(wgp, m); |
1897 | if (error == 0) | | 1945 | if (error == 0) |
1898 | WG_TRACE("resp msg sent"); | | 1946 | WG_TRACE("resp msg sent"); |
1899 | return error; | | 1947 | return error; |
1900 | } | | 1948 | } |
1901 | | | 1949 | |
1902 | static struct wg_peer * | | 1950 | static struct wg_peer * |
1903 | wg_lookup_peer_by_pubkey(struct wg_softc *wg, | | 1951 | wg_lookup_peer_by_pubkey(struct wg_softc *wg, |
1904 | const uint8_t pubkey[WG_STATIC_KEY_LEN], struct psref *psref) | | 1952 | const uint8_t pubkey[WG_STATIC_KEY_LEN], struct psref *psref) |
1905 | { | | 1953 | { |
1906 | struct wg_peer *wgp; | | 1954 | struct wg_peer *wgp; |
1907 | | | 1955 | |
1908 | int s = pserialize_read_enter(); | | 1956 | int s = pserialize_read_enter(); |
1909 | /* XXX O(n) */ | | 1957 | wgp = thmap_get(wg->wg_peers_bypubkey, pubkey, WG_STATIC_KEY_LEN); |
1910 | WG_PEER_READER_FOREACH(wgp, wg) { | | | |
1911 | if (consttime_memequal(wgp->wgp_pubkey, pubkey, | | | |
1912 | sizeof(wgp->wgp_pubkey))) | | | |
1913 | break; | | | |
1914 | } | | | |
1915 | if (wgp != NULL) | | 1958 | if (wgp != NULL) |
1916 | wg_get_peer(wgp, psref); | | 1959 | wg_get_peer(wgp, psref); |
1917 | pserialize_read_exit(s); | | 1960 | pserialize_read_exit(s); |
1918 | | | 1961 | |
1919 | return wgp; | | 1962 | return wgp; |
1920 | } | | 1963 | } |
1921 | | | 1964 | |
1922 | static void | | 1965 | static void |
1923 | wg_fill_msg_cookie(struct wg_softc *wg, struct wg_peer *wgp, | | 1966 | wg_fill_msg_cookie(struct wg_softc *wg, struct wg_peer *wgp, |
1924 | struct wg_msg_cookie *wgmc, const uint32_t sender, | | 1967 | struct wg_msg_cookie *wgmc, const uint32_t sender, |
1925 | const uint8_t mac1[WG_MAC_LEN], const struct sockaddr *src) | | 1968 | const uint8_t mac1[WG_MAC_LEN], const struct sockaddr *src) |
1926 | { | | 1969 | { |
1927 | uint8_t cookie[WG_COOKIE_LEN]; | | 1970 | uint8_t cookie[WG_COOKIE_LEN]; |
| @@ -2077,44 +2120,30 @@ wg_clear_states(struct wg_session *wgs) | | | @@ -2077,44 +2120,30 @@ wg_clear_states(struct wg_session *wgs) |
2077 | #define wgs_clear(v) explicit_memset(wgs->wgs_##v, 0, sizeof(wgs->wgs_##v)) | | 2120 | #define wgs_clear(v) explicit_memset(wgs->wgs_##v, 0, sizeof(wgs->wgs_##v)) |
2078 | wgs_clear(handshake_hash); | | 2121 | wgs_clear(handshake_hash); |
2079 | wgs_clear(chaining_key); | | 2122 | wgs_clear(chaining_key); |
2080 | wgs_clear(ephemeral_key_pub); | | 2123 | wgs_clear(ephemeral_key_pub); |
2081 | wgs_clear(ephemeral_key_priv); | | 2124 | wgs_clear(ephemeral_key_priv); |
2082 | wgs_clear(ephemeral_key_peer); | | 2125 | wgs_clear(ephemeral_key_peer); |
2083 | #undef wgs_clear | | 2126 | #undef wgs_clear |
2084 | } | | 2127 | } |
2085 | | | 2128 | |
2086 | static struct wg_session * | | 2129 | static struct wg_session * |
2087 | wg_lookup_session_by_index(struct wg_softc *wg, const uint32_t index, | | 2130 | wg_lookup_session_by_index(struct wg_softc *wg, const uint32_t index, |
2088 | struct psref *psref) | | 2131 | struct psref *psref) |
2089 | { | | 2132 | { |
2090 | struct wg_peer *wgp; | | | |
2091 | struct wg_session *wgs; | | 2133 | struct wg_session *wgs; |
2092 | | | 2134 | |
2093 | int s = pserialize_read_enter(); | | 2135 | int s = pserialize_read_enter(); |
2094 | /* XXX O(n) */ | | 2136 | wgs = thmap_get(wg->wg_sessions_byindex, &index, sizeof index); |
2095 | WG_PEER_READER_FOREACH(wgp, wg) { | | | |
2096 | wgs = wgp->wgp_session_stable; | | | |
2097 | WG_DLOG("index=%x wgs_sender_index=%x\n", | | | |
2098 | index, wgs->wgs_sender_index); | | | |
2099 | if (wgs->wgs_sender_index == index) | | | |
2100 | break; | | | |
2101 | wgs = wgp->wgp_session_unstable; | | | |
2102 | WG_DLOG("index=%x wgs_sender_index=%x\n", | | | |
2103 | index, wgs->wgs_sender_index); | | | |
2104 | if (wgs->wgs_sender_index == index) | | | |
2105 | break; | | | |
2106 | wgs = NULL; | | | |
2107 | } | | | |
2108 | if (wgs != NULL) | | 2137 | if (wgs != NULL) |
2109 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); | | 2138 | psref_acquire(psref, &wgs->wgs_psref, wg_psref_class); |
2110 | pserialize_read_exit(s); | | 2139 | pserialize_read_exit(s); |
2111 | | | 2140 | |
2112 | return wgs; | | 2141 | return wgs; |
2113 | } | | 2142 | } |
2114 | | | 2143 | |
2115 | static void | | 2144 | static void |
2116 | wg_schedule_rekey_timer(struct wg_peer *wgp) | | 2145 | wg_schedule_rekey_timer(struct wg_peer *wgp) |
2117 | { | | 2146 | { |
2118 | int timeout = MIN(wg_rekey_after_time, INT_MAX/hz); | | 2147 | int timeout = MIN(wg_rekey_after_time, INT_MAX/hz); |
2119 | | | 2148 | |
2120 | callout_schedule(&wgp->wgp_rekey_timer, timeout * hz); | | 2149 | callout_schedule(&wgp->wgp_rekey_timer, timeout * hz); |
| @@ -3252,137 +3281,178 @@ wg_alloc_peer(struct wg_softc *wg) | | | @@ -3252,137 +3281,178 @@ wg_alloc_peer(struct wg_softc *wg) |
3252 | mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET); | | 3281 | mutex_init(&wgs->wgs_send_counter_lock, MUTEX_DEFAULT, IPL_SOFTNET); |
3253 | #endif | | 3282 | #endif |
3254 | wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP); | | 3283 | wgs->wgs_recvwin = kmem_zalloc(sizeof(*wgs->wgs_recvwin), KM_SLEEP); |
3255 | mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_NONE); | | 3284 | mutex_init(&wgs->wgs_recvwin->lock, MUTEX_DEFAULT, IPL_NONE); |
3256 | | | 3285 | |
3257 | return wgp; | | 3286 | return wgp; |
3258 | } | | 3287 | } |
3259 | | | 3288 | |
3260 | static void | | 3289 | static void |
3261 | wg_destroy_peer(struct wg_peer *wgp) | | 3290 | wg_destroy_peer(struct wg_peer *wgp) |
3262 | { | | 3291 | { |
3263 | struct wg_session *wgs; | | 3292 | struct wg_session *wgs; |
3264 | struct wg_softc *wg = wgp->wgp_sc; | | 3293 | struct wg_softc *wg = wgp->wgp_sc; |
| | | 3294 | uint32_t index; |
| | | 3295 | void *garbage; |
3265 | | | 3296 | |
| | | 3297 | /* Prevent new packets from this peer on any source address. */ |
3266 | rw_enter(wg->wg_rwlock, RW_WRITER); | | 3298 | rw_enter(wg->wg_rwlock, RW_WRITER); |
3267 | for (int i = 0; i < wgp->wgp_n_allowedips; i++) { | | 3299 | for (int i = 0; i < wgp->wgp_n_allowedips; i++) { |
3268 | struct wg_allowedip *wga = &wgp->wgp_allowedips[i]; | | 3300 | struct wg_allowedip *wga = &wgp->wgp_allowedips[i]; |
3269 | struct radix_node_head *rnh = wg_rnh(wg, wga->wga_family); | | 3301 | struct radix_node_head *rnh = wg_rnh(wg, wga->wga_family); |
3270 | struct radix_node *rn; | | 3302 | struct radix_node *rn; |
3271 | | | 3303 | |
3272 | KASSERT(rnh != NULL); | | 3304 | KASSERT(rnh != NULL); |
3273 | rn = rnh->rnh_deladdr(&wga->wga_sa_addr, | | 3305 | rn = rnh->rnh_deladdr(&wga->wga_sa_addr, |
3274 | &wga->wga_sa_mask, rnh); | | 3306 | &wga->wga_sa_mask, rnh); |
3275 | if (rn == NULL) { | | 3307 | if (rn == NULL) { |
3276 | char addrstr[128]; | | 3308 | char addrstr[128]; |
3277 | sockaddr_format(&wga->wga_sa_addr, addrstr, | | 3309 | sockaddr_format(&wga->wga_sa_addr, addrstr, |
3278 | sizeof(addrstr)); | | 3310 | sizeof(addrstr)); |
3279 | WGLOG(LOG_WARNING, "Couldn't delete %s", addrstr); | | 3311 | WGLOG(LOG_WARNING, "Couldn't delete %s", addrstr); |
3280 | } | | 3312 | } |
3281 | } | | 3313 | } |
3282 | rw_exit(wg->wg_rwlock); | | 3314 | rw_exit(wg->wg_rwlock); |
3283 | | | 3315 | |
| | | 3316 | /* Halt all packet processing and timeouts. */ |
3284 | softint_disestablish(wgp->wgp_si); | | 3317 | softint_disestablish(wgp->wgp_si); |
3285 | callout_halt(&wgp->wgp_rekey_timer, NULL); | | 3318 | callout_halt(&wgp->wgp_rekey_timer, NULL); |
3286 | callout_halt(&wgp->wgp_handshake_timeout_timer, NULL); | | 3319 | callout_halt(&wgp->wgp_handshake_timeout_timer, NULL); |
3287 | callout_halt(&wgp->wgp_session_dtor_timer, NULL); | | 3320 | callout_halt(&wgp->wgp_session_dtor_timer, NULL); |
3288 | | | 3321 | |
| | | 3322 | /* Remove the sessions by index. */ |
| | | 3323 | if ((index = wgp->wgp_session_stable->wgs_sender_index) != 0) { |
| | | 3324 | thmap_del(wg->wg_sessions_byindex, &index, sizeof index); |
| | | 3325 | wgp->wgp_session_stable->wgs_sender_index = 0; |
| | | 3326 | } |
| | | 3327 | if ((index = wgp->wgp_session_unstable->wgs_sender_index) != 0) { |
| | | 3328 | thmap_del(wg->wg_sessions_byindex, &index, sizeof index); |
| | | 3329 | wgp->wgp_session_unstable->wgs_sender_index = 0; |
| | | 3330 | } |
| | | 3331 | |
| | | 3332 | /* Wait for all thmap_gets to complete, and GC. */ |
| | | 3333 | garbage = thmap_stage_gc(wg->wg_sessions_byindex); |
| | | 3334 | mutex_enter(wgp->wgp_lock); |
| | | 3335 | pserialize_perform(wgp->wgp_psz); |
| | | 3336 | mutex_exit(wgp->wgp_lock); |
| | | 3337 | thmap_gc(wg->wg_sessions_byindex, garbage); |
| | | 3338 | |
3289 | wgs = wgp->wgp_session_unstable; | | 3339 | wgs = wgp->wgp_session_unstable; |
3290 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); | | 3340 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); |
3291 | mutex_obj_free(wgs->wgs_lock); | | 3341 | mutex_obj_free(wgs->wgs_lock); |
3292 | mutex_destroy(&wgs->wgs_recvwin->lock); | | 3342 | mutex_destroy(&wgs->wgs_recvwin->lock); |
3293 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); | | 3343 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); |
3294 | #ifndef __HAVE_ATOMIC64_LOADSTORE | | 3344 | #ifndef __HAVE_ATOMIC64_LOADSTORE |
3295 | mutex_destroy(&wgs->wgs_send_counter_lock); | | 3345 | mutex_destroy(&wgs->wgs_send_counter_lock); |
3296 | #endif | | 3346 | #endif |
3297 | kmem_free(wgs, sizeof(*wgs)); | | 3347 | kmem_free(wgs, sizeof(*wgs)); |
| | | 3348 | |
3298 | wgs = wgp->wgp_session_stable; | | 3349 | wgs = wgp->wgp_session_stable; |
3299 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); | | 3350 | psref_target_destroy(&wgs->wgs_psref, wg_psref_class); |
3300 | mutex_obj_free(wgs->wgs_lock); | | 3351 | mutex_obj_free(wgs->wgs_lock); |
3301 | mutex_destroy(&wgs->wgs_recvwin->lock); | | 3352 | mutex_destroy(&wgs->wgs_recvwin->lock); |
3302 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); | | 3353 | kmem_free(wgs->wgs_recvwin, sizeof(*wgs->wgs_recvwin)); |
3303 | #ifndef __HAVE_ATOMIC64_LOADSTORE | | 3354 | #ifndef __HAVE_ATOMIC64_LOADSTORE |
3304 | mutex_destroy(&wgs->wgs_send_counter_lock); | | 3355 | mutex_destroy(&wgs->wgs_send_counter_lock); |
3305 | #endif | | 3356 | #endif |
3306 | kmem_free(wgs, sizeof(*wgs)); | | 3357 | kmem_free(wgs, sizeof(*wgs)); |
3307 | | | 3358 | |
3308 | psref_target_destroy(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class); | | 3359 | psref_target_destroy(&wgp->wgp_endpoint->wgsa_psref, wg_psref_class); |
3309 | psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class); | | 3360 | psref_target_destroy(&wgp->wgp_endpoint0->wgsa_psref, wg_psref_class); |
3310 | kmem_free(wgp->wgp_endpoint, sizeof(*wgp->wgp_endpoint)); | | 3361 | kmem_free(wgp->wgp_endpoint, sizeof(*wgp->wgp_endpoint)); |
3311 | kmem_free(wgp->wgp_endpoint0, sizeof(*wgp->wgp_endpoint0)); | | 3362 | kmem_free(wgp->wgp_endpoint0, sizeof(*wgp->wgp_endpoint0)); |
3312 | | | 3363 | |
3313 | pserialize_destroy(wgp->wgp_psz); | | 3364 | pserialize_destroy(wgp->wgp_psz); |
3314 | pcq_destroy(wgp->wgp_q); | | 3365 | pcq_destroy(wgp->wgp_q); |
3315 | mutex_obj_free(wgp->wgp_lock); | | 3366 | mutex_obj_free(wgp->wgp_lock); |
3316 | | | 3367 | |
3317 | kmem_free(wgp, sizeof(*wgp)); | | 3368 | kmem_free(wgp, sizeof(*wgp)); |
3318 | } | | 3369 | } |
3319 | | | 3370 | |
3320 | static void | | 3371 | static void |
3321 | wg_destroy_all_peers(struct wg_softc *wg) | | 3372 | wg_destroy_all_peers(struct wg_softc *wg) |
3322 | { | | 3373 | { |
3323 | struct wg_peer *wgp; | | 3374 | struct wg_peer *wgp, *wgp0 __diagused; |
| | | 3375 | void *garbage_byname, *garbage_bypubkey; |
3324 | | | 3376 | |
3325 | restart: | | 3377 | restart: |
| | | 3378 | garbage_byname = garbage_bypubkey = NULL; |
3326 | mutex_enter(wg->wg_lock); | | 3379 | mutex_enter(wg->wg_lock); |
3327 | WG_PEER_WRITER_FOREACH(wgp, wg) { | | 3380 | WG_PEER_WRITER_FOREACH(wgp, wg) { |
| | | 3381 | if (wgp->wgp_name[0]) { |
| | | 3382 | wgp0 = thmap_del(wg->wg_peers_byname, wgp->wgp_name, |
| | | 3383 | strlen(wgp->wgp_name)); |
| | | 3384 | KASSERT(wgp0 == wgp); |
| | | 3385 | garbage_byname = thmap_stage_gc(wg->wg_peers_byname); |
| | | 3386 | } |
| | | 3387 | wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey, |
| | | 3388 | sizeof(wgp->wgp_pubkey)); |
| | | 3389 | KASSERT(wgp0 == wgp); |
| | | 3390 | garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey); |
3328 | WG_PEER_WRITER_REMOVE(wgp); | | 3391 | WG_PEER_WRITER_REMOVE(wgp); |
3329 | wg->wg_npeers--; | | 3392 | wg->wg_npeers--; |
3330 | mutex_enter(wgp->wgp_lock); | | 3393 | mutex_enter(wgp->wgp_lock); |
3331 | wgp->wgp_state = WGP_STATE_DESTROYING; | | 3394 | wgp->wgp_state = WGP_STATE_DESTROYING; |
3332 | pserialize_perform(wgp->wgp_psz); | | 3395 | pserialize_perform(wgp->wgp_psz); |
3333 | mutex_exit(wgp->wgp_lock); | | 3396 | mutex_exit(wgp->wgp_lock); |
3334 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); | | 3397 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); |
3335 | break; | | 3398 | break; |
3336 | } | | 3399 | } |
3337 | mutex_exit(wg->wg_lock); | | 3400 | mutex_exit(wg->wg_lock); |
3338 | | | 3401 | |
3339 | if (wgp == NULL) | | 3402 | if (wgp == NULL) |
3340 | return; | | 3403 | return; |
3341 | | | 3404 | |
3342 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); | | 3405 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); |
3343 | | | 3406 | |
3344 | wg_destroy_peer(wgp); | | 3407 | wg_destroy_peer(wgp); |
| | | 3408 | thmap_gc(wg->wg_peers_byname, garbage_byname); |
| | | 3409 | thmap_gc(wg->wg_peers_bypubkey, garbage_bypubkey); |
3345 | | | 3410 | |
3346 | goto restart; | | 3411 | goto restart; |
3347 | } | | 3412 | } |
3348 | | | 3413 | |
3349 | static int | | 3414 | static int |
3350 | wg_destroy_peer_name(struct wg_softc *wg, const char *name) | | 3415 | wg_destroy_peer_name(struct wg_softc *wg, const char *name) |
3351 | { | | 3416 | { |
3352 | struct wg_peer *wgp; | | 3417 | struct wg_peer *wgp, *wgp0 __diagused; |
| | | 3418 | void *garbage_byname, *garbage_bypubkey; |
3353 | | | 3419 | |
3354 | mutex_enter(wg->wg_lock); | | 3420 | mutex_enter(wg->wg_lock); |
3355 | WG_PEER_WRITER_FOREACH(wgp, wg) { | | 3421 | wgp = thmap_del(wg->wg_peers_byname, name, strlen(name)); |
3356 | if (strcmp(wgp->wgp_name, name) == 0) | | | |
3357 | break; | | | |
3358 | } | | | |
3359 | if (wgp != NULL) { | | 3422 | if (wgp != NULL) { |
| | | 3423 | wgp0 = thmap_del(wg->wg_peers_bypubkey, wgp->wgp_pubkey, |
| | | 3424 | sizeof(wgp->wgp_pubkey)); |
| | | 3425 | KASSERT(wgp0 == wgp); |
| | | 3426 | garbage_byname = thmap_stage_gc(wg->wg_peers_byname); |
| | | 3427 | garbage_bypubkey = thmap_stage_gc(wg->wg_peers_bypubkey); |
3360 | WG_PEER_WRITER_REMOVE(wgp); | | 3428 | WG_PEER_WRITER_REMOVE(wgp); |
3361 | wg->wg_npeers--; | | 3429 | wg->wg_npeers--; |
3362 | mutex_enter(wgp->wgp_lock); | | 3430 | mutex_enter(wgp->wgp_lock); |
3363 | wgp->wgp_state = WGP_STATE_DESTROYING; | | 3431 | wgp->wgp_state = WGP_STATE_DESTROYING; |
3364 | pserialize_perform(wgp->wgp_psz); | | 3432 | pserialize_perform(wgp->wgp_psz); |
3365 | mutex_exit(wgp->wgp_lock); | | 3433 | mutex_exit(wgp->wgp_lock); |
3366 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); | | 3434 | PSLIST_ENTRY_DESTROY(wgp, wgp_peerlist_entry); |
3367 | } | | 3435 | } |
3368 | mutex_exit(wg->wg_lock); | | 3436 | mutex_exit(wg->wg_lock); |
3369 | | | 3437 | |
3370 | if (wgp == NULL) | | 3438 | if (wgp == NULL) |
3371 | return ENOENT; | | 3439 | return ENOENT; |
3372 | | | 3440 | |
3373 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); | | 3441 | psref_target_destroy(&wgp->wgp_psref, wg_psref_class); |
3374 | | | 3442 | |
3375 | wg_destroy_peer(wgp); | | 3443 | wg_destroy_peer(wgp); |
| | | 3444 | thmap_gc(wg->wg_peers_byname, garbage_byname); |
| | | 3445 | thmap_gc(wg->wg_peers_bypubkey, garbage_bypubkey); |
3376 | | | 3446 | |
3377 | return 0; | | 3447 | return 0; |
3378 | } | | 3448 | } |
3379 | | | 3449 | |
3380 | static int | | 3450 | static int |
3381 | wg_if_attach(struct wg_softc *wg) | | 3451 | wg_if_attach(struct wg_softc *wg) |
3382 | { | | 3452 | { |
3383 | int error; | | 3453 | int error; |
3384 | | | 3454 | |
3385 | wg->wg_if.if_addrlen = 0; | | 3455 | wg->wg_if.if_addrlen = 0; |
3386 | wg->wg_if.if_mtu = WG_MTU; | | 3456 | wg->wg_if.if_mtu = WG_MTU; |
3387 | wg->wg_if.if_flags = IFF_MULTICAST; | | 3457 | wg->wg_if.if_flags = IFF_MULTICAST; |
3388 | wg->wg_if.if_extflags = IFEF_NO_LINK_STATE_CHANGE; | | 3458 | wg->wg_if.if_extflags = IFEF_NO_LINK_STATE_CHANGE; |
| @@ -3422,39 +3492,45 @@ wg_clone_create(struct if_clone *ifc, in | | | @@ -3422,39 +3492,45 @@ wg_clone_create(struct if_clone *ifc, in |
3422 | if (error != 0) { | | 3492 | if (error != 0) { |
3423 | kmem_free(wg, sizeof(struct wg_softc)); | | 3493 | kmem_free(wg, sizeof(struct wg_softc)); |
3424 | return error; | | 3494 | return error; |
3425 | } | | 3495 | } |
3426 | | | 3496 | |
3427 | rn_inithead((void **)&wg->wg_rtable_ipv4, | | 3497 | rn_inithead((void **)&wg->wg_rtable_ipv4, |
3428 | offsetof(struct sockaddr_in, sin_addr) * NBBY); | | 3498 | offsetof(struct sockaddr_in, sin_addr) * NBBY); |
3429 | #ifdef INET6 | | 3499 | #ifdef INET6 |
3430 | rn_inithead((void **)&wg->wg_rtable_ipv6, | | 3500 | rn_inithead((void **)&wg->wg_rtable_ipv6, |
3431 | offsetof(struct sockaddr_in6, sin6_addr) * NBBY); | | 3501 | offsetof(struct sockaddr_in6, sin6_addr) * NBBY); |
3432 | #endif | | 3502 | #endif |
3433 | | | 3503 | |
3434 | PSLIST_INIT(&wg->wg_peers); | | 3504 | PSLIST_INIT(&wg->wg_peers); |
| | | 3505 | wg->wg_peers_bypubkey = thmap_create(0, NULL, THMAP_NOCOPY); |
| | | 3506 | wg->wg_peers_byname = thmap_create(0, NULL, THMAP_NOCOPY); |
| | | 3507 | wg->wg_sessions_byindex = thmap_create(0, NULL, THMAP_NOCOPY); |
3435 | wg->wg_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); | | 3508 | wg->wg_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); |
3436 | wg->wg_rwlock = rw_obj_alloc(); | | 3509 | wg->wg_rwlock = rw_obj_alloc(); |
3437 | wg->wg_ops = &wg_ops_rumpkernel; | | 3510 | wg->wg_ops = &wg_ops_rumpkernel; |
3438 | | | 3511 | |
3439 | error = wg_if_attach(wg); | | 3512 | error = wg_if_attach(wg); |
3440 | if (error != 0) { | | 3513 | if (error != 0) { |
3441 | wg_worker_destroy(wg); | | 3514 | wg_worker_destroy(wg); |
3442 | if (wg->wg_rtable_ipv4 != NULL) | | 3515 | if (wg->wg_rtable_ipv4 != NULL) |
3443 | free(wg->wg_rtable_ipv4, M_RTABLE); | | 3516 | free(wg->wg_rtable_ipv4, M_RTABLE); |
3444 | if (wg->wg_rtable_ipv6 != NULL) | | 3517 | if (wg->wg_rtable_ipv6 != NULL) |
3445 | free(wg->wg_rtable_ipv6, M_RTABLE); | | 3518 | free(wg->wg_rtable_ipv6, M_RTABLE); |
3446 | PSLIST_DESTROY(&wg->wg_peers); | | 3519 | PSLIST_DESTROY(&wg->wg_peers); |
3447 | mutex_obj_free(wg->wg_lock); | | 3520 | mutex_obj_free(wg->wg_lock); |
| | | 3521 | thmap_destroy(wg->wg_sessions_byindex); |
| | | 3522 | thmap_destroy(wg->wg_peers_byname); |
| | | 3523 | thmap_destroy(wg->wg_peers_bypubkey); |
3448 | kmem_free(wg, sizeof(struct wg_softc)); | | 3524 | kmem_free(wg, sizeof(struct wg_softc)); |
3449 | return error; | | 3525 | return error; |
3450 | } | | 3526 | } |
3451 | | | 3527 | |
3452 | mutex_enter(&wg_softcs.lock); | | 3528 | mutex_enter(&wg_softcs.lock); |
3453 | LIST_INSERT_HEAD(&wg_softcs.list, wg, wg_list); | | 3529 | LIST_INSERT_HEAD(&wg_softcs.list, wg, wg_list); |
3454 | mutex_exit(&wg_softcs.lock); | | 3530 | mutex_exit(&wg_softcs.lock); |
3455 | | | 3531 | |
3456 | return 0; | | 3532 | return 0; |
3457 | } | | 3533 | } |
3458 | | | 3534 | |
3459 | static int | | 3535 | static int |
3460 | wg_clone_destroy(struct ifnet *ifp) | | 3536 | wg_clone_destroy(struct ifnet *ifp) |
| @@ -3472,26 +3548,29 @@ wg_clone_destroy(struct ifnet *ifp) | | | @@ -3472,26 +3548,29 @@ wg_clone_destroy(struct ifnet *ifp) |
3472 | } | | 3548 | } |
3473 | #endif | | 3549 | #endif |
3474 | | | 3550 | |
3475 | bpf_detach(ifp); | | 3551 | bpf_detach(ifp); |
3476 | if_detach(ifp); | | 3552 | if_detach(ifp); |
3477 | wg_worker_destroy(wg); | | 3553 | wg_worker_destroy(wg); |
3478 | wg_destroy_all_peers(wg); | | 3554 | wg_destroy_all_peers(wg); |
3479 | if (wg->wg_rtable_ipv4 != NULL) | | 3555 | if (wg->wg_rtable_ipv4 != NULL) |
3480 | free(wg->wg_rtable_ipv4, M_RTABLE); | | 3556 | free(wg->wg_rtable_ipv4, M_RTABLE); |
3481 | if (wg->wg_rtable_ipv6 != NULL) | | 3557 | if (wg->wg_rtable_ipv6 != NULL) |
3482 | free(wg->wg_rtable_ipv6, M_RTABLE); | | 3558 | free(wg->wg_rtable_ipv6, M_RTABLE); |
3483 | | | 3559 | |
3484 | PSLIST_DESTROY(&wg->wg_peers); | | 3560 | PSLIST_DESTROY(&wg->wg_peers); |
| | | 3561 | thmap_destroy(wg->wg_sessions_byindex); |
| | | 3562 | thmap_destroy(wg->wg_peers_byname); |
| | | 3563 | thmap_destroy(wg->wg_peers_bypubkey); |
3485 | mutex_obj_free(wg->wg_lock); | | 3564 | mutex_obj_free(wg->wg_lock); |
3486 | rw_obj_free(wg->wg_rwlock); | | 3565 | rw_obj_free(wg->wg_rwlock); |
3487 | | | 3566 | |
3488 | kmem_free(wg, sizeof(struct wg_softc)); | | 3567 | kmem_free(wg, sizeof(struct wg_softc)); |
3489 | | | 3568 | |
3490 | return 0; | | 3569 | return 0; |
3491 | } | | 3570 | } |
3492 | | | 3571 | |
3493 | static struct wg_peer * | | 3572 | static struct wg_peer * |
3494 | wg_pick_peer_by_sa(struct wg_softc *wg, const struct sockaddr *sa, | | 3573 | wg_pick_peer_by_sa(struct wg_softc *wg, const struct sockaddr *sa, |
3495 | struct psref *psref) | | 3574 | struct psref *psref) |
3496 | { | | 3575 | { |
3497 | struct radix_node_head *rnh; | | 3576 | struct radix_node_head *rnh; |
| @@ -4066,41 +4145,59 @@ wg_ioctl_set_listen_port(struct wg_softc | | | @@ -4066,41 +4145,59 @@ wg_ioctl_set_listen_port(struct wg_softc |
4066 | error = wg->wg_ops->bind_port(wg, (uint16_t)port); | | 4145 | error = wg->wg_ops->bind_port(wg, (uint16_t)port); |
4067 | | | 4146 | |
4068 | out: | | 4147 | out: |
4069 | kmem_free(buf, ifd->ifd_len + 1); | | 4148 | kmem_free(buf, ifd->ifd_len + 1); |
4070 | return error; | | 4149 | return error; |
4071 | } | | 4150 | } |
4072 | | | 4151 | |
4073 | static int | | 4152 | static int |
4074 | wg_ioctl_add_peer(struct wg_softc *wg, struct ifdrv *ifd) | | 4153 | wg_ioctl_add_peer(struct wg_softc *wg, struct ifdrv *ifd) |
4075 | { | | 4154 | { |
4076 | int error; | | 4155 | int error; |
4077 | prop_dictionary_t prop_dict; | | 4156 | prop_dictionary_t prop_dict; |
4078 | char *buf = NULL; | | 4157 | char *buf = NULL; |
4079 | struct wg_peer *wgp = NULL; | | 4158 | struct wg_peer *wgp = NULL, *wgp0 __diagused; |
4080 | | | 4159 | |
4081 | error = wg_alloc_prop_buf(&buf, ifd); | | 4160 | error = wg_alloc_prop_buf(&buf, ifd); |
4082 | if (error != 0) | | 4161 | if (error != 0) |
4083 | return error; | | 4162 | return error; |
4084 | error = EINVAL; | | 4163 | error = EINVAL; |
4085 | prop_dict = prop_dictionary_internalize(buf); | | 4164 | prop_dict = prop_dictionary_internalize(buf); |
4086 | if (prop_dict == NULL) | | 4165 | if (prop_dict == NULL) |
4087 | goto out; | | 4166 | goto out; |
4088 | | | 4167 | |
4089 | error = wg_handle_prop_peer(wg, prop_dict, &wgp); | | 4168 | error = wg_handle_prop_peer(wg, prop_dict, &wgp); |
4090 | if (error != 0) | | 4169 | if (error != 0) |
4091 | goto out; | | 4170 | goto out; |
4092 | | | 4171 | |
4093 | mutex_enter(wg->wg_lock); | | 4172 | mutex_enter(wg->wg_lock); |
| | | 4173 | if (thmap_get(wg->wg_peers_bypubkey, wgp->wgp_pubkey, |
| | | 4174 | sizeof(wgp->wgp_pubkey)) != NULL || |
| | | 4175 | (wgp->wgp_name[0] && |
| | | 4176 | thmap_get(wg->wg_peers_byname, wgp->wgp_name, |
| | | 4177 | strlen(wgp->wgp_name)) != NULL)) { |
| | | 4178 | mutex_exit(wg->wg_lock); |
| | | 4179 | wg_destroy_peer(wgp); |
| | | 4180 | error = EEXIST; |
| | | 4181 | goto out; |
| | | 4182 | } |
| | | 4183 | wgp0 = thmap_put(wg->wg_peers_bypubkey, wgp->wgp_pubkey, |
| | | 4184 | sizeof(wgp->wgp_pubkey), wgp); |
| | | 4185 | KASSERT(wgp0 == wgp); |
| | | 4186 | if (wgp->wgp_name[0]) { |
| | | 4187 | wgp0 = thmap_put(wg->wg_peers_byname, wgp->wgp_name, |
| | | 4188 | strlen(wgp->wgp_name), wgp); |
| | | 4189 | KASSERT(wgp0 == wgp); |
| | | 4190 | } |
4094 | WG_PEER_WRITER_INSERT_HEAD(wgp, wg); | | 4191 | WG_PEER_WRITER_INSERT_HEAD(wgp, wg); |
4095 | wg->wg_npeers++; | | 4192 | wg->wg_npeers++; |
4096 | mutex_exit(wg->wg_lock); | | 4193 | mutex_exit(wg->wg_lock); |
4097 | | | 4194 | |
4098 | out: | | 4195 | out: |
4099 | kmem_free(buf, ifd->ifd_len + 1); | | 4196 | kmem_free(buf, ifd->ifd_len + 1); |
4100 | return error; | | 4197 | return error; |
4101 | } | | 4198 | } |
4102 | | | 4199 | |
4103 | static int | | 4200 | static int |
4104 | wg_ioctl_delete_peer(struct wg_softc *wg, struct ifdrv *ifd) | | 4201 | wg_ioctl_delete_peer(struct wg_softc *wg, struct ifdrv *ifd) |
4105 | { | | 4202 | { |
4106 | int error; | | 4203 | int error; |