^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * net/sched/em_ipset.c ipset ematch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2012 Florian Westphal <fw@strlen.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/netfilter/xt_set.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/ipv6.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <net/ip.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <net/pkt_cls.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static int em_ipset_change(struct net *net, void *data, int data_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct tcf_ematch *em)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct xt_set_info *set = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) ip_set_id_t index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) if (data_len != sizeof(*set))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) index = ip_set_nfnl_get_byindex(net, set->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (index == IPSET_INVALID_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) em->datalen = sizeof(*set);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) em->data = (unsigned long)kmemdup(data, em->datalen, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (em->data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) ip_set_nfnl_put(net, index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static void em_ipset_destroy(struct tcf_ematch *em)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) const struct xt_set_info *set = (const void *) em->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (set) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) ip_set_nfnl_put(em->net, set->index);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) kfree((void *) em->data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct tcf_pkt_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct ip_set_adt_opt opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct xt_action_param acpar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) const struct xt_set_info *set = (const void *) em->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct net_device *dev, *indev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) struct nf_hook_state state = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) .net = em->net,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) int ret, network_offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) switch (skb_protocol(skb, true)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) case htons(ETH_P_IP):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) state.pf = NFPROTO_IPV4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) acpar.thoff = ip_hdrlen(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) case htons(ETH_P_IPV6):
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) state.pf = NFPROTO_IPV6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /* doesn't call ipv6_find_hdr() because ipset doesn't use thoff, yet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) acpar.thoff = sizeof(struct ipv6hdr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) opt.family = state.pf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) opt.dim = set->dim;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) opt.flags = set->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) opt.cmdflags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) opt.ext.timeout = ~0u;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) network_offset = skb_network_offset(skb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) skb_pull(skb, network_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) dev = skb->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) if (skb->skb_iif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) indev = dev_get_by_index_rcu(em->net, skb->skb_iif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) state.in = indev ? indev : dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) state.out = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) acpar.state = &state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ret = ip_set_test(set->index, skb, &acpar, &opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) skb_push(skb, network_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static struct tcf_ematch_ops em_ipset_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .kind = TCF_EM_IPSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .change = em_ipset_change,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .destroy = em_ipset_destroy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) .match = em_ipset_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) .link = LIST_HEAD_INIT(em_ipset_ops.link)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int __init init_em_ipset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return tcf_em_register(&em_ipset_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static void __exit exit_em_ipset(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) tcf_em_unregister(&em_ipset_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) MODULE_DESCRIPTION("TC extended match for IP sets");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) module_init(init_em_ipset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) module_exit(exit_em_ipset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) MODULE_ALIAS_TCF_EMATCH(TCF_EM_IPSET);