]> git.ipfire.org Git - thirdparty/linux.git/blame - net/netfilter/nft_redir.c
arm64: tegra: Add Tegra234 thermal support
[thirdparty/linux.git] / net / netfilter / nft_redir.c
CommitLineData
d2912cb1 1// SPDX-License-Identifier: GPL-2.0-only
e9105f1b 2/*
cd727514 3 * Copyright (c) 2014 Arturo Borrero Gonzalez <arturo@debian.org>
e9105f1b
AB
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_nat.h>
c78efc99 13#include <net/netfilter/nf_nat_redirect.h>
e9105f1b 14#include <net/netfilter/nf_tables.h>
e9105f1b 15
c78efc99 16struct nft_redir {
4f16d25c
PNA
17 u8 sreg_proto_min;
18 u8 sreg_proto_max;
c78efc99
FW
19 u16 flags;
20};
21
22static const struct nla_policy nft_redir_policy[NFTA_REDIR_MAX + 1] = {
e9105f1b
AB
23 [NFTA_REDIR_REG_PROTO_MIN] = { .type = NLA_U32 },
24 [NFTA_REDIR_REG_PROTO_MAX] = { .type = NLA_U32 },
25 [NFTA_REDIR_FLAGS] = { .type = NLA_U32 },
26};
e9105f1b 27
c78efc99
FW
28static int nft_redir_validate(const struct nft_ctx *ctx,
29 const struct nft_expr *expr,
30 const struct nft_data **data)
75e8d06d
PNA
31{
32 int err;
33
34 err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
35 if (err < 0)
36 return err;
37
38 return nft_chain_validate_hooks(ctx->chain,
39 (1 << NF_INET_PRE_ROUTING) |
40 (1 << NF_INET_LOCAL_OUT));
41}
75e8d06d 42
c78efc99
FW
43static int nft_redir_init(const struct nft_ctx *ctx,
44 const struct nft_expr *expr,
45 const struct nlattr * const tb[])
e9105f1b
AB
46{
47 struct nft_redir *priv = nft_expr_priv(expr);
d07db988 48 unsigned int plen;
e9105f1b
AB
49 int err;
50
1f617b6b 51 plen = sizeof_field(struct nf_nat_range, min_proto.all);
e9105f1b 52 if (tb[NFTA_REDIR_REG_PROTO_MIN]) {
4f16d25c
PNA
53 err = nft_parse_register_load(tb[NFTA_REDIR_REG_PROTO_MIN],
54 &priv->sreg_proto_min, plen);
e9105f1b
AB
55 if (err < 0)
56 return err;
57
58 if (tb[NFTA_REDIR_REG_PROTO_MAX]) {
4f16d25c
PNA
59 err = nft_parse_register_load(tb[NFTA_REDIR_REG_PROTO_MAX],
60 &priv->sreg_proto_max,
61 plen);
e9105f1b
AB
62 if (err < 0)
63 return err;
64 } else {
65 priv->sreg_proto_max = priv->sreg_proto_min;
66 }
6f56ad1b
JS
67
68 priv->flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
e9105f1b
AB
69 }
70
71 if (tb[NFTA_REDIR_FLAGS]) {
72 priv->flags = ntohl(nla_get_be32(tb[NFTA_REDIR_FLAGS]));
73 if (priv->flags & ~NF_NAT_RANGE_MASK)
74 return -EINVAL;
75 }
76
36596dad 77 return nf_ct_netns_get(ctx->net, ctx->family);
e9105f1b 78}
e9105f1b 79
7d34aa3e
PS
80static int nft_redir_dump(struct sk_buff *skb,
81 const struct nft_expr *expr, bool reset)
e9105f1b
AB
82{
83 const struct nft_redir *priv = nft_expr_priv(expr);
84
85 if (priv->sreg_proto_min) {
b1c96ed3
PM
86 if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_MIN,
87 priv->sreg_proto_min))
e9105f1b 88 goto nla_put_failure;
b1c96ed3
PM
89 if (nft_dump_register(skb, NFTA_REDIR_REG_PROTO_MAX,
90 priv->sreg_proto_max))
e9105f1b
AB
91 goto nla_put_failure;
92 }
93
94 if (priv->flags != 0 &&
95 nla_put_be32(skb, NFTA_REDIR_FLAGS, htonl(priv->flags)))
96 goto nla_put_failure;
97
98 return 0;
99
100nla_put_failure:
101 return -1;
102}
c78efc99 103
6f56ad1b
JS
104static void nft_redir_eval(const struct nft_expr *expr,
105 struct nft_regs *regs,
106 const struct nft_pktinfo *pkt)
c78efc99 107{
6f56ad1b
JS
108 const struct nft_redir *priv = nft_expr_priv(expr);
109 struct nf_nat_range2 range;
c78efc99 110
6f56ad1b
JS
111 memset(&range, 0, sizeof(range));
112 range.flags = priv->flags;
c78efc99 113 if (priv->sreg_proto_min) {
6f56ad1b
JS
114 range.min_proto.all = (__force __be16)
115 nft_reg_load16(&regs->data[priv->sreg_proto_min]);
116 range.max_proto.all = (__force __be16)
117 nft_reg_load16(&regs->data[priv->sreg_proto_max]);
c78efc99
FW
118 }
119
6f56ad1b
JS
120 switch (nft_pf(pkt)) {
121 case NFPROTO_IPV4:
122 regs->verdict.code = nf_nat_redirect_ipv4(pkt->skb, &range,
123 nft_hook(pkt));
124 break;
125#ifdef CONFIG_NF_TABLES_IPV6
126 case NFPROTO_IPV6:
127 regs->verdict.code = nf_nat_redirect_ipv6(pkt->skb, &range,
128 nft_hook(pkt));
129 break;
130#endif
131 default:
132 WARN_ON_ONCE(1);
133 break;
134 }
c78efc99
FW
135}
136
137static void
138nft_redir_ipv4_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
139{
140 nf_ct_netns_put(ctx->net, NFPROTO_IPV4);
141}
142
143static struct nft_expr_type nft_redir_ipv4_type;
144static const struct nft_expr_ops nft_redir_ipv4_ops = {
145 .type = &nft_redir_ipv4_type,
146 .size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
6f56ad1b 147 .eval = nft_redir_eval,
c78efc99
FW
148 .init = nft_redir_init,
149 .destroy = nft_redir_ipv4_destroy,
150 .dump = nft_redir_dump,
151 .validate = nft_redir_validate,
b2d30654 152 .reduce = NFT_REDUCE_READONLY,
c78efc99
FW
153};
154
155static struct nft_expr_type nft_redir_ipv4_type __read_mostly = {
156 .family = NFPROTO_IPV4,
157 .name = "redir",
158 .ops = &nft_redir_ipv4_ops,
159 .policy = nft_redir_policy,
160 .maxattr = NFTA_REDIR_MAX,
161 .owner = THIS_MODULE,
162};
163
164#ifdef CONFIG_NF_TABLES_IPV6
c78efc99
FW
165static void
166nft_redir_ipv6_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
167{
168 nf_ct_netns_put(ctx->net, NFPROTO_IPV6);
169}
170
171static struct nft_expr_type nft_redir_ipv6_type;
172static const struct nft_expr_ops nft_redir_ipv6_ops = {
173 .type = &nft_redir_ipv6_type,
174 .size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
6f56ad1b 175 .eval = nft_redir_eval,
c78efc99
FW
176 .init = nft_redir_init,
177 .destroy = nft_redir_ipv6_destroy,
178 .dump = nft_redir_dump,
179 .validate = nft_redir_validate,
b2d30654 180 .reduce = NFT_REDUCE_READONLY,
c78efc99
FW
181};
182
183static struct nft_expr_type nft_redir_ipv6_type __read_mostly = {
184 .family = NFPROTO_IPV6,
185 .name = "redir",
186 .ops = &nft_redir_ipv6_ops,
187 .policy = nft_redir_policy,
188 .maxattr = NFTA_REDIR_MAX,
189 .owner = THIS_MODULE,
190};
191#endif
192
63ce3940 193#ifdef CONFIG_NF_TABLES_INET
63ce3940
FW
194static void
195nft_redir_inet_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr)
196{
197 nf_ct_netns_put(ctx->net, NFPROTO_INET);
198}
199
200static struct nft_expr_type nft_redir_inet_type;
201static const struct nft_expr_ops nft_redir_inet_ops = {
202 .type = &nft_redir_inet_type,
203 .size = NFT_EXPR_SIZE(sizeof(struct nft_redir)),
6f56ad1b 204 .eval = nft_redir_eval,
63ce3940
FW
205 .init = nft_redir_init,
206 .destroy = nft_redir_inet_destroy,
207 .dump = nft_redir_dump,
208 .validate = nft_redir_validate,
b2d30654 209 .reduce = NFT_REDUCE_READONLY,
63ce3940
FW
210};
211
212static struct nft_expr_type nft_redir_inet_type __read_mostly = {
213 .family = NFPROTO_INET,
214 .name = "redir",
215 .ops = &nft_redir_inet_ops,
216 .policy = nft_redir_policy,
49392451 217 .maxattr = NFTA_REDIR_MAX,
63ce3940
FW
218 .owner = THIS_MODULE,
219};
220
221static int __init nft_redir_module_init_inet(void)
222{
223 return nft_register_expr(&nft_redir_inet_type);
224}
225#else
226static inline int nft_redir_module_init_inet(void) { return 0; }
227#endif
228
c78efc99
FW
229static int __init nft_redir_module_init(void)
230{
231 int ret = nft_register_expr(&nft_redir_ipv4_type);
232
233 if (ret)
234 return ret;
235
236#ifdef CONFIG_NF_TABLES_IPV6
237 ret = nft_register_expr(&nft_redir_ipv6_type);
238 if (ret) {
239 nft_unregister_expr(&nft_redir_ipv4_type);
240 return ret;
241 }
242#endif
243
63ce3940
FW
244 ret = nft_redir_module_init_inet();
245 if (ret < 0) {
246 nft_unregister_expr(&nft_redir_ipv4_type);
247#ifdef CONFIG_NF_TABLES_IPV6
248 nft_unregister_expr(&nft_redir_ipv6_type);
249#endif
250 return ret;
251 }
252
c78efc99
FW
253 return ret;
254}
255
256static void __exit nft_redir_module_exit(void)
257{
258 nft_unregister_expr(&nft_redir_ipv4_type);
259#ifdef CONFIG_NF_TABLES_IPV6
260 nft_unregister_expr(&nft_redir_ipv6_type);
261#endif
63ce3940
FW
262#ifdef CONFIG_NF_TABLES_INET
263 nft_unregister_expr(&nft_redir_inet_type);
264#endif
c78efc99
FW
265}
266
267module_init(nft_redir_module_init);
268module_exit(nft_redir_module_exit);
e9105f1b 269
e9105f1b 270MODULE_LICENSE("GPL");
cd727514 271MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo@debian.org>");
f41828ee 272MODULE_ALIAS_NFT_EXPR("redir");
4cacc395 273MODULE_DESCRIPTION("Netfilter nftables redirect support");