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

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

Version: ~ [ linux-5.10-rc5 ] ~ [ linux-5.9.10 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.79 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.159 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.208 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.245 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.245 ] ~ [ 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.85 ] ~ [ 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-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 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  *
  4  * Generic part shared by ipv4 and ipv6 backends.
  5  */
  6 
  7 #include <linux/kernel.h>
  8 #include <linux/init.h>
  9 #include <linux/module.h>
 10 #include <linux/netlink.h>
 11 #include <linux/netfilter.h>
 12 #include <linux/netfilter/nf_tables.h>
 13 #include <net/netfilter/nf_tables_core.h>
 14 #include <net/netfilter/nf_tables.h>
 15 #include <linux/in.h>
 16 #include <net/xfrm.h>
 17 
 18 static const struct nla_policy nft_xfrm_policy[NFTA_XFRM_MAX + 1] = {
 19         [NFTA_XFRM_KEY]         = { .type = NLA_U32 },
 20         [NFTA_XFRM_DIR]         = { .type = NLA_U8 },
 21         [NFTA_XFRM_SPNUM]       = { .type = NLA_U32 },
 22         [NFTA_XFRM_DREG]        = { .type = NLA_U32 },
 23 };
 24 
 25 struct nft_xfrm {
 26         enum nft_xfrm_keys      key:8;
 27         enum nft_registers      dreg:8;
 28         u8                      dir;
 29         u8                      spnum;
 30 };
 31 
 32 static int nft_xfrm_get_init(const struct nft_ctx *ctx,
 33                              const struct nft_expr *expr,
 34                              const struct nlattr * const tb[])
 35 {
 36         struct nft_xfrm *priv = nft_expr_priv(expr);
 37         unsigned int len = 0;
 38         u32 spnum = 0;
 39         u8 dir;
 40 
 41         if (!tb[NFTA_XFRM_KEY] || !tb[NFTA_XFRM_DIR] || !tb[NFTA_XFRM_DREG])
 42                 return -EINVAL;
 43 
 44         switch (ctx->family) {
 45         case NFPROTO_IPV4:
 46         case NFPROTO_IPV6:
 47         case NFPROTO_INET:
 48                 break;
 49         default:
 50                 return -EOPNOTSUPP;
 51         }
 52 
 53         priv->key = ntohl(nla_get_u32(tb[NFTA_XFRM_KEY]));
 54         switch (priv->key) {
 55         case NFT_XFRM_KEY_REQID:
 56         case NFT_XFRM_KEY_SPI:
 57                 len = sizeof(u32);
 58                 break;
 59         case NFT_XFRM_KEY_DADDR_IP4:
 60         case NFT_XFRM_KEY_SADDR_IP4:
 61                 len = sizeof(struct in_addr);
 62                 break;
 63         case NFT_XFRM_KEY_DADDR_IP6:
 64         case NFT_XFRM_KEY_SADDR_IP6:
 65                 len = sizeof(struct in6_addr);
 66                 break;
 67         default:
 68                 return -EINVAL;
 69         }
 70 
 71         dir = nla_get_u8(tb[NFTA_XFRM_DIR]);
 72         switch (dir) {
 73         case XFRM_POLICY_IN:
 74         case XFRM_POLICY_OUT:
 75                 priv->dir = dir;
 76                 break;
 77         default:
 78                 return -EINVAL;
 79         }
 80 
 81         if (tb[NFTA_XFRM_SPNUM])
 82                 spnum = ntohl(nla_get_be32(tb[NFTA_XFRM_SPNUM]));
 83 
 84         if (spnum >= XFRM_MAX_DEPTH)
 85                 return -ERANGE;
 86 
 87         priv->spnum = spnum;
 88 
 89         priv->dreg = nft_parse_register(tb[NFTA_XFRM_DREG]);
 90         return nft_validate_register_store(ctx, priv->dreg, NULL,
 91                                            NFT_DATA_VALUE, len);
 92 }
 93 
 94 /* Return true if key asks for daddr/saddr and current
 95  * state does have a valid address (BEET, TUNNEL).
 96  */
 97 static bool xfrm_state_addr_ok(enum nft_xfrm_keys k, u8 family, u8 mode)
 98 {
 99         switch (k) {
100         case NFT_XFRM_KEY_DADDR_IP4:
101         case NFT_XFRM_KEY_SADDR_IP4:
102                 if (family == NFPROTO_IPV4)
103                         break;
104                 return false;
105         case NFT_XFRM_KEY_DADDR_IP6:
106         case NFT_XFRM_KEY_SADDR_IP6:
107                 if (family == NFPROTO_IPV6)
108                         break;
109                 return false;
110         default:
111                 return true;
112         }
113 
114         return mode == XFRM_MODE_BEET || mode == XFRM_MODE_TUNNEL;
115 }
116 
117 static void nft_xfrm_state_get_key(const struct nft_xfrm *priv,
118                                    struct nft_regs *regs,
119                                    const struct xfrm_state *state)
120 {
121         u32 *dest = &regs->data[priv->dreg];
122 
123         if (!xfrm_state_addr_ok(priv->key,
124                                 state->props.family,
125                                 state->props.mode)) {
126                 regs->verdict.code = NFT_BREAK;
127                 return;
128         }
129 
130         switch (priv->key) {
131         case NFT_XFRM_KEY_UNSPEC:
132         case __NFT_XFRM_KEY_MAX:
133                 WARN_ON_ONCE(1);
134                 break;
135         case NFT_XFRM_KEY_DADDR_IP4:
136                 *dest = state->id.daddr.a4;
137                 return;
138         case NFT_XFRM_KEY_DADDR_IP6:
139                 memcpy(dest, &state->id.daddr.in6, sizeof(struct in6_addr));
140                 return;
141         case NFT_XFRM_KEY_SADDR_IP4:
142                 *dest = state->props.saddr.a4;
143                 return;
144         case NFT_XFRM_KEY_SADDR_IP6:
145                 memcpy(dest, &state->props.saddr.in6, sizeof(struct in6_addr));
146                 return;
147         case NFT_XFRM_KEY_REQID:
148                 *dest = state->props.reqid;
149                 return;
150         case NFT_XFRM_KEY_SPI:
151                 *dest = state->id.spi;
152                 return;
153         }
154 
155         regs->verdict.code = NFT_BREAK;
156 }
157 
158 static void nft_xfrm_get_eval_in(const struct nft_xfrm *priv,
159                                     struct nft_regs *regs,
160                                     const struct nft_pktinfo *pkt)
161 {
162         const struct sec_path *sp = skb_sec_path(pkt->skb);
163         const struct xfrm_state *state;
164 
165         if (sp == NULL || sp->len <= priv->spnum) {
166                 regs->verdict.code = NFT_BREAK;
167                 return;
168         }
169 
170         state = sp->xvec[priv->spnum];
171         nft_xfrm_state_get_key(priv, regs, state);
172 }
173 
174 static void nft_xfrm_get_eval_out(const struct nft_xfrm *priv,
175                                   struct nft_regs *regs,
176                                   const struct nft_pktinfo *pkt)
177 {
178         const struct dst_entry *dst = skb_dst(pkt->skb);
179         int i;
180 
181         for (i = 0; dst && dst->xfrm;
182              dst = ((const struct xfrm_dst *)dst)->child, i++) {
183                 if (i < priv->spnum)
184                         continue;
185 
186                 nft_xfrm_state_get_key(priv, regs, dst->xfrm);
187                 return;
188         }
189 
190         regs->verdict.code = NFT_BREAK;
191 }
192 
193 static void nft_xfrm_get_eval(const struct nft_expr *expr,
194                               struct nft_regs *regs,
195                               const struct nft_pktinfo *pkt)
196 {
197         const struct nft_xfrm *priv = nft_expr_priv(expr);
198 
199         switch (priv->dir) {
200         case XFRM_POLICY_IN:
201                 nft_xfrm_get_eval_in(priv, regs, pkt);
202                 break;
203         case XFRM_POLICY_OUT:
204                 nft_xfrm_get_eval_out(priv, regs, pkt);
205                 break;
206         default:
207                 WARN_ON_ONCE(1);
208                 regs->verdict.code = NFT_BREAK;
209                 break;
210         }
211 }
212 
213 static int nft_xfrm_get_dump(struct sk_buff *skb,
214                              const struct nft_expr *expr)
215 {
216         const struct nft_xfrm *priv = nft_expr_priv(expr);
217 
218         if (nft_dump_register(skb, NFTA_XFRM_DREG, priv->dreg))
219                 return -1;
220 
221         if (nla_put_be32(skb, NFTA_XFRM_KEY, htonl(priv->key)))
222                 return -1;
223         if (nla_put_u8(skb, NFTA_XFRM_DIR, priv->dir))
224                 return -1;
225         if (nla_put_be32(skb, NFTA_XFRM_SPNUM, htonl(priv->spnum)))
226                 return -1;
227 
228         return 0;
229 }
230 
231 static int nft_xfrm_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
232                              const struct nft_data **data)
233 {
234         const struct nft_xfrm *priv = nft_expr_priv(expr);
235         unsigned int hooks;
236 
237         switch (priv->dir) {
238         case XFRM_POLICY_IN:
239                 hooks = (1 << NF_INET_FORWARD) |
240                         (1 << NF_INET_LOCAL_IN) |
241                         (1 << NF_INET_PRE_ROUTING);
242                 break;
243         case XFRM_POLICY_OUT:
244                 hooks = (1 << NF_INET_FORWARD) |
245                         (1 << NF_INET_LOCAL_OUT) |
246                         (1 << NF_INET_POST_ROUTING);
247                 break;
248         default:
249                 WARN_ON_ONCE(1);
250                 return -EINVAL;
251         }
252 
253         return nft_chain_validate_hooks(ctx->chain, hooks);
254 }
255 
256 
257 static struct nft_expr_type nft_xfrm_type;
258 static const struct nft_expr_ops nft_xfrm_get_ops = {
259         .type           = &nft_xfrm_type,
260         .size           = NFT_EXPR_SIZE(sizeof(struct nft_xfrm)),
261         .eval           = nft_xfrm_get_eval,
262         .init           = nft_xfrm_get_init,
263         .dump           = nft_xfrm_get_dump,
264         .validate       = nft_xfrm_validate,
265 };
266 
267 static struct nft_expr_type nft_xfrm_type __read_mostly = {
268         .name           = "xfrm",
269         .ops            = &nft_xfrm_get_ops,
270         .policy         = nft_xfrm_policy,
271         .maxattr        = NFTA_XFRM_MAX,
272         .owner          = THIS_MODULE,
273 };
274 
275 static int __init nft_xfrm_module_init(void)
276 {
277         return nft_register_expr(&nft_xfrm_type);
278 }
279 
280 static void __exit nft_xfrm_module_exit(void)
281 {
282         nft_unregister_expr(&nft_xfrm_type);
283 }
284 
285 module_init(nft_xfrm_module_init);
286 module_exit(nft_xfrm_module_exit);
287 
288 MODULE_LICENSE("GPL");
289 MODULE_DESCRIPTION("nf_tables: xfrm/IPSec matching");
290 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
291 MODULE_AUTHOR("Máté Eckl <ecklm94@gmail.com>");
292 MODULE_ALIAS_NFT_EXPR("xfrm");
293 

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