1 #include <linux/config.h>
2 #include <linux/init.h>
4 #ifdef CONFIG_NETFILTER
6 #include <linux/kernel.h>
7 #include <linux/ipv6.h>
8 #include <linux/netfilter.h>
9 #include <linux/netfilter_ipv6.h>
12 #include <net/ip6_route.h>
14 int ip6_route_me_harder(struct sk_buff
*skb
)
16 struct ipv6hdr
*iph
= skb
->nh
.ipv6h
;
17 struct dst_entry
*dst
;
19 .oif
= skb
->sk
? skb
->sk
->sk_bound_dev_if
: 0,
22 { .daddr
= iph
->daddr
,
23 .saddr
= iph
->saddr
, } },
24 .proto
= iph
->nexthdr
,
27 dst
= ip6_route_output(skb
->sk
, &fl
);
30 IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES
);
31 LIMIT_NETDEBUG(KERN_DEBUG
"ip6_route_me_harder: No more route.\n");
37 dst_release(skb
->dst
);
42 EXPORT_SYMBOL(ip6_route_me_harder
);
45 * Extra routing may needed on local out, as the QUEUE target never
46 * returns control to the table.
50 struct in6_addr daddr
;
51 struct in6_addr saddr
;
54 static void save(const struct sk_buff
*skb
, struct nf_info
*info
)
56 struct ip6_rt_info
*rt_info
= nf_info_reroute(info
);
58 if (info
->hook
== NF_IP6_LOCAL_OUT
) {
59 struct ipv6hdr
*iph
= skb
->nh
.ipv6h
;
61 rt_info
->daddr
= iph
->daddr
;
62 rt_info
->saddr
= iph
->saddr
;
66 static int reroute(struct sk_buff
**pskb
, const struct nf_info
*info
)
68 struct ip6_rt_info
*rt_info
= nf_info_reroute(info
);
70 if (info
->hook
== NF_IP6_LOCAL_OUT
) {
71 struct ipv6hdr
*iph
= (*pskb
)->nh
.ipv6h
;
72 if (!ipv6_addr_equal(&iph
->daddr
, &rt_info
->daddr
) ||
73 !ipv6_addr_equal(&iph
->saddr
, &rt_info
->saddr
))
74 return ip6_route_me_harder(*pskb
);
79 static struct nf_queue_rerouter ip6_reroute
= {
80 .rer_size
= sizeof(struct ip6_rt_info
),
85 int __init
ipv6_netfilter_init(void)
87 return nf_register_queue_rerouter(PF_INET6
, &ip6_reroute
);
90 void ipv6_netfilter_fini(void)
92 nf_unregister_queue_rerouter(PF_INET6
);
95 #else /* CONFIG_NETFILTER */
96 int __init
ipv6_netfilter_init(void)
101 void ipv6_netfilter_fini(void)
104 #endif /* CONFIG_NETFILTER */