Esempio n. 1
0
/** Examine the query and return hash and source of netblock. */
static void examine_query(query_type* query, uint32_t* hash, uint64_t* source,
	uint16_t* flags, uint32_t* lm)
{
	/* compile a binary string representing the query */
	uint16_t c, c2;
	/* size with 16 bytes to spare */
	uint8_t buf[MAXDOMAINLEN + sizeof(*source) + sizeof(c) + 16];
	const uint8_t* dname = NULL; size_t dname_len;
	uint32_t r = 0x267fcd16;

	*source = rrl_get_source(query, &c2);
	c = rrl_classify(query, &dname, &dname_len);
	if(query->zone && query->zone->opts && 
		(query->zone->opts->rrl_whitelist & c))
		*lm = rrl_whitelist_ratelimit;
	if(*lm == 0) return;
	c |= c2;
	*flags = c;
	memmove(buf, source, sizeof(*source));
	memmove(buf+sizeof(*source), &c, sizeof(c));

	DEBUG(DEBUG_QUERY, 1, (LOG_INFO, "rrl_examine type %s name %s", rrltype2str(c), dname?wiredname2str(dname):"NULL"));

	/* and hash it */
	if(dname && dname_len <= MAXDOMAINLEN) {
		memmove(buf+sizeof(*source)+sizeof(c), dname, dname_len);
		*hash = hashlittle(buf, sizeof(*source)+sizeof(c)+dname_len, r);
	} else
		*hash = hashlittle(buf, sizeof(*source)+sizeof(c), r);
}
Esempio n. 2
0
/** log a message about ratelimits */
static void
rrl_msg(query_type* query, const char* str)
{
	uint16_t c, c2, wl = 0;
	const uint8_t* d = NULL;
	size_t d_len;
	uint64_t s;
	if(verbosity < 2) return;
	s = rrl_get_source(query, &c2);
	c = rrl_classify(query, &d, &d_len) | c2;
	if(query->zone && query->zone->opts && 
		(query->zone->opts->rrl_whitelist & c))
		wl = 1;
	log_msg(LOG_INFO, "ratelimit %s %s type %s%s target %s",
		str, d?wiredname2str(d):"", rrltype2str(c),
		wl?"(whitelisted)":"", rrlsource2str(s, c2));
}
Esempio n. 3
0
rrl_item_t* rrl_hash(rrl_table_t *t, const struct sockaddr_storage *a, rrl_req_t *p,
                     const zone_t *zone, uint32_t stamp, int *lock)
{
    char buf[RRL_CLSBLK_MAXLEN];
    int len = rrl_classify(buf, sizeof(buf), a, p, zone, t->seed);
    if (len < 0) {
        return NULL;
    }

    uint32_t id = hash(buf, len) % t->size;

    /* Lock for lookup. */
    pthread_mutex_lock(&t->ll);

    /* Find an exact match in <id, id + HOP_LEN). */
    uint16_t *qname = (uint16_t*)(buf + sizeof(uint8_t) + sizeof(uint64_t));
    rrl_item_t match = {
        0, *((uint64_t*)(buf + 1)), t->rate,    /* hop, netblk, ntok */
        buf[0], RRL_BF_NULL,                    /* cls, flags */
        hash((char*)(qname + 1), *qname), stamp /* qname, time*/
    };

    unsigned d = find_match(t, id, &match);
    if (d > HOP_LEN) { /* not an exact match, find free element [f] */
        d = find_free(t, id, stamp);
    }

    /* Reduce distance to fit <id, id + HOP_LEN) */
    unsigned f = (id + d) % t->size;
    while (d >= HOP_LEN) {
        d = reduce_dist(t, id, d, &f);
    }

    /* Assign granular lock and unlock lookup. */
    *lock = f % t->lk_count;
    rrl_lock(t, *lock);
    pthread_mutex_unlock(&t->ll);

    /* found free elm 'k' which is in <id, id + HOP_LEN) */
    t->arr[id].hop |= (1 << d);
    rrl_item_t* b = t->arr + f;
    assert(f == (id+d) % t->size);
    dbg_rrl("%s: classified pkt as %4x '%u+%u' bucket=%p \n", __func__, f, id, d, b);

    /* Inspect bucket state. */
    unsigned hop = b->hop;
    if (b->cls == CLS_NULL) {
        memcpy(b, &match, sizeof(rrl_item_t));
        b->hop = hop;
    }
    /* Check for collisions. */
    if (!bucket_match(b, &match)) {
        dbg_rrl("%s: collision in bucket '%4x'\n", __func__, id);
        if (!(b->flags & RRL_BF_SSTART)) {
            memcpy(b, &match, sizeof(rrl_item_t));
            b->hop = hop;
            b->ntok = t->rate + t->rate / RRL_SSTART;
            b->flags |= RRL_BF_SSTART;
            dbg_rrl("%s: bucket '%4x' slow-start\n", __func__, id);
        }
    }

    return b;
}