1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo@debian.org>
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>
22 static const struct nla_policy nft_masq_policy
[NFTA_MASQ_MAX
+ 1] = {
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
},
29 static int nft_masq_validate(const struct nft_ctx
*ctx
,
30 const struct nft_expr
*expr
)
34 err
= nft_chain_validate_dependency(ctx
->chain
, NFT_CHAIN_T_NAT
);
38 return nft_chain_validate_hooks(ctx
->chain
,
39 (1 << NF_INET_POST_ROUTING
));
42 static int nft_masq_init(const struct nft_ctx
*ctx
,
43 const struct nft_expr
*expr
,
44 const struct nlattr
* const tb
[])
46 u32 plen
= sizeof_field(struct nf_nat_range
, min_proto
.all
);
47 struct nft_masq
*priv
= nft_expr_priv(expr
);
50 if (tb
[NFTA_MASQ_FLAGS
])
51 priv
->flags
= ntohl(nla_get_be32(tb
[NFTA_MASQ_FLAGS
]));
53 if (tb
[NFTA_MASQ_REG_PROTO_MIN
]) {
54 err
= nft_parse_register_load(ctx
, tb
[NFTA_MASQ_REG_PROTO_MIN
],
55 &priv
->sreg_proto_min
, plen
);
59 if (tb
[NFTA_MASQ_REG_PROTO_MAX
]) {
60 err
= nft_parse_register_load(ctx
, tb
[NFTA_MASQ_REG_PROTO_MAX
],
61 &priv
->sreg_proto_max
,
66 priv
->sreg_proto_max
= priv
->sreg_proto_min
;
70 return nf_ct_netns_get(ctx
->net
, ctx
->family
);
73 static int nft_masq_dump(struct sk_buff
*skb
,
74 const struct nft_expr
*expr
, bool reset
)
76 const struct nft_masq
*priv
= nft_expr_priv(expr
);
78 if (priv
->flags
!= 0 &&
79 nla_put_be32(skb
, NFTA_MASQ_FLAGS
, htonl(priv
->flags
)))
82 if (priv
->sreg_proto_min
) {
83 if (nft_dump_register(skb
, NFTA_MASQ_REG_PROTO_MIN
,
84 priv
->sreg_proto_min
) ||
85 nft_dump_register(skb
, NFTA_MASQ_REG_PROTO_MAX
,
86 priv
->sreg_proto_max
))
96 static void nft_masq_eval(const struct nft_expr
*expr
,
97 struct nft_regs
*regs
,
98 const struct nft_pktinfo
*pkt
)
100 const struct nft_masq
*priv
= nft_expr_priv(expr
);
101 struct nf_nat_range2 range
;
103 memset(&range
, 0, sizeof(range
));
104 range
.flags
= priv
->flags
;
105 if (priv
->sreg_proto_min
) {
106 range
.min_proto
.all
= (__force __be16
)
107 nft_reg_load16(®s
->data
[priv
->sreg_proto_min
]);
108 range
.max_proto
.all
= (__force __be16
)
109 nft_reg_load16(®s
->data
[priv
->sreg_proto_max
]);
112 switch (nft_pf(pkt
)) {
114 regs
->verdict
.code
= nf_nat_masquerade_ipv4(pkt
->skb
,
119 #ifdef CONFIG_NF_TABLES_IPV6
121 regs
->verdict
.code
= nf_nat_masquerade_ipv6(pkt
->skb
, &range
,
132 nft_masq_ipv4_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
134 nf_ct_netns_put(ctx
->net
, NFPROTO_IPV4
);
137 static struct nft_expr_type nft_masq_ipv4_type
;
138 static const struct nft_expr_ops nft_masq_ipv4_ops
= {
139 .type
= &nft_masq_ipv4_type
,
140 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
141 .eval
= nft_masq_eval
,
142 .init
= nft_masq_init
,
143 .destroy
= nft_masq_ipv4_destroy
,
144 .dump
= nft_masq_dump
,
145 .validate
= nft_masq_validate
,
146 .reduce
= NFT_REDUCE_READONLY
,
149 static struct nft_expr_type nft_masq_ipv4_type __read_mostly
= {
150 .family
= NFPROTO_IPV4
,
152 .ops
= &nft_masq_ipv4_ops
,
153 .policy
= nft_masq_policy
,
154 .maxattr
= NFTA_MASQ_MAX
,
155 .owner
= THIS_MODULE
,
158 #ifdef CONFIG_NF_TABLES_IPV6
160 nft_masq_ipv6_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
162 nf_ct_netns_put(ctx
->net
, NFPROTO_IPV6
);
165 static struct nft_expr_type nft_masq_ipv6_type
;
166 static const struct nft_expr_ops nft_masq_ipv6_ops
= {
167 .type
= &nft_masq_ipv6_type
,
168 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
169 .eval
= nft_masq_eval
,
170 .init
= nft_masq_init
,
171 .destroy
= nft_masq_ipv6_destroy
,
172 .dump
= nft_masq_dump
,
173 .validate
= nft_masq_validate
,
174 .reduce
= NFT_REDUCE_READONLY
,
177 static struct nft_expr_type nft_masq_ipv6_type __read_mostly
= {
178 .family
= NFPROTO_IPV6
,
180 .ops
= &nft_masq_ipv6_ops
,
181 .policy
= nft_masq_policy
,
182 .maxattr
= NFTA_MASQ_MAX
,
183 .owner
= THIS_MODULE
,
186 static int __init
nft_masq_module_init_ipv6(void)
188 return nft_register_expr(&nft_masq_ipv6_type
);
191 static void nft_masq_module_exit_ipv6(void)
193 nft_unregister_expr(&nft_masq_ipv6_type
);
196 static inline int nft_masq_module_init_ipv6(void) { return 0; }
197 static inline void nft_masq_module_exit_ipv6(void) {}
200 #ifdef CONFIG_NF_TABLES_INET
202 nft_masq_inet_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
204 nf_ct_netns_put(ctx
->net
, NFPROTO_INET
);
207 static struct nft_expr_type nft_masq_inet_type
;
208 static const struct nft_expr_ops nft_masq_inet_ops
= {
209 .type
= &nft_masq_inet_type
,
210 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
211 .eval
= nft_masq_eval
,
212 .init
= nft_masq_init
,
213 .destroy
= nft_masq_inet_destroy
,
214 .dump
= nft_masq_dump
,
215 .validate
= nft_masq_validate
,
216 .reduce
= NFT_REDUCE_READONLY
,
219 static struct nft_expr_type nft_masq_inet_type __read_mostly
= {
220 .family
= NFPROTO_INET
,
222 .ops
= &nft_masq_inet_ops
,
223 .policy
= nft_masq_policy
,
224 .maxattr
= NFTA_MASQ_MAX
,
225 .owner
= THIS_MODULE
,
228 static int __init
nft_masq_module_init_inet(void)
230 return nft_register_expr(&nft_masq_inet_type
);
233 static void nft_masq_module_exit_inet(void)
235 nft_unregister_expr(&nft_masq_inet_type
);
238 static inline int nft_masq_module_init_inet(void) { return 0; }
239 static inline void nft_masq_module_exit_inet(void) {}
242 static int __init
nft_masq_module_init(void)
246 ret
= nft_masq_module_init_ipv6();
250 ret
= nft_masq_module_init_inet();
252 nft_masq_module_exit_ipv6();
256 ret
= nft_register_expr(&nft_masq_ipv4_type
);
258 nft_masq_module_exit_inet();
259 nft_masq_module_exit_ipv6();
263 ret
= nf_nat_masquerade_inet_register_notifiers();
265 nft_masq_module_exit_ipv6();
266 nft_masq_module_exit_inet();
267 nft_unregister_expr(&nft_masq_ipv4_type
);
274 static void __exit
nft_masq_module_exit(void)
276 nft_masq_module_exit_ipv6();
277 nft_masq_module_exit_inet();
278 nft_unregister_expr(&nft_masq_ipv4_type
);
279 nf_nat_masquerade_inet_unregister_notifiers();
282 module_init(nft_masq_module_init
);
283 module_exit(nft_masq_module_exit
);
285 MODULE_LICENSE("GPL");
286 MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
287 MODULE_ALIAS_NFT_EXPR("masq");
288 MODULE_DESCRIPTION("Netfilter nftables masquerade expression support");