]>
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 |
d3c5ee6d JE |
38 | frag_mt6(const struct sk_buff *skb, const struct net_device *in, |
39 | const struct net_device *out, const struct xt_match *match, | |
40 | const void *matchinfo, int offset, unsigned int protoff, | |
41 | bool *hotdrop) | |
1da177e4 | 42 | { |
a47362a2 JE |
43 | struct frag_hdr _frag; |
44 | const struct frag_hdr *fh; | |
f0daaa65 YK |
45 | const struct ip6t_frag *fraginfo = matchinfo; |
46 | unsigned int ptr; | |
6d381634 | 47 | int err; |
1da177e4 | 48 | |
6d381634 PM |
49 | err = ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL); |
50 | if (err < 0) { | |
51 | if (err != -ENOENT) | |
cff533ac | 52 | *hotdrop = true; |
1d93a9cb | 53 | return false; |
6d381634 | 54 | } |
1da177e4 | 55 | |
e674d0f3 | 56 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); |
f0daaa65 | 57 | if (fh == NULL) { |
cff533ac | 58 | *hotdrop = true; |
1d93a9cb | 59 | return false; |
e674d0f3 | 60 | } |
1da177e4 | 61 | |
0d53778e PM |
62 | pr_debug("INFO %04X ", fh->frag_off); |
63 | pr_debug("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); | |
64 | pr_debug("RES %02X %04X", fh->reserved, ntohs(fh->frag_off) & 0x6); | |
65 | pr_debug("MF %04X ", fh->frag_off & htons(IP6_MF)); | |
66 | pr_debug("ID %u %08X\n", ntohl(fh->identification), | |
67 | ntohl(fh->identification)); | |
68 | ||
69 | pr_debug("IPv6 FRAG id %02X ", | |
70 | id_match(fraginfo->ids[0], fraginfo->ids[1], | |
71 | ntohl(fh->identification), | |
72 | !!(fraginfo->invflags & IP6T_FRAG_INV_IDS))); | |
73 | pr_debug("res %02X %02X%04X %02X ", | |
74 | fraginfo->flags & IP6T_FRAG_RES, fh->reserved, | |
75 | ntohs(fh->frag_off) & 0x6, | |
76 | !((fraginfo->flags & IP6T_FRAG_RES) | |
77 | && (fh->reserved || (ntohs(fh->frag_off) & 0x06)))); | |
78 | pr_debug("first %02X %02X %02X ", | |
79 | fraginfo->flags & IP6T_FRAG_FST, | |
80 | ntohs(fh->frag_off) & ~0x7, | |
81 | !((fraginfo->flags & IP6T_FRAG_FST) | |
82 | && (ntohs(fh->frag_off) & ~0x7))); | |
83 | pr_debug("mf %02X %02X %02X ", | |
84 | fraginfo->flags & IP6T_FRAG_MF, | |
85 | ntohs(fh->frag_off) & IP6_MF, | |
86 | !((fraginfo->flags & IP6T_FRAG_MF) | |
87 | && !((ntohs(fh->frag_off) & IP6_MF)))); | |
88 | pr_debug("last %02X %02X %02X\n", | |
89 | fraginfo->flags & IP6T_FRAG_NMF, | |
90 | ntohs(fh->frag_off) & IP6_MF, | |
91 | !((fraginfo->flags & IP6T_FRAG_NMF) | |
92 | && (ntohs(fh->frag_off) & IP6_MF))); | |
f0daaa65 YK |
93 | |
94 | return (fh != NULL) | |
95 | && | |
7c4e36bc JE |
96 | id_match(fraginfo->ids[0], fraginfo->ids[1], |
97 | ntohl(fh->identification), | |
98 | !!(fraginfo->invflags & IP6T_FRAG_INV_IDS)) | |
f0daaa65 YK |
99 | && |
100 | !((fraginfo->flags & IP6T_FRAG_RES) | |
101 | && (fh->reserved || (ntohs(fh->frag_off) & 0x6))) | |
102 | && | |
103 | !((fraginfo->flags & IP6T_FRAG_FST) | |
104 | && (ntohs(fh->frag_off) & ~0x7)) | |
105 | && | |
106 | !((fraginfo->flags & IP6T_FRAG_MF) | |
107 | && !(ntohs(fh->frag_off) & IP6_MF)) | |
108 | && | |
109 | !((fraginfo->flags & IP6T_FRAG_NMF) | |
110 | && (ntohs(fh->frag_off) & IP6_MF)); | |
1da177e4 LT |
111 | } |
112 | ||
113 | /* Called when user tries to insert an entry of this type. */ | |
ccb79bdc | 114 | static bool |
d3c5ee6d JE |
115 | frag_mt6_check(const char *tablename, const void *ip, |
116 | const struct xt_match *match, void *matchinfo, | |
117 | unsigned int hook_mask) | |
1da177e4 | 118 | { |
f0daaa65 YK |
119 | const struct ip6t_frag *fraginfo = matchinfo; |
120 | ||
f0daaa65 | 121 | if (fraginfo->invflags & ~IP6T_FRAG_INV_MASK) { |
0d53778e | 122 | pr_debug("ip6t_frag: unknown flags %X\n", fraginfo->invflags); |
ccb79bdc | 123 | return false; |
f0daaa65 | 124 | } |
ccb79bdc | 125 | return true; |
1da177e4 LT |
126 | } |
127 | ||
d3c5ee6d | 128 | static struct xt_match frag_mt6_reg __read_mostly = { |
1da177e4 | 129 | .name = "frag", |
6709dbbb | 130 | .family = AF_INET6, |
d3c5ee6d | 131 | .match = frag_mt6, |
7f939713 | 132 | .matchsize = sizeof(struct ip6t_frag), |
d3c5ee6d | 133 | .checkentry = frag_mt6_check, |
1da177e4 LT |
134 | .me = THIS_MODULE, |
135 | }; | |
136 | ||
d3c5ee6d | 137 | static int __init frag_mt6_init(void) |
1da177e4 | 138 | { |
d3c5ee6d | 139 | return xt_register_match(&frag_mt6_reg); |
1da177e4 LT |
140 | } |
141 | ||
d3c5ee6d | 142 | static void __exit frag_mt6_exit(void) |
1da177e4 | 143 | { |
d3c5ee6d | 144 | xt_unregister_match(&frag_mt6_reg); |
1da177e4 LT |
145 | } |
146 | ||
d3c5ee6d JE |
147 | module_init(frag_mt6_init); |
148 | module_exit(frag_mt6_exit); |