blob: b827a0f1f3510bc0fa4e6b0a498738806ac62e81 [file] [log] [blame]
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +02001/* Copyright (C) 2011-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Jozsef Kadlecsike3853572011-06-16 19:00:48 +02002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 as
5 * published by the Free Software Foundation.
6 */
7
8/* Kernel module implementing an IP set type: the hash:net,iface type */
9
10#include <linux/jhash.h>
11#include <linux/module.h>
12#include <linux/ip.h>
13#include <linux/skbuff.h>
14#include <linux/errno.h>
15#include <linux/random.h>
16#include <linux/rbtree.h>
17#include <net/ip.h>
18#include <net/ipv6.h>
19#include <net/netlink.h>
20
21#include <linux/netfilter.h>
22#include <linux/netfilter/ipset/pfxlen.h>
23#include <linux/netfilter/ipset/ip_set.h>
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020024#include <linux/netfilter/ipset/ip_set_hash.h>
25
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +020026#define IPSET_TYPE_REV_MIN 0
27/* 1 nomatch flag support added */
28/* 2 /0 support added */
Oliver Smithfda75c62013-09-22 20:56:31 +020029/* 3 Counters support added */
30#define IPSET_TYPE_REV_MAX 4 /* Comments support added */
Jozsef Kadlecsik10111a62012-09-21 21:59:32 +020031
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020032MODULE_LICENSE("GPL");
33MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +020034IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020035MODULE_ALIAS("ip_set_hash:net,iface");
36
37/* Interface name rbtree */
38
39struct iface_node {
40 struct rb_node node;
41 char iface[IFNAMSIZ];
42};
43
44#define iface_data(n) (rb_entry(n, struct iface_node, node)->iface)
45
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020046static void
47rbtree_destroy(struct rb_root *root)
48{
Cody P Schaferb1828372014-01-23 15:56:07 -080049 struct iface_node *node, *next;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020050
Cody P Schaferb1828372014-01-23 15:56:07 -080051 rbtree_postorder_for_each_entry_safe(node, next, root, node)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020052 kfree(node);
Cody P Schaferb1828372014-01-23 15:56:07 -080053
54 *root = RB_ROOT;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020055}
56
57static int
58iface_test(struct rb_root *root, const char **iface)
59{
60 struct rb_node *n = root->rb_node;
61
62 while (n) {
63 const char *d = iface_data(n);
Florian Westphalef5b6e12012-06-17 09:56:46 +000064 int res = strcmp(*iface, d);
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +020065
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020066 if (res < 0)
67 n = n->rb_left;
68 else if (res > 0)
69 n = n->rb_right;
70 else {
71 *iface = d;
72 return 1;
73 }
74 }
75 return 0;
76}
77
78static int
79iface_add(struct rb_root *root, const char **iface)
80{
81 struct rb_node **n = &(root->rb_node), *p = NULL;
82 struct iface_node *d;
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +020083
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020084 while (*n) {
85 char *ifname = iface_data(*n);
Florian Westphalef5b6e12012-06-17 09:56:46 +000086 int res = strcmp(*iface, ifname);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +020087
88 p = *n;
89 if (res < 0)
90 n = &((*n)->rb_left);
91 else if (res > 0)
92 n = &((*n)->rb_right);
93 else {
94 *iface = ifname;
95 return 0;
96 }
97 }
98
99 d = kzalloc(sizeof(*d), GFP_ATOMIC);
100 if (!d)
101 return -ENOMEM;
102 strcpy(d->iface, *iface);
103
104 rb_link_node(&d->node, p, n);
105 rb_insert_color(&d->node, root);
106
107 *iface = d->iface;
108 return 0;
109}
110
111/* Type specific function prefix */
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200112#define HTYPE hash_netiface
113#define IP_SET_HASH_WITH_NETS
114#define IP_SET_HASH_WITH_RBTREE
115#define IP_SET_HASH_WITH_MULTI
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200116
117#define STREQ(a, b) (strcmp(a, b) == 0)
118
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +0200119/* IPv4 variant */
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200120
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200121struct hash_netiface4_elem_hashed {
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200122 __be32 ip;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200123 u8 physdev;
124 u8 cidr;
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100125 u8 nomatch;
Jozsef Kadlecsikbd9087e2012-09-10 21:22:23 +0200126 u8 elem;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200127};
128
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +0200129/* Member elements */
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200130struct hash_netiface4_elem {
131 __be32 ip;
132 u8 physdev;
133 u8 cidr;
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100134 u8 nomatch;
Jozsef Kadlecsikbd9087e2012-09-10 21:22:23 +0200135 u8 elem;
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200136 const char *iface;
137};
138
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200139/* Common functions */
140
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200141static inline bool
142hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200143 const struct hash_netiface4_elem *ip2,
144 u32 *multi)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200145{
146 return ip1->ip == ip2->ip &&
147 ip1->cidr == ip2->cidr &&
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200148 (++*multi) &&
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200149 ip1->physdev == ip2->physdev &&
150 ip1->iface == ip2->iface;
151}
152
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200153static inline int
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200154hash_netiface4_do_data_match(const struct hash_netiface4_elem *elem)
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100155{
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200156 return elem->nomatch ? -ENOTEMPTY : 1;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200157}
158
159static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200160hash_netiface4_data_set_flags(struct hash_netiface4_elem *elem, u32 flags)
161{
162 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
163}
164
165static inline void
166hash_netiface4_data_reset_flags(struct hash_netiface4_elem *elem, u8 *flags)
167{
168 swap(*flags, elem->nomatch);
169}
170
171static inline void
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200172hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
173{
174 elem->ip &= ip_set_netmask(cidr);
175 elem->cidr = cidr;
176}
177
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200178static bool
179hash_netiface4_data_list(struct sk_buff *skb,
180 const struct hash_netiface4_elem *data)
181{
182 u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
183
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100184 if (data->nomatch)
185 flags |= IPSET_FLAG_NOMATCH;
David S. Miller7cf78992012-04-01 19:54:46 -0400186 if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
187 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
188 nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
189 (flags &&
190 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
191 goto nla_put_failure;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200192 return 0;
193
194nla_put_failure:
195 return 1;
196}
197
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200198static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200199hash_netiface4_data_next(struct hash_netiface4_elem *next,
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200200 const struct hash_netiface4_elem *d)
201{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200202 next->ip = d->ip;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200203}
204
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200205#define MTYPE hash_netiface4
206#define PF 4
207#define HOST_MASK 32
208#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
209#include "ip_set_hash_gen.h"
210
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200211static int
212hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
213 const struct xt_action_param *par,
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200214 enum ipset_adt adt, struct ip_set_adt_opt *opt)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200215{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200216 struct hash_netiface *h = set->data;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200217 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200218 struct hash_netiface4_elem e = {
Jozsef Kadlecsika04d8b62013-09-30 09:05:54 +0200219 .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
Jozsef Kadlecsikbd9087e2012-09-10 21:22:23 +0200220 .elem = 1,
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200221 };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200222 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200223 int ret;
224
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200225 if (e.cidr == 0)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200226 return -EINVAL;
227 if (adt == IPSET_TEST)
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200228 e.cidr = HOST_MASK;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200229
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200230 ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
231 e.ip &= ip_set_netmask(e.cidr);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200232
233#define IFACE(dir) (par->dir ? par->dir->name : NULL)
234#define PHYSDEV(dir) (nf_bridge->dir ? nf_bridge->dir->name : NULL)
235#define SRCDIR (opt->flags & IPSET_DIM_TWO_SRC)
236
237 if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
238#ifdef CONFIG_BRIDGE_NETFILTER
239 const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200240
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200241 if (!nf_bridge)
242 return -EINVAL;
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200243 e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
244 e.physdev = 1;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200245#else
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200246 e.iface = NULL;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200247#endif
248 } else
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200249 e.iface = SRCDIR ? IFACE(in) : IFACE(out);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200250
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200251 if (!e.iface)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200252 return -EINVAL;
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200253 ret = iface_test(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200254 if (adt == IPSET_ADD) {
255 if (!ret) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200256 ret = iface_add(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200257 if (ret)
258 return ret;
259 }
260 } else if (!ret)
261 return ret;
262
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200263 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200264}
265
266static int
267hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
268 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
269{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200270 struct hash_netiface *h = set->data;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200271 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200272 struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200273 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
Jozsef Kadlecsik20b2fab2013-05-01 18:47:32 +0200274 u32 ip = 0, ip_to = 0, last;
Florian Westphalef5b6e12012-06-17 09:56:46 +0000275 char iface[IFNAMSIZ];
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200276 int ret;
277
278 if (unlikely(!tb[IPSET_ATTR_IP] ||
279 !tb[IPSET_ATTR_IFACE] ||
280 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
Jozsef Kadlecsik00d71b22013-04-08 23:11:02 +0200281 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
282 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
283 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200284 return -IPSET_ERR_PROTOCOL;
285
286 if (tb[IPSET_ATTR_LINENO])
287 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
288
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200289 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
290 ip_set_get_extensions(set, tb, &ext);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200291 if (ret)
292 return ret;
293
294 if (tb[IPSET_ATTR_CIDR]) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200295 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
296 if (e.cidr > HOST_MASK)
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200297 return -IPSET_ERR_INVALID_CIDR;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200298 }
299
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200300 strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200301 e.iface = iface;
302 ret = iface_test(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200303 if (adt == IPSET_ADD) {
304 if (!ret) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200305 ret = iface_add(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200306 if (ret)
307 return ret;
308 }
309 } else if (!ret)
310 return ret;
311
312 if (tb[IPSET_ATTR_CADT_FLAGS]) {
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200313 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
314 if (cadt_flags & IPSET_FLAG_PHYSDEV)
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200315 e.physdev = 1;
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200316 if (cadt_flags & IPSET_FLAG_NOMATCH)
317 flags |= (IPSET_FLAG_NOMATCH << 16);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200318 }
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200319 if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200320 e.ip = htonl(ip & ip_set_hostmask(e.cidr));
321 ret = adtfn(set, &e, &ext, &ext, flags);
Jozsef Kadlecsik0f1799b2013-09-16 20:04:53 +0200322 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200323 ip_set_eexist(ret, flags) ? 0 : ret;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200324 }
325
326 if (tb[IPSET_ATTR_IP_TO]) {
327 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
328 if (ret)
329 return ret;
330 if (ip_to < ip)
331 swap(ip, ip_to);
332 if (ip + UINT_MAX == ip_to)
333 return -IPSET_ERR_HASH_RANGE;
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200334 } else
335 ip_set_mask_from_to(ip, ip_to, e.cidr);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200336
337 if (retried)
Jozsef Kadlecsik6e27c9b2012-09-21 21:44:58 +0200338 ip = ntohl(h->next.ip);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200339 while (!after(ip, ip_to)) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200340 e.ip = htonl(ip);
341 last = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
342 ret = adtfn(set, &e, &ext, &ext, flags);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200343
344 if (ret && !ip_set_eexist(ret, flags))
345 return ret;
346 else
347 ret = 0;
348 ip = last + 1;
349 }
350 return ret;
351}
352
Jozsef Kadlecsik03c8b232013-09-07 00:43:52 +0200353/* IPv6 variant */
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200354
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200355struct hash_netiface6_elem_hashed {
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200356 union nf_inet_addr ip;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200357 u8 physdev;
358 u8 cidr;
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100359 u8 nomatch;
Jozsef Kadlecsikbd9087e2012-09-10 21:22:23 +0200360 u8 elem;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200361};
362
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200363struct hash_netiface6_elem {
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200364 union nf_inet_addr ip;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200365 u8 physdev;
366 u8 cidr;
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100367 u8 nomatch;
Jozsef Kadlecsikbd9087e2012-09-10 21:22:23 +0200368 u8 elem;
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200369 const char *iface;
370};
371
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200372/* Common functions */
373
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200374static inline bool
375hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200376 const struct hash_netiface6_elem *ip2,
377 u32 *multi)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200378{
YOSHIFUJI Hideaki / 吉藤英明29e3b162013-01-29 12:49:03 +0000379 return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200380 ip1->cidr == ip2->cidr &&
Jozsef Kadlecsik89dc79b2011-07-21 12:06:18 +0200381 (++*multi) &&
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200382 ip1->physdev == ip2->physdev &&
383 ip1->iface == ip2->iface;
384}
385
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200386static inline int
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200387hash_netiface6_do_data_match(const struct hash_netiface6_elem *elem)
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100388{
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200389 return elem->nomatch ? -ENOTEMPTY : 1;
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100390}
391
392static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200393hash_netiface6_data_set_flags(struct hash_netiface6_elem *elem, u32 flags)
Jozsef Kadlecsik6eb4c7e2013-04-09 08:57:20 +0000394{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200395 elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
Jozsef Kadlecsik6eb4c7e2013-04-09 08:57:20 +0000396}
397
398static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200399hash_netiface6_data_reset_flags(struct hash_netiface6_elem *elem, u8 *flags)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200400{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200401 swap(*flags, elem->nomatch);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200402}
403
404static inline void
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200405hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
406{
407 ip6_netmask(&elem->ip, cidr);
408 elem->cidr = cidr;
409}
410
411static bool
412hash_netiface6_data_list(struct sk_buff *skb,
413 const struct hash_netiface6_elem *data)
414{
415 u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
416
Jozsef Kadlecsik2a7cef22012-01-14 17:16:36 +0100417 if (data->nomatch)
418 flags |= IPSET_FLAG_NOMATCH;
David S. Miller7cf78992012-04-01 19:54:46 -0400419 if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
420 nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
421 nla_put_string(skb, IPSET_ATTR_IFACE, data->iface) ||
422 (flags &&
423 nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
424 goto nla_put_failure;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200425 return 0;
426
427nla_put_failure:
428 return 1;
429}
430
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200431static inline void
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200432hash_netiface6_data_next(struct hash_netiface4_elem *next,
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200433 const struct hash_netiface6_elem *d)
434{
435}
436
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200437#undef MTYPE
438#undef PF
439#undef HOST_MASK
440#undef HKEY_DATALEN
441
442#define MTYPE hash_netiface6
443#define PF 6
444#define HOST_MASK 128
445#define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
446#define IP_SET_EMIT_CREATE
447#include "ip_set_hash_gen.h"
448
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200449static int
450hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
451 const struct xt_action_param *par,
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200452 enum ipset_adt adt, struct ip_set_adt_opt *opt)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200453{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200454 struct hash_netiface *h = set->data;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200455 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200456 struct hash_netiface6_elem e = {
Jozsef Kadlecsika04d8b62013-09-30 09:05:54 +0200457 .cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
Jozsef Kadlecsikbd9087e2012-09-10 21:22:23 +0200458 .elem = 1,
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200459 };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200460 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200461 int ret;
462
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200463 if (e.cidr == 0)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200464 return -EINVAL;
465 if (adt == IPSET_TEST)
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200466 e.cidr = HOST_MASK;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200467
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200468 ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
469 ip6_netmask(&e.ip, e.cidr);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200470
471 if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
472#ifdef CONFIG_BRIDGE_NETFILTER
473 const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200474
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200475 if (!nf_bridge)
476 return -EINVAL;
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200477 e.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
478 e.physdev = 1;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200479#else
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200480 e.iface = NULL;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200481#endif
482 } else
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200483 e.iface = SRCDIR ? IFACE(in) : IFACE(out);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200484
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200485 if (!e.iface)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200486 return -EINVAL;
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200487 ret = iface_test(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200488 if (adt == IPSET_ADD) {
489 if (!ret) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200490 ret = iface_add(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200491 if (ret)
492 return ret;
493 }
494 } else if (!ret)
495 return ret;
496
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200497 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200498}
499
500static int
501hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
502 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
503{
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200504 struct hash_netiface *h = set->data;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200505 ipset_adtfn adtfn = set->variant->adt[adt];
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200506 struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
Jozsef Kadlecsikca134ce2013-09-07 00:10:07 +0200507 struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
Florian Westphalef5b6e12012-06-17 09:56:46 +0000508 char iface[IFNAMSIZ];
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200509 int ret;
510
511 if (unlikely(!tb[IPSET_ATTR_IP] ||
512 !tb[IPSET_ATTR_IFACE] ||
513 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
Jozsef Kadlecsik00d71b22013-04-08 23:11:02 +0200514 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
515 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
516 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200517 return -IPSET_ERR_PROTOCOL;
518 if (unlikely(tb[IPSET_ATTR_IP_TO]))
519 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
520
521 if (tb[IPSET_ATTR_LINENO])
522 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
523
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200524 ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
525 ip_set_get_extensions(set, tb, &ext);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200526 if (ret)
527 return ret;
528
529 if (tb[IPSET_ATTR_CIDR])
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200530 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
531 if (e.cidr > HOST_MASK)
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200532 return -IPSET_ERR_INVALID_CIDR;
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200533 ip6_netmask(&e.ip, e.cidr);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200534
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200535 strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200536 e.iface = iface;
537 ret = iface_test(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200538 if (adt == IPSET_ADD) {
539 if (!ret) {
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200540 ret = iface_add(&h->rbtree, &e.iface);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200541 if (ret)
542 return ret;
543 }
544 } else if (!ret)
545 return ret;
546
547 if (tb[IPSET_ATTR_CADT_FLAGS]) {
Jozsef Kadlecsik15b4d932011-06-16 19:01:26 +0200548 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
549 if (cadt_flags & IPSET_FLAG_PHYSDEV)
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200550 e.physdev = 1;
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200551 if (cadt_flags & IPSET_FLAG_NOMATCH)
552 flags |= (IPSET_FLAG_NOMATCH << 16);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200553 }
554
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200555 ret = adtfn(set, &e, &ext, &ext, flags);
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200556
Jozsef Kadlecsik0f1799b2013-09-16 20:04:53 +0200557 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
Jozsef Kadlecsik43c56e52013-04-08 21:51:25 +0200558 ip_set_eexist(ret, flags) ? 0 : ret;
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200559}
560
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200561static struct ip_set_type hash_netiface_type __read_mostly = {
562 .name = "hash:net,iface",
563 .protocol = IPSET_PROTOCOL,
Jozsef Kadlecsik3e0304a2012-09-21 22:02:36 +0200564 .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE |
565 IPSET_TYPE_NOMATCH,
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200566 .dimension = IPSET_DIM_TWO,
Jan Engelhardtc15f1c82012-02-14 00:24:10 +0100567 .family = NFPROTO_UNSPEC,
Jozsef Kadlecsik35b8dcf2013-04-30 23:02:43 +0200568 .revision_min = IPSET_TYPE_REV_MIN,
569 .revision_max = IPSET_TYPE_REV_MAX,
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200570 .create = hash_netiface_create,
571 .create_policy = {
572 [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
573 [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
574 [IPSET_ATTR_PROBES] = { .type = NLA_U8 },
575 [IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
576 [IPSET_ATTR_PROTO] = { .type = NLA_U8 },
577 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
Jozsef Kadlecsik5d50e1d82013-04-08 22:50:55 +0200578 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200579 },
580 .adt_policy = {
581 [IPSET_ATTR_IP] = { .type = NLA_NESTED },
582 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
583 [IPSET_ATTR_IFACE] = { .type = NLA_NUL_STRING,
Florian Westphal4a6dd662012-11-22 01:32:45 +0000584 .len = IFNAMSIZ - 1 },
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200585 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
586 [IPSET_ATTR_CIDR] = { .type = NLA_U8 },
587 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
588 [IPSET_ATTR_LINENO] = { .type = NLA_U32 },
Jozsef Kadlecsik00d71b22013-04-08 23:11:02 +0200589 [IPSET_ATTR_BYTES] = { .type = NLA_U64 },
590 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
Oliver Smithfda75c62013-09-22 20:56:31 +0200591 [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
Jozsef Kadlecsike3853572011-06-16 19:00:48 +0200592 },
593 .me = THIS_MODULE,
594};
595
596static int __init
597hash_netiface_init(void)
598{
599 return ip_set_type_register(&hash_netiface_type);
600}
601
602static void __exit
603hash_netiface_fini(void)
604{
605 ip_set_type_unregister(&hash_netiface_type);
606}
607
608module_init(hash_netiface_init);
609module_exit(hash_netiface_fini);