Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v2.6.25-rc4 181 lines 5.3 kB view raw
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 19static bool 20iprange_mt_v0(const struct sk_buff *skb, const struct net_device *in, 21 const struct net_device *out, const struct xt_match *match, 22 const void *matchinfo, int offset, unsigned int protoff, 23 bool *hotdrop) 24{ 25 const struct ipt_iprange_info *info = matchinfo; 26 const struct iphdr *iph = ip_hdr(skb); 27 28 if (info->flags & IPRANGE_SRC) { 29 if ((ntohl(iph->saddr) < ntohl(info->src.min_ip) 30 || ntohl(iph->saddr) > ntohl(info->src.max_ip)) 31 ^ !!(info->flags & IPRANGE_SRC_INV)) { 32 pr_debug("src IP %u.%u.%u.%u NOT in range %s" 33 "%u.%u.%u.%u-%u.%u.%u.%u\n", 34 NIPQUAD(iph->saddr), 35 info->flags & IPRANGE_SRC_INV ? "(INV) " : "", 36 NIPQUAD(info->src.min_ip), 37 NIPQUAD(info->src.max_ip)); 38 return false; 39 } 40 } 41 if (info->flags & IPRANGE_DST) { 42 if ((ntohl(iph->daddr) < ntohl(info->dst.min_ip) 43 || ntohl(iph->daddr) > ntohl(info->dst.max_ip)) 44 ^ !!(info->flags & IPRANGE_DST_INV)) { 45 pr_debug("dst IP %u.%u.%u.%u NOT in range %s" 46 "%u.%u.%u.%u-%u.%u.%u.%u\n", 47 NIPQUAD(iph->daddr), 48 info->flags & IPRANGE_DST_INV ? "(INV) " : "", 49 NIPQUAD(info->dst.min_ip), 50 NIPQUAD(info->dst.max_ip)); 51 return false; 52 } 53 } 54 return true; 55} 56 57static bool 58iprange_mt4(const struct sk_buff *skb, const struct net_device *in, 59 const struct net_device *out, const struct xt_match *match, 60 const void *matchinfo, int offset, unsigned int protoff, 61 bool *hotdrop) 62{ 63 const struct xt_iprange_mtinfo *info = matchinfo; 64 const struct iphdr *iph = ip_hdr(skb); 65 bool m; 66 67 if (info->flags & IPRANGE_SRC) { 68 m = ntohl(iph->saddr) < ntohl(info->src_min.ip); 69 m |= ntohl(iph->saddr) > ntohl(info->src_max.ip); 70 m ^= info->flags & IPRANGE_SRC_INV; 71 if (m) { 72 pr_debug("src IP " NIPQUAD_FMT " NOT in range %s" 73 NIPQUAD_FMT "-" NIPQUAD_FMT "\n", 74 NIPQUAD(iph->saddr), 75 (info->flags & IPRANGE_SRC_INV) ? "(INV) " : "", 76 NIPQUAD(info->src_max.ip), 77 NIPQUAD(info->src_max.ip)); 78 return false; 79 } 80 } 81 if (info->flags & IPRANGE_DST) { 82 m = ntohl(iph->daddr) < ntohl(info->dst_min.ip); 83 m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip); 84 m ^= info->flags & IPRANGE_DST_INV; 85 if (m) { 86 pr_debug("dst IP " NIPQUAD_FMT " NOT in range %s" 87 NIPQUAD_FMT "-" NIPQUAD_FMT "\n", 88 NIPQUAD(iph->daddr), 89 (info->flags & IPRANGE_DST_INV) ? "(INV) " : "", 90 NIPQUAD(info->dst_min.ip), 91 NIPQUAD(info->dst_max.ip)); 92 return false; 93 } 94 } 95 return true; 96} 97 98static inline int 99iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b) 100{ 101 unsigned int i; 102 int r; 103 104 for (i = 0; i < 4; ++i) { 105 r = ntohl(a->s6_addr32[i]) - ntohl(b->s6_addr32[i]); 106 if (r != 0) 107 return r; 108 } 109 110 return 0; 111} 112 113static bool 114iprange_mt6(const struct sk_buff *skb, const struct net_device *in, 115 const struct net_device *out, const struct xt_match *match, 116 const void *matchinfo, int offset, unsigned int protoff, 117 bool *hotdrop) 118{ 119 const struct xt_iprange_mtinfo *info = matchinfo; 120 const struct ipv6hdr *iph = ipv6_hdr(skb); 121 bool m; 122 123 if (info->flags & IPRANGE_SRC) { 124 m = iprange_ipv6_sub(&iph->saddr, &info->src_min.in6) < 0; 125 m |= iprange_ipv6_sub(&iph->saddr, &info->src_max.in6) > 0; 126 m ^= info->flags & IPRANGE_SRC_INV; 127 if (m) 128 return false; 129 } 130 if (info->flags & IPRANGE_DST) { 131 m = iprange_ipv6_sub(&iph->daddr, &info->dst_min.in6) < 0; 132 m |= iprange_ipv6_sub(&iph->daddr, &info->dst_max.in6) > 0; 133 m ^= info->flags & IPRANGE_DST_INV; 134 if (m) 135 return false; 136 } 137 return true; 138} 139 140static struct xt_match iprange_mt_reg[] __read_mostly = { 141 { 142 .name = "iprange", 143 .revision = 0, 144 .family = AF_INET, 145 .match = iprange_mt_v0, 146 .matchsize = sizeof(struct ipt_iprange_info), 147 .me = THIS_MODULE, 148 }, 149 { 150 .name = "iprange", 151 .revision = 1, 152 .family = AF_INET, 153 .match = iprange_mt4, 154 .matchsize = sizeof(struct xt_iprange_mtinfo), 155 .me = THIS_MODULE, 156 }, 157 { 158 .name = "iprange", 159 .revision = 1, 160 .family = AF_INET6, 161 .match = iprange_mt6, 162 .matchsize = sizeof(struct xt_iprange_mtinfo), 163 .me = THIS_MODULE, 164 }, 165}; 166 167static int __init iprange_mt_init(void) 168{ 169 return xt_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 170} 171 172static void __exit iprange_mt_exit(void) 173{ 174 xt_unregister_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg)); 175} 176 177module_init(iprange_mt_init); 178module_exit(iprange_mt_exit); 179MODULE_LICENSE("GPL"); 180MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>, Jan Engelhardt <jengelh@computergmbh.de>"); 181MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching");