1 /* 2 * xt_iprange - Netfilter module to match IP address ranges 3 * 4 * (C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 5 * (C) CC Computer Consultants GmbH, 2008 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #include <linux/module.h> 12 #include <linux/skbuff.h> 13 #include <linux/ip.h> 14 #include <linux/ipv6.h> 15 #include <linux/netfilter/x_tables.h> 16 #include <linux/netfilter/xt_iprange.h> 17 #include <linux/netfilter_ipv4/ipt_iprange.h> 18 19 static bool 20 iprange_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) 21 { 22 const struct ipt_iprange_info *info = par->matchinfo; 23 const struct iphdr *iph = ip_hdr(skb); 24 25 if (info->flags & IPRANGE_SRC) { 26 if ((ntohl(iph->saddr) < ntohl(info->src.min_ip) 27 || ntohl(iph->saddr) > ntohl(info->src.max_ip)) 28 ^ !!(info->flags & IPRANGE_SRC_INV)) { 29 pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n", 30 &iph->saddr, 31 info->flags & IPRANGE_SRC_INV ? "(INV) " : "", 32 &info->src.min_ip, 33 &info->src.max_ip); 34 return false; 35 } 36 } 37 if (info->flags & IPRANGE_DST) { 38 if ((ntohl(iph->daddr) < ntohl(info->dst.min_ip) 39 || ntohl(iph->daddr) > ntohl(info->dst.max_ip)) 40 ^ !!(info->flags & IPRANGE_DST_INV)) { 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 bool 53 iprange_mt4(const struct sk_buff *skb, const struct xt_match_param *par) 54 { 55 const struct xt_iprange_mtinfo *info = par->matchinfo; 56 const struct iphdr *iph = ip_hdr(skb); 57 bool m; 58 59 if (info->flags & IPRANGE_SRC) { 60 m = ntohl(iph->saddr) < ntohl(info->src_min.ip); 61 m |= ntohl(iph->saddr) > ntohl(info->src_max.ip); 62 m ^= !!(info->flags & IPRANGE_SRC_INV); 63 if (m) { 64 pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n", 65 &iph->saddr, 66 (info->flags & IPRANGE_SRC_INV) ? "(INV) " : "", 67 &info->src_max.ip, 68 &info->src_max.ip); 69 return false; 70 } 71 } 72 if (info->flags & IPRANGE_DST) { 73 m = ntohl(iph->daddr) < ntohl(info->dst_min.ip); 74 m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip); 75 m ^= !!(info->flags & IPRANGE_DST_INV); 76 if (m) { 77 pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n", 78 &iph->daddr, 79 (info->flags & IPRANGE_DST_INV) ? "(INV) " : "", 80 &info->dst_min.ip, 81 &info->dst_max.ip); 82 return false; 83 } 84 } 85 return true; 86 } 87 88 static inline int 89 iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b) 90 { 91 unsigned int i; 92 int r; 93 94 for (i = 0; i < 4; ++i) { 95 r = ntohl(a->s6_addr32[i]) - ntohl(b->s6_addr32[i]); 96 if (r != 0) 97 return r; 98 } 99 100 return 0; 101 } 102 103 static bool 104 iprange_mt6(const struct sk_buff *skb, const struct xt_match_param *par) 105 { 106 const struct xt_iprange_mtinfo *info = par->matchinfo; 107 const struct ipv6hdr *iph = ipv6_hdr(skb); 108 bool m; 109 110 if (info->flags & IPRANGE_SRC) { 111 m = iprange_ipv6_sub(&iph->saddr, &info->src_min.in6) < 0; 112 m |= iprange_ipv6_sub(&iph->saddr, &info->src_max.in6) > 0; 113 m ^= !!(info->flags & IPRANGE_SRC_INV); 114 if (m) 115 return false; 116 } 117 if (info->flags & IPRANGE_DST) { 118 m = iprange_ipv6_sub(&iph->daddr, &info->dst_min.in6) < 0; 119 m |= iprange_ipv6_sub(&iph->daddr, &info->dst_max.in6) > 0; 120 m ^= !!(info->flags & IPRANGE_DST_INV); 121 if (m) 122 return false; 123 } 124 return true; 125 } 126 127 static struct xt_match iprange_mt_reg[] __read_mostly = { 128 { 129 .name = "iprange", 130 .revision = 0, 131 .family = NFPROTO_IPV4, 132 .match = iprange_mt_v0, 133 .matchsize = sizeof(struct ipt_iprange_info), 134 .me = THIS_MODULE, 135 }, 136 { 137 .name = "iprange", 138 .revision = 1, 139 .family = NFPROTO_IPV4, 140 .match = iprange_mt4, 141 .matchsize = sizeof(struct xt_iprange_mtinfo), 142 .me = THIS_MODULE, 143 }, 144 { 145 .name = "iprange", 146 .revision = 1, 147 .family = NFPROTO_IPV6, 148 .match = iprange_mt6, 149 .matchsize = sizeof(struct xt_iprange_mtinfo), 150 .me = THIS_MODULE, 151 }, 152 }; 153 154 static int __init iprange_mt_init(void) 155 { 156 return xt_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 157 } 158 159 static void __exit iprange_mt_exit(void) 160 { 161 xt_unregister_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 162 } 163 164 module_init(iprange_mt_init); 165 module_exit(iprange_mt_exit); 166 MODULE_LICENSE("GPL"); 167 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>, Jan Engelhardt <jengelh@computergmbh.de>"); 168 MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching"); 169 MODULE_ALIAS("ipt_iprange"); 170 MODULE_ALIAS("ip6t_iprange"); 171