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_max.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_sub(const struct in6_addr *a, const struct in6_addr *b) 57{ 58 unsigned int i; 59 int r; 60 61 for (i = 0; i < 4; ++i) { 62 r = ntohl(a->s6_addr32[i]) - ntohl(b->s6_addr32[i]); 63 if (r != 0) 64 return r; 65 } 66 67 return 0; 68} 69 70static bool 71iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par) 72{ 73 const struct xt_iprange_mtinfo *info = par->matchinfo; 74 const struct ipv6hdr *iph = ipv6_hdr(skb); 75 bool m; 76 77 if (info->flags & IPRANGE_SRC) { 78 m = iprange_ipv6_sub(&iph->saddr, &info->src_min.in6) < 0; 79 m |= iprange_ipv6_sub(&iph->saddr, &info->src_max.in6) > 0; 80 m ^= !!(info->flags & IPRANGE_SRC_INV); 81 if (m) 82 return false; 83 } 84 if (info->flags & IPRANGE_DST) { 85 m = iprange_ipv6_sub(&iph->daddr, &info->dst_min.in6) < 0; 86 m |= iprange_ipv6_sub(&iph->daddr, &info->dst_max.in6) > 0; 87 m ^= !!(info->flags & IPRANGE_DST_INV); 88 if (m) 89 return false; 90 } 91 return true; 92} 93 94static struct xt_match iprange_mt_reg[] __read_mostly = { 95 { 96 .name = "iprange", 97 .revision = 1, 98 .family = NFPROTO_IPV4, 99 .match = iprange_mt4, 100 .matchsize = sizeof(struct xt_iprange_mtinfo), 101 .me = THIS_MODULE, 102 }, 103 { 104 .name = "iprange", 105 .revision = 1, 106 .family = NFPROTO_IPV6, 107 .match = iprange_mt6, 108 .matchsize = sizeof(struct xt_iprange_mtinfo), 109 .me = THIS_MODULE, 110 }, 111}; 112 113static int __init iprange_mt_init(void) 114{ 115 return xt_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 116} 117 118static void __exit iprange_mt_exit(void) 119{ 120 xt_unregister_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 121} 122 123module_init(iprange_mt_init); 124module_exit(iprange_mt_exit); 125MODULE_LICENSE("GPL"); 126MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 127MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 128MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching"); 129MODULE_ALIAS("ipt_iprange"); 130MODULE_ALIAS("ip6t_iprange"); 131