| /* cdu_xt_target.c |
| * |
| * This file defines client data usage xtables target. |
| * |
| * 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/netfilter/xt_usage.h> |
| #include <linux/netfilter/x_tables.h> |
| #include <net/netfilter/nf_conntrack.h> |
| #include <net/netfilter/nf_conntrack_core.h> |
| #include <linux/netfilter/nf_conntrack_common.h> |
| #include <linux/etherdevice.h> |
| |
| |
| #include "cdu_types.h" |
| #include "cdu_xt_target.h" |
| #include "cdu_nf_events.h" |
| #include "cdu_seq_file.h" |
| #include "cdu_db.h" |
| |
| static unsigned int usage_tg(struct sk_buff *skb, const struct xt_action_param *par) |
| { |
| struct nf_conn *ct; |
| enum ip_conntrack_info ctinfo; |
| const struct xt_usage_tginfo *info = par->targinfo; |
| unsigned char direction = (info->src == 1); |
| |
| ct = nf_ct_get(skb, &ctinfo); |
| if (unlikely(!ct)) |
| return XT_CONTINUE; |
| |
| if (likely(ct->orig_direction != CDU_DIR_NOT_SET)) |
| return XT_CONTINUE; |
| |
| if (direction) { |
| |
| if (ctinfo == IP_CT_NEW) |
| ct->orig_direction = CDU_DIR_SRC; |
| else if (ctinfo == IP_CT_IS_REPLY) |
| ct->orig_direction = CDU_DIR_DEST; |
| else |
| return XT_CONTINUE; |
| |
| ether_addr_copy(ct->mac, eth_hdr(skb)->h_source); |
| |
| cdu_db_add_entry_ifmissing(ct); |
| } |
| |
| |
| return XT_CONTINUE; |
| } |
| |
| static int xt_usage_check(const struct xt_tgchk_param *par) |
| { |
| struct xt_usage_tginfo *info = par->targinfo; |
| |
| if (!info->priv) { |
| info->priv = cdu_seq_file_create(info->name, info->readreset); |
| if (!info->priv) |
| return -ENOMEM; |
| cdu_nf_events_register(); |
| } |
| |
| (info->priv->usecount)++; |
| |
| return 0; |
| } |
| |
| static void xt_usage_destroy(const struct xt_tgdtor_param *par) |
| { |
| struct xt_usage_tginfo *info = par->targinfo; |
| |
| if (info->priv) { |
| CDU_DEBUG("usecount=%u\n", info->priv->usecount); |
| (info->priv->usecount)--; |
| if (info->priv->usecount <= 0) { |
| cdu_seq_file_destroy(info->priv); |
| info->priv = NULL; |
| cdu_nf_events_unregister(); |
| } |
| } |
| } |
| |
| static struct xt_target usage_tg_reg __read_mostly = { |
| .name = "USAGE", |
| .revision = 0, |
| .family = NFPROTO_UNSPEC, |
| .target = usage_tg, |
| .checkentry = xt_usage_check, |
| .destroy = xt_usage_destroy, |
| .targetsize = sizeof(struct xt_usage_tginfo), |
| .hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | |
| (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING) | |
| (1 << NF_INET_LOCAL_OUT), |
| .me = THIS_MODULE, |
| }; |
| |
| int cdu_xt_target_register(void) |
| { |
| int result = xt_register_target(&usage_tg_reg); |
| |
| if (result < 0) { |
| CDU_INFO("Failed to register xt target notifier %d\n", result); |
| return result; |
| } |
| CDU_DEBUG("initialized\n"); |
| return 0; |
| } |
| |
| void cdu_xt_target_unregister(void) |
| { |
| xt_unregister_target(&usage_tg_reg); |
| CDU_DEBUG("uninitialized\n"); |
| } |