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>
18 enum nft_registers sreg_proto_min
:8;
19 enum nft_registers sreg_proto_max
:8;
22 static const struct nla_policy nft_masq_policy
[NFTA_MASQ_MAX
+ 1] = {
23 [NFTA_MASQ_FLAGS
] = { .type
= NLA_U32
},
24 [NFTA_MASQ_REG_PROTO_MIN
] = { .type
= NLA_U32
},
25 [NFTA_MASQ_REG_PROTO_MAX
] = { .type
= NLA_U32
},
28 static int nft_masq_validate(const struct nft_ctx
*ctx
,
29 const struct nft_expr
*expr
,
30 const struct nft_data
**data
)
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
= FIELD_SIZEOF(struct nf_nat_range
, min_addr
.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
]));
52 if (priv
->flags
& ~NF_NAT_RANGE_MASK
)
56 if (tb
[NFTA_MASQ_REG_PROTO_MIN
]) {
57 priv
->sreg_proto_min
=
58 nft_parse_register(tb
[NFTA_MASQ_REG_PROTO_MIN
]);
60 err
= nft_validate_register_load(priv
->sreg_proto_min
, plen
);
64 if (tb
[NFTA_MASQ_REG_PROTO_MAX
]) {
65 priv
->sreg_proto_max
=
66 nft_parse_register(tb
[NFTA_MASQ_REG_PROTO_MAX
]);
68 err
= nft_validate_register_load(priv
->sreg_proto_max
,
73 priv
->sreg_proto_max
= priv
->sreg_proto_min
;
77 return nf_ct_netns_get(ctx
->net
, ctx
->family
);
80 static int nft_masq_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
82 const struct nft_masq
*priv
= nft_expr_priv(expr
);
84 if (priv
->flags
!= 0 &&
85 nla_put_be32(skb
, NFTA_MASQ_FLAGS
, htonl(priv
->flags
)))
88 if (priv
->sreg_proto_min
) {
89 if (nft_dump_register(skb
, NFTA_MASQ_REG_PROTO_MIN
,
90 priv
->sreg_proto_min
) ||
91 nft_dump_register(skb
, NFTA_MASQ_REG_PROTO_MAX
,
92 priv
->sreg_proto_max
))
102 static void nft_masq_ipv4_eval(const struct nft_expr
*expr
,
103 struct nft_regs
*regs
,
104 const struct nft_pktinfo
*pkt
)
106 struct nft_masq
*priv
= nft_expr_priv(expr
);
107 struct nf_nat_range2 range
;
109 memset(&range
, 0, sizeof(range
));
110 range
.flags
= priv
->flags
;
111 if (priv
->sreg_proto_min
) {
112 range
.min_proto
.all
= (__force __be16
)nft_reg_load16(
113 ®s
->data
[priv
->sreg_proto_min
]);
114 range
.max_proto
.all
= (__force __be16
)nft_reg_load16(
115 ®s
->data
[priv
->sreg_proto_max
]);
117 regs
->verdict
.code
= nf_nat_masquerade_ipv4(pkt
->skb
, nft_hook(pkt
),
118 &range
, nft_out(pkt
));
122 nft_masq_ipv4_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
124 nf_ct_netns_put(ctx
->net
, NFPROTO_IPV4
);
127 static struct nft_expr_type nft_masq_ipv4_type
;
128 static const struct nft_expr_ops nft_masq_ipv4_ops
= {
129 .type
= &nft_masq_ipv4_type
,
130 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
131 .eval
= nft_masq_ipv4_eval
,
132 .init
= nft_masq_init
,
133 .destroy
= nft_masq_ipv4_destroy
,
134 .dump
= nft_masq_dump
,
135 .validate
= nft_masq_validate
,
138 static struct nft_expr_type nft_masq_ipv4_type __read_mostly
= {
139 .family
= NFPROTO_IPV4
,
141 .ops
= &nft_masq_ipv4_ops
,
142 .policy
= nft_masq_policy
,
143 .maxattr
= NFTA_MASQ_MAX
,
144 .owner
= THIS_MODULE
,
147 #ifdef CONFIG_NF_TABLES_IPV6
148 static void nft_masq_ipv6_eval(const struct nft_expr
*expr
,
149 struct nft_regs
*regs
,
150 const struct nft_pktinfo
*pkt
)
152 struct nft_masq
*priv
= nft_expr_priv(expr
);
153 struct nf_nat_range2 range
;
155 memset(&range
, 0, sizeof(range
));
156 range
.flags
= priv
->flags
;
157 if (priv
->sreg_proto_min
) {
158 range
.min_proto
.all
= (__force __be16
)nft_reg_load16(
159 ®s
->data
[priv
->sreg_proto_min
]);
160 range
.max_proto
.all
= (__force __be16
)nft_reg_load16(
161 ®s
->data
[priv
->sreg_proto_max
]);
163 regs
->verdict
.code
= nf_nat_masquerade_ipv6(pkt
->skb
, &range
,
168 nft_masq_ipv6_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
170 nf_ct_netns_put(ctx
->net
, NFPROTO_IPV6
);
173 static struct nft_expr_type nft_masq_ipv6_type
;
174 static const struct nft_expr_ops nft_masq_ipv6_ops
= {
175 .type
= &nft_masq_ipv6_type
,
176 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
177 .eval
= nft_masq_ipv6_eval
,
178 .init
= nft_masq_init
,
179 .destroy
= nft_masq_ipv6_destroy
,
180 .dump
= nft_masq_dump
,
181 .validate
= nft_masq_validate
,
184 static struct nft_expr_type nft_masq_ipv6_type __read_mostly
= {
185 .family
= NFPROTO_IPV6
,
187 .ops
= &nft_masq_ipv6_ops
,
188 .policy
= nft_masq_policy
,
189 .maxattr
= NFTA_MASQ_MAX
,
190 .owner
= THIS_MODULE
,
193 static int __init
nft_masq_module_init_ipv6(void)
195 return nft_register_expr(&nft_masq_ipv6_type
);
198 static void nft_masq_module_exit_ipv6(void)
200 nft_unregister_expr(&nft_masq_ipv6_type
);
203 static inline int nft_masq_module_init_ipv6(void) { return 0; }
204 static inline void nft_masq_module_exit_ipv6(void) {}
207 #ifdef CONFIG_NF_TABLES_INET
208 static void nft_masq_inet_eval(const struct nft_expr
*expr
,
209 struct nft_regs
*regs
,
210 const struct nft_pktinfo
*pkt
)
212 switch (nft_pf(pkt
)) {
214 return nft_masq_ipv4_eval(expr
, regs
, pkt
);
216 return nft_masq_ipv6_eval(expr
, regs
, pkt
);
223 nft_masq_inet_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
225 nf_ct_netns_put(ctx
->net
, NFPROTO_INET
);
228 static struct nft_expr_type nft_masq_inet_type
;
229 static const struct nft_expr_ops nft_masq_inet_ops
= {
230 .type
= &nft_masq_inet_type
,
231 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
232 .eval
= nft_masq_inet_eval
,
233 .init
= nft_masq_init
,
234 .destroy
= nft_masq_inet_destroy
,
235 .dump
= nft_masq_dump
,
236 .validate
= nft_masq_validate
,
239 static struct nft_expr_type nft_masq_inet_type __read_mostly
= {
240 .family
= NFPROTO_INET
,
242 .ops
= &nft_masq_inet_ops
,
243 .policy
= nft_masq_policy
,
244 .maxattr
= NFTA_MASQ_MAX
,
245 .owner
= THIS_MODULE
,
248 static int __init
nft_masq_module_init_inet(void)
250 return nft_register_expr(&nft_masq_inet_type
);
253 static void nft_masq_module_exit_inet(void)
255 nft_unregister_expr(&nft_masq_inet_type
);
258 static inline int nft_masq_module_init_inet(void) { return 0; }
259 static inline void nft_masq_module_exit_inet(void) {}
262 static int __init
nft_masq_module_init(void)
266 ret
= nft_masq_module_init_ipv6();
270 ret
= nft_masq_module_init_inet();
272 nft_masq_module_exit_ipv6();
276 ret
= nft_register_expr(&nft_masq_ipv4_type
);
278 nft_masq_module_exit_inet();
279 nft_masq_module_exit_ipv6();
283 ret
= nf_nat_masquerade_inet_register_notifiers();
285 nft_masq_module_exit_ipv6();
286 nft_masq_module_exit_inet();
287 nft_unregister_expr(&nft_masq_ipv4_type
);
294 static void __exit
nft_masq_module_exit(void)
296 nft_masq_module_exit_ipv6();
297 nft_masq_module_exit_inet();
298 nft_unregister_expr(&nft_masq_ipv4_type
);
299 nf_nat_masquerade_inet_unregister_notifiers();
302 module_init(nft_masq_module_init
);
303 module_exit(nft_masq_module_exit
);
305 MODULE_LICENSE("GPL");
306 MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
307 MODULE_ALIAS_NFT_EXPR("masq");