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

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

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ 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  * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
  3  * Copyright (c) 2012 Intel Corporation
  4  *
  5  * This program is free software; you can redistribute it and/or modify it
  6  * under the terms and conditions of the GNU General Public License,
  7  * version 2, as published by the Free Software Foundation.
  8  *
  9  */
 10 
 11 #include <linux/module.h>
 12 #include <linux/init.h>
 13 #include <linux/list.h>
 14 #include <linux/skbuff.h>
 15 #include <linux/ip.h>
 16 #include <linux/netfilter.h>
 17 #include <linux/netfilter_ipv6.h>
 18 #include <linux/netfilter/nf_tables.h>
 19 #include <net/netfilter/nf_conntrack.h>
 20 #include <net/netfilter/nf_nat.h>
 21 #include <net/netfilter/nf_nat_core.h>
 22 #include <net/netfilter/nf_tables.h>
 23 #include <net/netfilter/nf_tables_ipv6.h>
 24 #include <net/netfilter/nf_nat_l3proto.h>
 25 #include <net/ipv6.h>
 26 
 27 /*
 28  * IPv6 NAT chains
 29  */
 30 
 31 static unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops,
 32                               struct sk_buff *skb,
 33                               const struct net_device *in,
 34                               const struct net_device *out,
 35                               int (*okfn)(struct sk_buff *))
 36 {
 37         enum ip_conntrack_info ctinfo;
 38         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
 39         struct nf_conn_nat *nat;
 40         enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
 41         __be16 frag_off;
 42         int hdrlen;
 43         u8 nexthdr;
 44         struct nft_pktinfo pkt;
 45         unsigned int ret;
 46 
 47         if (ct == NULL || nf_ct_is_untracked(ct))
 48                 return NF_ACCEPT;
 49 
 50         nat = nfct_nat(ct);
 51         if (nat == NULL) {
 52                 /* Conntrack module was loaded late, can't add extension. */
 53                 if (nf_ct_is_confirmed(ct))
 54                         return NF_ACCEPT;
 55                 nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC);
 56                 if (nat == NULL)
 57                         return NF_ACCEPT;
 58         }
 59 
 60         switch (ctinfo) {
 61         case IP_CT_RELATED:
 62         case IP_CT_RELATED + IP_CT_IS_REPLY:
 63                 nexthdr = ipv6_hdr(skb)->nexthdr;
 64                 hdrlen = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr),
 65                                           &nexthdr, &frag_off);
 66 
 67                 if (hdrlen >= 0 && nexthdr == IPPROTO_ICMPV6) {
 68                         if (!nf_nat_icmpv6_reply_translation(skb, ct, ctinfo,
 69                                                            ops->hooknum,
 70                                                            hdrlen))
 71                                 return NF_DROP;
 72                         else
 73                                 return NF_ACCEPT;
 74                 }
 75                 /* Fall through */
 76         case IP_CT_NEW:
 77                 if (nf_nat_initialized(ct, maniptype))
 78                         break;
 79 
 80                 nft_set_pktinfo_ipv6(&pkt, ops, skb, in, out);
 81 
 82                 ret = nft_do_chain(&pkt, ops);
 83                 if (ret != NF_ACCEPT)
 84                         return ret;
 85                 if (!nf_nat_initialized(ct, maniptype)) {
 86                         ret = nf_nat_alloc_null_binding(ct, ops->hooknum);
 87                         if (ret != NF_ACCEPT)
 88                                 return ret;
 89                 }
 90         default:
 91                 break;
 92         }
 93 
 94         return nf_nat_packet(ct, ctinfo, ops->hooknum, skb);
 95 }
 96 
 97 static unsigned int nf_nat_ipv6_prerouting(const struct nf_hook_ops *ops,
 98                                       struct sk_buff *skb,
 99                                       const struct net_device *in,
100                                       const struct net_device *out,
101                                       int (*okfn)(struct sk_buff *))
102 {
103         struct in6_addr daddr = ipv6_hdr(skb)->daddr;
104         unsigned int ret;
105 
106         ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
107         if (ret != NF_DROP && ret != NF_STOLEN &&
108             ipv6_addr_cmp(&daddr, &ipv6_hdr(skb)->daddr))
109                 skb_dst_drop(skb);
110 
111         return ret;
112 }
113 
114 static unsigned int nf_nat_ipv6_postrouting(const struct nf_hook_ops *ops,
115                                        struct sk_buff *skb,
116                                        const struct net_device *in,
117                                        const struct net_device *out,
118                                        int (*okfn)(struct sk_buff *))
119 {
120         enum ip_conntrack_info ctinfo __maybe_unused;
121         const struct nf_conn *ct __maybe_unused;
122         unsigned int ret;
123 
124         ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
125 #ifdef CONFIG_XFRM
126         if (ret != NF_DROP && ret != NF_STOLEN &&
127             !(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
128             (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
129                 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
130 
131                 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
132                                       &ct->tuplehash[!dir].tuple.dst.u3) ||
133                     (ct->tuplehash[dir].tuple.src.u.all !=
134                      ct->tuplehash[!dir].tuple.dst.u.all))
135                         if (nf_xfrm_me_harder(skb, AF_INET6) < 0)
136                                 ret = NF_DROP;
137         }
138 #endif
139         return ret;
140 }
141 
142 static unsigned int nf_nat_ipv6_output(const struct nf_hook_ops *ops,
143                                   struct sk_buff *skb,
144                                   const struct net_device *in,
145                                   const struct net_device *out,
146                                   int (*okfn)(struct sk_buff *))
147 {
148         enum ip_conntrack_info ctinfo;
149         const struct nf_conn *ct;
150         unsigned int ret;
151 
152         ret = nf_nat_ipv6_fn(ops, skb, in, out, okfn);
153         if (ret != NF_DROP && ret != NF_STOLEN &&
154             (ct = nf_ct_get(skb, &ctinfo)) != NULL) {
155                 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
156 
157                 if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
158                                       &ct->tuplehash[!dir].tuple.src.u3)) {
159                         if (ip6_route_me_harder(skb))
160                                 ret = NF_DROP;
161                 }
162 #ifdef CONFIG_XFRM
163                 else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
164                          ct->tuplehash[dir].tuple.dst.u.all !=
165                          ct->tuplehash[!dir].tuple.src.u.all)
166                         if (nf_xfrm_me_harder(skb, AF_INET6))
167                                 ret = NF_DROP;
168 #endif
169         }
170         return ret;
171 }
172 
173 static const struct nf_chain_type nft_chain_nat_ipv6 = {
174         .name           = "nat",
175         .type           = NFT_CHAIN_T_NAT,
176         .family         = NFPROTO_IPV6,
177         .owner          = THIS_MODULE,
178         .hook_mask      = (1 << NF_INET_PRE_ROUTING) |
179                           (1 << NF_INET_POST_ROUTING) |
180                           (1 << NF_INET_LOCAL_OUT) |
181                           (1 << NF_INET_LOCAL_IN),
182         .hooks          = {
183                 [NF_INET_PRE_ROUTING]   = nf_nat_ipv6_prerouting,
184                 [NF_INET_POST_ROUTING]  = nf_nat_ipv6_postrouting,
185                 [NF_INET_LOCAL_OUT]     = nf_nat_ipv6_output,
186                 [NF_INET_LOCAL_IN]      = nf_nat_ipv6_fn,
187         },
188 };
189 
190 static int __init nft_chain_nat_ipv6_init(void)
191 {
192         int err;
193 
194         err = nft_register_chain_type(&nft_chain_nat_ipv6);
195         if (err < 0)
196                 return err;
197 
198         return 0;
199 }
200 
201 static void __exit nft_chain_nat_ipv6_exit(void)
202 {
203         nft_unregister_chain_type(&nft_chain_nat_ipv6);
204 }
205 
206 module_init(nft_chain_nat_ipv6_init);
207 module_exit(nft_chain_nat_ipv6_exit);
208 
209 MODULE_LICENSE("GPL");
210 MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
211 MODULE_ALIAS_NFT_CHAIN(AF_INET6, "nat");
212 

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