]>
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 | */ | |
ff67e4e4 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4 LT |
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; |
ff67e4e4 | 30 | pr_debug("id_match:%c 0x%x <= 0x%x <= 0x%x\n", invert ? '!' : ' ', |
0d53778e | 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 |
4b560b44 | 38 | frag_mt6(const struct sk_buff *skb, const struct xt_action_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, | |
3666ed1c JP |
73 | !((fraginfo->flags & IP6T_FRAG_RES) && |
74 | (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); | |
0d53778e PM |
75 | pr_debug("first %02X %02X %02X ", |
76 | fraginfo->flags & IP6T_FRAG_FST, | |
77 | ntohs(fh->frag_off) & ~0x7, | |
3666ed1c JP |
78 | !((fraginfo->flags & IP6T_FRAG_FST) && |
79 | (ntohs(fh->frag_off) & ~0x7))); | |
0d53778e PM |
80 | pr_debug("mf %02X %02X %02X ", |
81 | fraginfo->flags & IP6T_FRAG_MF, | |
82 | ntohs(fh->frag_off) & IP6_MF, | |
3666ed1c JP |
83 | !((fraginfo->flags & IP6T_FRAG_MF) && |
84 | !((ntohs(fh->frag_off) & IP6_MF)))); | |
0d53778e PM |
85 | pr_debug("last %02X %02X %02X\n", |
86 | fraginfo->flags & IP6T_FRAG_NMF, | |
87 | ntohs(fh->frag_off) & IP6_MF, | |
3666ed1c JP |
88 | !((fraginfo->flags & IP6T_FRAG_NMF) && |
89 | (ntohs(fh->frag_off) & IP6_MF))); | |
90 | ||
91 | return (fh != NULL) && | |
92 | id_match(fraginfo->ids[0], fraginfo->ids[1], | |
93 | ntohl(fh->identification), | |
94 | !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) && | |
95 | !((fraginfo->flags & IP6T_FRAG_RES) && | |
96 | (fh->reserved || (ntohs(fh->frag_off) & 0x6))) && | |
97 | !((fraginfo->flags & IP6T_FRAG_FST) && | |
98 | (ntohs(fh->frag_off) & ~0x7)) && | |
99 | !((fraginfo->flags & IP6T_FRAG_MF) && | |
100 | !(ntohs(fh->frag_off) & IP6_MF)) && | |
101 | !((fraginfo->flags & IP6T_FRAG_NMF) && | |
102 | (ntohs(fh->frag_off) & IP6_MF)); | |
1da177e4 LT |
103 | } |
104 | ||
b0f38452 | 105 | static int frag_mt6_check(const struct xt_mtchk_param *par) |
1da177e4 | 106 | { |
9b4fce7a | 107 | const struct ip6t_frag *fraginfo = par->matchinfo; |
f0daaa65 | 108 | |
f0daaa65 | 109 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { |
ff67e4e4 | 110 | pr_debug("unknown flags %X\n", fraginfo->invflags); |
bd414ee6 | 111 | return -EINVAL; |
f0daaa65 | 112 | } |
bd414ee6 | 113 | return 0; |
1da177e4 LT |
114 | } |
115 | ||
d3c5ee6d | 116 | static struct xt_match frag_mt6_reg __read_mostly = { |
1da177e4 | 117 | .name = "frag", |
ee999d8b | 118 | .family = NFPROTO_IPV6, |
d3c5ee6d | 119 | .match = frag_mt6, |
7f939713 | 120 | .matchsize = sizeof(struct ip6t_frag), |
d3c5ee6d | 121 | .checkentry = frag_mt6_check, |
1da177e4 LT |
122 | .me = THIS_MODULE, |
123 | }; | |
124 | ||
d3c5ee6d | 125 | static int __init frag_mt6_init(void) |
1da177e4 | 126 | { |
d3c5ee6d | 127 | return xt_register_match(&frag_mt6_reg); |
1da177e4 LT |
128 | } |
129 | ||
d3c5ee6d | 130 | static void __exit frag_mt6_exit(void) |
1da177e4 | 131 | { |
d3c5ee6d | 132 | xt_unregister_match(&frag_mt6_reg); |
1da177e4 LT |
133 | } |
134 | ||
d3c5ee6d JE |
135 | module_init(frag_mt6_init); |
136 | module_exit(frag_mt6_exit); |