1744bfb21SJohn Baldwin /* SPDX-License-Identifier: ISC
2744bfb21SJohn Baldwin *
3744bfb21SJohn Baldwin * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4744bfb21SJohn Baldwin * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net>
5744bfb21SJohn Baldwin */
6744bfb21SJohn Baldwin
7744bfb21SJohn Baldwin #include "opt_inet.h"
8744bfb21SJohn Baldwin #include "opt_inet6.h"
9744bfb21SJohn Baldwin
10744bfb21SJohn Baldwin #include <sys/param.h>
11744bfb21SJohn Baldwin #include <sys/systm.h>
12744bfb21SJohn Baldwin #include <sys/kernel.h>
13744bfb21SJohn Baldwin #include <sys/lock.h>
14744bfb21SJohn Baldwin #include <sys/mutex.h>
15744bfb21SJohn Baldwin #include <sys/rwlock.h>
16744bfb21SJohn Baldwin #include <sys/socket.h>
17744bfb21SJohn Baldwin #include <crypto/siphash/siphash.h>
18744bfb21SJohn Baldwin #include <netinet/in.h>
19744bfb21SJohn Baldwin #include <vm/uma.h>
20744bfb21SJohn Baldwin
21744bfb21SJohn Baldwin #include "wg_cookie.h"
22744bfb21SJohn Baldwin
23744bfb21SJohn Baldwin #define COOKIE_MAC1_KEY_LABEL "mac1----"
24744bfb21SJohn Baldwin #define COOKIE_COOKIE_KEY_LABEL "cookie--"
25744bfb21SJohn Baldwin #define COOKIE_SECRET_MAX_AGE 120
26744bfb21SJohn Baldwin #define COOKIE_SECRET_LATENCY 5
27744bfb21SJohn Baldwin
28744bfb21SJohn Baldwin /* Constants for initiation rate limiting */
29744bfb21SJohn Baldwin #define RATELIMIT_SIZE (1 << 13)
30744bfb21SJohn Baldwin #define RATELIMIT_MASK (RATELIMIT_SIZE - 1)
31744bfb21SJohn Baldwin #define RATELIMIT_SIZE_MAX (RATELIMIT_SIZE * 8)
32744bfb21SJohn Baldwin #define INITIATIONS_PER_SECOND 20
33744bfb21SJohn Baldwin #define INITIATIONS_BURSTABLE 5
34744bfb21SJohn Baldwin #define INITIATION_COST (SBT_1S / INITIATIONS_PER_SECOND)
35744bfb21SJohn Baldwin #define TOKEN_MAX (INITIATION_COST * INITIATIONS_BURSTABLE)
36744bfb21SJohn Baldwin #define ELEMENT_TIMEOUT 1
37744bfb21SJohn Baldwin #define IPV4_MASK_SIZE 4 /* Use all 4 bytes of IPv4 address */
38744bfb21SJohn Baldwin #define IPV6_MASK_SIZE 8 /* Use top 8 bytes (/64) of IPv6 address */
39744bfb21SJohn Baldwin
40744bfb21SJohn Baldwin struct ratelimit_key {
41744bfb21SJohn Baldwin struct vnet *vnet;
42744bfb21SJohn Baldwin uint8_t ip[IPV6_MASK_SIZE];
43744bfb21SJohn Baldwin };
44744bfb21SJohn Baldwin
45744bfb21SJohn Baldwin struct ratelimit_entry {
46744bfb21SJohn Baldwin LIST_ENTRY(ratelimit_entry) r_entry;
47744bfb21SJohn Baldwin struct ratelimit_key r_key;
48744bfb21SJohn Baldwin sbintime_t r_last_time; /* sbinuptime */
49744bfb21SJohn Baldwin uint64_t r_tokens;
50744bfb21SJohn Baldwin };
51744bfb21SJohn Baldwin
52744bfb21SJohn Baldwin struct ratelimit {
53744bfb21SJohn Baldwin uint8_t rl_secret[SIPHASH_KEY_LENGTH];
54744bfb21SJohn Baldwin struct mtx rl_mtx;
55744bfb21SJohn Baldwin struct callout rl_gc;
56744bfb21SJohn Baldwin LIST_HEAD(, ratelimit_entry) rl_table[RATELIMIT_SIZE];
57744bfb21SJohn Baldwin size_t rl_table_num;
58b08ee10cSKyle Evans bool rl_initialized;
59744bfb21SJohn Baldwin };
60744bfb21SJohn Baldwin
61744bfb21SJohn Baldwin static void precompute_key(uint8_t *,
62744bfb21SJohn Baldwin const uint8_t[COOKIE_INPUT_SIZE], const char *);
63744bfb21SJohn Baldwin static void macs_mac1(struct cookie_macs *, const void *, size_t,
64744bfb21SJohn Baldwin const uint8_t[COOKIE_KEY_SIZE]);
65744bfb21SJohn Baldwin static void macs_mac2(struct cookie_macs *, const void *, size_t,
66744bfb21SJohn Baldwin const uint8_t[COOKIE_COOKIE_SIZE]);
67744bfb21SJohn Baldwin static int timer_expired(sbintime_t, uint32_t, uint32_t);
68744bfb21SJohn Baldwin static void make_cookie(struct cookie_checker *,
69744bfb21SJohn Baldwin uint8_t[COOKIE_COOKIE_SIZE], struct sockaddr *);
70744bfb21SJohn Baldwin static void ratelimit_init(struct ratelimit *);
71744bfb21SJohn Baldwin static void ratelimit_deinit(struct ratelimit *);
72744bfb21SJohn Baldwin static void ratelimit_gc_callout(void *);
73744bfb21SJohn Baldwin static void ratelimit_gc_schedule(struct ratelimit *);
74744bfb21SJohn Baldwin static void ratelimit_gc(struct ratelimit *, bool);
75744bfb21SJohn Baldwin static int ratelimit_allow(struct ratelimit *, struct sockaddr *, struct vnet *);
76744bfb21SJohn Baldwin static uint64_t siphash13(const uint8_t [SIPHASH_KEY_LENGTH], const void *, size_t);
77744bfb21SJohn Baldwin
78744bfb21SJohn Baldwin static struct ratelimit ratelimit_v4;
79744bfb21SJohn Baldwin #ifdef INET6
80744bfb21SJohn Baldwin static struct ratelimit ratelimit_v6;
81744bfb21SJohn Baldwin #endif
82744bfb21SJohn Baldwin static uma_zone_t ratelimit_zone;
83744bfb21SJohn Baldwin
84744bfb21SJohn Baldwin /* Public Functions */
85744bfb21SJohn Baldwin int
cookie_init(void)86744bfb21SJohn Baldwin cookie_init(void)
87744bfb21SJohn Baldwin {
88*b6a0ed7cSMark Johnston ratelimit_zone = uma_zcreate("wg ratelimit",
89*b6a0ed7cSMark Johnston sizeof(struct ratelimit_entry), NULL, NULL, NULL, NULL, 0, 0);
90744bfb21SJohn Baldwin
91744bfb21SJohn Baldwin ratelimit_init(&ratelimit_v4);
92744bfb21SJohn Baldwin #ifdef INET6
93744bfb21SJohn Baldwin ratelimit_init(&ratelimit_v6);
94744bfb21SJohn Baldwin #endif
95744bfb21SJohn Baldwin return (0);
96744bfb21SJohn Baldwin }
97744bfb21SJohn Baldwin
98744bfb21SJohn Baldwin void
cookie_deinit(void)99744bfb21SJohn Baldwin cookie_deinit(void)
100744bfb21SJohn Baldwin {
101744bfb21SJohn Baldwin ratelimit_deinit(&ratelimit_v4);
102744bfb21SJohn Baldwin #ifdef INET6
103744bfb21SJohn Baldwin ratelimit_deinit(&ratelimit_v6);
104744bfb21SJohn Baldwin #endif
105b08ee10cSKyle Evans if (ratelimit_zone != NULL)
106744bfb21SJohn Baldwin uma_zdestroy(ratelimit_zone);
107744bfb21SJohn Baldwin }
108744bfb21SJohn Baldwin
109744bfb21SJohn Baldwin void
cookie_checker_init(struct cookie_checker * cc)110744bfb21SJohn Baldwin cookie_checker_init(struct cookie_checker *cc)
111744bfb21SJohn Baldwin {
112744bfb21SJohn Baldwin bzero(cc, sizeof(*cc));
113744bfb21SJohn Baldwin
114744bfb21SJohn Baldwin rw_init(&cc->cc_key_lock, "cookie_checker_key");
115744bfb21SJohn Baldwin mtx_init(&cc->cc_secret_mtx, "cookie_checker_secret", NULL, MTX_DEF);
116744bfb21SJohn Baldwin }
117744bfb21SJohn Baldwin
118744bfb21SJohn Baldwin void
cookie_checker_free(struct cookie_checker * cc)119744bfb21SJohn Baldwin cookie_checker_free(struct cookie_checker *cc)
120744bfb21SJohn Baldwin {
121744bfb21SJohn Baldwin rw_destroy(&cc->cc_key_lock);
122744bfb21SJohn Baldwin mtx_destroy(&cc->cc_secret_mtx);
123744bfb21SJohn Baldwin explicit_bzero(cc, sizeof(*cc));
124744bfb21SJohn Baldwin }
125744bfb21SJohn Baldwin
126744bfb21SJohn Baldwin void
cookie_checker_update(struct cookie_checker * cc,const uint8_t key[COOKIE_INPUT_SIZE])127744bfb21SJohn Baldwin cookie_checker_update(struct cookie_checker *cc,
128744bfb21SJohn Baldwin const uint8_t key[COOKIE_INPUT_SIZE])
129744bfb21SJohn Baldwin {
130744bfb21SJohn Baldwin rw_wlock(&cc->cc_key_lock);
131744bfb21SJohn Baldwin if (key) {
132744bfb21SJohn Baldwin precompute_key(cc->cc_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
133744bfb21SJohn Baldwin precompute_key(cc->cc_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
134744bfb21SJohn Baldwin } else {
135744bfb21SJohn Baldwin bzero(cc->cc_mac1_key, sizeof(cc->cc_mac1_key));
136744bfb21SJohn Baldwin bzero(cc->cc_cookie_key, sizeof(cc->cc_cookie_key));
137744bfb21SJohn Baldwin }
138744bfb21SJohn Baldwin rw_wunlock(&cc->cc_key_lock);
139744bfb21SJohn Baldwin }
140744bfb21SJohn Baldwin
141744bfb21SJohn Baldwin void
cookie_checker_create_payload(struct cookie_checker * cc,struct cookie_macs * macs,uint8_t nonce[COOKIE_NONCE_SIZE],uint8_t ecookie[COOKIE_ENCRYPTED_SIZE],struct sockaddr * sa)142744bfb21SJohn Baldwin cookie_checker_create_payload(struct cookie_checker *cc,
143744bfb21SJohn Baldwin struct cookie_macs *macs, uint8_t nonce[COOKIE_NONCE_SIZE],
144744bfb21SJohn Baldwin uint8_t ecookie[COOKIE_ENCRYPTED_SIZE], struct sockaddr *sa)
145744bfb21SJohn Baldwin {
146744bfb21SJohn Baldwin uint8_t cookie[COOKIE_COOKIE_SIZE];
147744bfb21SJohn Baldwin
148744bfb21SJohn Baldwin make_cookie(cc, cookie, sa);
149744bfb21SJohn Baldwin arc4random_buf(nonce, COOKIE_NONCE_SIZE);
150744bfb21SJohn Baldwin
151744bfb21SJohn Baldwin rw_rlock(&cc->cc_key_lock);
152744bfb21SJohn Baldwin xchacha20poly1305_encrypt(ecookie, cookie, COOKIE_COOKIE_SIZE,
153744bfb21SJohn Baldwin macs->mac1, COOKIE_MAC_SIZE, nonce, cc->cc_cookie_key);
154744bfb21SJohn Baldwin rw_runlock(&cc->cc_key_lock);
155744bfb21SJohn Baldwin
156744bfb21SJohn Baldwin explicit_bzero(cookie, sizeof(cookie));
157744bfb21SJohn Baldwin }
158744bfb21SJohn Baldwin
159744bfb21SJohn Baldwin void
cookie_maker_init(struct cookie_maker * cm,const uint8_t key[COOKIE_INPUT_SIZE])160744bfb21SJohn Baldwin cookie_maker_init(struct cookie_maker *cm, const uint8_t key[COOKIE_INPUT_SIZE])
161744bfb21SJohn Baldwin {
162744bfb21SJohn Baldwin bzero(cm, sizeof(*cm));
163744bfb21SJohn Baldwin precompute_key(cm->cm_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
164744bfb21SJohn Baldwin precompute_key(cm->cm_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
165744bfb21SJohn Baldwin rw_init(&cm->cm_lock, "cookie_maker");
166744bfb21SJohn Baldwin }
167744bfb21SJohn Baldwin
168744bfb21SJohn Baldwin void
cookie_maker_free(struct cookie_maker * cm)169744bfb21SJohn Baldwin cookie_maker_free(struct cookie_maker *cm)
170744bfb21SJohn Baldwin {
171744bfb21SJohn Baldwin rw_destroy(&cm->cm_lock);
172744bfb21SJohn Baldwin explicit_bzero(cm, sizeof(*cm));
173744bfb21SJohn Baldwin }
174744bfb21SJohn Baldwin
175744bfb21SJohn Baldwin int
cookie_maker_consume_payload(struct cookie_maker * cm,uint8_t nonce[COOKIE_NONCE_SIZE],uint8_t ecookie[COOKIE_ENCRYPTED_SIZE])176744bfb21SJohn Baldwin cookie_maker_consume_payload(struct cookie_maker *cm,
177744bfb21SJohn Baldwin uint8_t nonce[COOKIE_NONCE_SIZE], uint8_t ecookie[COOKIE_ENCRYPTED_SIZE])
178744bfb21SJohn Baldwin {
179744bfb21SJohn Baldwin uint8_t cookie[COOKIE_COOKIE_SIZE];
180744bfb21SJohn Baldwin int ret;
181744bfb21SJohn Baldwin
182744bfb21SJohn Baldwin rw_rlock(&cm->cm_lock);
183744bfb21SJohn Baldwin if (!cm->cm_mac1_sent) {
184744bfb21SJohn Baldwin ret = ETIMEDOUT;
185744bfb21SJohn Baldwin goto error;
186744bfb21SJohn Baldwin }
187744bfb21SJohn Baldwin
188744bfb21SJohn Baldwin if (!xchacha20poly1305_decrypt(cookie, ecookie, COOKIE_ENCRYPTED_SIZE,
189744bfb21SJohn Baldwin cm->cm_mac1_last, COOKIE_MAC_SIZE, nonce, cm->cm_cookie_key)) {
190744bfb21SJohn Baldwin ret = EINVAL;
191744bfb21SJohn Baldwin goto error;
192744bfb21SJohn Baldwin }
193744bfb21SJohn Baldwin rw_runlock(&cm->cm_lock);
194744bfb21SJohn Baldwin
195744bfb21SJohn Baldwin rw_wlock(&cm->cm_lock);
196744bfb21SJohn Baldwin memcpy(cm->cm_cookie, cookie, COOKIE_COOKIE_SIZE);
197744bfb21SJohn Baldwin cm->cm_cookie_birthdate = getsbinuptime();
198744bfb21SJohn Baldwin cm->cm_cookie_valid = true;
199744bfb21SJohn Baldwin cm->cm_mac1_sent = false;
200744bfb21SJohn Baldwin rw_wunlock(&cm->cm_lock);
201744bfb21SJohn Baldwin
202744bfb21SJohn Baldwin return 0;
203744bfb21SJohn Baldwin error:
204744bfb21SJohn Baldwin rw_runlock(&cm->cm_lock);
205744bfb21SJohn Baldwin return ret;
206744bfb21SJohn Baldwin }
207744bfb21SJohn Baldwin
208744bfb21SJohn Baldwin void
cookie_maker_mac(struct cookie_maker * cm,struct cookie_macs * macs,void * buf,size_t len)209744bfb21SJohn Baldwin cookie_maker_mac(struct cookie_maker *cm, struct cookie_macs *macs, void *buf,
210744bfb21SJohn Baldwin size_t len)
211744bfb21SJohn Baldwin {
212744bfb21SJohn Baldwin rw_wlock(&cm->cm_lock);
213744bfb21SJohn Baldwin macs_mac1(macs, buf, len, cm->cm_mac1_key);
214744bfb21SJohn Baldwin memcpy(cm->cm_mac1_last, macs->mac1, COOKIE_MAC_SIZE);
215744bfb21SJohn Baldwin cm->cm_mac1_sent = true;
216744bfb21SJohn Baldwin
217744bfb21SJohn Baldwin if (cm->cm_cookie_valid &&
218744bfb21SJohn Baldwin !timer_expired(cm->cm_cookie_birthdate,
219744bfb21SJohn Baldwin COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY, 0)) {
220744bfb21SJohn Baldwin macs_mac2(macs, buf, len, cm->cm_cookie);
221744bfb21SJohn Baldwin } else {
222744bfb21SJohn Baldwin bzero(macs->mac2, COOKIE_MAC_SIZE);
223744bfb21SJohn Baldwin cm->cm_cookie_valid = false;
224744bfb21SJohn Baldwin }
225744bfb21SJohn Baldwin rw_wunlock(&cm->cm_lock);
226744bfb21SJohn Baldwin }
227744bfb21SJohn Baldwin
228744bfb21SJohn Baldwin int
cookie_checker_validate_macs(struct cookie_checker * cc,struct cookie_macs * macs,void * buf,size_t len,bool check_cookie,struct sockaddr * sa,struct vnet * vnet)229744bfb21SJohn Baldwin cookie_checker_validate_macs(struct cookie_checker *cc, struct cookie_macs *macs,
230744bfb21SJohn Baldwin void *buf, size_t len, bool check_cookie, struct sockaddr *sa, struct vnet *vnet)
231744bfb21SJohn Baldwin {
232744bfb21SJohn Baldwin struct cookie_macs our_macs;
233744bfb21SJohn Baldwin uint8_t cookie[COOKIE_COOKIE_SIZE];
234744bfb21SJohn Baldwin
235744bfb21SJohn Baldwin /* Validate incoming MACs */
236744bfb21SJohn Baldwin rw_rlock(&cc->cc_key_lock);
237744bfb21SJohn Baldwin macs_mac1(&our_macs, buf, len, cc->cc_mac1_key);
238744bfb21SJohn Baldwin rw_runlock(&cc->cc_key_lock);
239744bfb21SJohn Baldwin
240744bfb21SJohn Baldwin /* If mac1 is invald, we want to drop the packet */
241744bfb21SJohn Baldwin if (timingsafe_bcmp(our_macs.mac1, macs->mac1, COOKIE_MAC_SIZE) != 0)
242744bfb21SJohn Baldwin return EINVAL;
243744bfb21SJohn Baldwin
244744bfb21SJohn Baldwin if (check_cookie) {
245744bfb21SJohn Baldwin make_cookie(cc, cookie, sa);
246744bfb21SJohn Baldwin macs_mac2(&our_macs, buf, len, cookie);
247744bfb21SJohn Baldwin
248744bfb21SJohn Baldwin /* If the mac2 is invalid, we want to send a cookie response */
249744bfb21SJohn Baldwin if (timingsafe_bcmp(our_macs.mac2, macs->mac2, COOKIE_MAC_SIZE) != 0)
250744bfb21SJohn Baldwin return EAGAIN;
251744bfb21SJohn Baldwin
252744bfb21SJohn Baldwin /* If the mac2 is valid, we may want rate limit the peer.
253744bfb21SJohn Baldwin * ratelimit_allow will return either 0 or ECONNREFUSED,
254744bfb21SJohn Baldwin * implying there is no ratelimiting, or we should ratelimit
255744bfb21SJohn Baldwin * (refuse) respectively. */
256744bfb21SJohn Baldwin if (sa->sa_family == AF_INET)
257744bfb21SJohn Baldwin return ratelimit_allow(&ratelimit_v4, sa, vnet);
258744bfb21SJohn Baldwin #ifdef INET6
259744bfb21SJohn Baldwin else if (sa->sa_family == AF_INET6)
260744bfb21SJohn Baldwin return ratelimit_allow(&ratelimit_v6, sa, vnet);
261744bfb21SJohn Baldwin #endif
262744bfb21SJohn Baldwin else
263744bfb21SJohn Baldwin return EAFNOSUPPORT;
264744bfb21SJohn Baldwin }
265744bfb21SJohn Baldwin
266744bfb21SJohn Baldwin return 0;
267744bfb21SJohn Baldwin }
268744bfb21SJohn Baldwin
269744bfb21SJohn Baldwin /* Private functions */
270744bfb21SJohn Baldwin static void
precompute_key(uint8_t * key,const uint8_t input[COOKIE_INPUT_SIZE],const char * label)271744bfb21SJohn Baldwin precompute_key(uint8_t *key, const uint8_t input[COOKIE_INPUT_SIZE],
272744bfb21SJohn Baldwin const char *label)
273744bfb21SJohn Baldwin {
274744bfb21SJohn Baldwin struct blake2s_state blake;
275744bfb21SJohn Baldwin blake2s_init(&blake, COOKIE_KEY_SIZE);
276744bfb21SJohn Baldwin blake2s_update(&blake, label, strlen(label));
277744bfb21SJohn Baldwin blake2s_update(&blake, input, COOKIE_INPUT_SIZE);
278744bfb21SJohn Baldwin blake2s_final(&blake, key);
279744bfb21SJohn Baldwin }
280744bfb21SJohn Baldwin
281744bfb21SJohn Baldwin static void
macs_mac1(struct cookie_macs * macs,const void * buf,size_t len,const uint8_t key[COOKIE_KEY_SIZE])282744bfb21SJohn Baldwin macs_mac1(struct cookie_macs *macs, const void *buf, size_t len,
283744bfb21SJohn Baldwin const uint8_t key[COOKIE_KEY_SIZE])
284744bfb21SJohn Baldwin {
285744bfb21SJohn Baldwin struct blake2s_state state;
286744bfb21SJohn Baldwin blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_KEY_SIZE);
287744bfb21SJohn Baldwin blake2s_update(&state, buf, len);
288744bfb21SJohn Baldwin blake2s_final(&state, macs->mac1);
289744bfb21SJohn Baldwin }
290744bfb21SJohn Baldwin
291744bfb21SJohn Baldwin static void
macs_mac2(struct cookie_macs * macs,const void * buf,size_t len,const uint8_t key[COOKIE_COOKIE_SIZE])292744bfb21SJohn Baldwin macs_mac2(struct cookie_macs *macs, const void *buf, size_t len,
293744bfb21SJohn Baldwin const uint8_t key[COOKIE_COOKIE_SIZE])
294744bfb21SJohn Baldwin {
295744bfb21SJohn Baldwin struct blake2s_state state;
296744bfb21SJohn Baldwin blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_COOKIE_SIZE);
297744bfb21SJohn Baldwin blake2s_update(&state, buf, len);
298744bfb21SJohn Baldwin blake2s_update(&state, macs->mac1, COOKIE_MAC_SIZE);
299744bfb21SJohn Baldwin blake2s_final(&state, macs->mac2);
300744bfb21SJohn Baldwin }
301744bfb21SJohn Baldwin
302744bfb21SJohn Baldwin static __inline int
timer_expired(sbintime_t timer,uint32_t sec,uint32_t nsec)303744bfb21SJohn Baldwin timer_expired(sbintime_t timer, uint32_t sec, uint32_t nsec)
304744bfb21SJohn Baldwin {
305744bfb21SJohn Baldwin sbintime_t now = getsbinuptime();
306744bfb21SJohn Baldwin return (now > (timer + sec * SBT_1S + nstosbt(nsec))) ? ETIMEDOUT : 0;
307744bfb21SJohn Baldwin }
308744bfb21SJohn Baldwin
309744bfb21SJohn Baldwin static void
make_cookie(struct cookie_checker * cc,uint8_t cookie[COOKIE_COOKIE_SIZE],struct sockaddr * sa)310744bfb21SJohn Baldwin make_cookie(struct cookie_checker *cc, uint8_t cookie[COOKIE_COOKIE_SIZE],
311744bfb21SJohn Baldwin struct sockaddr *sa)
312744bfb21SJohn Baldwin {
313744bfb21SJohn Baldwin struct blake2s_state state;
314744bfb21SJohn Baldwin
315744bfb21SJohn Baldwin mtx_lock(&cc->cc_secret_mtx);
316744bfb21SJohn Baldwin if (timer_expired(cc->cc_secret_birthdate,
317744bfb21SJohn Baldwin COOKIE_SECRET_MAX_AGE, 0)) {
318744bfb21SJohn Baldwin arc4random_buf(cc->cc_secret, COOKIE_SECRET_SIZE);
319744bfb21SJohn Baldwin cc->cc_secret_birthdate = getsbinuptime();
320744bfb21SJohn Baldwin }
321744bfb21SJohn Baldwin blake2s_init_key(&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
322744bfb21SJohn Baldwin COOKIE_SECRET_SIZE);
323744bfb21SJohn Baldwin mtx_unlock(&cc->cc_secret_mtx);
324744bfb21SJohn Baldwin
325744bfb21SJohn Baldwin if (sa->sa_family == AF_INET) {
326744bfb21SJohn Baldwin blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_addr,
327744bfb21SJohn Baldwin sizeof(struct in_addr));
328744bfb21SJohn Baldwin blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_port,
329744bfb21SJohn Baldwin sizeof(in_port_t));
330744bfb21SJohn Baldwin blake2s_final(&state, cookie);
331744bfb21SJohn Baldwin #ifdef INET6
332744bfb21SJohn Baldwin } else if (sa->sa_family == AF_INET6) {
333744bfb21SJohn Baldwin blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_addr,
334744bfb21SJohn Baldwin sizeof(struct in6_addr));
335744bfb21SJohn Baldwin blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_port,
336744bfb21SJohn Baldwin sizeof(in_port_t));
337744bfb21SJohn Baldwin blake2s_final(&state, cookie);
338744bfb21SJohn Baldwin #endif
339744bfb21SJohn Baldwin } else {
340744bfb21SJohn Baldwin arc4random_buf(cookie, COOKIE_COOKIE_SIZE);
341744bfb21SJohn Baldwin }
342744bfb21SJohn Baldwin }
343744bfb21SJohn Baldwin
344744bfb21SJohn Baldwin static void
ratelimit_init(struct ratelimit * rl)345744bfb21SJohn Baldwin ratelimit_init(struct ratelimit *rl)
346744bfb21SJohn Baldwin {
347744bfb21SJohn Baldwin size_t i;
348744bfb21SJohn Baldwin mtx_init(&rl->rl_mtx, "ratelimit_lock", NULL, MTX_DEF);
349744bfb21SJohn Baldwin callout_init_mtx(&rl->rl_gc, &rl->rl_mtx, 0);
350744bfb21SJohn Baldwin arc4random_buf(rl->rl_secret, sizeof(rl->rl_secret));
351744bfb21SJohn Baldwin for (i = 0; i < RATELIMIT_SIZE; i++)
352744bfb21SJohn Baldwin LIST_INIT(&rl->rl_table[i]);
353744bfb21SJohn Baldwin rl->rl_table_num = 0;
354b08ee10cSKyle Evans rl->rl_initialized = true;
355744bfb21SJohn Baldwin }
356744bfb21SJohn Baldwin
357744bfb21SJohn Baldwin static void
ratelimit_deinit(struct ratelimit * rl)358744bfb21SJohn Baldwin ratelimit_deinit(struct ratelimit *rl)
359744bfb21SJohn Baldwin {
360b08ee10cSKyle Evans if (!rl->rl_initialized)
361b08ee10cSKyle Evans return;
362744bfb21SJohn Baldwin mtx_lock(&rl->rl_mtx);
363744bfb21SJohn Baldwin callout_stop(&rl->rl_gc);
364744bfb21SJohn Baldwin ratelimit_gc(rl, true);
365744bfb21SJohn Baldwin mtx_unlock(&rl->rl_mtx);
366744bfb21SJohn Baldwin mtx_destroy(&rl->rl_mtx);
367b08ee10cSKyle Evans
368b08ee10cSKyle Evans rl->rl_initialized = false;
369744bfb21SJohn Baldwin }
370744bfb21SJohn Baldwin
371744bfb21SJohn Baldwin static void
ratelimit_gc_callout(void * _rl)372744bfb21SJohn Baldwin ratelimit_gc_callout(void *_rl)
373744bfb21SJohn Baldwin {
374744bfb21SJohn Baldwin /* callout will lock rl_mtx for us */
375744bfb21SJohn Baldwin ratelimit_gc(_rl, false);
376744bfb21SJohn Baldwin }
377744bfb21SJohn Baldwin
378744bfb21SJohn Baldwin static void
ratelimit_gc_schedule(struct ratelimit * rl)379744bfb21SJohn Baldwin ratelimit_gc_schedule(struct ratelimit *rl)
380744bfb21SJohn Baldwin {
381744bfb21SJohn Baldwin /* Trigger another GC if needed. There is no point calling GC if there
382744bfb21SJohn Baldwin * are no entries in the table. We also want to ensure that GC occurs
383744bfb21SJohn Baldwin * on a regular interval, so don't override a currently pending GC.
384744bfb21SJohn Baldwin *
385744bfb21SJohn Baldwin * In the case of a forced ratelimit_gc, there will be no entries left
386744bfb21SJohn Baldwin * so we will will not schedule another GC. */
387744bfb21SJohn Baldwin if (rl->rl_table_num > 0 && !callout_pending(&rl->rl_gc))
388744bfb21SJohn Baldwin callout_reset(&rl->rl_gc, ELEMENT_TIMEOUT * hz,
389744bfb21SJohn Baldwin ratelimit_gc_callout, rl);
390744bfb21SJohn Baldwin }
391744bfb21SJohn Baldwin
392744bfb21SJohn Baldwin static void
ratelimit_gc(struct ratelimit * rl,bool force)393744bfb21SJohn Baldwin ratelimit_gc(struct ratelimit *rl, bool force)
394744bfb21SJohn Baldwin {
395744bfb21SJohn Baldwin size_t i;
396744bfb21SJohn Baldwin struct ratelimit_entry *r, *tr;
397744bfb21SJohn Baldwin sbintime_t expiry;
398744bfb21SJohn Baldwin
399744bfb21SJohn Baldwin mtx_assert(&rl->rl_mtx, MA_OWNED);
400744bfb21SJohn Baldwin
401744bfb21SJohn Baldwin if (rl->rl_table_num == 0)
402744bfb21SJohn Baldwin return;
403744bfb21SJohn Baldwin
404744bfb21SJohn Baldwin expiry = getsbinuptime() - ELEMENT_TIMEOUT * SBT_1S;
405744bfb21SJohn Baldwin
406744bfb21SJohn Baldwin for (i = 0; i < RATELIMIT_SIZE; i++) {
407744bfb21SJohn Baldwin LIST_FOREACH_SAFE(r, &rl->rl_table[i], r_entry, tr) {
408744bfb21SJohn Baldwin if (r->r_last_time < expiry || force) {
409744bfb21SJohn Baldwin rl->rl_table_num--;
410744bfb21SJohn Baldwin LIST_REMOVE(r, r_entry);
411744bfb21SJohn Baldwin uma_zfree(ratelimit_zone, r);
412744bfb21SJohn Baldwin }
413744bfb21SJohn Baldwin }
414744bfb21SJohn Baldwin }
415744bfb21SJohn Baldwin
416744bfb21SJohn Baldwin ratelimit_gc_schedule(rl);
417744bfb21SJohn Baldwin }
418744bfb21SJohn Baldwin
419744bfb21SJohn Baldwin static int
ratelimit_allow(struct ratelimit * rl,struct sockaddr * sa,struct vnet * vnet)420744bfb21SJohn Baldwin ratelimit_allow(struct ratelimit *rl, struct sockaddr *sa, struct vnet *vnet)
421744bfb21SJohn Baldwin {
422744bfb21SJohn Baldwin uint64_t bucket, tokens;
423744bfb21SJohn Baldwin sbintime_t diff, now;
424744bfb21SJohn Baldwin struct ratelimit_entry *r;
425744bfb21SJohn Baldwin int ret = ECONNREFUSED;
426744bfb21SJohn Baldwin struct ratelimit_key key = { .vnet = vnet };
427744bfb21SJohn Baldwin size_t len = sizeof(key);
428744bfb21SJohn Baldwin
429744bfb21SJohn Baldwin if (sa->sa_family == AF_INET) {
430744bfb21SJohn Baldwin memcpy(key.ip, &satosin(sa)->sin_addr, IPV4_MASK_SIZE);
431744bfb21SJohn Baldwin len -= IPV6_MASK_SIZE - IPV4_MASK_SIZE;
432744bfb21SJohn Baldwin }
433744bfb21SJohn Baldwin #ifdef INET6
434744bfb21SJohn Baldwin else if (sa->sa_family == AF_INET6)
435744bfb21SJohn Baldwin memcpy(key.ip, &satosin6(sa)->sin6_addr, IPV6_MASK_SIZE);
436744bfb21SJohn Baldwin #endif
437744bfb21SJohn Baldwin else
438744bfb21SJohn Baldwin return ret;
439744bfb21SJohn Baldwin
440744bfb21SJohn Baldwin bucket = siphash13(rl->rl_secret, &key, len) & RATELIMIT_MASK;
441744bfb21SJohn Baldwin mtx_lock(&rl->rl_mtx);
442744bfb21SJohn Baldwin
443744bfb21SJohn Baldwin LIST_FOREACH(r, &rl->rl_table[bucket], r_entry) {
444744bfb21SJohn Baldwin if (bcmp(&r->r_key, &key, len) != 0)
445744bfb21SJohn Baldwin continue;
446744bfb21SJohn Baldwin
447744bfb21SJohn Baldwin /* If we get to here, we've found an entry for the endpoint.
448744bfb21SJohn Baldwin * We apply standard token bucket, by calculating the time
449744bfb21SJohn Baldwin * lapsed since our last_time, adding that, ensuring that we
450744bfb21SJohn Baldwin * cap the tokens at TOKEN_MAX. If the endpoint has no tokens
451744bfb21SJohn Baldwin * left (that is tokens <= INITIATION_COST) then we block the
452744bfb21SJohn Baldwin * request, otherwise we subtract the INITITIATION_COST and
453744bfb21SJohn Baldwin * return OK. */
454744bfb21SJohn Baldwin now = getsbinuptime();
455744bfb21SJohn Baldwin diff = now - r->r_last_time;
456744bfb21SJohn Baldwin r->r_last_time = now;
457744bfb21SJohn Baldwin
458744bfb21SJohn Baldwin tokens = r->r_tokens + diff;
459744bfb21SJohn Baldwin
460744bfb21SJohn Baldwin if (tokens > TOKEN_MAX)
461744bfb21SJohn Baldwin tokens = TOKEN_MAX;
462744bfb21SJohn Baldwin
463744bfb21SJohn Baldwin if (tokens >= INITIATION_COST) {
464744bfb21SJohn Baldwin r->r_tokens = tokens - INITIATION_COST;
465744bfb21SJohn Baldwin goto ok;
466744bfb21SJohn Baldwin } else {
467744bfb21SJohn Baldwin r->r_tokens = tokens;
468744bfb21SJohn Baldwin goto error;
469744bfb21SJohn Baldwin }
470744bfb21SJohn Baldwin }
471744bfb21SJohn Baldwin
472744bfb21SJohn Baldwin /* If we get to here, we didn't have an entry for the endpoint, let's
473744bfb21SJohn Baldwin * add one if we have space. */
474744bfb21SJohn Baldwin if (rl->rl_table_num >= RATELIMIT_SIZE_MAX)
475744bfb21SJohn Baldwin goto error;
476744bfb21SJohn Baldwin
477744bfb21SJohn Baldwin /* Goto error if out of memory */
478744bfb21SJohn Baldwin if ((r = uma_zalloc(ratelimit_zone, M_NOWAIT | M_ZERO)) == NULL)
479744bfb21SJohn Baldwin goto error;
480744bfb21SJohn Baldwin
481744bfb21SJohn Baldwin rl->rl_table_num++;
482744bfb21SJohn Baldwin
483744bfb21SJohn Baldwin /* Insert entry into the hashtable and ensure it's initialised */
484744bfb21SJohn Baldwin LIST_INSERT_HEAD(&rl->rl_table[bucket], r, r_entry);
485744bfb21SJohn Baldwin r->r_key = key;
486744bfb21SJohn Baldwin r->r_last_time = getsbinuptime();
487744bfb21SJohn Baldwin r->r_tokens = TOKEN_MAX - INITIATION_COST;
488744bfb21SJohn Baldwin
489744bfb21SJohn Baldwin /* If we've added a new entry, let's trigger GC. */
490744bfb21SJohn Baldwin ratelimit_gc_schedule(rl);
491744bfb21SJohn Baldwin ok:
492744bfb21SJohn Baldwin ret = 0;
493744bfb21SJohn Baldwin error:
494744bfb21SJohn Baldwin mtx_unlock(&rl->rl_mtx);
495744bfb21SJohn Baldwin return ret;
496744bfb21SJohn Baldwin }
497744bfb21SJohn Baldwin
siphash13(const uint8_t key[SIPHASH_KEY_LENGTH],const void * src,size_t len)498744bfb21SJohn Baldwin static uint64_t siphash13(const uint8_t key[SIPHASH_KEY_LENGTH], const void *src, size_t len)
499744bfb21SJohn Baldwin {
500744bfb21SJohn Baldwin SIPHASH_CTX ctx;
501744bfb21SJohn Baldwin return (SipHashX(&ctx, 1, 3, key, src, len));
502744bfb21SJohn Baldwin }
503744bfb21SJohn Baldwin
504744bfb21SJohn Baldwin #ifdef SELFTESTS
505744bfb21SJohn Baldwin #include "selftest/cookie.c"
506744bfb21SJohn Baldwin #endif /* SELFTESTS */
507