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

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

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

~ [ 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