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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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