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] = {
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
= sizeof_field(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 err
= nft_parse_register_load(tb
[NFTA_MASQ_REG_PROTO_MIN
],
58 &priv
->sreg_proto_min
, plen
);
62 if (tb
[NFTA_MASQ_REG_PROTO_MAX
]) {
63 err
= nft_parse_register_load(tb
[NFTA_MASQ_REG_PROTO_MAX
],
64 &priv
->sreg_proto_max
,
69 priv
->sreg_proto_max
= priv
->sreg_proto_min
;
73 return nf_ct_netns_get(ctx
->net
, ctx
->family
);
76 static int nft_masq_dump(struct sk_buff
*skb
, const struct nft_expr
*expr
)
78 const struct nft_masq
*priv
= nft_expr_priv(expr
);
80 if (priv
->flags
!= 0 &&
81 nla_put_be32(skb
, NFTA_MASQ_FLAGS
, htonl(priv
->flags
)))
84 if (priv
->sreg_proto_min
) {
85 if (nft_dump_register(skb
, NFTA_MASQ_REG_PROTO_MIN
,
86 priv
->sreg_proto_min
) ||
87 nft_dump_register(skb
, NFTA_MASQ_REG_PROTO_MAX
,
88 priv
->sreg_proto_max
))
98 static void nft_masq_ipv4_eval(const struct nft_expr
*expr
,
99 struct nft_regs
*regs
,
100 const struct nft_pktinfo
*pkt
)
102 struct nft_masq
*priv
= nft_expr_priv(expr
);
103 struct nf_nat_range2 range
;
105 memset(&range
, 0, sizeof(range
));
106 range
.flags
= priv
->flags
;
107 if (priv
->sreg_proto_min
) {
108 range
.min_proto
.all
= (__force __be16
)nft_reg_load16(
109 ®s
->data
[priv
->sreg_proto_min
]);
110 range
.max_proto
.all
= (__force __be16
)nft_reg_load16(
111 ®s
->data
[priv
->sreg_proto_max
]);
113 regs
->verdict
.code
= nf_nat_masquerade_ipv4(pkt
->skb
, nft_hook(pkt
),
114 &range
, nft_out(pkt
));
118 nft_masq_ipv4_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
120 nf_ct_netns_put(ctx
->net
, NFPROTO_IPV4
);
123 static struct nft_expr_type nft_masq_ipv4_type
;
124 static const struct nft_expr_ops nft_masq_ipv4_ops
= {
125 .type
= &nft_masq_ipv4_type
,
126 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
127 .eval
= nft_masq_ipv4_eval
,
128 .init
= nft_masq_init
,
129 .destroy
= nft_masq_ipv4_destroy
,
130 .dump
= nft_masq_dump
,
131 .validate
= nft_masq_validate
,
134 static struct nft_expr_type nft_masq_ipv4_type __read_mostly
= {
135 .family
= NFPROTO_IPV4
,
137 .ops
= &nft_masq_ipv4_ops
,
138 .policy
= nft_masq_policy
,
139 .maxattr
= NFTA_MASQ_MAX
,
140 .owner
= THIS_MODULE
,
143 #ifdef CONFIG_NF_TABLES_IPV6
144 static void nft_masq_ipv6_eval(const struct nft_expr
*expr
,
145 struct nft_regs
*regs
,
146 const struct nft_pktinfo
*pkt
)
148 struct nft_masq
*priv
= nft_expr_priv(expr
);
149 struct nf_nat_range2 range
;
151 memset(&range
, 0, sizeof(range
));
152 range
.flags
= priv
->flags
;
153 if (priv
->sreg_proto_min
) {
154 range
.min_proto
.all
= (__force __be16
)nft_reg_load16(
155 ®s
->data
[priv
->sreg_proto_min
]);
156 range
.max_proto
.all
= (__force __be16
)nft_reg_load16(
157 ®s
->data
[priv
->sreg_proto_max
]);
159 regs
->verdict
.code
= nf_nat_masquerade_ipv6(pkt
->skb
, &range
,
164 nft_masq_ipv6_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
166 nf_ct_netns_put(ctx
->net
, NFPROTO_IPV6
);
169 static struct nft_expr_type nft_masq_ipv6_type
;
170 static const struct nft_expr_ops nft_masq_ipv6_ops
= {
171 .type
= &nft_masq_ipv6_type
,
172 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
173 .eval
= nft_masq_ipv6_eval
,
174 .init
= nft_masq_init
,
175 .destroy
= nft_masq_ipv6_destroy
,
176 .dump
= nft_masq_dump
,
177 .validate
= nft_masq_validate
,
180 static struct nft_expr_type nft_masq_ipv6_type __read_mostly
= {
181 .family
= NFPROTO_IPV6
,
183 .ops
= &nft_masq_ipv6_ops
,
184 .policy
= nft_masq_policy
,
185 .maxattr
= NFTA_MASQ_MAX
,
186 .owner
= THIS_MODULE
,
189 static int __init
nft_masq_module_init_ipv6(void)
191 return nft_register_expr(&nft_masq_ipv6_type
);
194 static void nft_masq_module_exit_ipv6(void)
196 nft_unregister_expr(&nft_masq_ipv6_type
);
199 static inline int nft_masq_module_init_ipv6(void) { return 0; }
200 static inline void nft_masq_module_exit_ipv6(void) {}
203 #ifdef CONFIG_NF_TABLES_INET
204 static void nft_masq_inet_eval(const struct nft_expr
*expr
,
205 struct nft_regs
*regs
,
206 const struct nft_pktinfo
*pkt
)
208 switch (nft_pf(pkt
)) {
210 return nft_masq_ipv4_eval(expr
, regs
, pkt
);
212 return nft_masq_ipv6_eval(expr
, regs
, pkt
);
219 nft_masq_inet_destroy(const struct nft_ctx
*ctx
, const struct nft_expr
*expr
)
221 nf_ct_netns_put(ctx
->net
, NFPROTO_INET
);
224 static struct nft_expr_type nft_masq_inet_type
;
225 static const struct nft_expr_ops nft_masq_inet_ops
= {
226 .type
= &nft_masq_inet_type
,
227 .size
= NFT_EXPR_SIZE(sizeof(struct nft_masq
)),
228 .eval
= nft_masq_inet_eval
,
229 .init
= nft_masq_init
,
230 .destroy
= nft_masq_inet_destroy
,
231 .dump
= nft_masq_dump
,
232 .validate
= nft_masq_validate
,
235 static struct nft_expr_type nft_masq_inet_type __read_mostly
= {
236 .family
= NFPROTO_INET
,
238 .ops
= &nft_masq_inet_ops
,
239 .policy
= nft_masq_policy
,
240 .maxattr
= NFTA_MASQ_MAX
,
241 .owner
= THIS_MODULE
,
244 static int __init
nft_masq_module_init_inet(void)
246 return nft_register_expr(&nft_masq_inet_type
);
249 static void nft_masq_module_exit_inet(void)
251 nft_unregister_expr(&nft_masq_inet_type
);
254 static inline int nft_masq_module_init_inet(void) { return 0; }
255 static inline void nft_masq_module_exit_inet(void) {}
258 static int __init
nft_masq_module_init(void)
262 ret
= nft_masq_module_init_ipv6();
266 ret
= nft_masq_module_init_inet();
268 nft_masq_module_exit_ipv6();
272 ret
= nft_register_expr(&nft_masq_ipv4_type
);
274 nft_masq_module_exit_inet();
275 nft_masq_module_exit_ipv6();
279 ret
= nf_nat_masquerade_inet_register_notifiers();
281 nft_masq_module_exit_ipv6();
282 nft_masq_module_exit_inet();
283 nft_unregister_expr(&nft_masq_ipv4_type
);
290 static void __exit
nft_masq_module_exit(void)
292 nft_masq_module_exit_ipv6();
293 nft_masq_module_exit_inet();
294 nft_unregister_expr(&nft_masq_ipv4_type
);
295 nf_nat_masquerade_inet_unregister_notifiers();
298 module_init(nft_masq_module_init
);
299 module_exit(nft_masq_module_exit
);
301 MODULE_LICENSE("GPL");
302 MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
303 MODULE_ALIAS_NFT_EXPR("masq");
304 MODULE_DESCRIPTION("Netfilter nftables masquerade expression support");