xref: /linux/net/ipv6/netfilter/ip6t_frag.c (revision 49bda4826843be0ef97a162009a29ea3a63f3935)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Kernel module to match FRAG parameters. */
3 
4 /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
5  */
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 #include <linux/module.h>
8 #include <linux/skbuff.h>
9 #include <linux/ipv6.h>
10 #include <linux/types.h>
11 #include <net/checksum.h>
12 #include <net/ipv6.h>
13 
14 #include <linux/netfilter/x_tables.h>
15 #include <linux/netfilter_ipv6/ip6_tables.h>
16 #include <linux/netfilter_ipv6/ip6t_frag.h>
17 
18 MODULE_LICENSE("GPL");
19 MODULE_DESCRIPTION("Xtables: IPv6 fragment match");
20 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
21 
22 /* Returns 1 if the id is matched by the range, 0 otherwise */
23 static inline bool
id_match(u_int32_t min,u_int32_t max,u_int32_t id,bool invert)24 id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert)
25 {
26 	return (id >= min && id <= max) ^ invert;
27 }
28 
29 static bool
frag_mt6(const struct sk_buff * skb,struct xt_action_param * par)30 frag_mt6(const struct sk_buff *skb, struct xt_action_param *par)
31 {
32 	struct frag_hdr _frag;
33 	const struct frag_hdr *fh;
34 	const struct ip6t_frag *fraginfo = par->matchinfo;
35 	unsigned int ptr = 0;
36 	int err;
37 
38 	err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL, NULL);
39 	if (err < 0) {
40 		if (err != -ENOENT)
41 			par->hotdrop = true;
42 		return false;
43 	}
44 
45 	fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag);
46 	if (fh == NULL) {
47 		par->hotdrop = true;
48 		return false;
49 	}
50 
51 	return id_match(fraginfo->ids[0], fraginfo->ids[1],
52 			 ntohl(fh->identification),
53 			 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) &&
54 		!((fraginfo->flags & IP6T_FRAG_RES) &&
55 		  (fh->reserved || (ntohs(fh->frag_off) & 0x6))) &&
56 		!((fraginfo->flags & IP6T_FRAG_FST) &&
57 		  (ntohs(fh->frag_off) & ~0x7)) &&
58 		!((fraginfo->flags & IP6T_FRAG_MF) &&
59 		  !(ntohs(fh->frag_off) & IP6_MF)) &&
60 		!((fraginfo->flags & IP6T_FRAG_NMF) &&
61 		  (ntohs(fh->frag_off) & IP6_MF));
62 }
63 
frag_mt6_check(const struct xt_mtchk_param * par)64 static int frag_mt6_check(const struct xt_mtchk_param *par)
65 {
66 	const struct ip6t_frag *fraginfo = par->matchinfo;
67 
68 	if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
69 		pr_info_ratelimited("unknown flags %X\n", fraginfo->invflags);
70 		return -EINVAL;
71 	}
72 	return 0;
73 }
74 
75 static struct xt_match frag_mt6_reg __read_mostly = {
76 	.name		= "frag",
77 	.family		= NFPROTO_IPV6,
78 	.match		= frag_mt6,
79 	.matchsize	= sizeof(struct ip6t_frag),
80 	.checkentry	= frag_mt6_check,
81 	.me		= THIS_MODULE,
82 };
83 
frag_mt6_init(void)84 static int __init frag_mt6_init(void)
85 {
86 	return xt_register_match(&frag_mt6_reg);
87 }
88 
frag_mt6_exit(void)89 static void __exit frag_mt6_exit(void)
90 {
91 	xt_unregister_match(&frag_mt6_reg);
92 }
93 
94 module_init(frag_mt6_init);
95 module_exit(frag_mt6_exit);
96