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 16 static bool 17 iprange_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 52 static inline int 53 iprange_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 65 static bool 66 iprange_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 101 static 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 120 static int __init iprange_mt_init(void) 121 { 122 return xt_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 123 } 124 125 static void __exit iprange_mt_exit(void) 126 { 127 xt_unregister_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 128 } 129 130 module_init(iprange_mt_init); 131 module_exit(iprange_mt_exit); 132 MODULE_LICENSE("GPL"); 133 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>"); 134 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 135 MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching"); 136 MODULE_ALIAS("ipt_iprange"); 137 MODULE_ALIAS("ip6t_iprange"); 138