3 * Linux INET6 implementation
6 * Pedro Roque <roque@di.fc.ul.pt>
8 * $Id: ip6_fw.c,v 1.15 1999/08/31 07:04:03 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>
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
= {
42 static int ip6_fw_accept(struct dst_entry
*dst
, struct fl_acc_args
*args
);
44 struct flow_rule_ops ip6_fw_ops
= {
49 static struct rt6_info ip6_fw_null_entry
= {
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
,
60 0, RTN_ROOT
|RTN_TL_ROOT
, 0
63 rwlock_t ip6_fw_lock
= RW_LOCK_UNLOCKED
;
66 static void ip6_rule_add(struct ip6_fw_rule
*rl
)
68 struct ip6_fw_rule
*next
;
70 write_lock_bh(&ip6_fw_lock
);
72 next
= &ip6_fw_rule_list
;
74 rl
->prev
= next
->prev
;
77 write_unlock_bh(&ip6_fw_lock
);
80 static void ip6_rule_del(struct ip6_fw_rule
*rl
)
82 struct ip6_fw_rule
*next
, *prev
;
84 write_lock_bh(&ip6_fw_lock
);
90 write_unlock_bh(&ip6_fw_lock
);
93 static __inline__
struct ip6_fw_rule
* ip6_fwrule_alloc(void)
95 struct ip6_fw_rule
*rl
;
97 rl
= kmalloc(sizeof(struct ip6_fw_rule
), GFP_ATOMIC
);
100 memset(rl
, 0, sizeof(struct ip6_fw_rule
));
101 rl
->flowr
.ops
= &ip6_fw_ops
;
106 static __inline__
void ip6_fwrule_free(struct ip6_fw_rule
* rl
)
111 static __inline__
int port_match(int rl_port
, int fl_port
)
114 if (rl_port
== 0 || (rl_port
== fl_port
))
119 static int ip6_fw_accept_trans(struct ip6_fw_rule
*rl
,
120 struct fl_acc_args
*args
)
122 int res
= FLOWR_NODECISION
;
127 switch (args
->type
) {
130 struct sk_buff
*skb
= args
->fl_u
.skb
;
131 struct ipv6hdr
*hdr
= skb
->nh
.ipv6h
;
134 len
= skb
->len
- sizeof(struct ipv6hdr
);
136 proto
= hdr
->nexthdr
;
143 if (len
< sizeof(struct tcphdr
)) {
147 th
= (struct tcphdr
*)(hdr
+ 1);
156 if (len
< sizeof(struct udphdr
)) {
160 uh
= (struct udphdr
*)(hdr
+ 1);
173 proto
= args
->fl_u
.fl_o
.flow
->proto
;
175 if (proto
== IPPROTO_ICMPV6
) {
178 sport
= args
->fl_u
.fl_o
.flow
->uli_u
.ports
.sport
;
179 dport
= args
->fl_u
.fl_o
.flow
->uli_u
.ports
.dport
;
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
)
194 #if IP6_FW_DEBUG >= 1
195 printk(KERN_DEBUG
"ip6_fw_accept: unknown arg type\n");
204 static int ip6_fw_accept(struct dst_entry
*dst
, struct fl_acc_args
*args
)
207 struct ip6_fw_rule
*rl
;
209 int res
= FLOWR_NODECISION
;
211 rt
= (struct rt6_info
*) dst
;
212 rl
= (struct ip6_fw_rule
*) rt
->rt6i_flowr
;
214 proto
= rl
->info
.proto
;
218 if (rl
->policy
& IP6_FW_REJECT
)
225 res
= ip6_fw_accept_trans(rl
, args
);
233 static struct dst_entry
* ip6_fw_dup(struct dst_entry
*frule
,
234 struct dst_entry
*rt
,
235 struct fl_acc_args
*args
)
237 struct ip6_fw_rule
*rl
;
238 struct rt6_info
*nrt
;
239 struct rt6_info
*frt
;
241 frt
= (struct rt6_info
*) frule
;
243 rl
= (struct ip6_fw_rule
*) frt
->rt6i_flowr
;
245 nrt
= ip6_rt_copy((struct rt6_info
*) rt
);
248 nrt
->u
.dst
.input
= frule
->input
;
249 nrt
->u
.dst
.output
= frule
->output
;
251 nrt
->rt6i_flowr
= flow_clone(frt
->rt6i_flowr
);
253 nrt
->rt6i_flags
|= RTF_CACHE
;
254 nrt
->rt6i_tstamp
= jiffies
;
257 return (struct dst_entry
*) nrt
;
260 int ip6_fw_reject(struct sk_buff
*skb
)
262 #if IP6_FW_DEBUG >= 1
263 printk(KERN_DEBUG
"packet rejected: \n");
266 icmpv6_send(skb
, ICMPV6_DEST_UNREACH
, ICMPV6_ADM_PROHIBITED
, 0,
269 * send it via netlink, as (rule, skb)
276 int ip6_fw_discard(struct sk_buff
*skb
)
278 printk(KERN_DEBUG
"ip6_fw: BUG fw_reject called\n");
283 int ip6_fw_msg_add(struct ip6_fw_msg
*msg
)
285 struct in6_rtmsg rtmsg
;
286 struct ip6_fw_rule
*rl
;
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
;
296 rl
= ip6_fwrule_alloc();
301 rl
->policy
= msg
->policy
;
302 rl
->info
.proto
= msg
->proto
;
303 rl
->info
.uli_u
.data
= msg
->u
.data
;
305 rtmsg
.rtmsg_flags
= RTF_NONEXTHOP
|RTF_POLICY
;
306 err
= ip6_route_add(&rtmsg
);
313 /* The rest will not work for now. --ABK (989725) */
319 rt
->u
.dst
.error
= -EPERM
;
321 if (msg
->policy
== IP6_FW_ACCEPT
) {
323 * Accept rules are never selected
324 * (i.e. packets use normal forwarding)
326 rt
->u
.dst
.input
= ip6_fw_discard
;
327 rt
->u
.dst
.output
= ip6_fw_discard
;
329 rt
->u
.dst
.input
= ip6_fw_reject
;
330 rt
->u
.dst
.output
= ip6_fw_reject
;
335 rt
->rt6i_flowr
= flow_clone((struct flow_rule
*)rl
);
341 static int ip6_fw_msgrcv(int unit
, struct sk_buff
*skb
)
346 struct ip6_fw_msg
*msg
;
348 if (skb
->len
< sizeof(struct ip6_fw_msg
)) {
353 msg
= (struct ip6_fw_msg
*) skb
->data
;
354 skb_pull(skb
, sizeof(struct ip6_fw_msg
));
355 count
+= sizeof(struct ip6_fw_msg
);
357 switch (msg
->action
) {
371 static void ip6_fw_destroy(struct flow_rule
*rl
)
373 ip6_fwrule_free((struct ip6_fw_rule
*)rl
);
377 #define ip6_fw_init module_init
380 void __init
ip6_fw_init(void)
382 #ifdef CONFIG_NETLINK
383 netlink_attach(NETLINK_IP6_FW
, ip6_fw_msgrcv
);
388 void cleanup_module(void)
390 #ifdef CONFIG_NETLINK
391 netlink_detach(NETLINK_IP6_FW
);