RT-AC66 3.0.0.4.374.130 core
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / net / ipv4 / netfilter / ipt_ipv4options.c
blob28d2b4dbef8f02eccc0fd88dd3c4f050d1d5e267
1 /*
2 This is a module which is used to match ipv4 options.
3 This file is distributed under the terms of the GNU General Public
4 License (GPL). Copies of the GPL can be obtained from:
5 ftp://prep.ai.mit.edu/pub/gnu/GPL
7 11-mars-2001 Fabrice MARIE <fabrice@netfilter.org> : initial development.
8 12-july-2001 Fabrice MARIE <fabrice@netfilter.org> : added router-alert otions matching. Fixed a bug with no-srr
9 12-august-2001 Imran Patel <ipatel@crosswinds.net> : optimization of the match.
10 18-november-2001 Fabrice MARIE <fabrice@netfilter.org> : added [!] 'any' option match.
11 19-february-2004 Harald Welte <laforge@netfilter.org> : merge with 2.6.x
14 #include <linux/module.h>
15 #include <linux/skbuff.h>
16 #include <linux/version.h>
17 #include <net/ip.h>
19 #include <linux/netfilter_ipv4/ip_tables.h>
20 #include <linux/netfilter_ipv4/ipt_ipv4options.h>
22 MODULE_LICENSE("GPL");
23 MODULE_AUTHOR("Fabrice Marie <fabrice@netfilter.org>");
25 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
26 static int
27 match(const struct sk_buff *skb,
28 const struct net_device *in,
29 const struct net_device *out,
30 const void *matchinfo,
31 int offset,
32 const void *hdr,
33 u_int16_t datalen,
34 int *hotdrop)
35 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
36 static int
37 match(const struct sk_buff *skb,
38 const struct net_device *in,
39 const struct net_device *out,
40 const void *matchinfo,
41 int offset,
42 int *hotdrop)
43 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
44 static int
45 match(const struct sk_buff *skb,
46 const struct net_device *in,
47 const struct net_device *out,
48 const void *matchinfo,
49 int offset,
50 unsigned int protoff,
51 int *hotdrop)
52 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
53 static int
54 match(const struct sk_buff *skb,
55 const struct net_device *in,
56 const struct net_device *out,
57 const struct xt_match *match,
58 const void *matchinfo,
59 int offset,
60 unsigned int protoff,
61 int *hotdrop)
62 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
63 static bool
64 match(const struct sk_buff *skb,
65 const struct net_device *in,
66 const struct net_device *out,
67 const struct xt_match *match,
68 const void *matchinfo,
69 int offset,
70 unsigned int protoff,
71 bool *hotdrop)
72 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
73 static bool
74 match(const struct sk_buff *skb,
75 const struct xt_match_param *par)
76 #endif
78 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
79 const struct ipt_ipv4options_info *info = matchinfo;
80 #else
81 const struct ipt_ipv4options_info *info = par->matchinfo;
82 #endif
83 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
84 const struct iphdr *iph = ip_hdr(skb);
85 #else
86 const struct iphdr *iph = skb->nh.iph;
87 #endif
88 const struct ip_options *opt;
90 if (iph->ihl * 4 == sizeof(struct iphdr)) {
91 /* No options, so we match only the "DONTs" and the "IGNOREs" */
93 if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) ||
94 ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
95 ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
96 ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
97 ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
98 ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT))
99 return 0;
100 return 1;
102 else {
103 if ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)
104 /* there are options, and we don't need to care which one */
105 return 1;
106 else {
107 if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)
108 /* there are options but we don't want any ! */
109 return 0;
113 opt = &(IPCB(skb)->opt);
115 /* source routing */
116 if ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) {
117 if (!((opt->srr) && (opt->is_strictroute)))
118 return 0;
120 else if ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) {
121 if (!((opt->srr) && (!opt->is_strictroute)))
122 return 0;
124 else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) {
125 if (opt->srr)
126 return 0;
128 /* record route */
129 if ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) {
130 if (!opt->rr)
131 return 0;
133 else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) {
134 if (opt->rr)
135 return 0;
137 /* timestamp */
138 if ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) {
139 if (!opt->ts)
140 return 0;
142 else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) {
143 if (opt->ts)
144 return 0;
146 /* router-alert option */
147 if ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) {
148 if (!opt->router_alert)
149 return 0;
151 else if ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) {
152 if (opt->router_alert)
153 return 0;
156 /* we match ! */
157 return 1;
160 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
161 static int
162 checkentry(const char *tablename,
163 const struct ipt_ip *ip,
164 void *matchinfo,
165 unsigned int matchsize,
166 unsigned int hook_mask)
167 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
168 static int
169 checkentry(const char *tablename,
170 const void *inf,
171 void *matchinfo,
172 unsigned int matchsize,
173 unsigned int hook_mask)
174 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
175 static int
176 checkentry(const char *tablename,
177 const void *inf,
178 const struct xt_match *match,
179 void *matchinfo,
180 unsigned int matchsize,
181 unsigned int hook_mask)
182 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
183 static int
184 checkentry(const char *tablename,
185 const void *inf,
186 const struct xt_match *match,
187 void *matchinfo,
188 unsigned int hook_mask)
189 #elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
190 static bool
191 checkentry(const char *tablename,
192 const void *inf,
193 const struct xt_match *match,
194 void *matchinfo,
195 unsigned int hook_mask)
196 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) */
197 static bool
198 checkentry(const struct xt_mtchk_param *par)
199 #endif
201 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
202 struct ipt_ipv4options_info *info = matchinfo;
203 #else
204 struct ipt_ipv4options_info *info = par->matchinfo;
205 #endif
206 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
207 /* Check the size */
208 if (matchsize != IPT_ALIGN(sizeof(struct ipt_ipv4options_info)))
209 return 0;
210 #endif
212 /* Now check the coherence of the data ... */
213 if (((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT) &&
214 (((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR) ||
215 ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR) ||
216 ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) ||
217 ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) ||
218 ((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT)))
219 return 0; /* opposites */
220 if (((info->options & IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) == IPT_IPV4OPTION_DONT_MATCH_ANY_OPT) &&
221 (((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR) ||
222 ((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
223 ((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) ||
224 ((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) ||
225 ((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) ||
226 ((info->options & IPT_IPV4OPTION_MATCH_ANY_OPT) == IPT_IPV4OPTION_MATCH_ANY_OPT)))
227 return 0; /* opposites */
228 if (((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) &&
229 ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR))
230 return 0; /* cannot match in the same time loose and strict source routing */
231 if ((((info->options & IPT_IPV4OPTION_MATCH_SSRR) == IPT_IPV4OPTION_MATCH_SSRR) ||
232 ((info->options & IPT_IPV4OPTION_MATCH_LSRR) == IPT_IPV4OPTION_MATCH_LSRR)) &&
233 ((info->options & IPT_IPV4OPTION_DONT_MATCH_SRR) == IPT_IPV4OPTION_DONT_MATCH_SRR))
234 return 0; /* opposites */
235 if (((info->options & IPT_IPV4OPTION_MATCH_RR) == IPT_IPV4OPTION_MATCH_RR) &&
236 ((info->options & IPT_IPV4OPTION_DONT_MATCH_RR) == IPT_IPV4OPTION_DONT_MATCH_RR))
237 return 0; /* opposites */
238 if (((info->options & IPT_IPV4OPTION_MATCH_TIMESTAMP) == IPT_IPV4OPTION_MATCH_TIMESTAMP) &&
239 ((info->options & IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP) == IPT_IPV4OPTION_DONT_MATCH_TIMESTAMP))
240 return 0; /* opposites */
241 if (((info->options & IPT_IPV4OPTION_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_MATCH_ROUTER_ALERT) &&
242 ((info->options & IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT) == IPT_IPV4OPTION_DONT_MATCH_ROUTER_ALERT))
243 return 0; /* opposites */
245 /* everything looks ok. */
246 return 1;
249 static struct ipt_match ipv4options_match = {
250 .name = "ipv4options",
251 .match = match,
252 .matchsize = sizeof(struct ipt_ipv4options_info),
253 .checkentry = checkentry,
254 .me = THIS_MODULE
257 static int __init init(void)
259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
260 return xt_register_match(&ipv4options_match);
261 #else
262 return ipt_register_match(&ipv4options_match);
263 #endif
266 static void __exit fini(void)
268 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
269 xt_unregister_match(&ipv4options_match);
270 #else
271 ipt_unregister_match(&ipv4options_match);
272 #endif
275 module_init(init);
276 module_exit(fini);