xref: /freebsd/sys/dev/wg/wg_cookie.c (revision 744bfb213144c63cbaf38d91a1c4f7aebb9b9fbc)
1*744bfb21SJohn Baldwin /* SPDX-License-Identifier: ISC
2*744bfb21SJohn Baldwin  *
3*744bfb21SJohn Baldwin  * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4*744bfb21SJohn Baldwin  * Copyright (C) 2019-2021 Matt Dunwoodie <ncon@noconroy.net>
5*744bfb21SJohn Baldwin  */
6*744bfb21SJohn Baldwin 
7*744bfb21SJohn Baldwin #include "opt_inet.h"
8*744bfb21SJohn Baldwin #include "opt_inet6.h"
9*744bfb21SJohn Baldwin 
10*744bfb21SJohn Baldwin #include <sys/param.h>
11*744bfb21SJohn Baldwin #include <sys/systm.h>
12*744bfb21SJohn Baldwin #include <sys/kernel.h>
13*744bfb21SJohn Baldwin #include <sys/lock.h>
14*744bfb21SJohn Baldwin #include <sys/mutex.h>
15*744bfb21SJohn Baldwin #include <sys/rwlock.h>
16*744bfb21SJohn Baldwin #include <sys/socket.h>
17*744bfb21SJohn Baldwin #include <crypto/siphash/siphash.h>
18*744bfb21SJohn Baldwin #include <netinet/in.h>
19*744bfb21SJohn Baldwin #include <vm/uma.h>
20*744bfb21SJohn Baldwin 
21*744bfb21SJohn Baldwin #include "wg_cookie.h"
22*744bfb21SJohn Baldwin 
23*744bfb21SJohn Baldwin #define COOKIE_MAC1_KEY_LABEL	"mac1----"
24*744bfb21SJohn Baldwin #define COOKIE_COOKIE_KEY_LABEL	"cookie--"
25*744bfb21SJohn Baldwin #define COOKIE_SECRET_MAX_AGE	120
26*744bfb21SJohn Baldwin #define COOKIE_SECRET_LATENCY	5
27*744bfb21SJohn Baldwin 
28*744bfb21SJohn Baldwin /* Constants for initiation rate limiting */
29*744bfb21SJohn Baldwin #define RATELIMIT_SIZE		(1 << 13)
30*744bfb21SJohn Baldwin #define RATELIMIT_MASK		(RATELIMIT_SIZE - 1)
31*744bfb21SJohn Baldwin #define RATELIMIT_SIZE_MAX	(RATELIMIT_SIZE * 8)
32*744bfb21SJohn Baldwin #define INITIATIONS_PER_SECOND	20
33*744bfb21SJohn Baldwin #define INITIATIONS_BURSTABLE	5
34*744bfb21SJohn Baldwin #define INITIATION_COST		(SBT_1S / INITIATIONS_PER_SECOND)
35*744bfb21SJohn Baldwin #define TOKEN_MAX		(INITIATION_COST * INITIATIONS_BURSTABLE)
36*744bfb21SJohn Baldwin #define ELEMENT_TIMEOUT		1
37*744bfb21SJohn Baldwin #define IPV4_MASK_SIZE		4 /* Use all 4 bytes of IPv4 address */
38*744bfb21SJohn Baldwin #define IPV6_MASK_SIZE		8 /* Use top 8 bytes (/64) of IPv6 address */
39*744bfb21SJohn Baldwin 
40*744bfb21SJohn Baldwin struct ratelimit_key {
41*744bfb21SJohn Baldwin 	struct vnet *vnet;
42*744bfb21SJohn Baldwin 	uint8_t ip[IPV6_MASK_SIZE];
43*744bfb21SJohn Baldwin };
44*744bfb21SJohn Baldwin 
45*744bfb21SJohn Baldwin struct ratelimit_entry {
46*744bfb21SJohn Baldwin 	LIST_ENTRY(ratelimit_entry)	r_entry;
47*744bfb21SJohn Baldwin 	struct ratelimit_key		r_key;
48*744bfb21SJohn Baldwin 	sbintime_t			r_last_time;	/* sbinuptime */
49*744bfb21SJohn Baldwin 	uint64_t			r_tokens;
50*744bfb21SJohn Baldwin };
51*744bfb21SJohn Baldwin 
52*744bfb21SJohn Baldwin struct ratelimit {
53*744bfb21SJohn Baldwin 	uint8_t				rl_secret[SIPHASH_KEY_LENGTH];
54*744bfb21SJohn Baldwin 	struct mtx			rl_mtx;
55*744bfb21SJohn Baldwin 	struct callout			rl_gc;
56*744bfb21SJohn Baldwin 	LIST_HEAD(, ratelimit_entry)	rl_table[RATELIMIT_SIZE];
57*744bfb21SJohn Baldwin 	size_t				rl_table_num;
58*744bfb21SJohn Baldwin };
59*744bfb21SJohn Baldwin 
60*744bfb21SJohn Baldwin static void	precompute_key(uint8_t *,
61*744bfb21SJohn Baldwin 			const uint8_t[COOKIE_INPUT_SIZE], const char *);
62*744bfb21SJohn Baldwin static void	macs_mac1(struct cookie_macs *, const void *, size_t,
63*744bfb21SJohn Baldwin 			const uint8_t[COOKIE_KEY_SIZE]);
64*744bfb21SJohn Baldwin static void	macs_mac2(struct cookie_macs *, const void *, size_t,
65*744bfb21SJohn Baldwin 			const uint8_t[COOKIE_COOKIE_SIZE]);
66*744bfb21SJohn Baldwin static int	timer_expired(sbintime_t, uint32_t, uint32_t);
67*744bfb21SJohn Baldwin static void	make_cookie(struct cookie_checker *,
68*744bfb21SJohn Baldwin 			uint8_t[COOKIE_COOKIE_SIZE], struct sockaddr *);
69*744bfb21SJohn Baldwin static void	ratelimit_init(struct ratelimit *);
70*744bfb21SJohn Baldwin static void	ratelimit_deinit(struct ratelimit *);
71*744bfb21SJohn Baldwin static void	ratelimit_gc_callout(void *);
72*744bfb21SJohn Baldwin static void	ratelimit_gc_schedule(struct ratelimit *);
73*744bfb21SJohn Baldwin static void	ratelimit_gc(struct ratelimit *, bool);
74*744bfb21SJohn Baldwin static int	ratelimit_allow(struct ratelimit *, struct sockaddr *, struct vnet *);
75*744bfb21SJohn Baldwin static uint64_t siphash13(const uint8_t [SIPHASH_KEY_LENGTH], const void *, size_t);
76*744bfb21SJohn Baldwin 
77*744bfb21SJohn Baldwin static struct ratelimit ratelimit_v4;
78*744bfb21SJohn Baldwin #ifdef INET6
79*744bfb21SJohn Baldwin static struct ratelimit ratelimit_v6;
80*744bfb21SJohn Baldwin #endif
81*744bfb21SJohn Baldwin static uma_zone_t ratelimit_zone;
82*744bfb21SJohn Baldwin 
83*744bfb21SJohn Baldwin /* Public Functions */
84*744bfb21SJohn Baldwin int
85*744bfb21SJohn Baldwin cookie_init(void)
86*744bfb21SJohn Baldwin {
87*744bfb21SJohn Baldwin 	if ((ratelimit_zone = uma_zcreate("wg ratelimit",
88*744bfb21SJohn Baldwin 	    sizeof(struct ratelimit_entry), NULL, NULL, NULL, NULL, 0, 0)) == NULL)
89*744bfb21SJohn Baldwin 		return ENOMEM;
90*744bfb21SJohn Baldwin 
91*744bfb21SJohn Baldwin 	ratelimit_init(&ratelimit_v4);
92*744bfb21SJohn Baldwin #ifdef INET6
93*744bfb21SJohn Baldwin 	ratelimit_init(&ratelimit_v6);
94*744bfb21SJohn Baldwin #endif
95*744bfb21SJohn Baldwin 	return (0);
96*744bfb21SJohn Baldwin }
97*744bfb21SJohn Baldwin 
98*744bfb21SJohn Baldwin void
99*744bfb21SJohn Baldwin cookie_deinit(void)
100*744bfb21SJohn Baldwin {
101*744bfb21SJohn Baldwin 	ratelimit_deinit(&ratelimit_v4);
102*744bfb21SJohn Baldwin #ifdef INET6
103*744bfb21SJohn Baldwin 	ratelimit_deinit(&ratelimit_v6);
104*744bfb21SJohn Baldwin #endif
105*744bfb21SJohn Baldwin 	uma_zdestroy(ratelimit_zone);
106*744bfb21SJohn Baldwin }
107*744bfb21SJohn Baldwin 
108*744bfb21SJohn Baldwin void
109*744bfb21SJohn Baldwin cookie_checker_init(struct cookie_checker *cc)
110*744bfb21SJohn Baldwin {
111*744bfb21SJohn Baldwin 	bzero(cc, sizeof(*cc));
112*744bfb21SJohn Baldwin 
113*744bfb21SJohn Baldwin 	rw_init(&cc->cc_key_lock, "cookie_checker_key");
114*744bfb21SJohn Baldwin 	mtx_init(&cc->cc_secret_mtx, "cookie_checker_secret", NULL, MTX_DEF);
115*744bfb21SJohn Baldwin }
116*744bfb21SJohn Baldwin 
117*744bfb21SJohn Baldwin void
118*744bfb21SJohn Baldwin cookie_checker_free(struct cookie_checker *cc)
119*744bfb21SJohn Baldwin {
120*744bfb21SJohn Baldwin 	rw_destroy(&cc->cc_key_lock);
121*744bfb21SJohn Baldwin 	mtx_destroy(&cc->cc_secret_mtx);
122*744bfb21SJohn Baldwin 	explicit_bzero(cc, sizeof(*cc));
123*744bfb21SJohn Baldwin }
124*744bfb21SJohn Baldwin 
125*744bfb21SJohn Baldwin void
126*744bfb21SJohn Baldwin cookie_checker_update(struct cookie_checker *cc,
127*744bfb21SJohn Baldwin     const uint8_t key[COOKIE_INPUT_SIZE])
128*744bfb21SJohn Baldwin {
129*744bfb21SJohn Baldwin 	rw_wlock(&cc->cc_key_lock);
130*744bfb21SJohn Baldwin 	if (key) {
131*744bfb21SJohn Baldwin 		precompute_key(cc->cc_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
132*744bfb21SJohn Baldwin 		precompute_key(cc->cc_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
133*744bfb21SJohn Baldwin 	} else {
134*744bfb21SJohn Baldwin 		bzero(cc->cc_mac1_key, sizeof(cc->cc_mac1_key));
135*744bfb21SJohn Baldwin 		bzero(cc->cc_cookie_key, sizeof(cc->cc_cookie_key));
136*744bfb21SJohn Baldwin 	}
137*744bfb21SJohn Baldwin 	rw_wunlock(&cc->cc_key_lock);
138*744bfb21SJohn Baldwin }
139*744bfb21SJohn Baldwin 
140*744bfb21SJohn Baldwin void
141*744bfb21SJohn Baldwin cookie_checker_create_payload(struct cookie_checker *cc,
142*744bfb21SJohn Baldwin     struct cookie_macs *macs, uint8_t nonce[COOKIE_NONCE_SIZE],
143*744bfb21SJohn Baldwin     uint8_t ecookie[COOKIE_ENCRYPTED_SIZE], struct sockaddr *sa)
144*744bfb21SJohn Baldwin {
145*744bfb21SJohn Baldwin 	uint8_t cookie[COOKIE_COOKIE_SIZE];
146*744bfb21SJohn Baldwin 
147*744bfb21SJohn Baldwin 	make_cookie(cc, cookie, sa);
148*744bfb21SJohn Baldwin 	arc4random_buf(nonce, COOKIE_NONCE_SIZE);
149*744bfb21SJohn Baldwin 
150*744bfb21SJohn Baldwin 	rw_rlock(&cc->cc_key_lock);
151*744bfb21SJohn Baldwin 	xchacha20poly1305_encrypt(ecookie, cookie, COOKIE_COOKIE_SIZE,
152*744bfb21SJohn Baldwin 	    macs->mac1, COOKIE_MAC_SIZE, nonce, cc->cc_cookie_key);
153*744bfb21SJohn Baldwin 	rw_runlock(&cc->cc_key_lock);
154*744bfb21SJohn Baldwin 
155*744bfb21SJohn Baldwin 	explicit_bzero(cookie, sizeof(cookie));
156*744bfb21SJohn Baldwin }
157*744bfb21SJohn Baldwin 
158*744bfb21SJohn Baldwin void
159*744bfb21SJohn Baldwin cookie_maker_init(struct cookie_maker *cm, const uint8_t key[COOKIE_INPUT_SIZE])
160*744bfb21SJohn Baldwin {
161*744bfb21SJohn Baldwin 	bzero(cm, sizeof(*cm));
162*744bfb21SJohn Baldwin 	precompute_key(cm->cm_mac1_key, key, COOKIE_MAC1_KEY_LABEL);
163*744bfb21SJohn Baldwin 	precompute_key(cm->cm_cookie_key, key, COOKIE_COOKIE_KEY_LABEL);
164*744bfb21SJohn Baldwin 	rw_init(&cm->cm_lock, "cookie_maker");
165*744bfb21SJohn Baldwin }
166*744bfb21SJohn Baldwin 
167*744bfb21SJohn Baldwin void
168*744bfb21SJohn Baldwin cookie_maker_free(struct cookie_maker *cm)
169*744bfb21SJohn Baldwin {
170*744bfb21SJohn Baldwin 	rw_destroy(&cm->cm_lock);
171*744bfb21SJohn Baldwin 	explicit_bzero(cm, sizeof(*cm));
172*744bfb21SJohn Baldwin }
173*744bfb21SJohn Baldwin 
174*744bfb21SJohn Baldwin int
175*744bfb21SJohn Baldwin cookie_maker_consume_payload(struct cookie_maker *cm,
176*744bfb21SJohn Baldwin     uint8_t nonce[COOKIE_NONCE_SIZE], uint8_t ecookie[COOKIE_ENCRYPTED_SIZE])
177*744bfb21SJohn Baldwin {
178*744bfb21SJohn Baldwin 	uint8_t cookie[COOKIE_COOKIE_SIZE];
179*744bfb21SJohn Baldwin 	int ret;
180*744bfb21SJohn Baldwin 
181*744bfb21SJohn Baldwin 	rw_rlock(&cm->cm_lock);
182*744bfb21SJohn Baldwin 	if (!cm->cm_mac1_sent) {
183*744bfb21SJohn Baldwin 		ret = ETIMEDOUT;
184*744bfb21SJohn Baldwin 		goto error;
185*744bfb21SJohn Baldwin 	}
186*744bfb21SJohn Baldwin 
187*744bfb21SJohn Baldwin 	if (!xchacha20poly1305_decrypt(cookie, ecookie, COOKIE_ENCRYPTED_SIZE,
188*744bfb21SJohn Baldwin 	    cm->cm_mac1_last, COOKIE_MAC_SIZE, nonce, cm->cm_cookie_key)) {
189*744bfb21SJohn Baldwin 		ret = EINVAL;
190*744bfb21SJohn Baldwin 		goto error;
191*744bfb21SJohn Baldwin 	}
192*744bfb21SJohn Baldwin 	rw_runlock(&cm->cm_lock);
193*744bfb21SJohn Baldwin 
194*744bfb21SJohn Baldwin 	rw_wlock(&cm->cm_lock);
195*744bfb21SJohn Baldwin 	memcpy(cm->cm_cookie, cookie, COOKIE_COOKIE_SIZE);
196*744bfb21SJohn Baldwin 	cm->cm_cookie_birthdate = getsbinuptime();
197*744bfb21SJohn Baldwin 	cm->cm_cookie_valid = true;
198*744bfb21SJohn Baldwin 	cm->cm_mac1_sent = false;
199*744bfb21SJohn Baldwin 	rw_wunlock(&cm->cm_lock);
200*744bfb21SJohn Baldwin 
201*744bfb21SJohn Baldwin 	return 0;
202*744bfb21SJohn Baldwin error:
203*744bfb21SJohn Baldwin 	rw_runlock(&cm->cm_lock);
204*744bfb21SJohn Baldwin 	return ret;
205*744bfb21SJohn Baldwin }
206*744bfb21SJohn Baldwin 
207*744bfb21SJohn Baldwin void
208*744bfb21SJohn Baldwin cookie_maker_mac(struct cookie_maker *cm, struct cookie_macs *macs, void *buf,
209*744bfb21SJohn Baldwin     size_t len)
210*744bfb21SJohn Baldwin {
211*744bfb21SJohn Baldwin 	rw_wlock(&cm->cm_lock);
212*744bfb21SJohn Baldwin 	macs_mac1(macs, buf, len, cm->cm_mac1_key);
213*744bfb21SJohn Baldwin 	memcpy(cm->cm_mac1_last, macs->mac1, COOKIE_MAC_SIZE);
214*744bfb21SJohn Baldwin 	cm->cm_mac1_sent = true;
215*744bfb21SJohn Baldwin 
216*744bfb21SJohn Baldwin 	if (cm->cm_cookie_valid &&
217*744bfb21SJohn Baldwin 	    !timer_expired(cm->cm_cookie_birthdate,
218*744bfb21SJohn Baldwin 	    COOKIE_SECRET_MAX_AGE - COOKIE_SECRET_LATENCY, 0)) {
219*744bfb21SJohn Baldwin 		macs_mac2(macs, buf, len, cm->cm_cookie);
220*744bfb21SJohn Baldwin 	} else {
221*744bfb21SJohn Baldwin 		bzero(macs->mac2, COOKIE_MAC_SIZE);
222*744bfb21SJohn Baldwin 		cm->cm_cookie_valid = false;
223*744bfb21SJohn Baldwin 	}
224*744bfb21SJohn Baldwin 	rw_wunlock(&cm->cm_lock);
225*744bfb21SJohn Baldwin }
226*744bfb21SJohn Baldwin 
227*744bfb21SJohn Baldwin int
228*744bfb21SJohn Baldwin cookie_checker_validate_macs(struct cookie_checker *cc, struct cookie_macs *macs,
229*744bfb21SJohn Baldwin     void *buf, size_t len, bool check_cookie, struct sockaddr *sa, struct vnet *vnet)
230*744bfb21SJohn Baldwin {
231*744bfb21SJohn Baldwin 	struct cookie_macs our_macs;
232*744bfb21SJohn Baldwin 	uint8_t cookie[COOKIE_COOKIE_SIZE];
233*744bfb21SJohn Baldwin 
234*744bfb21SJohn Baldwin 	/* Validate incoming MACs */
235*744bfb21SJohn Baldwin 	rw_rlock(&cc->cc_key_lock);
236*744bfb21SJohn Baldwin 	macs_mac1(&our_macs, buf, len, cc->cc_mac1_key);
237*744bfb21SJohn Baldwin 	rw_runlock(&cc->cc_key_lock);
238*744bfb21SJohn Baldwin 
239*744bfb21SJohn Baldwin 	/* If mac1 is invald, we want to drop the packet */
240*744bfb21SJohn Baldwin 	if (timingsafe_bcmp(our_macs.mac1, macs->mac1, COOKIE_MAC_SIZE) != 0)
241*744bfb21SJohn Baldwin 		return EINVAL;
242*744bfb21SJohn Baldwin 
243*744bfb21SJohn Baldwin 	if (check_cookie) {
244*744bfb21SJohn Baldwin 		make_cookie(cc, cookie, sa);
245*744bfb21SJohn Baldwin 		macs_mac2(&our_macs, buf, len, cookie);
246*744bfb21SJohn Baldwin 
247*744bfb21SJohn Baldwin 		/* If the mac2 is invalid, we want to send a cookie response */
248*744bfb21SJohn Baldwin 		if (timingsafe_bcmp(our_macs.mac2, macs->mac2, COOKIE_MAC_SIZE) != 0)
249*744bfb21SJohn Baldwin 			return EAGAIN;
250*744bfb21SJohn Baldwin 
251*744bfb21SJohn Baldwin 		/* If the mac2 is valid, we may want rate limit the peer.
252*744bfb21SJohn Baldwin 		 * ratelimit_allow will return either 0 or ECONNREFUSED,
253*744bfb21SJohn Baldwin 		 * implying there is no ratelimiting, or we should ratelimit
254*744bfb21SJohn Baldwin 		 * (refuse) respectively. */
255*744bfb21SJohn Baldwin 		if (sa->sa_family == AF_INET)
256*744bfb21SJohn Baldwin 			return ratelimit_allow(&ratelimit_v4, sa, vnet);
257*744bfb21SJohn Baldwin #ifdef INET6
258*744bfb21SJohn Baldwin 		else if (sa->sa_family == AF_INET6)
259*744bfb21SJohn Baldwin 			return ratelimit_allow(&ratelimit_v6, sa, vnet);
260*744bfb21SJohn Baldwin #endif
261*744bfb21SJohn Baldwin 		else
262*744bfb21SJohn Baldwin 			return EAFNOSUPPORT;
263*744bfb21SJohn Baldwin 	}
264*744bfb21SJohn Baldwin 
265*744bfb21SJohn Baldwin 	return 0;
266*744bfb21SJohn Baldwin }
267*744bfb21SJohn Baldwin 
268*744bfb21SJohn Baldwin /* Private functions */
269*744bfb21SJohn Baldwin static void
270*744bfb21SJohn Baldwin precompute_key(uint8_t *key, const uint8_t input[COOKIE_INPUT_SIZE],
271*744bfb21SJohn Baldwin     const char *label)
272*744bfb21SJohn Baldwin {
273*744bfb21SJohn Baldwin 	struct blake2s_state blake;
274*744bfb21SJohn Baldwin 	blake2s_init(&blake, COOKIE_KEY_SIZE);
275*744bfb21SJohn Baldwin 	blake2s_update(&blake, label, strlen(label));
276*744bfb21SJohn Baldwin 	blake2s_update(&blake, input, COOKIE_INPUT_SIZE);
277*744bfb21SJohn Baldwin 	blake2s_final(&blake, key);
278*744bfb21SJohn Baldwin }
279*744bfb21SJohn Baldwin 
280*744bfb21SJohn Baldwin static void
281*744bfb21SJohn Baldwin macs_mac1(struct cookie_macs *macs, const void *buf, size_t len,
282*744bfb21SJohn Baldwin     const uint8_t key[COOKIE_KEY_SIZE])
283*744bfb21SJohn Baldwin {
284*744bfb21SJohn Baldwin 	struct blake2s_state state;
285*744bfb21SJohn Baldwin 	blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_KEY_SIZE);
286*744bfb21SJohn Baldwin 	blake2s_update(&state, buf, len);
287*744bfb21SJohn Baldwin 	blake2s_final(&state, macs->mac1);
288*744bfb21SJohn Baldwin }
289*744bfb21SJohn Baldwin 
290*744bfb21SJohn Baldwin static void
291*744bfb21SJohn Baldwin macs_mac2(struct cookie_macs *macs, const void *buf, size_t len,
292*744bfb21SJohn Baldwin     const uint8_t key[COOKIE_COOKIE_SIZE])
293*744bfb21SJohn Baldwin {
294*744bfb21SJohn Baldwin 	struct blake2s_state state;
295*744bfb21SJohn Baldwin 	blake2s_init_key(&state, COOKIE_MAC_SIZE, key, COOKIE_COOKIE_SIZE);
296*744bfb21SJohn Baldwin 	blake2s_update(&state, buf, len);
297*744bfb21SJohn Baldwin 	blake2s_update(&state, macs->mac1, COOKIE_MAC_SIZE);
298*744bfb21SJohn Baldwin 	blake2s_final(&state, macs->mac2);
299*744bfb21SJohn Baldwin }
300*744bfb21SJohn Baldwin 
301*744bfb21SJohn Baldwin static __inline int
302*744bfb21SJohn Baldwin timer_expired(sbintime_t timer, uint32_t sec, uint32_t nsec)
303*744bfb21SJohn Baldwin {
304*744bfb21SJohn Baldwin 	sbintime_t now = getsbinuptime();
305*744bfb21SJohn Baldwin 	return (now > (timer + sec * SBT_1S + nstosbt(nsec))) ? ETIMEDOUT : 0;
306*744bfb21SJohn Baldwin }
307*744bfb21SJohn Baldwin 
308*744bfb21SJohn Baldwin static void
309*744bfb21SJohn Baldwin make_cookie(struct cookie_checker *cc, uint8_t cookie[COOKIE_COOKIE_SIZE],
310*744bfb21SJohn Baldwin     struct sockaddr *sa)
311*744bfb21SJohn Baldwin {
312*744bfb21SJohn Baldwin 	struct blake2s_state state;
313*744bfb21SJohn Baldwin 
314*744bfb21SJohn Baldwin 	mtx_lock(&cc->cc_secret_mtx);
315*744bfb21SJohn Baldwin 	if (timer_expired(cc->cc_secret_birthdate,
316*744bfb21SJohn Baldwin 	    COOKIE_SECRET_MAX_AGE, 0)) {
317*744bfb21SJohn Baldwin 		arc4random_buf(cc->cc_secret, COOKIE_SECRET_SIZE);
318*744bfb21SJohn Baldwin 		cc->cc_secret_birthdate = getsbinuptime();
319*744bfb21SJohn Baldwin 	}
320*744bfb21SJohn Baldwin 	blake2s_init_key(&state, COOKIE_COOKIE_SIZE, cc->cc_secret,
321*744bfb21SJohn Baldwin 	    COOKIE_SECRET_SIZE);
322*744bfb21SJohn Baldwin 	mtx_unlock(&cc->cc_secret_mtx);
323*744bfb21SJohn Baldwin 
324*744bfb21SJohn Baldwin 	if (sa->sa_family == AF_INET) {
325*744bfb21SJohn Baldwin 		blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_addr,
326*744bfb21SJohn Baldwin 				sizeof(struct in_addr));
327*744bfb21SJohn Baldwin 		blake2s_update(&state, (uint8_t *)&satosin(sa)->sin_port,
328*744bfb21SJohn Baldwin 				sizeof(in_port_t));
329*744bfb21SJohn Baldwin 		blake2s_final(&state, cookie);
330*744bfb21SJohn Baldwin #ifdef INET6
331*744bfb21SJohn Baldwin 	} else if (sa->sa_family == AF_INET6) {
332*744bfb21SJohn Baldwin 		blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_addr,
333*744bfb21SJohn Baldwin 				sizeof(struct in6_addr));
334*744bfb21SJohn Baldwin 		blake2s_update(&state, (uint8_t *)&satosin6(sa)->sin6_port,
335*744bfb21SJohn Baldwin 				sizeof(in_port_t));
336*744bfb21SJohn Baldwin 		blake2s_final(&state, cookie);
337*744bfb21SJohn Baldwin #endif
338*744bfb21SJohn Baldwin 	} else {
339*744bfb21SJohn Baldwin 		arc4random_buf(cookie, COOKIE_COOKIE_SIZE);
340*744bfb21SJohn Baldwin 	}
341*744bfb21SJohn Baldwin }
342*744bfb21SJohn Baldwin 
343*744bfb21SJohn Baldwin static void
344*744bfb21SJohn Baldwin ratelimit_init(struct ratelimit *rl)
345*744bfb21SJohn Baldwin {
346*744bfb21SJohn Baldwin 	size_t i;
347*744bfb21SJohn Baldwin 	mtx_init(&rl->rl_mtx, "ratelimit_lock", NULL, MTX_DEF);
348*744bfb21SJohn Baldwin 	callout_init_mtx(&rl->rl_gc, &rl->rl_mtx, 0);
349*744bfb21SJohn Baldwin 	arc4random_buf(rl->rl_secret, sizeof(rl->rl_secret));
350*744bfb21SJohn Baldwin 	for (i = 0; i < RATELIMIT_SIZE; i++)
351*744bfb21SJohn Baldwin 		LIST_INIT(&rl->rl_table[i]);
352*744bfb21SJohn Baldwin 	rl->rl_table_num = 0;
353*744bfb21SJohn Baldwin }
354*744bfb21SJohn Baldwin 
355*744bfb21SJohn Baldwin static void
356*744bfb21SJohn Baldwin ratelimit_deinit(struct ratelimit *rl)
357*744bfb21SJohn Baldwin {
358*744bfb21SJohn Baldwin 	mtx_lock(&rl->rl_mtx);
359*744bfb21SJohn Baldwin 	callout_stop(&rl->rl_gc);
360*744bfb21SJohn Baldwin 	ratelimit_gc(rl, true);
361*744bfb21SJohn Baldwin 	mtx_unlock(&rl->rl_mtx);
362*744bfb21SJohn Baldwin 	mtx_destroy(&rl->rl_mtx);
363*744bfb21SJohn Baldwin }
364*744bfb21SJohn Baldwin 
365*744bfb21SJohn Baldwin static void
366*744bfb21SJohn Baldwin ratelimit_gc_callout(void *_rl)
367*744bfb21SJohn Baldwin {
368*744bfb21SJohn Baldwin 	/* callout will lock rl_mtx for us */
369*744bfb21SJohn Baldwin 	ratelimit_gc(_rl, false);
370*744bfb21SJohn Baldwin }
371*744bfb21SJohn Baldwin 
372*744bfb21SJohn Baldwin static void
373*744bfb21SJohn Baldwin ratelimit_gc_schedule(struct ratelimit *rl)
374*744bfb21SJohn Baldwin {
375*744bfb21SJohn Baldwin 	/* Trigger another GC if needed. There is no point calling GC if there
376*744bfb21SJohn Baldwin 	 * are no entries in the table. We also want to ensure that GC occurs
377*744bfb21SJohn Baldwin 	 * on a regular interval, so don't override a currently pending GC.
378*744bfb21SJohn Baldwin 	 *
379*744bfb21SJohn Baldwin 	 * In the case of a forced ratelimit_gc, there will be no entries left
380*744bfb21SJohn Baldwin 	 * so we will will not schedule another GC. */
381*744bfb21SJohn Baldwin 	if (rl->rl_table_num > 0 && !callout_pending(&rl->rl_gc))
382*744bfb21SJohn Baldwin 		callout_reset(&rl->rl_gc, ELEMENT_TIMEOUT * hz,
383*744bfb21SJohn Baldwin 		    ratelimit_gc_callout, rl);
384*744bfb21SJohn Baldwin }
385*744bfb21SJohn Baldwin 
386*744bfb21SJohn Baldwin static void
387*744bfb21SJohn Baldwin ratelimit_gc(struct ratelimit *rl, bool force)
388*744bfb21SJohn Baldwin {
389*744bfb21SJohn Baldwin 	size_t i;
390*744bfb21SJohn Baldwin 	struct ratelimit_entry *r, *tr;
391*744bfb21SJohn Baldwin 	sbintime_t expiry;
392*744bfb21SJohn Baldwin 
393*744bfb21SJohn Baldwin 	mtx_assert(&rl->rl_mtx, MA_OWNED);
394*744bfb21SJohn Baldwin 
395*744bfb21SJohn Baldwin 	if (rl->rl_table_num == 0)
396*744bfb21SJohn Baldwin 		return;
397*744bfb21SJohn Baldwin 
398*744bfb21SJohn Baldwin 	expiry = getsbinuptime() - ELEMENT_TIMEOUT * SBT_1S;
399*744bfb21SJohn Baldwin 
400*744bfb21SJohn Baldwin 	for (i = 0; i < RATELIMIT_SIZE; i++) {
401*744bfb21SJohn Baldwin 		LIST_FOREACH_SAFE(r, &rl->rl_table[i], r_entry, tr) {
402*744bfb21SJohn Baldwin 			if (r->r_last_time < expiry || force) {
403*744bfb21SJohn Baldwin 				rl->rl_table_num--;
404*744bfb21SJohn Baldwin 				LIST_REMOVE(r, r_entry);
405*744bfb21SJohn Baldwin 				uma_zfree(ratelimit_zone, r);
406*744bfb21SJohn Baldwin 			}
407*744bfb21SJohn Baldwin 		}
408*744bfb21SJohn Baldwin 	}
409*744bfb21SJohn Baldwin 
410*744bfb21SJohn Baldwin 	ratelimit_gc_schedule(rl);
411*744bfb21SJohn Baldwin }
412*744bfb21SJohn Baldwin 
413*744bfb21SJohn Baldwin static int
414*744bfb21SJohn Baldwin ratelimit_allow(struct ratelimit *rl, struct sockaddr *sa, struct vnet *vnet)
415*744bfb21SJohn Baldwin {
416*744bfb21SJohn Baldwin 	uint64_t bucket, tokens;
417*744bfb21SJohn Baldwin 	sbintime_t diff, now;
418*744bfb21SJohn Baldwin 	struct ratelimit_entry *r;
419*744bfb21SJohn Baldwin 	int ret = ECONNREFUSED;
420*744bfb21SJohn Baldwin 	struct ratelimit_key key = { .vnet = vnet };
421*744bfb21SJohn Baldwin 	size_t len = sizeof(key);
422*744bfb21SJohn Baldwin 
423*744bfb21SJohn Baldwin 	if (sa->sa_family == AF_INET) {
424*744bfb21SJohn Baldwin 		memcpy(key.ip, &satosin(sa)->sin_addr, IPV4_MASK_SIZE);
425*744bfb21SJohn Baldwin 		len -= IPV6_MASK_SIZE - IPV4_MASK_SIZE;
426*744bfb21SJohn Baldwin 	}
427*744bfb21SJohn Baldwin #ifdef INET6
428*744bfb21SJohn Baldwin 	else if (sa->sa_family == AF_INET6)
429*744bfb21SJohn Baldwin 		memcpy(key.ip, &satosin6(sa)->sin6_addr, IPV6_MASK_SIZE);
430*744bfb21SJohn Baldwin #endif
431*744bfb21SJohn Baldwin 	else
432*744bfb21SJohn Baldwin 		return ret;
433*744bfb21SJohn Baldwin 
434*744bfb21SJohn Baldwin 	bucket = siphash13(rl->rl_secret, &key, len) & RATELIMIT_MASK;
435*744bfb21SJohn Baldwin 	mtx_lock(&rl->rl_mtx);
436*744bfb21SJohn Baldwin 
437*744bfb21SJohn Baldwin 	LIST_FOREACH(r, &rl->rl_table[bucket], r_entry) {
438*744bfb21SJohn Baldwin 		if (bcmp(&r->r_key, &key, len) != 0)
439*744bfb21SJohn Baldwin 			continue;
440*744bfb21SJohn Baldwin 
441*744bfb21SJohn Baldwin 		/* If we get to here, we've found an entry for the endpoint.
442*744bfb21SJohn Baldwin 		 * We apply standard token bucket, by calculating the time
443*744bfb21SJohn Baldwin 		 * lapsed since our last_time, adding that, ensuring that we
444*744bfb21SJohn Baldwin 		 * cap the tokens at TOKEN_MAX. If the endpoint has no tokens
445*744bfb21SJohn Baldwin 		 * left (that is tokens <= INITIATION_COST) then we block the
446*744bfb21SJohn Baldwin 		 * request, otherwise we subtract the INITITIATION_COST and
447*744bfb21SJohn Baldwin 		 * return OK. */
448*744bfb21SJohn Baldwin 		now = getsbinuptime();
449*744bfb21SJohn Baldwin 		diff = now - r->r_last_time;
450*744bfb21SJohn Baldwin 		r->r_last_time = now;
451*744bfb21SJohn Baldwin 
452*744bfb21SJohn Baldwin 		tokens = r->r_tokens + diff;
453*744bfb21SJohn Baldwin 
454*744bfb21SJohn Baldwin 		if (tokens > TOKEN_MAX)
455*744bfb21SJohn Baldwin 			tokens = TOKEN_MAX;
456*744bfb21SJohn Baldwin 
457*744bfb21SJohn Baldwin 		if (tokens >= INITIATION_COST) {
458*744bfb21SJohn Baldwin 			r->r_tokens = tokens - INITIATION_COST;
459*744bfb21SJohn Baldwin 			goto ok;
460*744bfb21SJohn Baldwin 		} else {
461*744bfb21SJohn Baldwin 			r->r_tokens = tokens;
462*744bfb21SJohn Baldwin 			goto error;
463*744bfb21SJohn Baldwin 		}
464*744bfb21SJohn Baldwin 	}
465*744bfb21SJohn Baldwin 
466*744bfb21SJohn Baldwin 	/* If we get to here, we didn't have an entry for the endpoint, let's
467*744bfb21SJohn Baldwin 	 * add one if we have space. */
468*744bfb21SJohn Baldwin 	if (rl->rl_table_num >= RATELIMIT_SIZE_MAX)
469*744bfb21SJohn Baldwin 		goto error;
470*744bfb21SJohn Baldwin 
471*744bfb21SJohn Baldwin 	/* Goto error if out of memory */
472*744bfb21SJohn Baldwin 	if ((r = uma_zalloc(ratelimit_zone, M_NOWAIT | M_ZERO)) == NULL)
473*744bfb21SJohn Baldwin 		goto error;
474*744bfb21SJohn Baldwin 
475*744bfb21SJohn Baldwin 	rl->rl_table_num++;
476*744bfb21SJohn Baldwin 
477*744bfb21SJohn Baldwin 	/* Insert entry into the hashtable and ensure it's initialised */
478*744bfb21SJohn Baldwin 	LIST_INSERT_HEAD(&rl->rl_table[bucket], r, r_entry);
479*744bfb21SJohn Baldwin 	r->r_key = key;
480*744bfb21SJohn Baldwin 	r->r_last_time = getsbinuptime();
481*744bfb21SJohn Baldwin 	r->r_tokens = TOKEN_MAX - INITIATION_COST;
482*744bfb21SJohn Baldwin 
483*744bfb21SJohn Baldwin 	/* If we've added a new entry, let's trigger GC. */
484*744bfb21SJohn Baldwin 	ratelimit_gc_schedule(rl);
485*744bfb21SJohn Baldwin ok:
486*744bfb21SJohn Baldwin 	ret = 0;
487*744bfb21SJohn Baldwin error:
488*744bfb21SJohn Baldwin 	mtx_unlock(&rl->rl_mtx);
489*744bfb21SJohn Baldwin 	return ret;
490*744bfb21SJohn Baldwin }
491*744bfb21SJohn Baldwin 
492*744bfb21SJohn Baldwin static uint64_t siphash13(const uint8_t key[SIPHASH_KEY_LENGTH], const void *src, size_t len)
493*744bfb21SJohn Baldwin {
494*744bfb21SJohn Baldwin 	SIPHASH_CTX ctx;
495*744bfb21SJohn Baldwin 	return (SipHashX(&ctx, 1, 3, key, src, len));
496*744bfb21SJohn Baldwin }
497*744bfb21SJohn Baldwin 
498*744bfb21SJohn Baldwin #ifdef SELFTESTS
499*744bfb21SJohn Baldwin #include "selftest/cookie.c"
500*744bfb21SJohn Baldwin #endif /* SELFTESTS */
501