root/net/netfilter/nft_xfrm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nft_xfrm_get_init
  2. xfrm_state_addr_ok
  3. nft_xfrm_state_get_key
  4. nft_xfrm_get_eval_in
  5. nft_xfrm_get_eval_out
  6. nft_xfrm_get_eval
  7. nft_xfrm_get_dump
  8. nft_xfrm_validate
  9. nft_xfrm_module_init
  10. nft_xfrm_module_exit

   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");

/* [<][>][^][v][top][bottom][index][help] */