1 /* Kernel module to match FRAG parameters. */
3 /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
10 #include <linux/module.h>
11 #include <linux/skbuff.h>
12 #include <linux/ipv6.h>
13 #include <linux/types.h>
14 #include <net/checksum.h>
17 #include <asm/byteorder.h>
19 #include <linux/netfilter_ipv6/ip6_tables.h>
20 #include <linux/netfilter_ipv6/ip6t_frag.h>
22 MODULE_LICENSE("GPL");
23 MODULE_DESCRIPTION("IPv6 FRAG match");
24 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
29 #define DEBUGP(format, args...)
33 #if BYTE_ORDER == BIG_ENDIAN
34 #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */
35 #define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */
36 #define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */
37 #else /* BYTE_ORDER == LITTLE_ENDIAN */
38 #define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
39 #define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
40 #define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
44 #define IP6F_OFF_MASK 0xf8ff /* mask out offset from _offlg */
45 #define IP6F_RESERVED_MASK 0x0600 /* reserved bits in ip6f_offlg */
46 #define IP6F_MORE_FRAG 0x0100 /* more-fragments flag */
55 /* Returns 1 if the id is matched by the range, 0 otherwise */
57 id_match(u_int32_t min, u_int32_t max, u_int32_t id, int invert)
60 DEBUGP("frag id_match:%c 0x%x <= 0x%x <= 0x%x",invert? '!':' ',
62 r=(id >= min && id <= max) ^ invert;
63 DEBUGP(" result %s\n",r? "PASS" : "FAILED");
68 match(const struct sk_buff *skb,
69 const struct net_device *in,
70 const struct net_device *out,
71 const void *matchinfo,
77 struct fraghdr *frag = NULL;
78 const struct ip6t_frag *fraginfo = matchinfo;
83 unsigned int hdrlen = 0;
85 /* type of the 1st exthdr */
86 nexthdr = skb->nh.ipv6h->nexthdr;
87 /* pointer to the 1st exthdr */
88 ptr = sizeof(struct ipv6hdr);
89 /* available length */
93 while (ip6t_ext_hdr(nexthdr)) {
94 struct ipv6_opt_hdr *hdr;
96 DEBUGP("ipv6_frag header iteration \n");
98 /* Is there enough space for the next ext header? */
99 if (len < (int)sizeof(struct ipv6_opt_hdr))
101 /* No more exthdr -> evaluate */
102 if (nexthdr == NEXTHDR_NONE) {
105 /* ESP -> evaluate */
106 if (nexthdr == NEXTHDR_ESP) {
110 hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
112 /* Calculate the header length */
113 if (nexthdr == NEXTHDR_FRAGMENT) {
115 } else if (nexthdr == NEXTHDR_AUTH)
116 hdrlen = (hdr->hdrlen+2)<<2;
118 hdrlen = ipv6_optlen(hdr);
120 /* FRAG -> evaluate */
121 if (nexthdr == NEXTHDR_FRAGMENT) {
122 temp |= MASK_FRAGMENT;
130 case NEXTHDR_ROUTING:
131 case NEXTHDR_FRAGMENT:
136 DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr);
141 nexthdr = hdr->nexthdr;
144 if ( ptr > skb->len ) {
145 DEBUGP("ipv6_frag: new pointer too large! \n");
150 /* FRAG header not found */
151 if ( temp != MASK_FRAGMENT ) return 0;
153 if (len < (int)sizeof(struct fraghdr)){
158 frag = (struct fraghdr *) (skb->data + ptr);
160 DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
161 DEBUGP("INFO %04X ", frag->info);
162 DEBUGP("OFFSET %04X ", frag->info & IP6F_OFF_MASK);
163 DEBUGP("RES %04X ", frag->info & IP6F_RESERVED_MASK);
164 DEBUGP("MF %04X ", frag->info & IP6F_MORE_FRAG);
165 DEBUGP("ID %u %08X\n", ntohl(frag->id), ntohl(frag->id));
167 DEBUGP("IPv6 FRAG id %02X ",
168 (id_match(fraginfo->ids[0], fraginfo->ids[1],
170 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))));
171 DEBUGP("len %02X %04X %02X ",
172 fraginfo->hdrlen, hdrlen,
173 (!fraginfo->hdrlen ||
174 (fraginfo->hdrlen == hdrlen) ^
175 !!(fraginfo->invflags & IP6T_FRAG_INV_LEN)));
176 DEBUGP("res %02X %02X %02X ",
177 (fraginfo->flags & IP6T_FRAG_RES), frag->info & IP6F_RESERVED_MASK,
178 !((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK)));
179 DEBUGP("first %02X %02X %02X ",
180 (fraginfo->flags & IP6T_FRAG_FST), frag->info & IP6F_OFF_MASK,
181 !((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK)));
182 DEBUGP("mf %02X %02X %02X ",
183 (fraginfo->flags & IP6T_FRAG_MF), frag->info & IP6F_MORE_FRAG,
184 !((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG))));
185 DEBUGP("last %02X %02X %02X\n",
186 (fraginfo->flags & IP6T_FRAG_NMF), frag->info & IP6F_MORE_FRAG,
187 !((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG)));
189 return (frag != NULL)
191 (id_match(fraginfo->ids[0], fraginfo->ids[1],
193 !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)))
195 (!fraginfo->hdrlen ||
196 (fraginfo->hdrlen == hdrlen) ^
197 !!(fraginfo->invflags & IP6T_FRAG_INV_LEN))
199 !((fraginfo->flags & IP6T_FRAG_RES) && (frag->info & IP6F_RESERVED_MASK))
201 !((fraginfo->flags & IP6T_FRAG_FST) && (frag->info & IP6F_OFF_MASK))
203 !((fraginfo->flags & IP6T_FRAG_MF) && !((frag->info & IP6F_MORE_FRAG)))
205 !((fraginfo->flags & IP6T_FRAG_NMF) && (frag->info & IP6F_MORE_FRAG));
208 /* Called when user tries to insert an entry of this type. */
210 checkentry(const char *tablename,
211 const struct ip6t_ip6 *ip,
213 unsigned int matchinfosize,
214 unsigned int hook_mask)
216 const struct ip6t_frag *fraginfo = matchinfo;
218 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_frag))) {
219 DEBUGP("ip6t_frag: matchsize %u != %u\n",
220 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_frag)));
223 if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) {
224 DEBUGP("ip6t_frag: unknown flags %X\n",
232 static struct ip6t_match frag_match = {
235 .checkentry = &checkentry,
239 static int __init init(void)
241 return ip6t_register_match(&frag_match);
244 static void __exit cleanup(void)
246 ip6t_unregister_match(&frag_match);
250 module_exit(cleanup);