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