Import 2.3.5
[davej-history.git] / net / ipv6 / ip6_fw.c
blob560f1feeff875efec50569c3d83cb8d239318677
1 /*
2 * IPv6 Firewall
3 * Linux INET6 implementation
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
8 * $Id: ip6_fw.c,v 1.10 1998/08/26 12:04:57 davem Exp $
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.
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>
29 #include <net/ipv6.h>
30 #include <net/ip6_route.h>
31 #include <net/ip6_fw.h>
32 #include <net/netlink.h>
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
42 static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args);
44 struct flow_rule_ops ip6_fw_ops = {
45 ip6_fw_accept
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}
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
63 static void ip6_rule_add(struct ip6_fw_rule *rl)
65 struct ip6_fw_rule *next;
67 start_bh_atomic();
68 ip6_fw_rule_cnt++;
69 next = &ip6_fw_rule_list;
70 rl->next = next;
71 rl->prev = next->prev;
72 rl->prev->next = rl;
73 next->prev = rl;
74 end_bh_atomic();
77 static void ip6_rule_del(struct ip6_fw_rule *rl)
79 struct ip6_fw_rule *next, *prev;
81 start_bh_atomic();
82 ip6_fw_rule_cnt--;
83 next = rl->next;
84 prev = rl->prev;
85 next->prev = prev;
86 prev->next = next;
87 end_bh_atomic();
90 static __inline__ struct ip6_fw_rule * ip6_fwrule_alloc(void)
92 struct ip6_fw_rule *rl;
94 rl = kmalloc(sizeof(struct ip6_fw_rule), GFP_ATOMIC);
96 memset(rl, 0, sizeof(struct ip6_fw_rule));
98 if (rl)
99 rl->flowr.ops = &ip6_fw_ops;
101 return rl;
104 static __inline__ void ip6_fwrule_free(struct ip6_fw_rule * rl)
106 kfree(rl);
109 static __inline__ int port_match(int rl_port, int fl_port)
111 int res = 0;
112 if (rl_port == 0 || (rl_port == fl_port))
113 res = 1;
114 return res;
117 static int ip6_fw_accept_trans(struct ip6_fw_rule *rl,
118 struct fl_acc_args *args)
120 int res = FLOWR_NODECISION;
121 int proto = 0;
122 int sport = 0;
123 int dport = 0;
125 switch (args->type) {
126 case FL_ARG_FORWARD:
128 struct sk_buff *skb = args->fl_u.skb;
129 struct ipv6hdr *hdr = skb->nh.ipv6h;
130 int len;
132 len = skb->len - sizeof(struct ipv6hdr);
134 proto = hdr->nexthdr;
136 switch (proto) {
137 case IPPROTO_TCP:
139 struct tcphdr *th;
141 if (len < sizeof(struct tcphdr)) {
142 res = FLOWR_ERROR;
143 goto out;
145 th = (struct tcphdr *)(hdr + 1);
146 sport = th->source;
147 dport = th->dest;
148 break;
150 case IPPROTO_UDP:
152 struct udphdr *uh;
154 if (len < sizeof(struct udphdr)) {
155 res = FLOWR_ERROR;
156 goto out;
158 uh = (struct udphdr *)(hdr + 1);
159 sport = uh->source;
160 dport = uh->dest;
161 break;
163 default:
164 goto out;
166 break;
169 case FL_ARG_ORIGIN:
171 proto = args->fl_u.fl_o.flow->proto;
173 if (proto == IPPROTO_ICMPV6) {
174 goto out;
175 } else {
176 sport = args->fl_u.fl_o.flow->uli_u.ports.sport;
177 dport = args->fl_u.fl_o.flow->uli_u.ports.dport;
179 break;
182 if (proto == rl->info.proto &&
183 port_match(args->fl_u.fl_o.flow->uli_u.ports.sport, sport) &&
184 port_match(args->fl_u.fl_o.flow->uli_u.ports.dport, dport)) {
185 if (rl->policy & IP6_FW_REJECT)
186 res = FLOWR_SELECT;
187 else
188 res = FLOWR_CLEAR;
191 default:
192 #if IP6_FW_DEBUG >= 1
193 printk(KERN_DEBUG "ip6_fw_accept: unknown arg type\n");
194 #endif
195 goto out;
198 out:
199 return res;
202 static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args)
204 struct rt6_info *rt;
205 struct ip6_fw_rule *rl;
206 int proto;
207 int res = FLOWR_NODECISION;
209 rt = (struct rt6_info *) dst;
210 rl = (struct ip6_fw_rule *) rt->rt6i_flowr;
212 proto = rl->info.proto;
214 switch (proto) {
215 case 0:
216 if (rl->policy & IP6_FW_REJECT)
217 res = FLOWR_SELECT;
218 else
219 res = FLOWR_CLEAR;
220 break;
221 case IPPROTO_TCP:
222 case IPPROTO_UDP:
223 res = ip6_fw_accept_trans(rl, args);
224 break;
225 case IPPROTO_ICMPV6:
228 return res;
231 static struct dst_entry * ip6_fw_dup(struct dst_entry *frule,
232 struct dst_entry *rt,
233 struct fl_acc_args *args)
235 struct ip6_fw_rule *rl;
236 struct rt6_info *nrt;
237 struct rt6_info *frt;
239 frt = (struct rt6_info *) frule;
241 rl = (struct ip6_fw_rule *) frt->rt6i_flowr;
243 nrt = ip6_rt_copy((struct rt6_info *) rt);
245 if (nrt) {
246 nrt->u.dst.input = frule->input;
247 nrt->u.dst.output = frule->output;
249 nrt->rt6i_flowr = flow_clone(frt->rt6i_flowr);
251 nrt->rt6i_flags |= RTF_CACHE;
252 nrt->rt6i_tstamp = jiffies;
255 return (struct dst_entry *) nrt;
258 int ip6_fw_reject(struct sk_buff *skb)
260 #if IP6_FW_DEBUG >= 1
261 printk(KERN_DEBUG "packet rejected: \n");
262 #endif
264 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0,
265 skb->dev);
267 * send it via netlink, as (rule, skb)
270 kfree_skb(skb);
271 return 0;
274 int ip6_fw_discard(struct sk_buff *skb)
276 printk(KERN_DEBUG "ip6_fw: BUG fw_reject called\n");
277 kfree_skb(skb);
278 return 0;
281 int ip6_fw_msg_add(struct ip6_fw_msg *msg)
283 struct in6_rtmsg rtmsg;
284 struct ip6_fw_rule *rl;
285 struct rt6_info *rt;
286 int err;
288 ipv6_addr_copy(&rtmsg.rtmsg_dst, &msg->dst);
289 ipv6_addr_copy(&rtmsg.rtmsg_src, &msg->src);
290 rtmsg.rtmsg_dst_len = msg->dst_len;
291 rtmsg.rtmsg_src_len = msg->src_len;
292 rtmsg.rtmsg_metric = IP6_RT_PRIO_FW;
294 rl = ip6_fwrule_alloc();
296 if (rl == NULL)
297 return -ENOMEM;
299 rl->policy = msg->policy;
300 rl->info.proto = msg->proto;
301 rl->info.uli_u.data = msg->u.data;
303 rtmsg.rtmsg_flags = RTF_NONEXTHOP|RTF_POLICY;
304 err = ip6_route_add(&rtmsg);
306 if (err) {
307 ip6_fwrule_free(rl);
308 return err;
311 /* The rest will not work for now. --ABK (989725) */
313 #ifndef notdef
314 ip6_fwrule_free(rl);
315 return -EPERM;
316 #else
317 rt->u.dst.error = -EPERM;
319 if (msg->policy == IP6_FW_ACCEPT) {
321 * Accept rules are never selected
322 * (i.e. packets use normal forwarding)
324 rt->u.dst.input = ip6_fw_discard;
325 rt->u.dst.output = ip6_fw_discard;
326 } else {
327 rt->u.dst.input = ip6_fw_reject;
328 rt->u.dst.output = ip6_fw_reject;
331 ip6_rule_add(rl);
333 rt->rt6i_flowr = flow_clone((struct flow_rule *)rl);
335 return 0;
336 #endif
339 static int ip6_fw_msgrcv(int unit, struct sk_buff *skb)
341 int count = 0;
343 while (skb->len) {
344 struct ip6_fw_msg *msg;
346 if (skb->len < sizeof(struct ip6_fw_msg)) {
347 count = -EINVAL;
348 break;
351 msg = (struct ip6_fw_msg *) skb->data;
352 skb_pull(skb, sizeof(struct ip6_fw_msg));
353 count += sizeof(struct ip6_fw_msg);
355 switch (msg->action) {
356 case IP6_FW_MSG_ADD:
357 ip6_fw_msg_add(msg);
358 break;
359 case IP6_FW_MSG_DEL:
360 break;
361 default:
362 return -EINVAL;
366 return count;
369 static void ip6_fw_destroy(struct flow_rule *rl)
371 ip6_fwrule_free((struct ip6_fw_rule *)rl);
374 #ifdef MODULE
375 #define ip6_fw_init module_init
376 #endif
378 __initfunc(void ip6_fw_init(void))
380 #ifdef CONFIG_NETLINK
381 netlink_attach(NETLINK_IP6_FW, ip6_fw_msgrcv);
382 #endif
385 #ifdef MODULE
386 void module_cleanup(void)
388 #ifdef CONFIG_NETLINK
389 netlink_detach(NETLINK_IP6_FW);
390 #endif
392 #endif