1 /*
2 * IPv6 Firewall
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 *
8 * $Id: ip6_fw.c,v 1.15 1999/08/31 07:04:03 davem Exp $
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
14 */
15
16 #include <linux/config.h>
17 #include <linux/errno.h>
18 #include <linux/types.h>
19 #include <linux/string.h>
20 #include <linux/socket.h>
21 #include <linux/sockios.h>
22 #include <linux/net.h>
23 #include <linux/route.h>
24 #include <linux/netdevice.h>
25 #include <linux/in6.h>
26 #include <linux/udp.h>
27 #include <linux/init.h>
28
29 #include <net/ipv6.h>
30 #include <net/ip6_route.h>
31 #include <net/ip6_fw.h>
32 #include <net/netlink.h>
33
34 static unsigned long ip6_fw_rule_cnt;
35 static struct ip6_fw_rule ip6_fw_rule_list = {
36 {0},
37 NULL, NULL,
38 {0},
39 IP6_FW_REJECT
40 };
41
42 static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args);
43
44 struct flow_rule_ops ip6_fw_ops = {
45 ip6_fw_accept
46 };
47
48
49 static struct rt6_info ip6_fw_null_entry = {
50 {{NULL, 0, 0, NULL,
51 0, 0, 0, 0, 0, 0, 0, 0, -ENETUNREACH, NULL, NULL,
52 ip6_pkt_discard, ip6_pkt_discard, NULL}},
53 NULL, {{{0}}}, 256, RTF_REJECT|RTF_NONEXTHOP, ~0UL,
54 0, &ip6_fw_rule_list, {{{{0}}}, 128}, {{{{0}}}, 128}
55 };
56
57 static struct fib6_node ip6_fw_fib = {
58 NULL, NULL, NULL, NULL,
59 &ip6_fw_null_entry,
60 0, RTN_ROOT|RTN_TL_ROOT, 0
61 };
62
63 rwlock_t ip6_fw_lock = RW_LOCK_UNLOCKED;
64
65
66 static void ip6_rule_add(struct ip6_fw_rule *rl)
67 {
68 struct ip6_fw_rule *next;
69
70 write_lock_bh(&ip6_fw_lock);
71 ip6_fw_rule_cnt++;
72 next = &ip6_fw_rule_list;
73 rl->next = next;
74 rl->prev = next->prev;
75 rl->prev->next = rl;
76 next->prev = rl;
77 write_unlock_bh(&ip6_fw_lock);
78 }
79
80 static void ip6_rule_del(struct ip6_fw_rule *rl)
81 {
82 struct ip6_fw_rule *next, *prev;
83
84 write_lock_bh(&ip6_fw_lock);
85 ip6_fw_rule_cnt--;
86 next = rl->next;
87 prev = rl->prev;
88 next->prev = prev;
89 prev->next = next;
90 write_unlock_bh(&ip6_fw_lock);
91 }
92
93 static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void)
94 {
95 struct ip6_fw_rule *rl;
96
97 rl = kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC);
98 if (rl)
99 {
100 memset(rl, 0, sizeof(struct ip6_fw_rule));
101 rl->flowr.ops = &ip6_fw_ops;
102 }
103 return rl;
104 }
105
106 static __inline__ void ip6_fwrule_free(struct ip6_fw_rule * rl)
107 {
108 kfree(rl);
109 }
110
111 static __inline__ int port_match(int rl_port, int fl_port)
112 {
113 int res = 0;
114 if (rl_port == 0 || (rl_port == fl_port))
115 res = 1;
116 return res;
117 }
118
119 static int ip6_fw_accept_trans(struct ip6_fw_rule *rl,
120 struct fl_acc_args *args)
121 {
122 int res = FLOWR_NODECISION;
123 int proto = 0;
124 int sport = 0;
125 int dport = 0;
126
127 switch (args->type) {
128 case FL_ARG_FORWARD:
129 {
130 struct sk_buff *skb = args->fl_u.skb;
131 struct ipv6hdr *hdr = skb->nh.ipv6h;
132 int len;
133
134 len = skb->len - sizeof(struct ipv6hdr);
135
136 proto = hdr->nexthdr;
137
138 switch (proto) {
139 case IPPROTO_TCP:
140 {
141 struct tcphdr *th;
142
143 if (len < sizeof(struct tcphdr)) {
144 res = FLOWR_ERROR;
145 goto out;
146 }
147 th = (struct tcphdr *)(hdr + 1);
148 sport = th->source;
149 dport = th->dest;
150 break;
151 }
152 case IPPROTO_UDP:
153 {
154 struct udphdr *uh;
155
156 if (len < sizeof(struct udphdr)) {
157 res = FLOWR_ERROR;
158 goto out;
159 }
160 uh = (struct udphdr *)(hdr + 1);
161 sport = uh->source;
162 dport = uh->dest;
163 break;
164 }
165 default:
166 goto out;
167 };
168 break;
169 }
170
171 case FL_ARG_ORIGIN:
172 {
173 proto = args->fl_u.fl_o.flow->proto;
174
175 if (proto == IPPROTO_ICMPV6) {
176 goto out;
177 } else {
178 sport = args->fl_u.fl_o.flow->uli_u.ports.sport;
179 dport = args->fl_u.fl_o.flow->uli_u.ports.dport;
180 }
181 break;
182 }
183
184 if (proto == rl->info.proto &&
185 port_match(args->fl_u.fl_o.flow->uli_u.ports.sport, sport) &&
186 port_match(args->fl_u.fl_o.flow->uli_u.ports.dport, dport)) {
187 if (rl->policy & IP6_FW_REJECT)
188 res = FLOWR_SELECT;
189 else
190 res = FLOWR_CLEAR;
191 }
192
193 default:
194 #if IP6_FW_DEBUG >= 1
195 printk(KERN_DEBUG "ip6_fw_accept: unknown arg type\n");
196 #endif
197 goto out;
198 };
199
200 out:
201 return res;
202 }
203
204 static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args)
205 {
206 struct rt6_info *rt;
207 struct ip6_fw_rule *rl;
208 int proto;
209 int res = FLOWR_NODECISION;
210
211 rt = (struct rt6_info *) dst;
212 rl = (struct ip6_fw_rule *) rt->rt6i_flowr;
213
214 proto = rl->info.proto;
215
216 switch (proto) {
217 case 0:
218 if (rl->policy & IP6_FW_REJECT)
219 res = FLOWR_SELECT;
220 else
221 res = FLOWR_CLEAR;
222 break;
223 case IPPROTO_TCP:
224 case IPPROTO_UDP:
225 res = ip6_fw_accept_trans(rl, args);
226 break;
227 case IPPROTO_ICMPV6:
228 };
229
230 return res;
231 }
232
233 static struct dst_entry * ip6_fw_dup(struct dst_entry *frule,
234 struct dst_entry *rt,
235 struct fl_acc_args *args)
236 {
237 struct ip6_fw_rule *rl;
238 struct rt6_info *nrt;
239 struct rt6_info *frt;
240
241 frt = (struct rt6_info *) frule;
242
243 rl = (struct ip6_fw_rule *) frt->rt6i_flowr;
244
245 nrt = ip6_rt_copy((struct rt6_info *) rt);
246
247 if (nrt) {
248 nrt->u.dst.input = frule->input;
249 nrt->u.dst.output = frule->output;
250
251 nrt->rt6i_flowr = flow_clone(frt->rt6i_flowr);
252
253 nrt->rt6i_flags |= RTF_CACHE;
254 nrt->rt6i_tstamp = jiffies;
255 }
256
257 return (struct dst_entry *) nrt;
258 }
259
260 int ip6_fw_reject(struct sk_buff *skb)
261 {
262 #if IP6_FW_DEBUG >= 1
263 printk(KERN_DEBUG "packet rejected: \n");
264 #endif
265
266 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0,
267 skb->dev);
268 /*
269 * send it via netlink, as (rule, skb)
270 */
271
272 kfree_skb(skb);
273 return 0;
274 }
275
276 int ip6_fw_discard(struct sk_buff *skb)
277 {
278 printk(KERN_DEBUG "ip6_fw: BUG fw_reject called\n");
279 kfree_skb(skb);
280 return 0;
281 }
282
283 int ip6_fw_msg_add(struct ip6_fw_msg *msg)
284 {
285 struct in6_rtmsg rtmsg;
286 struct ip6_fw_rule *rl;
287 struct rt6_info *rt;
288 int err;
289
290 ipv6_addr_copy(&rtmsg.rtmsg_dst, &msg->dst);
291 ipv6_addr_copy(&rtmsg.rtmsg_src, &msg->src);
292 rtmsg.rtmsg_dst_len = msg->dst_len;
293 rtmsg.rtmsg_src_len = msg->src_len;
294 rtmsg.rtmsg_metric = IP6_RT_PRIO_FW;
295
296 rl = ip6_fwrule_alloc();
297
298 if (rl == NULL)
299 return -ENOMEM;
300
301 rl->policy = msg->policy;
302 rl->info.proto = msg->proto;
303 rl->info.uli_u.data = msg->u.data;
304
305 rtmsg.rtmsg_flags = RTF_NONEXTHOP|RTF_POLICY;
306 err = ip6_route_add(&rtmsg);
307
308 if (err) {
309 ip6_fwrule_free(rl);
310 return err;
311 }
312
313 /* The rest will not work for now. --ABK (989725) */
314
315 #ifndef notdef
316 ip6_fwrule_free(rl);
317 return -EPERM;
318 #else
319 rt->u.dst.error = -EPERM;
320
321 if (msg->policy == IP6_FW_ACCEPT) {
322 /*
323 * Accept rules are never selected
324 * (i.e. packets use normal forwarding)
325 */
326 rt->u.dst.input = ip6_fw_discard;
327 rt->u.dst.output = ip6_fw_discard;
328 } else {
329 rt->u.dst.input = ip6_fw_reject;
330 rt->u.dst.output = ip6_fw_reject;
331 }
332
333 ip6_rule_add(rl);
334
335 rt->rt6i_flowr = flow_clone((struct flow_rule *)rl);
336
337 return 0;
338 #endif
339 }
340
341 static int ip6_fw_msgrcv(int unit, struct sk_buff *skb)
342 {
343 int count = 0;
344
345 while (skb->len) {
346 struct ip6_fw_msg *msg;
347
348 if (skb->len < sizeof(struct ip6_fw_msg)) {
349 count = -EINVAL;
350 break;
351 }
352
353 msg = (struct ip6_fw_msg *) skb->data;
354 skb_pull(skb, sizeof(struct ip6_fw_msg));
355 count += sizeof(struct ip6_fw_msg);
356
357 switch (msg->action) {
358 case IP6_FW_MSG_ADD:
359 ip6_fw_msg_add(msg);
360 break;
361 case IP6_FW_MSG_DEL:
362 break;
363 default:
364 return -EINVAL;
365 };
366 }
367
368 return count;
369 }
370
371 static void ip6_fw_destroy(struct flow_rule *rl)
372 {
373 ip6_fwrule_free((struct ip6_fw_rule *)rl);
374 }
375
376 #ifdef MODULE
377 #define ip6_fw_init module_init
378 #endif
379
380 void __init ip6_fw_init(void)
381 {
382 #ifdef CONFIG_NETLINK
383 netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
384 #endif
385 }
386
387 #ifdef MODULE
388 void cleanup_module(void)
389 {
390 #ifdef CONFIG_NETLINK
391 netlink_detach(NETLINK_IP6_FW);
392 #endif
393 }
394 #endif
395
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.