aboutsummaryrefslogtreecommitdiffstats
path: root/nflog.c
diff options
context:
space:
mode:
authorYunchih Chen <yunchih.cat@gmail.com>2017-12-01 10:12:45 +0800
committerYunchih Chen <yunchih.cat@gmail.com>2017-12-01 10:12:45 +0800
commitec0e71f4c1eefce0ae650c9340522c377a6abff3 (patch)
treefda235af8b7fada9456b8dec29f006fc570c4400 /nflog.c
downloadnfcollect-ec0e71f4c1eefce0ae650c9340522c377a6abff3.tar
nfcollect-ec0e71f4c1eefce0ae650c9340522c377a6abff3.tar.gz
nfcollect-ec0e71f4c1eefce0ae650c9340522c377a6abff3.tar.bz2
nfcollect-ec0e71f4c1eefce0ae650c9340522c377a6abff3.tar.lz
nfcollect-ec0e71f4c1eefce0ae650c9340522c377a6abff3.tar.xz
nfcollect-ec0e71f4c1eefce0ae650c9340522c377a6abff3.tar.zst
nfcollect-ec0e71f4c1eefce0ae650c9340522c377a6abff3.zip
First commit
Diffstat (limited to 'nflog.c')
-rw-r--r--nflog.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/nflog.c b/nflog.c
new file mode 100644
index 0000000..bd32b83
--- /dev/null
+++ b/nflog.c
@@ -0,0 +1,151 @@
+
+// The MIT License (MIT)
+
+// Copyright (c) 2017 Yun-Chih Chen
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in
+// all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#include "commit.h"
+#include "nflog.h"
+#include "main.h"
+#include <stddef.h> // size_t for libnetfilter_log
+#include <sys/types.h> // u_int32_t for libnetfilter_log
+#include <libnetfilter_log/libnetfilter_log.h>
+#include <pthread.h>
+#include <time.h>
+
+extern sem_t nfl_commit_queue;
+extern uint16_t nfl_group_id;
+
+static void nfl_cleanup(nflog_state_t *nf);
+static void nfl_init(nflog_state_t *nf);
+static void *_nfl_commit_worker(void *targs);
+static void nfl_commit(nflog_state_t *nf);
+
+static int handle_packet(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg,
+ struct nflog_data *nfa, void *_nf) {
+ char *payload;
+ int payload_len = nflog_get_payload(nfa, &payload);
+ nflog_state_t *nf = (nflog_state_t *)_nf;
+
+ // only process ipv4 packet
+ if (payload_len >= 0 && ((payload[0] & 0xf0) == 0x40)) {
+ struct iphdr *iph = (struct iphdr *)payload;
+ nflog_entry_t *entry = &(nf->store[nf->header.n_entries]);
+
+ void *inner_hdr = iph + iph->ihl;
+ // Only accept TCP / UDP packets
+ if (iph->protocol == IPPROTO_TCP) {
+ struct tcphdr *tcph = (struct tcphdr *)inner_hdr;
+ entry->sport = ntohs(tcph->source);
+ entry->dport = ntohs(tcph->dest);
+ } else if (iph->protocol == IPPROTO_UDP) {
+ struct udphdr *tcph = (struct udphdr *)inner_hdr;
+ entry->sport = ntohs(tcph->source);
+ entry->dport = ntohs(tcph->dest);
+ } else
+ return 1; // Ignore other types of packet
+
+ entry->daddr.s_addr = iph->daddr;
+ entry->protocol = iph->protocol;
+
+ // get sender uid
+ uint32_t uid;
+ if (nflog_get_uid(nfa, &uid) == 0)
+ entry->uid = uid;
+ else
+ entry->uid = (uint32_t)~0;
+
+ // get current timestamp
+ time(&entry->timestamp);
+ nf->header.n_entries++;
+ }
+
+ // Ignore IPv6 packet for now Q_Q
+ return 0;
+}
+
+static void nfl_init(nflog_state_t *nf) {
+ // open nflog
+ ERR((nf->nfl_fd = nflog_open()) == NULL, "error during nflog_open()")
+
+ // monitor IPv4 packets only
+ ERR(nflog_bind_pf(nf->nfl_fd, AF_INET) < 0, "error during nflog_bind_pf()");
+
+ // bind to group
+ nf->nfl_group_fd = nflog_bind_group(nf->nfl_fd, nfl_group_id);
+
+ // only copy size of ipv4 header + tcp/udp src/dest port (first 4 bytes of their headers
+ ERR(nflog_set_mode(nf->nfl_group_fd, NFULNL_COPY_PACKET, sizeof(struct iphdr) + 4) < 0,
+ "Could not set copy mode");
+
+ nflog_callback_register(nf->nfl_group_fd, &handle_packet, NULL);
+}
+
+static void nfl_cleanup(nflog_state_t *nf) {
+ nflog_unbind_group(nf->nfl_group_fd);
+ nflog_close(nf->nfl_fd);
+}
+
+void *nflog_worker(void *targs) {
+ nflog_state_t *nf = (nflog_state_t *)targs;
+ nfl_init(nf);
+
+ int fd = nflog_fd(nf->nfl_fd);
+ uint32_t *p_cnt_now = &(nf->header.n_entries);
+ uint32_t cnt_max = nf->header.max_n_entries;
+
+ debug("Recv worker #%u: main loop starts\n", nf->header.id);
+ nf->header.start_time = time(NULL);
+ while (*p_cnt_now < cnt_max) {
+ int rv; char buf[4096];
+ if ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
+ debug("Recv worker #%u: nflog packet received (len=%u)\n", nf->header.id,
+ rv);
+ nflog_handle_packet(nf->nfl_fd, buf, rv);
+ }
+ }
+
+ nf->header.end_time = time(NULL);
+ nfl_cleanup(nf);
+ nfl_commit(nf);
+
+ /* TODO: can return exit status */
+ pthread_exit(NULL);
+}
+
+void nfl_commit(nflog_state_t *nf) {
+ pthread_t tid;
+ pthread_create(&tid, NULL, _nfl_commit_worker, (void *)nf);
+ pthread_detach(tid);
+}
+
+void *_nfl_commit_worker(void *targs) {
+ nflog_state_t* nf = (nflog_state_t*) targs;
+ debug("Comm worker #%u: thread started\n", nf->header.id);
+
+ sem_wait(&nfl_commit_queue);
+ debug("Comm worker #%u: commit started\n", nf->header.id);
+ nfl_commit_worker(&(nf->header), nf->store);
+ debug("Comm worker #%u: commit done\n", nf->header.id);
+ sem_post(&nfl_commit_queue);
+
+ pthread_mutex_unlock(&(nf->lock));
+}