Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo@debian.org>
0004  */
0005 
0006 #include <linux/kernel.h>
0007 #include <linux/init.h>
0008 #include <linux/module.h>
0009 #include <linux/netlink.h>
0010 #include <linux/netfilter.h>
0011 #include <linux/netfilter/nf_tables.h>
0012 #include <net/netfilter/nf_tables.h>
0013 #include <net/netfilter/nf_nat.h>
0014 #include <net/netfilter/nf_nat_masquerade.h>
0015 
0016 struct nft_masq {
0017     u32         flags;
0018     u8          sreg_proto_min;
0019     u8          sreg_proto_max;
0020 };
0021 
0022 static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = {
0023     [NFTA_MASQ_FLAGS]       = { .type = NLA_U32 },
0024     [NFTA_MASQ_REG_PROTO_MIN]   = { .type = NLA_U32 },
0025     [NFTA_MASQ_REG_PROTO_MAX]   = { .type = NLA_U32 },
0026 };
0027 
0028 static int nft_masq_validate(const struct nft_ctx *ctx,
0029                  const struct nft_expr *expr,
0030                  const struct nft_data **data)
0031 {
0032     int err;
0033 
0034     err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
0035     if (err < 0)
0036         return err;
0037 
0038     return nft_chain_validate_hooks(ctx->chain,
0039                         (1 << NF_INET_POST_ROUTING));
0040 }
0041 
0042 static int nft_masq_init(const struct nft_ctx *ctx,
0043              const struct nft_expr *expr,
0044              const struct nlattr * const tb[])
0045 {
0046     u32 plen = sizeof_field(struct nf_nat_range, min_addr.all);
0047     struct nft_masq *priv = nft_expr_priv(expr);
0048     int err;
0049 
0050     if (tb[NFTA_MASQ_FLAGS]) {
0051         priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS]));
0052         if (priv->flags & ~NF_NAT_RANGE_MASK)
0053             return -EINVAL;
0054     }
0055 
0056     if (tb[NFTA_MASQ_REG_PROTO_MIN]) {
0057         err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MIN],
0058                           &priv->sreg_proto_min, plen);
0059         if (err < 0)
0060             return err;
0061 
0062         if (tb[NFTA_MASQ_REG_PROTO_MAX]) {
0063             err = nft_parse_register_load(tb[NFTA_MASQ_REG_PROTO_MAX],
0064                               &priv->sreg_proto_max,
0065                               plen);
0066             if (err < 0)
0067                 return err;
0068         } else {
0069             priv->sreg_proto_max = priv->sreg_proto_min;
0070         }
0071     }
0072 
0073     return nf_ct_netns_get(ctx->net, ctx->family);
0074 }
0075 
0076 static int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr)
0077 {
0078     const struct nft_masq *priv = nft_expr_priv(expr);
0079 
0080     if (priv->flags != 0 &&
0081         nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags)))
0082         goto nla_put_failure;
0083 
0084     if (priv->sreg_proto_min) {
0085         if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN,
0086                       priv->sreg_proto_min) ||
0087             nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX,
0088                       priv->sreg_proto_max))
0089             goto nla_put_failure;
0090     }
0091 
0092     return 0;
0093 
0094 nla_put_failure:
0095     return -1;
0096 }
0097 
0098 static void nft_masq_ipv4_eval(const struct nft_expr *expr,
0099                    struct nft_regs *regs,
0100                    const struct nft_pktinfo *pkt)
0101 {
0102     struct nft_masq *priv = nft_expr_priv(expr);
0103     struct nf_nat_range2 range;
0104 
0105     memset(&range, 0, sizeof(range));
0106     range.flags = priv->flags;
0107     if (priv->sreg_proto_min) {
0108         range.min_proto.all = (__force __be16)nft_reg_load16(
0109             &regs->data[priv->sreg_proto_min]);
0110         range.max_proto.all = (__force __be16)nft_reg_load16(
0111             &regs->data[priv->sreg_proto_max]);
0112     }
0113     regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, nft_hook(pkt),
0114                             &range, nft_out(pkt));
0115 }
0116 
0117 static void
0118 nft_masq_ipv4_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
0119 {
0120     nf_ct_netns_put(ctx->net, NFPROTO_IPV4);
0121 }
0122 
0123 static struct nft_expr_type nft_masq_ipv4_type;
0124 static const struct nft_expr_ops nft_masq_ipv4_ops = {
0125     .type       = &nft_masq_ipv4_type,
0126     .size       = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
0127     .eval       = nft_masq_ipv4_eval,
0128     .init       = nft_masq_init,
0129     .destroy    = nft_masq_ipv4_destroy,
0130     .dump       = nft_masq_dump,
0131     .validate   = nft_masq_validate,
0132     .reduce     = NFT_REDUCE_READONLY,
0133 };
0134 
0135 static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
0136     .family     = NFPROTO_IPV4,
0137     .name       = "masq",
0138     .ops        = &nft_masq_ipv4_ops,
0139     .policy     = nft_masq_policy,
0140     .maxattr    = NFTA_MASQ_MAX,
0141     .owner      = THIS_MODULE,
0142 };
0143 
0144 #ifdef CONFIG_NF_TABLES_IPV6
0145 static void nft_masq_ipv6_eval(const struct nft_expr *expr,
0146                    struct nft_regs *regs,
0147                    const struct nft_pktinfo *pkt)
0148 {
0149     struct nft_masq *priv = nft_expr_priv(expr);
0150     struct nf_nat_range2 range;
0151 
0152     memset(&range, 0, sizeof(range));
0153     range.flags = priv->flags;
0154     if (priv->sreg_proto_min) {
0155         range.min_proto.all = (__force __be16)nft_reg_load16(
0156             &regs->data[priv->sreg_proto_min]);
0157         range.max_proto.all = (__force __be16)nft_reg_load16(
0158             &regs->data[priv->sreg_proto_max]);
0159     }
0160     regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range,
0161                             nft_out(pkt));
0162 }
0163 
0164 static void
0165 nft_masq_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
0166 {
0167     nf_ct_netns_put(ctx->net, NFPROTO_IPV6);
0168 }
0169 
0170 static struct nft_expr_type nft_masq_ipv6_type;
0171 static const struct nft_expr_ops nft_masq_ipv6_ops = {
0172     .type       = &nft_masq_ipv6_type,
0173     .size       = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
0174     .eval       = nft_masq_ipv6_eval,
0175     .init       = nft_masq_init,
0176     .destroy    = nft_masq_ipv6_destroy,
0177     .dump       = nft_masq_dump,
0178     .validate   = nft_masq_validate,
0179     .reduce     = NFT_REDUCE_READONLY,
0180 };
0181 
0182 static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
0183     .family     = NFPROTO_IPV6,
0184     .name       = "masq",
0185     .ops        = &nft_masq_ipv6_ops,
0186     .policy     = nft_masq_policy,
0187     .maxattr    = NFTA_MASQ_MAX,
0188     .owner      = THIS_MODULE,
0189 };
0190 
0191 static int __init nft_masq_module_init_ipv6(void)
0192 {
0193     return nft_register_expr(&nft_masq_ipv6_type);
0194 }
0195 
0196 static void nft_masq_module_exit_ipv6(void)
0197 {
0198     nft_unregister_expr(&nft_masq_ipv6_type);
0199 }
0200 #else
0201 static inline int nft_masq_module_init_ipv6(void) { return 0; }
0202 static inline void nft_masq_module_exit_ipv6(void) {}
0203 #endif
0204 
0205 #ifdef CONFIG_NF_TABLES_INET
0206 static void nft_masq_inet_eval(const struct nft_expr *expr,
0207                    struct nft_regs *regs,
0208                    const struct nft_pktinfo *pkt)
0209 {
0210     switch (nft_pf(pkt)) {
0211     case NFPROTO_IPV4:
0212         return nft_masq_ipv4_eval(expr, regs, pkt);
0213     case NFPROTO_IPV6:
0214         return nft_masq_ipv6_eval(expr, regs, pkt);
0215     }
0216 
0217     WARN_ON_ONCE(1);
0218 }
0219 
0220 static void
0221 nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
0222 {
0223     nf_ct_netns_put(ctx->net, NFPROTO_INET);
0224 }
0225 
0226 static struct nft_expr_type nft_masq_inet_type;
0227 static const struct nft_expr_ops nft_masq_inet_ops = {
0228     .type       = &nft_masq_inet_type,
0229     .size       = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
0230     .eval       = nft_masq_inet_eval,
0231     .init       = nft_masq_init,
0232     .destroy    = nft_masq_inet_destroy,
0233     .dump       = nft_masq_dump,
0234     .validate   = nft_masq_validate,
0235     .reduce     = NFT_REDUCE_READONLY,
0236 };
0237 
0238 static struct nft_expr_type nft_masq_inet_type __read_mostly = {
0239     .family     = NFPROTO_INET,
0240     .name       = "masq",
0241     .ops        = &nft_masq_inet_ops,
0242     .policy     = nft_masq_policy,
0243     .maxattr    = NFTA_MASQ_MAX,
0244     .owner      = THIS_MODULE,
0245 };
0246 
0247 static int __init nft_masq_module_init_inet(void)
0248 {
0249     return nft_register_expr(&nft_masq_inet_type);
0250 }
0251 
0252 static void nft_masq_module_exit_inet(void)
0253 {
0254     nft_unregister_expr(&nft_masq_inet_type);
0255 }
0256 #else
0257 static inline int nft_masq_module_init_inet(void) { return 0; }
0258 static inline void nft_masq_module_exit_inet(void) {}
0259 #endif
0260 
0261 static int __init nft_masq_module_init(void)
0262 {
0263     int ret;
0264 
0265     ret = nft_masq_module_init_ipv6();
0266     if (ret < 0)
0267         return ret;
0268 
0269     ret = nft_masq_module_init_inet();
0270     if (ret < 0) {
0271         nft_masq_module_exit_ipv6();
0272         return ret;
0273     }
0274 
0275     ret = nft_register_expr(&nft_masq_ipv4_type);
0276     if (ret < 0) {
0277         nft_masq_module_exit_inet();
0278         nft_masq_module_exit_ipv6();
0279         return ret;
0280     }
0281 
0282     ret = nf_nat_masquerade_inet_register_notifiers();
0283     if (ret < 0) {
0284         nft_masq_module_exit_ipv6();
0285         nft_masq_module_exit_inet();
0286         nft_unregister_expr(&nft_masq_ipv4_type);
0287         return ret;
0288     }
0289 
0290     return ret;
0291 }
0292 
0293 static void __exit nft_masq_module_exit(void)
0294 {
0295     nft_masq_module_exit_ipv6();
0296     nft_masq_module_exit_inet();
0297     nft_unregister_expr(&nft_masq_ipv4_type);
0298     nf_nat_masquerade_inet_unregister_notifiers();
0299 }
0300 
0301 module_init(nft_masq_module_init);
0302 module_exit(nft_masq_module_exit);
0303 
0304 MODULE_LICENSE("GPL");
0305 MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
0306 MODULE_ALIAS_NFT_EXPR("masq");
0307 MODULE_DESCRIPTION("Netfilter nftables masquerade expression support");