1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2014 Arturo Borrero Gonzalez <[email protected]> 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/init.h> 8 #include <linux/module.h> 9 #include <linux/netlink.h> 10 #include <linux/netfilter.h> 11 #include <linux/netfilter/nf_tables.h> 12 #include <net/netfilter/nf_tables.h> 13 #include <net/netfilter/nf_nat.h> 14 #include <net/netfilter/nf_nat_masquerade.h> 15 16 struct nft_masq { 17 u32 flags; 18 u8 sreg_proto_min; 19 u8 sreg_proto_max; 20 }; 21 22 static const struct nla_policy nft_masq_policy[NFTA_MASQ_MAX + 1] = { 23 [NFTA_MASQ_FLAGS] = 24 NLA_POLICY_MASK(NLA_BE32, NF_NAT_RANGE_MASK), 25 [NFTA_MASQ_REG_PROTO_MIN] = { .type = NLA_U32 }, 26 [NFTA_MASQ_REG_PROTO_MAX] = { .type = NLA_U32 }, 27 }; 28 29 static int nft_masq_validate(const struct nft_ctx *ctx, 30 const struct nft_expr *expr, 31 const struct nft_data **data) 32 { 33 int err; 34 35 err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); 36 if (err < 0) 37 return err; 38 39 return nft_chain_validate_hooks(ctx->chain, 40 (1 << NF_INET_POST_ROUTING)); 41 } 42 43 static int nft_masq_init(const struct nft_ctx *ctx, 44 const struct nft_expr *expr, 45 const struct nlattr * const tb[]) 46 { 47 u32 plen = sizeof_field(struct nf_nat_range, min_proto.all); 48 struct nft_masq *priv = nft_expr_priv(expr); 49 int err; 50 51 if (tb[NFTA_MASQ_FLAGS]) 52 priv->flags = ntohl(nla_get_be32(tb[NFTA_MASQ_FLAGS])); 53 54 if (tb[NFTA_MASQ_REG_PROTO_MIN]) { 55 err = nft_parse_register_load(ctx, tb[NFTA_MASQ_REG_PROTO_MIN], 56 &priv->sreg_proto_min, plen); 57 if (err < 0) 58 return err; 59 60 if (tb[NFTA_MASQ_REG_PROTO_MAX]) { 61 err = nft_parse_register_load(ctx, tb[NFTA_MASQ_REG_PROTO_MAX], 62 &priv->sreg_proto_max, 63 plen); 64 if (err < 0) 65 return err; 66 } else { 67 priv->sreg_proto_max = priv->sreg_proto_min; 68 } 69 } 70 71 return nf_ct_netns_get(ctx->net, ctx->family); 72 } 73 74 static int nft_masq_dump(struct sk_buff *skb, 75 const struct nft_expr *expr, bool reset) 76 { 77 const struct nft_masq *priv = nft_expr_priv(expr); 78 79 if (priv->flags != 0 && 80 nla_put_be32(skb, NFTA_MASQ_FLAGS, htonl(priv->flags))) 81 goto nla_put_failure; 82 83 if (priv->sreg_proto_min) { 84 if (nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MIN, 85 priv->sreg_proto_min) || 86 nft_dump_register(skb, NFTA_MASQ_REG_PROTO_MAX, 87 priv->sreg_proto_max)) 88 goto nla_put_failure; 89 } 90 91 return 0; 92 93 nla_put_failure: 94 return -1; 95 } 96 97 static void nft_masq_eval(const struct nft_expr *expr, 98 struct nft_regs *regs, 99 const struct nft_pktinfo *pkt) 100 { 101 const struct nft_masq *priv = nft_expr_priv(expr); 102 struct nf_nat_range2 range; 103 104 memset(&range, 0, sizeof(range)); 105 range.flags = priv->flags; 106 if (priv->sreg_proto_min) { 107 range.min_proto.all = (__force __be16) 108 nft_reg_load16(®s->data[priv->sreg_proto_min]); 109 range.max_proto.all = (__force __be16) 110 nft_reg_load16(®s->data[priv->sreg_proto_max]); 111 } 112 113 switch (nft_pf(pkt)) { 114 case NFPROTO_IPV4: 115 regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, 116 nft_hook(pkt), 117 &range, 118 nft_out(pkt)); 119 break; 120 #ifdef CONFIG_NF_TABLES_IPV6 121 case NFPROTO_IPV6: 122 regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, 123 nft_out(pkt)); 124 break; 125 #endif 126 default: 127 WARN_ON_ONCE(1); 128 break; 129 } 130 } 131 132 static void 133 nft_masq_ipv4_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) 134 { 135 nf_ct_netns_put(ctx->net, NFPROTO_IPV4); 136 } 137 138 static struct nft_expr_type nft_masq_ipv4_type; 139 static const struct nft_expr_ops nft_masq_ipv4_ops = { 140 .type = &nft_masq_ipv4_type, 141 .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)), 142 .eval = nft_masq_eval, 143 .init = nft_masq_init, 144 .destroy = nft_masq_ipv4_destroy, 145 .dump = nft_masq_dump, 146 .validate = nft_masq_validate, 147 .reduce = NFT_REDUCE_READONLY, 148 }; 149 150 static struct nft_expr_type nft_masq_ipv4_type __read_mostly = { 151 .family = NFPROTO_IPV4, 152 .name = "masq", 153 .ops = &nft_masq_ipv4_ops, 154 .policy = nft_masq_policy, 155 .maxattr = NFTA_MASQ_MAX, 156 .owner = THIS_MODULE, 157 }; 158 159 #ifdef CONFIG_NF_TABLES_IPV6 160 static void 161 nft_masq_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) 162 { 163 nf_ct_netns_put(ctx->net, NFPROTO_IPV6); 164 } 165 166 static struct nft_expr_type nft_masq_ipv6_type; 167 static const struct nft_expr_ops nft_masq_ipv6_ops = { 168 .type = &nft_masq_ipv6_type, 169 .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)), 170 .eval = nft_masq_eval, 171 .init = nft_masq_init, 172 .destroy = nft_masq_ipv6_destroy, 173 .dump = nft_masq_dump, 174 .validate = nft_masq_validate, 175 .reduce = NFT_REDUCE_READONLY, 176 }; 177 178 static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { 179 .family = NFPROTO_IPV6, 180 .name = "masq", 181 .ops = &nft_masq_ipv6_ops, 182 .policy = nft_masq_policy, 183 .maxattr = NFTA_MASQ_MAX, 184 .owner = THIS_MODULE, 185 }; 186 187 static int __init nft_masq_module_init_ipv6(void) 188 { 189 return nft_register_expr(&nft_masq_ipv6_type); 190 } 191 192 static void nft_masq_module_exit_ipv6(void) 193 { 194 nft_unregister_expr(&nft_masq_ipv6_type); 195 } 196 #else 197 static inline int nft_masq_module_init_ipv6(void) { return 0; } 198 static inline void nft_masq_module_exit_ipv6(void) {} 199 #endif 200 201 #ifdef CONFIG_NF_TABLES_INET 202 static void 203 nft_masq_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) 204 { 205 nf_ct_netns_put(ctx->net, NFPROTO_INET); 206 } 207 208 static struct nft_expr_type nft_masq_inet_type; 209 static const struct nft_expr_ops nft_masq_inet_ops = { 210 .type = &nft_masq_inet_type, 211 .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)), 212 .eval = nft_masq_eval, 213 .init = nft_masq_init, 214 .destroy = nft_masq_inet_destroy, 215 .dump = nft_masq_dump, 216 .validate = nft_masq_validate, 217 .reduce = NFT_REDUCE_READONLY, 218 }; 219 220 static struct nft_expr_type nft_masq_inet_type __read_mostly = { 221 .family = NFPROTO_INET, 222 .name = "masq", 223 .ops = &nft_masq_inet_ops, 224 .policy = nft_masq_policy, 225 .maxattr = NFTA_MASQ_MAX, 226 .owner = THIS_MODULE, 227 }; 228 229 static int __init nft_masq_module_init_inet(void) 230 { 231 return nft_register_expr(&nft_masq_inet_type); 232 } 233 234 static void nft_masq_module_exit_inet(void) 235 { 236 nft_unregister_expr(&nft_masq_inet_type); 237 } 238 #else 239 static inline int nft_masq_module_init_inet(void) { return 0; } 240 static inline void nft_masq_module_exit_inet(void) {} 241 #endif 242 243 static int __init nft_masq_module_init(void) 244 { 245 int ret; 246 247 ret = nft_masq_module_init_ipv6(); 248 if (ret < 0) 249 return ret; 250 251 ret = nft_masq_module_init_inet(); 252 if (ret < 0) { 253 nft_masq_module_exit_ipv6(); 254 return ret; 255 } 256 257 ret = nft_register_expr(&nft_masq_ipv4_type); 258 if (ret < 0) { 259 nft_masq_module_exit_inet(); 260 nft_masq_module_exit_ipv6(); 261 return ret; 262 } 263 264 ret = nf_nat_masquerade_inet_register_notifiers(); 265 if (ret < 0) { 266 nft_masq_module_exit_ipv6(); 267 nft_masq_module_exit_inet(); 268 nft_unregister_expr(&nft_masq_ipv4_type); 269 return ret; 270 } 271 272 return ret; 273 } 274 275 static void __exit nft_masq_module_exit(void) 276 { 277 nft_masq_module_exit_ipv6(); 278 nft_masq_module_exit_inet(); 279 nft_unregister_expr(&nft_masq_ipv4_type); 280 nf_nat_masquerade_inet_unregister_notifiers(); 281 } 282 283 module_init(nft_masq_module_init); 284 module_exit(nft_masq_module_exit); 285 286 MODULE_LICENSE("GPL"); 287 MODULE_AUTHOR("Arturo Borrero Gonzalez <[email protected]>"); 288 MODULE_ALIAS_NFT_EXPR("masq"); 289 MODULE_DESCRIPTION("Netfilter nftables masquerade expression support"); 290