From e2959c046013a2d668a6adb26d4e938c37444af7 Mon Sep 17 00:00:00 2001 From: handf0830 Date: Thu, 19 Jan 2023 14:33:20 +0800 Subject: [PATCH] modify quota2 report function Signed-off-by: handf0830 --- net/netfilter/Kconfig | 11 ++++++ net/netfilter/xt_quota2.c | 74 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 212568882ce3..50951ea82675 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -1488,6 +1488,17 @@ config NETFILTER_XT_MATCH_QUOTA2 If you want to compile it as a module, say M here and read . If unsure, say `N'. +config NETFILTER_XT_MATCH_QUOTA2_REPORT + bool '"quota2" Netfilter REPORT support' + depends on NETFILTER_XT_MATCH_QUOTA2 + default n + help + This option allows `quota2' to report ONCE when a quota limit + is passed. It report via NETLINK using the NETLINK_NFLOG family. + It report similarly to how ipt_ULOG would without data. + + If unsure, say `N'. + config NETFILTER_XT_MATCH_RATEEST tristate '"rateest" match support' depends on NETFILTER_ADVANCED diff --git a/net/netfilter/xt_quota2.c b/net/netfilter/xt_quota2.c index 6a641005adc7..cabd7d0a8e2d 100644 --- a/net/netfilter/xt_quota2.c +++ b/net/netfilter/xt_quota2.c @@ -29,6 +29,23 @@ #include #include +#ifdef NETFILTER_XT_MATCH_QUOTA2_REPORT +#define PREFIX_LEN 32 + +typedef struct report_packet { + unsigned int hook; + char in_dev_name[IFNAMSIZ]; + char out_dev_name[IFNAMSIZ]; + size_t data_len; + char prefix[PREFIX_LEN]; +} report_packet_t; + +static int report_netlink_event = 122; +module_param_named(event_num, report_netlink_event, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(event_num, "Event number for NETLINK_NFLOG message."); +static struct sock *quota2_report_sock; +#endif + /** * @lock: lock to protect quota writers from each other */ @@ -61,6 +78,50 @@ module_param_named(perms, quota_list_perms, uint, S_IRUGO | S_IWUSR); module_param_named(uid, quota_list_uid, uint, S_IRUGO | S_IWUSR); module_param_named(gid, quota_list_gid, uint, S_IRUGO | S_IWUSR); +#ifdef NETFILTER_XT_MATCH_QUOTA2_REPORT +static void quota2_report(unsigned int hookindex, const char *prefix, + const struct net_device *in, const struct net_device *out) +{ + if (!report_netlink_event) + return; + + report_packet_t *report_packet; + struct sk_buff *skb; + size_t size; + struct nlmsghdr *msg_header; + + size = NLMSG_SPACE(sizeof(*report_packet)); + size = max(size, (size_t)NLMSG_GOODSIZE); + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + pr_err("xt quota2 report: alloc skb failed\n"); + return; + } + msg_header = nlmsg_put(skb, 0, 0, report_netlink_event, sizeof(*report_packet), 0); + if (!msg_header) { + pr_err("xt_quota2 report: nlmsg_put failed\n"); + kfree_skb(skb); + return; + } + + report_packet = nlmsg_data(msg_header); + report_packet->data_len = 0; + report_packet->hook = hookindex; + report_packet->prefix[0] = '\0'; + report_packet->in_dev_name[0] = '\0'; + report_packet->out_dev_name[0] = '\0'; + + if (prefix != NULL) + strlcpy(report_packet->prefix, prefix, sizeof(report_packet->prefix)); + if (in) + strlcpy(report_packet->in_dev_name, in->name, sizeof(report_packet->in_dev_name)); + if (out) + strlcpy(report_packet->out_dev_name, out->name, sizeof(report_packet->out_dev_name)); + + NETLINK_CB(skb).dst_group = 1; + netlink_broadcast_filtered(quota2_report_sock, skb, 0, 1, GFP_ATOMIC, NULL, NULL); +} +#endif static int quota_proc_show(struct seq_file *m, void *data) { @@ -262,6 +323,13 @@ quota_mt2(const struct sk_buff *skb, struct xt_action_param *par) e->quota -= (q->flags & XT_QUOTA_PACKET) ? 1 : skb->len; ret = !ret; } else { +#ifdef NETFILTER_XT_MATCH_QUOTA2_REPORT + if (e->quota) { + if (skb->tstamp == 0) + __net_timestamp(skb); + quota2_report(xt_hooknum(par), q->name, xt_in(par), xt_out(par)); + } +#endif /* we do not allow even small packets from now on */ if (!(q->flags & XT_QUOTA_NO_CHANGE)) e->quota = 0; @@ -300,6 +368,12 @@ static int __net_init quota2_net_init(struct net *net) struct quota2_net *quota2_net = quota2_pernet(net); INIT_LIST_HEAD("a2_net->counter_list); +#ifdef NETFILTER_XT_MATCH_QUOTA2_REPORT + quota2_report_sock = netlink_kernel_create(&init_net, NETLINK_NFLOG, NULL); + if (!quota2_report_sock) + return -ENOMEM; +#endif + quota2_net->proc_xt_quota = proc_mkdir("xt_quota", net->proc_net); if (quota2_net->proc_xt_quota == NULL) return -EACCES; -- Gitee