1 #include <linux/config.h> 2 #include <linux/init.h> 3 4 #ifdef CONFIG_NETFILTER 5 6 #include <linux/kernel.h> 7 #include <linux/ipv6.h> 8 #include <linux/netfilter.h> 9 #include <linux/netfilter_ipv6.h> 10 #include <net/dst.h> 11 #include <net/ipv6.h> 12 #include <net/ip6_route.h> 13 #include <net/xfrm.h> 14 15 int ip6_route_me_harder(struct sk_buff *skb) 16 { 17 struct ipv6hdr *iph = skb->nh.ipv6h; 18 struct dst_entry *dst; 19 struct flowi fl = { 20 .oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, 21 .nl_u = 22 { .ip6_u = 23 { .daddr = iph->daddr, 24 .saddr = iph->saddr, } }, 25 }; 26 27 dst = ip6_route_output(skb->sk, &fl); 28 29 #ifdef CONFIG_XFRM 30 if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && 31 xfrm_decode_session(skb, &fl, AF_INET6) == 0) 32 if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0)) 33 return -1; 34 #endif 35 36 if (dst->error) { 37 IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); 38 LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); 39 dst_release(dst); 40 return -EINVAL; 41 } 42 43 /* Drop old route. */ 44 dst_release(skb->dst); 45 46 skb->dst = dst; 47 return 0; 48 } 49 EXPORT_SYMBOL(ip6_route_me_harder); 50 51 /* 52 * Extra routing may needed on local out, as the QUEUE target never 53 * returns control to the table. 54 */ 55 56 struct ip6_rt_info { 57 struct in6_addr daddr; 58 struct in6_addr saddr; 59 }; 60 61 static void save(const struct sk_buff *skb, struct nf_info *info) 62 { 63 struct ip6_rt_info *rt_info = nf_info_reroute(info); 64 65 if (info->hook == NF_IP6_LOCAL_OUT) { 66 struct ipv6hdr *iph = skb->nh.ipv6h; 67 68 rt_info->daddr = iph->daddr; 69 rt_info->saddr = iph->saddr; 70 } 71 } 72 73 static int reroute(struct sk_buff **pskb, const struct nf_info *info) 74 { 75 struct ip6_rt_info *rt_info = nf_info_reroute(info); 76 77 if (info->hook == NF_IP6_LOCAL_OUT) { 78 struct ipv6hdr *iph = (*pskb)->nh.ipv6h; 79 if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || 80 !ipv6_addr_equal(&iph->saddr, &rt_info->saddr)) 81 return ip6_route_me_harder(*pskb); 82 } 83 return 0; 84 } 85 86 static struct nf_queue_rerouter ip6_reroute = { 87 .rer_size = sizeof(struct ip6_rt_info), 88 .save = &save, 89 .reroute = &reroute, 90 }; 91 92 int __init ipv6_netfilter_init(void) 93 { 94 return nf_register_queue_rerouter(PF_INET6, &ip6_reroute); 95 } 96 97 void ipv6_netfilter_fini(void) 98 { 99 nf_unregister_queue_rerouter(PF_INET6); 100 } 101 102 #else /* CONFIG_NETFILTER */ 103 int __init ipv6_netfilter_init(void) 104 { 105 return 0; 106 } 107 108 void ipv6_netfilter_fini(void) 109 { 110 } 111 #endif /* CONFIG_NETFILTER */ 112