Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* Kernel module to match FRAG parameters. */ |
2 | ||
3 | /* (C) 2001-2002 Andras Kis-Szabo <kisza@sch.bme.hu> | |
4 | * | |
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. | |
8 | */ | |
9 | ||
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> | |
15 | #include <net/ipv6.h> | |
16 | ||
6709dbbb | 17 | #include <linux/netfilter/x_tables.h> |
1da177e4 LT |
18 | #include <linux/netfilter_ipv6/ip6_tables.h> |
19 | #include <linux/netfilter_ipv6/ip6t_frag.h> | |
20 | ||
21 | MODULE_LICENSE("GPL"); | |
2ae15b64 | 22 | MODULE_DESCRIPTION("Xtables: IPv6 fragment match"); |
1da177e4 LT |
23 | MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>"); |
24 | ||
1da177e4 | 25 | /* Returns 1 if the id is matched by the range, 0 otherwise */ |
1d93a9cb JE |
26 | static inline bool |
27 | id_match(u_int32_t min, u_int32_t max, u_int32_t id, bool invert) | |
1da177e4 | 28 | { |
1d93a9cb | 29 | bool r; |
0d53778e PM |
30 | pr_debug("frag id_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ', |
31 | min, id, max); | |
f0daaa65 | 32 | r = (id >= min && id <= max) ^ invert; |
0d53778e | 33 | pr_debug(" result %s\n", r ? "PASS" : "FAILED"); |
f0daaa65 | 34 | return r; |
1da177e4 LT |
35 | } |
36 | ||
1d93a9cb | 37 | static bool |
f7108a20 | 38 | frag_mt6(const struct sk_buff *skb, const struct xt_match_param *par) |
1da177e4 | 39 | { |
a47362a2 JE |
40 | struct frag_hdr _frag; |
41 | const struct frag_hdr *fh; | |
f7108a20 | 42 | const struct ip6t_frag *fraginfo = par->matchinfo; |
f0daaa65 | 43 | unsigned int ptr; |
6d381634 | 44 | int err; |
1da177e4 | 45 | |
6d381634 PM |
46 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL); |
47 | if (err < 0) { | |
48 | if (err != -ENOENT) | |
f7108a20 | 49 | *par->hotdrop = true; |
1d93a9cb | 50 | return false; |
6d381634 | 51 | } |
1da177e4 | 52 | |
e674d0f3 | 53 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); |
f0daaa65 | 54 | if (fh == NULL) { |
f7108a20 | 55 | *par->hotdrop = true; |
1d93a9cb | 56 | return false; |
e674d0f3 | 57 | } |
1da177e4 | 58 | |
0d53778e PM |
59 | pr_debug("INFO %04X ", fh->frag_off); |
60 | pr_debug("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); | |
61 | pr_debug("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6); | |
62 | pr_debug("MF %04X ", fh->frag_off & htons(IP6_MF)); | |
63 | pr_debug("ID %u %08X\n", ntohl(fh->identification), | |
64 | ntohl(fh->identification)); | |
65 | ||
66 | pr_debug("IPv6 FRAG id %02X ", | |
67 | id_match(fraginfo->ids[0], fraginfo->ids[1], | |
68 | ntohl(fh->identification), | |
69 | !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))); | |
70 | pr_debug("res %02X %02X%04X %02X ", | |
71 | fraginfo->flags & IP6T_FRAG_RES, fh->reserved, | |
72 | ntohs(fh->frag_off) & 0x6, | |
73 | !((fraginfo->flags & IP6T_FRAG_RES) | |
74 | && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); | |
75 | pr_debug("first %02X %02X %02X ", | |
76 | fraginfo->flags & IP6T_FRAG_FST, | |
77 | ntohs(fh->frag_off) & ~0x7, | |
78 | !((fraginfo->flags & IP6T_FRAG_FST) | |
79 | && (ntohs(fh->frag_off) & ~0x7))); | |
80 | pr_debug("mf %02X %02X %02X ", | |
81 | fraginfo->flags & IP6T_FRAG_MF, | |
82 | ntohs(fh->frag_off) & IP6_MF, | |
83 | !((fraginfo->flags & IP6T_FRAG_MF) | |
84 | && !((ntohs(fh->frag_off) & IP6_MF)))); | |
85 | pr_debug("last %02X %02X %02X\n", | |
86 | fraginfo->flags & IP6T_FRAG_NMF, | |
87 | ntohs(fh->frag_off) & IP6_MF, | |
88 | !((fraginfo->flags & IP6T_FRAG_NMF) | |
89 | && (ntohs(fh->frag_off) & IP6_MF))); | |
f0daaa65 YK |
90 | |
91 | return (fh != NULL) | |
92 | && | |
7c4e36bc JE |
93 | id_match(fraginfo->ids[0], fraginfo->ids[1], |
94 | ntohl(fh->identification), | |
95 | !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) | |
f0daaa65 YK |
96 | && |
97 | !((fraginfo->flags & IP6T_FRAG_RES) | |
98 | && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) | |
99 | && | |
100 | !((fraginfo->flags & IP6T_FRAG_FST) | |
101 | && (ntohs(fh->frag_off) & ~0x7)) | |
102 | && | |
103 | !((fraginfo->flags & IP6T_FRAG_MF) | |
104 | && !(ntohs(fh->frag_off) & IP6_MF)) | |
105 | && | |
106 | !((fraginfo->flags & IP6T_FRAG_NMF) | |
107 | && (ntohs(fh->frag_off) & IP6_MF)); | |
1da177e4 LT |
108 | } |
109 | ||
110 | /* Called when user tries to insert an entry of this type. */ | |
ccb79bdc | 111 | static bool |
d3c5ee6d JE |
112 | frag_mt6_check(const char *tablename, const void *ip, |
113 | const struct xt_match *match, void *matchinfo, | |
114 | unsigned int hook_mask) | |
1da177e4 | 115 | { |
f0daaa65 YK |
116 | const struct ip6t_frag *fraginfo = matchinfo; |
117 | ||
f0daaa65 | 118 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { |
0d53778e | 119 | pr_debug("ip6t_frag: unknown flags %X\n", fraginfo->invflags); |
ccb79bdc | 120 | return false; |
f0daaa65 | 121 | } |
ccb79bdc | 122 | return true; |
1da177e4 LT |
123 | } |
124 | ||
d3c5ee6d | 125 | static struct xt_match frag_mt6_reg __read_mostly = { |
1da177e4 | 126 | .name = "frag", |
ee999d8b | 127 | .family = NFPROTO_IPV6, |
d3c5ee6d | 128 | .match = frag_mt6, |
7f939713 | 129 | .matchsize = sizeof(struct ip6t_frag), |
d3c5ee6d | 130 | .checkentry = frag_mt6_check, |
1da177e4 LT |
131 | .me = THIS_MODULE, |
132 | }; | |
133 | ||
d3c5ee6d | 134 | static int __init frag_mt6_init(void) |
1da177e4 | 135 | { |
d3c5ee6d | 136 | return xt_register_match(&frag_mt6_reg); |
1da177e4 LT |
137 | } |
138 | ||
d3c5ee6d | 139 | static void __exit frag_mt6_exit(void) |
1da177e4 | 140 | { |
d3c5ee6d | 141 | xt_unregister_match(&frag_mt6_reg); |
1da177e4 LT |
142 | } |
143 | ||
d3c5ee6d JE |
144 | module_init(frag_mt6_init); |
145 | module_exit(frag_mt6_exit); |