~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/ipv6/netfilter.c

Version: ~ [ linux-5.13-rc2 ] ~ [ linux-5.12.4 ] ~ [ linux-5.11.21 ] ~ [ linux-5.10.37 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.119 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp