xref: /openbmc/linux/net/netfilter/xt_iprange.c (revision 08b5194b)
1f72e25a8SJan Engelhardt /*
2f72e25a8SJan Engelhardt  *	xt_iprange - Netfilter module to match IP address ranges
3f72e25a8SJan Engelhardt  *
4f72e25a8SJan Engelhardt  *	(C) 2003 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
51a50c5a1SJan Engelhardt  *	(C) CC Computer Consultants GmbH, 2008
6f72e25a8SJan Engelhardt  *
7f72e25a8SJan Engelhardt  *	This program is free software; you can redistribute it and/or modify
8f72e25a8SJan Engelhardt  *	it under the terms of the GNU General Public License version 2 as
9f72e25a8SJan Engelhardt  *	published by the Free Software Foundation.
10f72e25a8SJan Engelhardt  */
11ff67e4e4SJan Engelhardt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12f72e25a8SJan Engelhardt #include <linux/module.h>
13f72e25a8SJan Engelhardt #include <linux/skbuff.h>
14f72e25a8SJan Engelhardt #include <linux/ip.h>
151a50c5a1SJan Engelhardt #include <linux/ipv6.h>
16f72e25a8SJan Engelhardt #include <linux/netfilter/x_tables.h>
175da621f1SJan Engelhardt #include <linux/netfilter/xt_iprange.h>
18f72e25a8SJan Engelhardt 
191a50c5a1SJan Engelhardt static bool
2062fc8051SJan Engelhardt iprange_mt4(const struct sk_buff *skb, struct xt_action_param *par)
211a50c5a1SJan Engelhardt {
22f7108a20SJan Engelhardt 	const struct xt_iprange_mtinfo *info = par->matchinfo;
231a50c5a1SJan Engelhardt 	const struct iphdr *iph = ip_hdr(skb);
241a50c5a1SJan Engelhardt 	bool m;
251a50c5a1SJan Engelhardt 
261a50c5a1SJan Engelhardt 	if (info->flags & IPRANGE_SRC) {
271a50c5a1SJan Engelhardt 		m  = ntohl(iph->saddr) < ntohl(info->src_min.ip);
281a50c5a1SJan Engelhardt 		m |= ntohl(iph->saddr) > ntohl(info->src_max.ip);
296def1eb4SAlexey Dobriyan 		m ^= !!(info->flags & IPRANGE_SRC_INV);
301a50c5a1SJan Engelhardt 		if (m) {
3114d5e834SHarvey Harrison 			pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n",
3214d5e834SHarvey Harrison 			         &iph->saddr,
331a50c5a1SJan Engelhardt 			         (info->flags & IPRANGE_SRC_INV) ? "(INV) " : "",
3414d5e834SHarvey Harrison 			         &info->src_max.ip,
3514d5e834SHarvey Harrison 			         &info->src_max.ip);
361a50c5a1SJan Engelhardt 			return false;
371a50c5a1SJan Engelhardt 		}
381a50c5a1SJan Engelhardt 	}
391a50c5a1SJan Engelhardt 	if (info->flags & IPRANGE_DST) {
401a50c5a1SJan Engelhardt 		m  = ntohl(iph->daddr) < ntohl(info->dst_min.ip);
411a50c5a1SJan Engelhardt 		m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip);
426def1eb4SAlexey Dobriyan 		m ^= !!(info->flags & IPRANGE_DST_INV);
431a50c5a1SJan Engelhardt 		if (m) {
4414d5e834SHarvey Harrison 			pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n",
4514d5e834SHarvey Harrison 			         &iph->daddr,
461a50c5a1SJan Engelhardt 			         (info->flags & IPRANGE_DST_INV) ? "(INV) " : "",
4714d5e834SHarvey Harrison 			         &info->dst_min.ip,
4814d5e834SHarvey Harrison 			         &info->dst_max.ip);
491a50c5a1SJan Engelhardt 			return false;
501a50c5a1SJan Engelhardt 		}
511a50c5a1SJan Engelhardt 	}
521a50c5a1SJan Engelhardt 	return true;
531a50c5a1SJan Engelhardt }
541a50c5a1SJan Engelhardt 
551a50c5a1SJan Engelhardt static inline int
5608b5194bSThomas Jacob iprange_ipv6_lt(const struct in6_addr *a, const struct in6_addr *b)
571a50c5a1SJan Engelhardt {
581a50c5a1SJan Engelhardt 	unsigned int i;
591a50c5a1SJan Engelhardt 
601a50c5a1SJan Engelhardt 	for (i = 0; i < 4; ++i) {
6108b5194bSThomas Jacob 		if (a->s6_addr32[i] != b->s6_addr32[i])
6208b5194bSThomas Jacob 			return ntohl(a->s6_addr32[i]) < ntohl(b->s6_addr32[i]);
631a50c5a1SJan Engelhardt 	}
641a50c5a1SJan Engelhardt 
651a50c5a1SJan Engelhardt 	return 0;
661a50c5a1SJan Engelhardt }
671a50c5a1SJan Engelhardt 
681a50c5a1SJan Engelhardt static bool
6962fc8051SJan Engelhardt iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par)
701a50c5a1SJan Engelhardt {
71f7108a20SJan Engelhardt 	const struct xt_iprange_mtinfo *info = par->matchinfo;
721a50c5a1SJan Engelhardt 	const struct ipv6hdr *iph = ipv6_hdr(skb);
731a50c5a1SJan Engelhardt 	bool m;
741a50c5a1SJan Engelhardt 
751a50c5a1SJan Engelhardt 	if (info->flags & IPRANGE_SRC) {
7608b5194bSThomas Jacob 		m  = iprange_ipv6_lt(&iph->saddr, &info->src_min.in6);
7708b5194bSThomas Jacob 		m |= iprange_ipv6_lt(&info->src_max.in6, &iph->saddr);
786def1eb4SAlexey Dobriyan 		m ^= !!(info->flags & IPRANGE_SRC_INV);
791a50c5a1SJan Engelhardt 		if (m)
801a50c5a1SJan Engelhardt 			return false;
811a50c5a1SJan Engelhardt 	}
821a50c5a1SJan Engelhardt 	if (info->flags & IPRANGE_DST) {
8308b5194bSThomas Jacob 		m  = iprange_ipv6_lt(&iph->daddr, &info->dst_min.in6);
8408b5194bSThomas Jacob 		m |= iprange_ipv6_lt(&info->dst_max.in6, &iph->daddr);
856def1eb4SAlexey Dobriyan 		m ^= !!(info->flags & IPRANGE_DST_INV);
861a50c5a1SJan Engelhardt 		if (m)
871a50c5a1SJan Engelhardt 			return false;
881a50c5a1SJan Engelhardt 	}
891a50c5a1SJan Engelhardt 	return true;
901a50c5a1SJan Engelhardt }
911a50c5a1SJan Engelhardt 
921a50c5a1SJan Engelhardt static struct xt_match iprange_mt_reg[] __read_mostly = {
931a50c5a1SJan Engelhardt 	{
94f72e25a8SJan Engelhardt 		.name      = "iprange",
951a50c5a1SJan Engelhardt 		.revision  = 1,
96ee999d8bSJan Engelhardt 		.family    = NFPROTO_IPV4,
971a50c5a1SJan Engelhardt 		.match     = iprange_mt4,
981a50c5a1SJan Engelhardt 		.matchsize = sizeof(struct xt_iprange_mtinfo),
991a50c5a1SJan Engelhardt 		.me        = THIS_MODULE,
1001a50c5a1SJan Engelhardt 	},
1011a50c5a1SJan Engelhardt 	{
1021a50c5a1SJan Engelhardt 		.name      = "iprange",
1031a50c5a1SJan Engelhardt 		.revision  = 1,
104ee999d8bSJan Engelhardt 		.family    = NFPROTO_IPV6,
1051a50c5a1SJan Engelhardt 		.match     = iprange_mt6,
1061a50c5a1SJan Engelhardt 		.matchsize = sizeof(struct xt_iprange_mtinfo),
1071a50c5a1SJan Engelhardt 		.me        = THIS_MODULE,
1081a50c5a1SJan Engelhardt 	},
109f72e25a8SJan Engelhardt };
110f72e25a8SJan Engelhardt 
111f72e25a8SJan Engelhardt static int __init iprange_mt_init(void)
112f72e25a8SJan Engelhardt {
1131a50c5a1SJan Engelhardt 	return xt_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
114f72e25a8SJan Engelhardt }
115f72e25a8SJan Engelhardt 
116f72e25a8SJan Engelhardt static void __exit iprange_mt_exit(void)
117f72e25a8SJan Engelhardt {
1181a50c5a1SJan Engelhardt 	xt_unregister_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));
119f72e25a8SJan Engelhardt }
120f72e25a8SJan Engelhardt 
121f72e25a8SJan Engelhardt module_init(iprange_mt_init);
122f72e25a8SJan Engelhardt module_exit(iprange_mt_exit);
123f72e25a8SJan Engelhardt MODULE_LICENSE("GPL");
12436d4084dSJan Engelhardt MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
12536d4084dSJan Engelhardt MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
126f72e25a8SJan Engelhardt MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching");
12701b7a314SPhil Oester MODULE_ALIAS("ipt_iprange");
12801b7a314SPhil Oester MODULE_ALIAS("ip6t_iprange");
129