0001
0002
0003
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 ®s->data[priv->sreg_proto_min]);
0110 range.max_proto.all = (__force __be16)nft_reg_load16(
0111 ®s->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 ®s->data[priv->sreg_proto_min]);
0157 range.max_proto.all = (__force __be16)nft_reg_load16(
0158 ®s->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");