linux/net/netfilter/xt_iprange.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *      xt_iprange - Netfilter module to match IP address ranges
   4 *
   5 *      (C) 2003 Jozsef Kadlecsik <kadlec@netfilter.org>
   6 *      (C) CC Computer Consultants GmbH, 2008
   7 */
   8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9#include <linux/module.h>
  10#include <linux/skbuff.h>
  11#include <linux/ip.h>
  12#include <linux/ipv6.h>
  13#include <linux/netfilter/x_tables.h>
  14#include <linux/netfilter/xt_iprange.h>
  15
  16static bool
  17iprange_mt4(const struct sk_buff *skb, struct xt_action_param *par)
  18{
  19        const struct xt_iprange_mtinfo *info = par->matchinfo;
  20        const struct iphdr *iph = ip_hdr(skb);
  21        bool m;
  22
  23        if (info->flags & IPRANGE_SRC) {
  24                m  = ntohl(iph->saddr) < ntohl(info->src_min.ip);
  25                m |= ntohl(iph->saddr) > ntohl(info->src_max.ip);
  26                m ^= !!(info->flags & IPRANGE_SRC_INV);
  27                if (m) {
  28                        pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n",
  29                                 &iph->saddr,
  30                                 (info->flags & IPRANGE_SRC_INV) ? "(INV) " : "",
  31                                 &info->src_min.ip,
  32                                 &info->src_max.ip);
  33                        return false;
  34                }
  35        }
  36        if (info->flags & IPRANGE_DST) {
  37                m  = ntohl(iph->daddr) < ntohl(info->dst_min.ip);
  38                m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip);
  39                m ^= !!(info->flags & IPRANGE_DST_INV);
  40                if (m) {
  41                        pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n",
  42                                 &iph->daddr,
  43                                 (info->flags & IPRANGE_DST_INV) ? "(INV) " : "",
  44                                 &info->dst_min.ip,
  45                                 &info->dst_max.ip);
  46                        return false;
  47                }
  48        }
  49        return true;
  50}
  51
  52static inline int
  53iprange_ipv6_lt(const struct in6_addr *a, const struct in6_addr *b)
  54{
  55        unsigned int i;
  56
  57        for (i = 0; i < 4; ++i) {
  58                if (a->s6_addr32[i] != b->s6_addr32[i])
  59                        return ntohl(a->s6_addr32[i]) < ntohl(b->s6_addr32[i]);
  60        }
  61
  62        return 0;
  63}
  64
  65static bool
  66iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par)
  67{
  68        const struct xt_iprange_mtinfo *info = par->matchinfo;
  69        const struct ipv6hdr *iph = ipv6_hdr(skb);
  70        bool m;
  71
  72        if (info->flags & IPRANGE_SRC) {
  73                m  = iprange_ipv6_lt(&iph->saddr, &info->src_min.in6);
  74                m |= iprange_ipv6_lt(&info->src_max.in6, &iph->saddr);
  75                m ^= !!(info->flags & IPRANGE_SRC_INV);
  76                if (m) {
  77                        pr_debug("src IP %pI6 NOT in range %s%pI6-%pI6\n",
  78                                 &iph->saddr,
  79                                 (info->flags & IPRANGE_SRC_INV) ? "(INV) " : "",
  80                                 &info->src_min.in6,
  81                                 &info->src_max.in6);
  82                        return false;
  83                }
  84        }
  85        if (info->flags & IPRANGE_DST) {
  86                m  = iprange_ipv6_lt(&iph->daddr, &info->dst_min.in6);
  87                m |= iprange_ipv6_lt(&info->dst_max.in6, &iph->daddr);
  88                m ^= !!(info->flags & IPRANGE_DST_INV);
  89                if (m) {
  90                        pr_debug("dst IP %pI6 NOT in range %s%pI6-%pI6\n",
  91                                 &iph->daddr,
  92                                 (info->flags & IPRANGE_DST_INV) ? "(INV) " : "",
  93                                 &info->dst_min.in6,
  94                                 &info->dst_max.in6);
  95                        return false;
  96                }
  97        }
  98        return true;
  99}
 100
 101static struct xt_match iprange_mt_reg[] __read_mostly = {
 102        {
 103                .name      = "iprange",
 104                .revision  = 1,
 105                .family    = NFPROTO_IPV4,
 106                .match     = iprange_mt4,
 107                .matchsize = sizeof(struct xt_iprange_mtinfo),
 108                .me        = THIS_MODULE,
 109        },
 110        {
 111                .name      = "iprange",
 112                .revision  = 1,
 113                .family    = NFPROTO_IPV6,
 114                .match     = iprange_mt6,
 115                .matchsize = sizeof(struct xt_iprange_mtinfo),
 116                .me        = THIS_MODULE,
 117        },
 118};
 119
 120static int __init iprange_mt_init(void)
 121{
 122        return xt_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
 123}
 124
 125static void __exit iprange_mt_exit(void)
 126{
 127        xt_unregister_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
 128}
 129
 130module_init(iprange_mt_init);
 131module_exit(iprange_mt_exit);
 132MODULE_LICENSE("GPL");
 133MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 134MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
 135MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching");
 136MODULE_ALIAS("ipt_iprange");
 137MODULE_ALIAS("ip6t_iprange");
 138