| /* cdu_nf_events.c |
| * |
| * This file handles client data usage netfilter conntrack events. |
| * |
| * Author: Cradlepoint Technology, Inc. <source@cradlepoint.com> |
| * Adrian Sitterle <asitterle@cradlepoint.com> |
| * |
| * Copyright (C) 2019 Cradlepoint Technology, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 |
| * as published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| */ |
| |
| #include <linux/version.h> |
| #include <linux/types.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/netfilter/x_tables.h> |
| #include <net/netfilter/nf_conntrack.h> |
| #include <net/netfilter/nf_conntrack_core.h> |
| |
| #include "cdu_db.h" |
| #include "cdu_nf_events.h" |
| #include "cdu_xt_target.h" |
| #include "cdu_types.h" |
| |
| #ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS |
| #error Can not use this module without conntrack events |
| #endif |
| |
| static u_int8_t nf_registered; |
| |
| static int cdu_nf_event(struct notifier_block *this, unsigned long events, void *ptr) |
| { |
| struct nf_ct_event *item = (struct nf_ct_event *)ptr; |
| struct nf_conn *ct = item->ct; |
| |
| if (!ct) { |
| CDU_DEBUG("No ct available\n"); |
| return -EINVAL; |
| } |
| |
| if (ct->orig_direction == CDU_DIR_NOT_SET) { |
| /* This ct does not have a direction information because it didn't |
| * travel through the xt hook, which means that we don't care |
| * about this traffic |
| */ |
| return NOTIFY_DONE; |
| } |
| |
| /* Update data usage htable entry on end of flow trigger */ |
| if (events & (1 << IPCT_DESTROY)) { |
| CDU_DEBUG("Caught %s NF event. mac=%pM, dir %s, ct %p\n", |
| events & (1 << IPCT_NEW)?"NEW":"DESTROY", ct->mac, |
| (ct->orig_direction == CDU_DIR_SRC)?"DIR_SRC":"DIR_DEST", ct); |
| |
| cdu_db_update_entry(ct, CDU_DB_UPDATE_PERMA_SET, CDU_DB_CONNTR_NOCLEAR); |
| } |
| |
| return NOTIFY_DONE; |
| } |
| |
| static struct notifier_block cdu_nf_notifier = { |
| .notifier_call = cdu_nf_event, |
| }; |
| |
| int cdu_nf_events_register(void) |
| { |
| int result; |
| |
| if (!nf_registered) { |
| result = nf_conntrack_register_notifier(&init_net, &cdu_nf_notifier); |
| if (result < 0) { |
| CDU_INFO("Failed to register conntrack notifier %d\n", result); |
| return result; |
| } |
| nf_registered = 1; |
| } |
| |
| CDU_DEBUG("initialized\n"); |
| return 0; |
| } |
| |
| void cdu_nf_events_unregister(void) |
| { |
| if (nf_registered) { |
| nf_conntrack_unregister_notifier(&init_net, &cdu_nf_notifier); |
| CDU_DEBUG("uninitialized\n"); |
| } |
| } |
| |