xt_iprange.c (3712B)
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");