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