2013-04-06 15:24:29 +02:00
/*
* IPv6 specific functions of netfilter core
*
* Rusty Russell ( C ) 2000 - - This code is GPL .
* Patrick McHardy ( C ) 2006 - 2012
*/
2005-08-09 19:39:00 -07:00
# include <linux/kernel.h>
2006-01-09 16:43:13 -08:00
# include <linux/init.h>
2005-08-09 19:39:00 -07:00
# include <linux/ipv6.h>
2005-08-09 19:42:34 -07:00
# include <linux/netfilter.h>
# include <linux/netfilter_ipv6.h>
2011-07-15 11:47:34 -04:00
# include <linux/export.h>
2013-05-17 03:56:10 +00:00
# include <net/addrconf.h>
2005-08-09 19:39:00 -07:00
# include <net/dst.h>
# include <net/ipv6.h>
# include <net/ip6_route.h>
2006-01-06 23:04:54 -08:00
# include <net/xfrm.h>
2007-12-05 01:24:48 -08:00
# include <net/netfilter/nf_queue.h>
2005-08-09 19:39:00 -07:00
2015-09-25 15:07:31 -05:00
int ip6_route_me_harder ( struct net * net , struct sk_buff * skb )
2005-08-09 19:39:00 -07:00
{
2011-04-22 04:53:02 +00:00
const struct ipv6hdr * iph = ipv6_hdr ( skb ) ;
2018-02-25 11:49:07 -08:00
struct sock * sk = sk_to_full_sk ( skb - > sk ) ;
2012-08-26 19:14:08 +02:00
unsigned int hh_len ;
2005-08-09 19:39:00 -07:00
struct dst_entry * dst ;
2019-01-21 18:45:27 +08:00
int strict = ( ipv6_addr_type ( & iph - > daddr ) &
( IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL ) ) ;
2011-03-12 16:22:43 -05:00
struct flowi6 fl6 = {
2018-11-21 14:00:30 +01:00
. flowi6_oif = sk & & sk - > sk_bound_dev_if ? sk - > sk_bound_dev_if :
2019-01-21 18:45:27 +08:00
strict ? skb_dst ( skb ) - > dev - > ifindex : 0 ,
2011-03-12 16:22:43 -05:00
. flowi6_mark = skb - > mark ,
2018-02-25 11:49:07 -08:00
. flowi6_uid = sock_net_uid ( net , sk ) ,
2011-03-12 16:22:43 -05:00
. daddr = iph - > daddr ,
. saddr = iph - > saddr ,
2005-08-09 19:39:00 -07:00
} ;
2014-05-08 16:22:35 +03:00
int err ;
2005-08-09 19:39:00 -07:00
2018-02-25 11:49:07 -08:00
dst = ip6_route_output ( net , sk , & fl6 ) ;
2014-05-08 16:22:35 +03:00
err = dst - > error ;
if ( err ) {
2008-10-14 22:55:21 -07:00
IP6_INC_STATS ( net , ip6_dst_idev ( dst ) , IPSTATS_MIB_OUTNOROUTES ) ;
2014-11-11 10:59:17 -08:00
net_dbg_ratelimited ( " ip6_route_me_harder: No more route \n " ) ;
2005-08-09 19:39:00 -07:00
dst_release ( dst ) ;
2014-05-08 16:22:35 +03:00
return err ;
2005-08-09 19:39:00 -07:00
}
/* Drop old route. */
2009-06-02 05:19:30 +00:00
skb_dst_drop ( skb ) ;
2005-08-09 19:39:00 -07:00
2009-06-02 05:19:30 +00:00
skb_dst_set ( skb , dst ) ;
2010-04-15 12:37:18 +02:00
# ifdef CONFIG_XFRM
if ( ! ( IP6CB ( skb ) - > flags & IP6SKB_XFRM_TRANSFORMED ) & &
2011-03-12 16:22:43 -05:00
xfrm_decode_session ( skb , flowi6_to_flowi ( & fl6 ) , AF_INET6 ) = = 0 ) {
2010-04-15 12:37:18 +02:00
skb_dst_set ( skb , NULL ) ;
2018-02-25 11:49:07 -08:00
dst = xfrm_lookup ( net , dst , flowi6_to_flowi ( & fl6 ) , sk , 0 ) ;
2011-03-02 13:27:41 -08:00
if ( IS_ERR ( dst ) )
2013-04-05 06:41:11 +00:00
return PTR_ERR ( dst ) ;
2010-04-15 12:37:18 +02:00
skb_dst_set ( skb , dst ) ;
}
# endif
2012-08-26 19:14:08 +02:00
/* Change in oif may mean change in hh_len. */
hh_len = skb_dst ( skb ) - > dev - > hard_header_len ;
if ( skb_headroom ( skb ) < hh_len & &
pskb_expand_head ( skb , HH_DATA_ALIGN ( hh_len - skb_headroom ( skb ) ) ,
0 , GFP_ATOMIC ) )
2013-04-05 06:41:11 +00:00
return - ENOMEM ;
2012-08-26 19:14:08 +02:00
2005-08-09 19:39:00 -07:00
return 0 ;
}
EXPORT_SYMBOL ( ip6_route_me_harder ) ;
2017-11-27 22:50:26 +01:00
static int nf_ip6_reroute ( struct sk_buff * skb ,
2007-12-05 01:26:33 -08:00
const struct nf_queue_entry * entry )
2005-08-09 19:42:34 -07:00
{
2007-12-05 01:26:33 -08:00
struct ip6_rt_info * rt_info = nf_queue_entry_reroute ( entry ) ;
2005-08-09 19:42:34 -07:00
2015-04-03 16:31:01 -04:00
if ( entry - > state . hook = = NF_INET_LOCAL_OUT ) {
2011-04-22 04:53:02 +00:00
const struct ipv6hdr * iph = ipv6_hdr ( skb ) ;
2005-08-09 19:42:34 -07:00
if ( ! ipv6_addr_equal ( & iph - > daddr , & rt_info - > daddr ) | |
2008-11-25 12:18:11 +01:00
! ipv6_addr_equal ( & iph - > saddr , & rt_info - > saddr ) | |
skb - > mark ! = rt_info - > mark )
2017-11-27 22:50:26 +01:00
return ip6_route_me_harder ( entry - > state . net , skb ) ;
2005-08-09 19:42:34 -07:00
}
return 0 ;
}
2019-02-02 10:17:00 +01:00
int __nf_ip6_route ( struct net * net , struct dst_entry * * dst ,
struct flowi * fl , bool strict )
2007-12-05 01:22:05 -08:00
{
2011-04-04 17:00:54 +02:00
static const struct ipv6_pinfo fake_pinfo ;
static const struct inet_sock fake_sk = {
/* makes ip6_route_output set RT6_LOOKUP_F_IFACE: */
. sk . sk_bound_dev_if = 1 ,
. pinet6 = ( struct ipv6_pinfo * ) & fake_pinfo ,
} ;
const void * sk = strict ? & fake_sk : NULL ;
2011-10-19 13:23:06 +02:00
struct dst_entry * result ;
int err ;
result = ip6_route_output ( net , sk , & fl - > u . ip6 ) ;
err = result - > error ;
if ( err )
dst_release ( result ) ;
else
* dst = result ;
return err ;
2007-12-05 01:22:05 -08:00
}
2019-02-02 10:17:00 +01:00
EXPORT_SYMBOL_GPL ( __nf_ip6_route ) ;
2007-12-05 01:22:05 -08:00
2013-05-17 03:56:10 +00:00
static const struct nf_ipv6_ops ipv6ops = {
2019-02-02 10:16:59 +01:00
# if IS_MODULE(CONFIG_IPV6)
2017-12-20 16:04:18 +01:00
. chk_addr = ipv6_chk_addr ,
2019-02-02 10:16:59 +01:00
. route_me_harder = ip6_route_me_harder ,
. dev_get_saddr = ipv6_dev_get_saddr ,
2019-02-02 10:17:00 +01:00
. route = __nf_ip6_route ,
2019-02-02 10:16:59 +01:00
# endif
2019-02-02 10:17:00 +01:00
. route_input = ip6_route_input ,
2017-12-20 16:04:18 +01:00
. fragment = ip6_fragment ,
2017-11-27 22:50:26 +01:00
. reroute = nf_ip6_reroute ,
2013-05-17 03:56:10 +00:00
} ;
2005-08-09 19:42:34 -07:00
int __init ipv6_netfilter_init ( void )
{
2013-05-17 03:56:10 +00:00
RCU_INIT_POINTER ( nf_ipv6_ops , & ipv6ops ) ;
2017-12-09 17:05:53 +01:00
return 0 ;
2005-08-09 19:42:34 -07:00
}
2006-01-10 21:02:21 -08:00
/* This can be called from inet6_init() on errors, so it cannot
* be marked __exit . - DaveM
*/
void ipv6_netfilter_fini ( void )
2005-08-09 19:42:34 -07:00
{
2013-05-17 03:56:10 +00:00
RCU_INIT_POINTER ( nf_ipv6_ops , NULL ) ;
2005-08-09 19:42:34 -07:00
}