LCOV - code coverage report
Current view: top level - net/ipv6 - netfilter.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 64 0.0 %
Date: 2014-04-07 Functions: 0 8 0.0 %
Branches: 0 46 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * IPv6 specific functions of netfilter core
       3                 :            :  *
       4                 :            :  * Rusty Russell (C) 2000 -- This code is GPL.
       5                 :            :  * Patrick McHardy (C) 2006-2012
       6                 :            :  */
       7                 :            : #include <linux/kernel.h>
       8                 :            : #include <linux/init.h>
       9                 :            : #include <linux/ipv6.h>
      10                 :            : #include <linux/netfilter.h>
      11                 :            : #include <linux/netfilter_ipv6.h>
      12                 :            : #include <linux/export.h>
      13                 :            : #include <net/addrconf.h>
      14                 :            : #include <net/dst.h>
      15                 :            : #include <net/ipv6.h>
      16                 :            : #include <net/ip6_route.h>
      17                 :            : #include <net/xfrm.h>
      18                 :            : #include <net/ip6_checksum.h>
      19                 :            : #include <net/netfilter/nf_queue.h>
      20                 :            : 
      21                 :          0 : int ip6_route_me_harder(struct sk_buff *skb)
      22                 :            : {
      23                 :            :         struct net *net = dev_net(skb_dst(skb)->dev);
      24                 :            :         const struct ipv6hdr *iph = ipv6_hdr(skb);
      25                 :            :         unsigned int hh_len;
      26                 :            :         struct dst_entry *dst;
      27                 :          0 :         struct flowi6 fl6 = {
      28         [ #  # ]:          0 :                 .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
      29                 :          0 :                 .flowi6_mark = skb->mark,
      30                 :            :                 .daddr = iph->daddr,
      31                 :            :                 .saddr = iph->saddr,
      32                 :            :         };
      33                 :            : 
      34                 :          0 :         dst = ip6_route_output(net, skb->sk, &fl6);
      35         [ #  # ]:          0 :         if (dst->error) {
      36         [ #  # ]:          0 :                 IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
      37 [ #  # ][ #  # ]:          0 :                 LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
      38                 :          0 :                 dst_release(dst);
      39                 :          0 :                 return dst->error;
      40                 :            :         }
      41                 :            : 
      42                 :            :         /* Drop old route. */
      43                 :            :         skb_dst_drop(skb);
      44                 :            : 
      45                 :            :         skb_dst_set(skb, dst);
      46                 :            : 
      47                 :            : #ifdef CONFIG_XFRM
      48   [ #  #  #  # ]:          0 :         if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
      49                 :            :             xfrm_decode_session(skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) {
      50                 :            :                 skb_dst_set(skb, NULL);
      51                 :          0 :                 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0);
      52         [ #  # ]:          0 :                 if (IS_ERR(dst))
      53                 :          0 :                         return PTR_ERR(dst);
      54                 :            :                 skb_dst_set(skb, dst);
      55                 :            :         }
      56                 :            : #endif
      57                 :            : 
      58                 :            :         /* Change in oif may mean change in hh_len. */
      59                 :          0 :         hh_len = skb_dst(skb)->dev->hard_header_len;
      60   [ #  #  #  # ]:          0 :         if (skb_headroom(skb) < hh_len &&
      61                 :          0 :             pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)),
      62                 :            :                              0, GFP_ATOMIC))
      63                 :            :                 return -ENOMEM;
      64                 :            : 
      65                 :            :         return 0;
      66                 :            : }
      67                 :            : EXPORT_SYMBOL(ip6_route_me_harder);
      68                 :            : 
      69                 :            : /*
      70                 :            :  * Extra routing may needed on local out, as the QUEUE target never
      71                 :            :  * returns control to the table.
      72                 :            :  */
      73                 :            : 
      74                 :            : struct ip6_rt_info {
      75                 :            :         struct in6_addr daddr;
      76                 :            :         struct in6_addr saddr;
      77                 :            :         u_int32_t mark;
      78                 :            : };
      79                 :            : 
      80                 :          0 : static void nf_ip6_saveroute(const struct sk_buff *skb,
      81                 :            :                              struct nf_queue_entry *entry)
      82                 :            : {
      83                 :            :         struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
      84                 :            : 
      85         [ #  # ]:          0 :         if (entry->hook == NF_INET_LOCAL_OUT) {
      86                 :            :                 const struct ipv6hdr *iph = ipv6_hdr(skb);
      87                 :            : 
      88                 :          0 :                 rt_info->daddr = iph->daddr;
      89                 :          0 :                 rt_info->saddr = iph->saddr;
      90                 :          0 :                 rt_info->mark = skb->mark;
      91                 :            :         }
      92                 :          0 : }
      93                 :            : 
      94                 :          0 : static int nf_ip6_reroute(struct sk_buff *skb,
      95                 :            :                           const struct nf_queue_entry *entry)
      96                 :            : {
      97                 :            :         struct ip6_rt_info *rt_info = nf_queue_entry_reroute(entry);
      98                 :            : 
      99         [ #  # ]:          0 :         if (entry->hook == NF_INET_LOCAL_OUT) {
     100                 :            :                 const struct ipv6hdr *iph = ipv6_hdr(skb);
     101 [ #  # ][ #  # ]:          0 :                 if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) ||
     102         [ #  # ]:          0 :                     !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) ||
     103                 :          0 :                     skb->mark != rt_info->mark)
     104                 :          0 :                         return ip6_route_me_harder(skb);
     105                 :            :         }
     106                 :            :         return 0;
     107                 :            : }
     108                 :            : 
     109                 :          0 : static int nf_ip6_route(struct net *net, struct dst_entry **dst,
     110                 :            :                         struct flowi *fl, bool strict)
     111                 :            : {
     112                 :            :         static const struct ipv6_pinfo fake_pinfo;
     113                 :            :         static const struct inet_sock fake_sk = {
     114                 :            :                 /* makes ip6_route_output set RT6_LOOKUP_F_IFACE: */
     115                 :            :                 .sk.sk_bound_dev_if = 1,
     116                 :            :                 .pinet6 = (struct ipv6_pinfo *) &fake_pinfo,
     117                 :            :         };
     118         [ #  # ]:          0 :         const void *sk = strict ? &fake_sk : NULL;
     119                 :            :         struct dst_entry *result;
     120                 :            :         int err;
     121                 :            : 
     122                 :          0 :         result = ip6_route_output(net, sk, &fl->u.ip6);
     123                 :          0 :         err = result->error;
     124         [ #  # ]:          0 :         if (err)
     125                 :          0 :                 dst_release(result);
     126                 :            :         else
     127                 :          0 :                 *dst = result;
     128                 :          0 :         return err;
     129                 :            : }
     130                 :            : 
     131                 :          0 : __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,
     132                 :            :                              unsigned int dataoff, u_int8_t protocol)
     133                 :            : {
     134                 :            :         const struct ipv6hdr *ip6h = ipv6_hdr(skb);
     135                 :            :         __sum16 csum = 0;
     136                 :            : 
     137      [ #  #  # ]:          0 :         switch (skb->ip_summed) {
     138                 :            :         case CHECKSUM_COMPLETE:
     139         [ #  # ]:          0 :                 if (hook != NF_INET_PRE_ROUTING && hook != NF_INET_LOCAL_IN)
     140                 :            :                         break;
     141         [ #  # ]:          0 :                 if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
     142                 :          0 :                                      skb->len - dataoff, protocol,
     143                 :            :                                      csum_sub(skb->csum,
     144                 :            :                                               skb_checksum(skb, 0,
     145                 :            :                                                            dataoff, 0)))) {
     146                 :          0 :                         skb->ip_summed = CHECKSUM_UNNECESSARY;
     147                 :          0 :                         break;
     148                 :            :                 }
     149                 :            :                 /* fall through */
     150                 :            :         case CHECKSUM_NONE:
     151                 :          0 :                 skb->csum = ~csum_unfold(
     152                 :            :                                 csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
     153                 :          0 :                                              skb->len - dataoff,
     154                 :            :                                              protocol,
     155                 :            :                                              csum_sub(0,
     156                 :            :                                                       skb_checksum(skb, 0,
     157                 :            :                                                                    dataoff, 0))));
     158                 :          0 :                 csum = __skb_checksum_complete(skb);
     159                 :            :         }
     160                 :          0 :         return csum;
     161                 :            : }
     162                 :            : EXPORT_SYMBOL(nf_ip6_checksum);
     163                 :            : 
     164                 :          0 : static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
     165                 :            :                                        unsigned int dataoff, unsigned int len,
     166                 :            :                                        u_int8_t protocol)
     167                 :            : {
     168                 :            :         const struct ipv6hdr *ip6h = ipv6_hdr(skb);
     169                 :            :         __wsum hsum;
     170                 :            :         __sum16 csum = 0;
     171                 :            : 
     172      [ #  #  # ]:          0 :         switch (skb->ip_summed) {
     173                 :            :         case CHECKSUM_COMPLETE:
     174         [ #  # ]:          0 :                 if (len == skb->len - dataoff)
     175                 :          0 :                         return nf_ip6_checksum(skb, hook, dataoff, protocol);
     176                 :            :                 /* fall through */
     177                 :            :         case CHECKSUM_NONE:
     178                 :          0 :                 hsum = skb_checksum(skb, 0, dataoff, 0);
     179                 :          0 :                 skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
     180                 :            :                                                          &ip6h->daddr,
     181                 :          0 :                                                          skb->len - dataoff,
     182                 :            :                                                          protocol,
     183                 :            :                                                          csum_sub(0, hsum)));
     184                 :          0 :                 skb->ip_summed = CHECKSUM_NONE;
     185                 :          0 :                 return __skb_checksum_complete_head(skb, dataoff + len);
     186                 :            :         }
     187                 :            :         return csum;
     188                 :            : };
     189                 :            : 
     190                 :            : static const struct nf_ipv6_ops ipv6ops = {
     191                 :            :         .chk_addr       = ipv6_chk_addr,
     192                 :            : };
     193                 :            : 
     194                 :            : static const struct nf_afinfo nf_ip6_afinfo = {
     195                 :            :         .family                 = AF_INET6,
     196                 :            :         .checksum               = nf_ip6_checksum,
     197                 :            :         .checksum_partial       = nf_ip6_checksum_partial,
     198                 :            :         .route                  = nf_ip6_route,
     199                 :            :         .saveroute              = nf_ip6_saveroute,
     200                 :            :         .reroute                = nf_ip6_reroute,
     201                 :            :         .route_key_size         = sizeof(struct ip6_rt_info),
     202                 :            : };
     203                 :            : 
     204                 :          0 : int __init ipv6_netfilter_init(void)
     205                 :            : {
     206                 :          0 :         RCU_INIT_POINTER(nf_ipv6_ops, &ipv6ops);
     207                 :          0 :         return nf_register_afinfo(&nf_ip6_afinfo);
     208                 :            : }
     209                 :            : 
     210                 :            : /* This can be called from inet6_init() on errors, so it cannot
     211                 :            :  * be marked __exit. -DaveM
     212                 :            :  */
     213                 :          0 : void ipv6_netfilter_fini(void)
     214                 :            : {
     215                 :          0 :         RCU_INIT_POINTER(nf_ipv6_ops, NULL);
     216                 :          0 :         nf_unregister_afinfo(&nf_ip6_afinfo);
     217                 :          0 : }

Generated by: LCOV version 1.9