File Index
Files and directories
Sign in
FILE

ebt_ip6.c

File preview with syntax highlighting.

linux-6.19.14/net/bridge/netfilter/ebt_ip6.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 *  ebt_ip6
  4 *
  5 *	Authors:
  6 *	Manohar Castelino <manohar.r.castelino@intel.com>
  7 *	Kuo-Lang Tseng <kuo-lang.tseng@intel.com>
  8 *	Jan Engelhardt <jengelh@medozas.de>
  9 *
 10 * Summary:
 11 * This is just a modification of the IPv4 code written by
 12 * Bart De Schuymer <bdschuym@pandora.be>
 13 * with the changes required to support IPv6
 14 *
 15 *  Jan, 2008
 16 */
 17#include <linux/ipv6.h>
 18#include <net/ipv6.h>
 19#include <linux/in.h>
 20#include <linux/module.h>
 21#include <net/dsfield.h>
 22#include <linux/netfilter/x_tables.h>
 23#include <linux/netfilter_bridge/ebtables.h>
 24#include <linux/netfilter_bridge/ebt_ip6.h>
 25
 26union pkthdr {
 27	struct {
 28		__be16 src;
 29		__be16 dst;
 30	} tcpudphdr;
 31	struct {
 32		u8 type;
 33		u8 code;
 34	} icmphdr;
 35};
 36
 37static bool
 38ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
 39{
 40	const struct ebt_ip6_info *info = par->matchinfo;
 41	const struct ipv6hdr *ih6;
 42	struct ipv6hdr _ip6h;
 43	const union pkthdr *pptr;
 44	union pkthdr _pkthdr;
 45
 46	ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
 47	if (ih6 == NULL)
 48		return false;
 49	if ((info->bitmask & EBT_IP6_TCLASS) &&
 50	    NF_INVF(info, EBT_IP6_TCLASS,
 51		    info->tclass != ipv6_get_dsfield(ih6)))
 52		return false;
 53	if (((info->bitmask & EBT_IP6_SOURCE) &&
 54	     NF_INVF(info, EBT_IP6_SOURCE,
 55		     ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk,
 56					  &info->saddr))) ||
 57	    ((info->bitmask & EBT_IP6_DEST) &&
 58	     NF_INVF(info, EBT_IP6_DEST,
 59		     ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk,
 60					  &info->daddr))))
 61		return false;
 62	if (info->bitmask & EBT_IP6_PROTO) {
 63		uint8_t nexthdr = ih6->nexthdr;
 64		__be16 frag_off;
 65		int offset_ph;
 66
 67		offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off);
 68		if (offset_ph == -1)
 69			return false;
 70		if (NF_INVF(info, EBT_IP6_PROTO, info->protocol != nexthdr))
 71			return false;
 72		if (!(info->bitmask & (EBT_IP6_DPORT |
 73				       EBT_IP6_SPORT | EBT_IP6_ICMP6)))
 74			return true;
 75
 76		/* min icmpv6 headersize is 4, so sizeof(_pkthdr) is ok. */
 77		pptr = skb_header_pointer(skb, offset_ph, sizeof(_pkthdr),
 78					  &_pkthdr);
 79		if (pptr == NULL)
 80			return false;
 81		if (info->bitmask & EBT_IP6_DPORT) {
 82			u16 dst = ntohs(pptr->tcpudphdr.dst);
 83			if (NF_INVF(info, EBT_IP6_DPORT,
 84				    dst < info->dport[0] ||
 85				    dst > info->dport[1]))
 86				return false;
 87		}
 88		if (info->bitmask & EBT_IP6_SPORT) {
 89			u16 src = ntohs(pptr->tcpudphdr.src);
 90			if (NF_INVF(info, EBT_IP6_SPORT,
 91				    src < info->sport[0] ||
 92				    src > info->sport[1]))
 93				return false;
 94		}
 95		if ((info->bitmask & EBT_IP6_ICMP6) &&
 96		    NF_INVF(info, EBT_IP6_ICMP6,
 97			    pptr->icmphdr.type < info->icmpv6_type[0] ||
 98			    pptr->icmphdr.type > info->icmpv6_type[1] ||
 99			    pptr->icmphdr.code < info->icmpv6_code[0] ||
100			    pptr->icmphdr.code > info->icmpv6_code[1]))
101			return false;
102	}
103	return true;
104}
105
106static int ebt_ip6_mt_check(const struct xt_mtchk_param *par)
107{
108	const struct ebt_entry *e = par->entryinfo;
109	struct ebt_ip6_info *info = par->matchinfo;
110
111	if (e->ethproto != htons(ETH_P_IPV6) || e->invflags & EBT_IPROTO)
112		return -EINVAL;
113	if (info->bitmask & ~EBT_IP6_MASK || info->invflags & ~EBT_IP6_MASK)
114		return -EINVAL;
115	if (info->bitmask & (EBT_IP6_DPORT | EBT_IP6_SPORT)) {
116		if (info->invflags & EBT_IP6_PROTO)
117			return -EINVAL;
118		if (info->protocol != IPPROTO_TCP &&
119		    info->protocol != IPPROTO_UDP &&
120		    info->protocol != IPPROTO_UDPLITE &&
121		    info->protocol != IPPROTO_SCTP &&
122		    info->protocol != IPPROTO_DCCP)
123			return -EINVAL;
124	}
125	if (info->bitmask & EBT_IP6_DPORT && info->dport[0] > info->dport[1])
126		return -EINVAL;
127	if (info->bitmask & EBT_IP6_SPORT && info->sport[0] > info->sport[1])
128		return -EINVAL;
129	if (info->bitmask & EBT_IP6_ICMP6) {
130		if ((info->invflags & EBT_IP6_PROTO) ||
131		     info->protocol != IPPROTO_ICMPV6)
132			return -EINVAL;
133		if (info->icmpv6_type[0] > info->icmpv6_type[1] ||
134		    info->icmpv6_code[0] > info->icmpv6_code[1])
135			return -EINVAL;
136	}
137	return 0;
138}
139
140static struct xt_match ebt_ip6_mt_reg __read_mostly = {
141	.name		= "ip6",
142	.revision	= 0,
143	.family		= NFPROTO_BRIDGE,
144	.match		= ebt_ip6_mt,
145	.checkentry	= ebt_ip6_mt_check,
146	.matchsize	= sizeof(struct ebt_ip6_info),
147	.me		= THIS_MODULE,
148};
149
150static int __init ebt_ip6_init(void)
151{
152	return xt_register_match(&ebt_ip6_mt_reg);
153}
154
155static void __exit ebt_ip6_fini(void)
156{
157	xt_unregister_match(&ebt_ip6_mt_reg);
158}
159
160module_init(ebt_ip6_init);
161module_exit(ebt_ip6_fini);
162MODULE_DESCRIPTION("Ebtables: IPv6 protocol packet match");
163MODULE_AUTHOR("Kuo-Lang Tseng <kuo-lang.tseng@intel.com>");
164MODULE_LICENSE("GPL");
~/ Read-only file preview.