diff options
author | Yunchih Chen <yunchih.cat@gmail.com> | 2018-03-20 15:56:32 +0800 |
---|---|---|
committer | Yunchih Chen <yunchih.cat@gmail.com> | 2018-03-20 15:56:32 +0800 |
commit | 9055aef7f6fea73dc74981b262151823b142f0d6 (patch) | |
tree | b831d98af3db90f50a3b4cb6c6f7fe9bf89b507c | |
parent | fc5d23e8062c4a16b4dbacefb7c501886781453c (diff) | |
download | nfcollect-9055aef7f6fea73dc74981b262151823b142f0d6.tar nfcollect-9055aef7f6fea73dc74981b262151823b142f0d6.tar.gz nfcollect-9055aef7f6fea73dc74981b262151823b142f0d6.tar.bz2 nfcollect-9055aef7f6fea73dc74981b262151823b142f0d6.tar.lz nfcollect-9055aef7f6fea73dc74981b262151823b142f0d6.tar.xz nfcollect-9055aef7f6fea73dc74981b262151823b142f0d6.tar.zst nfcollect-9055aef7f6fea73dc74981b262151823b142f0d6.zip |
Add simple rate-limiting
-rw-r--r-- | lib/collect.c | 36 |
1 files changed, 32 insertions, 4 deletions
diff --git a/lib/collect.c b/lib/collect.c index 3e3f7a3..fe8d5c1 100644 --- a/lib/collect.c +++ b/lib/collect.c @@ -31,6 +31,11 @@ #include <sys/types.h> // u_int32_t for libnetfilter_log #include <time.h> +// Number of packet to queue inside kernel before sending to userspsace. +// Setting this value to, e.g. 64 accumulates ten packets inside the +// kernel and transmits them as one netlink multipart message to userspace. +#define NF_NFLOG_QTHRESH 64 + nfl_global_t g; static void nfl_init(nfl_state_t *nf); @@ -40,6 +45,7 @@ static void nfl_state_free(nfl_state_t *nf); static int handle_packet(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, struct nflog_data *nfa, void *_nf) { +#define HASH_ENTRY(e) (e->sport ^ e->timestamp) register const struct iphdr *iph; register nfl_entry_t *entry; const struct tcphdr *tcph; @@ -48,12 +54,18 @@ static int handle_packet(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, void *inner_hdr; uint32_t uid; + // Store previous data hash (see HASH_ENTRY above) for rate-limiting purpose + static uint64_t prev_entry_hash; + int payload_len = nflog_get_payload(nfa, &payload); nfl_state_t *nf = (nfl_state_t *)_nf; // only process ipv4 packet - if (unlikely(payload_len < 0) || ((payload[0] & 0xf0) != 0x40)) + if (unlikely(payload_len < 0) || ((payload[0] & 0xf0) != 0x40)) { + debug("Ignore non-IPv4 packet"); return 1; + } + if (unlikely(nf->header->n_entries >= nf->header->max_n_entries)) return 1; @@ -74,8 +86,25 @@ static int handle_packet(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, udph = (struct udphdr *)inner_hdr; entry->sport = ntohs(udph->source); entry->dport = ntohs(udph->dest); - } else + } else { + debug("Ignore non-TCP/UDP packet"); return 1; // Ignore other types of packet + } + + // get current timestamp + time(&entry->timestamp); + + // Rate-limit incoming packets: + // Ignore those with identical hash to prevent + // packet flooding. This simple trick is based + // on the observation that packet surge usually + // originates from one process. Even if different + // processes send simultaneously, the kernel deliver + // packets in batch instead in interleaving manner. + uint64_t entry_hash = HASH_ENTRY(entry); + if (entry_hash == prev_entry_hash) + return 1; + prev_entry_hash = entry_hash; entry->daddr.s_addr = iph->daddr; entry->protocol = iph->protocol; @@ -85,8 +114,7 @@ static int handle_packet(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg, return 1; entry->uid = uid; - // get current timestamp - time(&entry->timestamp); + // Advance to next entry nf->header->n_entries++; debug("Recv packet info entry #%d: " |