Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  * Generic part shared by ipv4 and ipv6 backends.
0005  */
0006 
0007 #include <linux/kernel.h>
0008 #include <linux/init.h>
0009 #include <linux/module.h>
0010 #include <linux/netlink.h>
0011 #include <linux/netfilter.h>
0012 #include <linux/netfilter/nf_tables.h>
0013 #include <net/netfilter/nf_tables_core.h>
0014 #include <net/netfilter/nf_tables.h>
0015 #include <linux/in.h>
0016 #include <net/xfrm.h>
0017 
0018 static const struct nla_policy nft_xfrm_policy[NFTA_XFRM_MAX + 1] = {
0019     [NFTA_XFRM_KEY]     = { .type = NLA_U32 },
0020     [NFTA_XFRM_DIR]     = { .type = NLA_U8 },
0021     [NFTA_XFRM_SPNUM]   = { .type = NLA_U32 },
0022     [NFTA_XFRM_DREG]    = { .type = NLA_U32 },
0023 };
0024 
0025 struct nft_xfrm {
0026     enum nft_xfrm_keys  key:8;
0027     u8          dreg;
0028     u8          dir;
0029     u8          spnum;
0030     u8          len;
0031 };
0032 
0033 static int nft_xfrm_get_init(const struct nft_ctx *ctx,
0034                  const struct nft_expr *expr,
0035                  const struct nlattr * const tb[])
0036 {
0037     struct nft_xfrm *priv = nft_expr_priv(expr);
0038     unsigned int len = 0;
0039     u32 spnum = 0;
0040     u8 dir;
0041 
0042     if (!tb[NFTA_XFRM_KEY] || !tb[NFTA_XFRM_DIR] || !tb[NFTA_XFRM_DREG])
0043         return -EINVAL;
0044 
0045     switch (ctx->family) {
0046     case NFPROTO_IPV4:
0047     case NFPROTO_IPV6:
0048     case NFPROTO_INET:
0049         break;
0050     default:
0051         return -EOPNOTSUPP;
0052     }
0053 
0054     priv->key = ntohl(nla_get_be32(tb[NFTA_XFRM_KEY]));
0055     switch (priv->key) {
0056     case NFT_XFRM_KEY_REQID:
0057     case NFT_XFRM_KEY_SPI:
0058         len = sizeof(u32);
0059         break;
0060     case NFT_XFRM_KEY_DADDR_IP4:
0061     case NFT_XFRM_KEY_SADDR_IP4:
0062         len = sizeof(struct in_addr);
0063         break;
0064     case NFT_XFRM_KEY_DADDR_IP6:
0065     case NFT_XFRM_KEY_SADDR_IP6:
0066         len = sizeof(struct in6_addr);
0067         break;
0068     default:
0069         return -EINVAL;
0070     }
0071 
0072     dir = nla_get_u8(tb[NFTA_XFRM_DIR]);
0073     switch (dir) {
0074     case XFRM_POLICY_IN:
0075     case XFRM_POLICY_OUT:
0076         priv->dir = dir;
0077         break;
0078     default:
0079         return -EINVAL;
0080     }
0081 
0082     if (tb[NFTA_XFRM_SPNUM])
0083         spnum = ntohl(nla_get_be32(tb[NFTA_XFRM_SPNUM]));
0084 
0085     if (spnum >= XFRM_MAX_DEPTH)
0086         return -ERANGE;
0087 
0088     priv->spnum = spnum;
0089 
0090     priv->len = len;
0091     return nft_parse_register_store(ctx, tb[NFTA_XFRM_DREG], &priv->dreg,
0092                     NULL, NFT_DATA_VALUE, len);
0093 }
0094 
0095 /* Return true if key asks for daddr/saddr and current
0096  * state does have a valid address (BEET, TUNNEL).
0097  */
0098 static bool xfrm_state_addr_ok(enum nft_xfrm_keys k, u8 family, u8 mode)
0099 {
0100     switch (k) {
0101     case NFT_XFRM_KEY_DADDR_IP4:
0102     case NFT_XFRM_KEY_SADDR_IP4:
0103         if (family == NFPROTO_IPV4)
0104             break;
0105         return false;
0106     case NFT_XFRM_KEY_DADDR_IP6:
0107     case NFT_XFRM_KEY_SADDR_IP6:
0108         if (family == NFPROTO_IPV6)
0109             break;
0110         return false;
0111     default:
0112         return true;
0113     }
0114 
0115     return mode == XFRM_MODE_BEET || mode == XFRM_MODE_TUNNEL;
0116 }
0117 
0118 static void nft_xfrm_state_get_key(const struct nft_xfrm *priv,
0119                    struct nft_regs *regs,
0120                    const struct xfrm_state *state)
0121 {
0122     u32 *dest = &regs->data[priv->dreg];
0123 
0124     if (!xfrm_state_addr_ok(priv->key,
0125                 state->props.family,
0126                 state->props.mode)) {
0127         regs->verdict.code = NFT_BREAK;
0128         return;
0129     }
0130 
0131     switch (priv->key) {
0132     case NFT_XFRM_KEY_UNSPEC:
0133     case __NFT_XFRM_KEY_MAX:
0134         WARN_ON_ONCE(1);
0135         break;
0136     case NFT_XFRM_KEY_DADDR_IP4:
0137         *dest = (__force __u32)state->id.daddr.a4;
0138         return;
0139     case NFT_XFRM_KEY_DADDR_IP6:
0140         memcpy(dest, &state->id.daddr.in6, sizeof(struct in6_addr));
0141         return;
0142     case NFT_XFRM_KEY_SADDR_IP4:
0143         *dest = (__force __u32)state->props.saddr.a4;
0144         return;
0145     case NFT_XFRM_KEY_SADDR_IP6:
0146         memcpy(dest, &state->props.saddr.in6, sizeof(struct in6_addr));
0147         return;
0148     case NFT_XFRM_KEY_REQID:
0149         *dest = state->props.reqid;
0150         return;
0151     case NFT_XFRM_KEY_SPI:
0152         *dest = (__force __u32)state->id.spi;
0153         return;
0154     }
0155 
0156     regs->verdict.code = NFT_BREAK;
0157 }
0158 
0159 static void nft_xfrm_get_eval_in(const struct nft_xfrm *priv,
0160                     struct nft_regs *regs,
0161                     const struct nft_pktinfo *pkt)
0162 {
0163     const struct sec_path *sp = skb_sec_path(pkt->skb);
0164     const struct xfrm_state *state;
0165 
0166     if (sp == NULL || sp->len <= priv->spnum) {
0167         regs->verdict.code = NFT_BREAK;
0168         return;
0169     }
0170 
0171     state = sp->xvec[priv->spnum];
0172     nft_xfrm_state_get_key(priv, regs, state);
0173 }
0174 
0175 static void nft_xfrm_get_eval_out(const struct nft_xfrm *priv,
0176                   struct nft_regs *regs,
0177                   const struct nft_pktinfo *pkt)
0178 {
0179     const struct dst_entry *dst = skb_dst(pkt->skb);
0180     int i;
0181 
0182     for (i = 0; dst && dst->xfrm;
0183          dst = ((const struct xfrm_dst *)dst)->child, i++) {
0184         if (i < priv->spnum)
0185             continue;
0186 
0187         nft_xfrm_state_get_key(priv, regs, dst->xfrm);
0188         return;
0189     }
0190 
0191     regs->verdict.code = NFT_BREAK;
0192 }
0193 
0194 static void nft_xfrm_get_eval(const struct nft_expr *expr,
0195                   struct nft_regs *regs,
0196                   const struct nft_pktinfo *pkt)
0197 {
0198     const struct nft_xfrm *priv = nft_expr_priv(expr);
0199 
0200     switch (priv->dir) {
0201     case XFRM_POLICY_IN:
0202         nft_xfrm_get_eval_in(priv, regs, pkt);
0203         break;
0204     case XFRM_POLICY_OUT:
0205         nft_xfrm_get_eval_out(priv, regs, pkt);
0206         break;
0207     default:
0208         WARN_ON_ONCE(1);
0209         regs->verdict.code = NFT_BREAK;
0210         break;
0211     }
0212 }
0213 
0214 static int nft_xfrm_get_dump(struct sk_buff *skb,
0215                  const struct nft_expr *expr)
0216 {
0217     const struct nft_xfrm *priv = nft_expr_priv(expr);
0218 
0219     if (nft_dump_register(skb, NFTA_XFRM_DREG, priv->dreg))
0220         return -1;
0221 
0222     if (nla_put_be32(skb, NFTA_XFRM_KEY, htonl(priv->key)))
0223         return -1;
0224     if (nla_put_u8(skb, NFTA_XFRM_DIR, priv->dir))
0225         return -1;
0226     if (nla_put_be32(skb, NFTA_XFRM_SPNUM, htonl(priv->spnum)))
0227         return -1;
0228 
0229     return 0;
0230 }
0231 
0232 static int nft_xfrm_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
0233                  const struct nft_data **data)
0234 {
0235     const struct nft_xfrm *priv = nft_expr_priv(expr);
0236     unsigned int hooks;
0237 
0238     switch (priv->dir) {
0239     case XFRM_POLICY_IN:
0240         hooks = (1 << NF_INET_FORWARD) |
0241             (1 << NF_INET_LOCAL_IN) |
0242             (1 << NF_INET_PRE_ROUTING);
0243         break;
0244     case XFRM_POLICY_OUT:
0245         hooks = (1 << NF_INET_FORWARD) |
0246             (1 << NF_INET_LOCAL_OUT) |
0247             (1 << NF_INET_POST_ROUTING);
0248         break;
0249     default:
0250         WARN_ON_ONCE(1);
0251         return -EINVAL;
0252     }
0253 
0254     return nft_chain_validate_hooks(ctx->chain, hooks);
0255 }
0256 
0257 static bool nft_xfrm_reduce(struct nft_regs_track *track,
0258                 const struct nft_expr *expr)
0259 {
0260     const struct nft_xfrm *priv = nft_expr_priv(expr);
0261     const struct nft_xfrm *xfrm;
0262 
0263     if (!nft_reg_track_cmp(track, expr, priv->dreg)) {
0264         nft_reg_track_update(track, expr, priv->dreg, priv->len);
0265         return false;
0266     }
0267 
0268     xfrm = nft_expr_priv(track->regs[priv->dreg].selector);
0269     if (priv->key != xfrm->key ||
0270         priv->dreg != xfrm->dreg ||
0271         priv->dir != xfrm->dir ||
0272         priv->spnum != xfrm->spnum) {
0273         nft_reg_track_update(track, expr, priv->dreg, priv->len);
0274         return false;
0275     }
0276 
0277     if (!track->regs[priv->dreg].bitwise)
0278         return true;
0279 
0280     return nft_expr_reduce_bitwise(track, expr);
0281 }
0282 
0283 static struct nft_expr_type nft_xfrm_type;
0284 static const struct nft_expr_ops nft_xfrm_get_ops = {
0285     .type       = &nft_xfrm_type,
0286     .size       = NFT_EXPR_SIZE(sizeof(struct nft_xfrm)),
0287     .eval       = nft_xfrm_get_eval,
0288     .init       = nft_xfrm_get_init,
0289     .dump       = nft_xfrm_get_dump,
0290     .validate   = nft_xfrm_validate,
0291     .reduce     = nft_xfrm_reduce,
0292 };
0293 
0294 static struct nft_expr_type nft_xfrm_type __read_mostly = {
0295     .name       = "xfrm",
0296     .ops        = &nft_xfrm_get_ops,
0297     .policy     = nft_xfrm_policy,
0298     .maxattr    = NFTA_XFRM_MAX,
0299     .owner      = THIS_MODULE,
0300 };
0301 
0302 static int __init nft_xfrm_module_init(void)
0303 {
0304     return nft_register_expr(&nft_xfrm_type);
0305 }
0306 
0307 static void __exit nft_xfrm_module_exit(void)
0308 {
0309     nft_unregister_expr(&nft_xfrm_type);
0310 }
0311 
0312 module_init(nft_xfrm_module_init);
0313 module_exit(nft_xfrm_module_exit);
0314 
0315 MODULE_LICENSE("GPL");
0316 MODULE_DESCRIPTION("nf_tables: xfrm/IPSec matching");
0317 MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
0318 MODULE_AUTHOR("Máté Eckl <ecklm94@gmail.com>");
0319 MODULE_ALIAS_NFT_EXPR("xfrm");