3 * Linux INET6 implementation
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>
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 static void ip6_rule_add(struct ip6_fw_rule
*rl
)
65 struct ip6_fw_rule
*next
;
69 next
= &ip6_fw_rule_list
;
71 rl
->prev
= next
->prev
;
77 static void ip6_rule_del(struct ip6_fw_rule
*rl
)
79 struct ip6_fw_rule
*next
, *prev
;
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
));
99 rl
->flowr
.ops
= &ip6_fw_ops
;
104 static __inline__
void ip6_fwrule_free(struct ip6_fw_rule
* rl
)
109 static __inline__
int port_match(int rl_port
, int fl_port
)
112 if (rl_port
== 0 || (rl_port
== fl_port
))
117 static int ip6_fw_accept_trans(struct ip6_fw_rule
*rl
,
118 struct fl_acc_args
*args
)
120 int res
= FLOWR_NODECISION
;
125 switch (args
->type
) {
128 struct sk_buff
*skb
= args
->fl_u
.skb
;
129 struct ipv6hdr
*hdr
= skb
->nh
.ipv6h
;
132 len
= skb
->len
- sizeof(struct ipv6hdr
);
134 proto
= hdr
->nexthdr
;
141 if (len
< sizeof(struct tcphdr
)) {
145 th
= (struct tcphdr
*)(hdr
+ 1);
154 if (len
< sizeof(struct udphdr
)) {
158 uh
= (struct udphdr
*)(hdr
+ 1);
171 proto
= args
->fl_u
.fl_o
.flow
->proto
;
173 if (proto
== IPPROTO_ICMPV6
) {
176 sport
= args
->fl_u
.fl_o
.flow
->uli_u
.ports
.sport
;
177 dport
= args
->fl_u
.fl_o
.flow
->uli_u
.ports
.dport
;
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
)
192 #if IP6_FW_DEBUG >= 1
193 printk(KERN_DEBUG
"ip6_fw_accept: unknown arg type\n");
202 static int ip6_fw_accept(struct dst_entry
*dst
, struct fl_acc_args
*args
)
205 struct ip6_fw_rule
*rl
;
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
;
216 if (rl
->policy
& IP6_FW_REJECT
)
223 res
= ip6_fw_accept_trans(rl
, args
);
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
);
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");
264 icmpv6_send(skb
, ICMPV6_DEST_UNREACH
, ICMPV6_ADM_PROHIBITED
, 0,
267 * send it via netlink, as (rule, skb)
274 int ip6_fw_discard(struct sk_buff
*skb
)
276 printk(KERN_DEBUG
"ip6_fw: BUG fw_reject called\n");
281 int ip6_fw_msg_add(struct ip6_fw_msg
*msg
)
283 struct in6_rtmsg rtmsg
;
284 struct ip6_fw_rule
*rl
;
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();
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
);
311 /* The rest will not work for now. --ABK (989725) */
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
;
327 rt
->u
.dst
.input
= ip6_fw_reject
;
328 rt
->u
.dst
.output
= ip6_fw_reject
;
333 rt
->rt6i_flowr
= flow_clone((struct flow_rule
*)rl
);
339 static int ip6_fw_msgrcv(int unit
, struct sk_buff
*skb
)
344 struct ip6_fw_msg
*msg
;
346 if (skb
->len
< sizeof(struct ip6_fw_msg
)) {
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
) {
369 static void ip6_fw_destroy(struct flow_rule
*rl
)
371 ip6_fwrule_free((struct ip6_fw_rule
*)rl
);
375 #define ip6_fw_init module_init
378 __initfunc(void ip6_fw_init(void))
380 #ifdef CONFIG_NETLINK
381 netlink_attach(NETLINK_IP6_FW
, ip6_fw_msgrcv
);
386 void module_cleanup(void)
388 #ifdef CONFIG_NETLINK
389 netlink_detach(NETLINK_IP6_FW
);