static void* rrl_runnable(void *arg) { struct runnable_data* d = (struct runnable_data*)arg; sockaddr_t addr; memcpy(&addr, d->addr, sizeof(sockaddr_t)); int lock = -1; uint32_t now = time(NULL); struct bucketmap_t *m = malloc(RRL_INSERTS * sizeof(struct bucketmap_t)); for (unsigned i = 0; i < RRL_INSERTS; ++i) { m[i].i = knot_random_uint32_t(UINT32_MAX); addr.addr4.sin_addr.s_addr = m[i].i; rrl_item_t *b = rrl_hash(d->rrl, &addr, d->rq, d->zone, now, &lock); rrl_unlock(d->rrl, lock); m[i].x = b->netblk; } for (unsigned i = 0; i < RRL_INSERTS; ++i) { addr.addr4.sin_addr.s_addr = m[i].i; rrl_item_t *b = rrl_hash(d->rrl, &addr, d->rq, d->zone, now, &lock); rrl_unlock(d->rrl, lock); if (b->netblk != m[i].x) { d->passed = 0; } } free(m); return NULL; }
int rrl_reseed(rrl_table_t *rrl) { /* Lock entire table. */ if (rrl->lk_count > 0) { pthread_mutex_lock(&rrl->ll); for (unsigned i = 0; i < rrl->lk_count; ++i) { rrl_lock(rrl, i); } } memset(rrl->arr, 0, rrl->size * sizeof(rrl_item_t)); rrl->seed = dnssec_random_uint32_t(); dbg_rrl("%s: reseed to '%u'\n", __func__, rrl->seed); if (rrl->lk_count > 0) { for (unsigned i = 0; i < rrl->lk_count; ++i) { rrl_unlock(rrl, i); } pthread_mutex_unlock(&rrl->ll); } return KNOT_EOK; }
int rrl_query(rrl_table_t *rrl, const struct sockaddr_storage *a, rrl_req_t *req, const zone_t *zone) { if (!rrl || !req || !a) return KNOT_EINVAL; /* Calculate hash and fetch */ int ret = KNOT_EOK; int lock = -1; uint32_t now = time(NULL); rrl_item_t *b = rrl_hash(rrl, a, req, zone, now, &lock); if (!b) { dbg_rrl("%s: failed to compute bucket from packet\n", __func__); if (lock > -1) rrl_unlock(rrl, lock); return KNOT_ERROR; } /* Calculate rate for dT */ uint32_t dt = now - b->time; if (dt > RRL_CAPACITY) { dt = RRL_CAPACITY; } /* Visit bucket. */ b->time = now; dbg_rrl("%s: bucket=0x%x tokens=%hu flags=%x dt=%u\n", __func__, (unsigned)(b - rrl->arr), b->ntok, b->flags, dt); if (dt > 0) { /* Window moved. */ /* Check state change. */ if ((b->ntok > 0 || dt > 1) && (b->flags & RRL_BF_ELIMIT)) { b->flags &= ~RRL_BF_ELIMIT; rrl_log_state(a, b->flags, b->cls); } /* Add new tokens. */ uint32_t dn = rrl->rate * dt; if (b->flags & RRL_BF_SSTART) { /* Bucket in slow-start. */ b->flags &= ~RRL_BF_SSTART; dbg_rrl("%s: bucket '0x%x' slow-start finished\n", __func__, (unsigned)(b - rrl->arr)); } b->ntok += dn; if (b->ntok > RRL_CAPACITY * rrl->rate) { b->ntok = RRL_CAPACITY * rrl->rate; } } /* Last item taken. */ if (b->ntok == 1 && !(b->flags & RRL_BF_ELIMIT)) { b->flags |= RRL_BF_ELIMIT; rrl_log_state(a, b->flags, b->cls); } /* Decay current bucket. */ if (b->ntok > 0) { --b->ntok; } else if (b->ntok == 0) { ret = KNOT_ELIMIT; } if (lock > -1) rrl_unlock(rrl, lock); return ret; }