]> git.karo-electronics.de Git - karo-tx-linux.git/blob - net/netfilter/nft_nat.c
Merge remote-tracking branch 'clk/clk-next'
[karo-tx-linux.git] / net / netfilter / nft_nat.c
1 /*
2  * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3  * Copyright (c) 2012 Pablo Neira Ayuso <pablo@netfilter.org>
4  * Copyright (c) 2012 Intel Corporation
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU General Public License,
8  * version 2, as published by the Free Software Foundation.
9  *
10  */
11
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/skbuff.h>
15 #include <linux/ip.h>
16 #include <linux/string.h>
17 #include <linux/netlink.h>
18 #include <linux/netfilter.h>
19 #include <linux/netfilter_ipv4.h>
20 #include <linux/netfilter/nfnetlink.h>
21 #include <linux/netfilter/nf_tables.h>
22 #include <net/netfilter/nf_conntrack.h>
23 #include <net/netfilter/nf_nat.h>
24 #include <net/netfilter/nf_nat_core.h>
25 #include <net/netfilter/nf_tables.h>
26 #include <net/netfilter/nf_nat_l3proto.h>
27 #include <net/ip.h>
28
29 struct nft_nat {
30         enum nft_registers      sreg_addr_min:8;
31         enum nft_registers      sreg_addr_max:8;
32         enum nft_registers      sreg_proto_min:8;
33         enum nft_registers      sreg_proto_max:8;
34         int                     family;
35         enum nf_nat_manip_type  type;
36 };
37
38 static void nft_nat_eval(const struct nft_expr *expr,
39                          struct nft_data data[NFT_REG_MAX + 1],
40                          const struct nft_pktinfo *pkt)
41 {
42         const struct nft_nat *priv = nft_expr_priv(expr);
43         enum ip_conntrack_info ctinfo;
44         struct nf_conn *ct = nf_ct_get(pkt->skb, &ctinfo);
45         struct nf_nat_range range;
46
47         memset(&range, 0, sizeof(range));
48         if (priv->sreg_addr_min) {
49                 if (priv->family == AF_INET) {
50                         range.min_addr.ip = data[priv->sreg_addr_min].data[0];
51                         range.max_addr.ip = data[priv->sreg_addr_max].data[0];
52
53                 } else {
54                         memcpy(range.min_addr.ip6,
55                                data[priv->sreg_addr_min].data,
56                                sizeof(struct nft_data));
57                         memcpy(range.max_addr.ip6,
58                                data[priv->sreg_addr_max].data,
59                                sizeof(struct nft_data));
60                 }
61                 range.flags |= NF_NAT_RANGE_MAP_IPS;
62         }
63
64         if (priv->sreg_proto_min) {
65                 range.min_proto.all = data[priv->sreg_proto_min].data[0];
66                 range.max_proto.all = data[priv->sreg_proto_max].data[0];
67                 range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
68         }
69
70         data[NFT_REG_VERDICT].verdict =
71                 nf_nat_setup_info(ct, &range, priv->type);
72 }
73
74 static const struct nla_policy nft_nat_policy[NFTA_NAT_MAX + 1] = {
75         [NFTA_NAT_TYPE]          = { .type = NLA_U32 },
76         [NFTA_NAT_FAMILY]        = { .type = NLA_U32 },
77         [NFTA_NAT_REG_ADDR_MIN]  = { .type = NLA_U32 },
78         [NFTA_NAT_REG_ADDR_MAX]  = { .type = NLA_U32 },
79         [NFTA_NAT_REG_PROTO_MIN] = { .type = NLA_U32 },
80         [NFTA_NAT_REG_PROTO_MAX] = { .type = NLA_U32 },
81 };
82
83 static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
84                         const struct nlattr * const tb[])
85 {
86         struct nft_nat *priv = nft_expr_priv(expr);
87         int err;
88
89         if (tb[NFTA_NAT_TYPE] == NULL)
90                 return -EINVAL;
91
92         switch (ntohl(nla_get_be32(tb[NFTA_NAT_TYPE]))) {
93         case NFT_NAT_SNAT:
94                 priv->type = NF_NAT_MANIP_SRC;
95                 break;
96         case NFT_NAT_DNAT:
97                 priv->type = NF_NAT_MANIP_DST;
98                 break;
99         default:
100                 return -EINVAL;
101         }
102
103         if (tb[NFTA_NAT_FAMILY] == NULL)
104                 return -EINVAL;
105
106         priv->family = ntohl(nla_get_be32(tb[NFTA_NAT_FAMILY]));
107         if (priv->family != AF_INET && priv->family != AF_INET6)
108                 return -EINVAL;
109
110         if (tb[NFTA_NAT_REG_ADDR_MIN]) {
111                 priv->sreg_addr_min = ntohl(nla_get_be32(
112                                                 tb[NFTA_NAT_REG_ADDR_MIN]));
113                 err = nft_validate_input_register(priv->sreg_addr_min);
114                 if (err < 0)
115                         return err;
116         }
117
118         if (tb[NFTA_NAT_REG_ADDR_MAX]) {
119                 priv->sreg_addr_max = ntohl(nla_get_be32(
120                                                 tb[NFTA_NAT_REG_ADDR_MAX]));
121                 err = nft_validate_input_register(priv->sreg_addr_max);
122                 if (err < 0)
123                         return err;
124         } else
125                 priv->sreg_addr_max = priv->sreg_addr_min;
126
127         if (tb[NFTA_NAT_REG_PROTO_MIN]) {
128                 priv->sreg_proto_min = ntohl(nla_get_be32(
129                                                 tb[NFTA_NAT_REG_PROTO_MIN]));
130                 err = nft_validate_input_register(priv->sreg_proto_min);
131                 if (err < 0)
132                         return err;
133         }
134
135         if (tb[NFTA_NAT_REG_PROTO_MAX]) {
136                 priv->sreg_proto_max = ntohl(nla_get_be32(
137                                                 tb[NFTA_NAT_REG_PROTO_MAX]));
138                 err = nft_validate_input_register(priv->sreg_proto_max);
139                 if (err < 0)
140                         return err;
141         } else
142                 priv->sreg_proto_max = priv->sreg_proto_min;
143
144         return 0;
145 }
146
147 static int nft_nat_dump(struct sk_buff *skb, const struct nft_expr *expr)
148 {
149         const struct nft_nat *priv = nft_expr_priv(expr);
150
151         switch (priv->type) {
152         case NF_NAT_MANIP_SRC:
153                 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_SNAT)))
154                         goto nla_put_failure;
155                 break;
156         case NF_NAT_MANIP_DST:
157                 if (nla_put_be32(skb, NFTA_NAT_TYPE, htonl(NFT_NAT_DNAT)))
158                         goto nla_put_failure;
159                 break;
160         }
161
162         if (nla_put_be32(skb, NFTA_NAT_FAMILY, htonl(priv->family)))
163                 goto nla_put_failure;
164         if (nla_put_be32(skb,
165                          NFTA_NAT_REG_ADDR_MIN, htonl(priv->sreg_addr_min)))
166                 goto nla_put_failure;
167         if (nla_put_be32(skb,
168                          NFTA_NAT_REG_ADDR_MAX, htonl(priv->sreg_addr_max)))
169                 goto nla_put_failure;
170         if (nla_put_be32(skb,
171                          NFTA_NAT_REG_PROTO_MIN, htonl(priv->sreg_proto_min)))
172                 goto nla_put_failure;
173         if (nla_put_be32(skb,
174                          NFTA_NAT_REG_PROTO_MAX, htonl(priv->sreg_proto_max)))
175                 goto nla_put_failure;
176         return 0;
177
178 nla_put_failure:
179         return -1;
180 }
181
182 static struct nft_expr_type nft_nat_type;
183 static const struct nft_expr_ops nft_nat_ops = {
184         .type           = &nft_nat_type,
185         .size           = NFT_EXPR_SIZE(sizeof(struct nft_nat)),
186         .eval           = nft_nat_eval,
187         .init           = nft_nat_init,
188         .dump           = nft_nat_dump,
189 };
190
191 static struct nft_expr_type nft_nat_type __read_mostly = {
192         .name           = "nat",
193         .ops            = &nft_nat_ops,
194         .policy         = nft_nat_policy,
195         .maxattr        = NFTA_NAT_MAX,
196         .owner          = THIS_MODULE,
197 };
198
199 static int __init nft_nat_module_init(void)
200 {
201         int err;
202
203         err = nft_register_expr(&nft_nat_type);
204         if (err < 0)
205                 return err;
206
207         return 0;
208 }
209
210 static void __exit nft_nat_module_exit(void)
211 {
212         nft_unregister_expr(&nft_nat_type);
213 }
214
215 module_init(nft_nat_module_init);
216 module_exit(nft_nat_module_exit);
217
218 MODULE_LICENSE("GPL");
219 MODULE_AUTHOR("Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com>");
220 MODULE_ALIAS_NFT_EXPR("nat");