1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> |
3 | * Patrick Schaaf <bof@bof.de> |
4 | * Martin Josefsson <gandalf@wlug.westbo.se> |
5 | */ |
6 | |
7 | /* Kernel module implementing an IP set type: the bitmap:ip,mac type */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/ip.h> |
11 | #include <linux/etherdevice.h> |
12 | #include <linux/skbuff.h> |
13 | #include <linux/errno.h> |
14 | #include <linux/if_ether.h> |
15 | #include <linux/netlink.h> |
16 | #include <linux/jiffies.h> |
17 | #include <linux/timer.h> |
18 | #include <net/netlink.h> |
19 | |
20 | #include <linux/netfilter/ipset/pfxlen.h> |
21 | #include <linux/netfilter/ipset/ip_set.h> |
22 | #include <linux/netfilter/ipset/ip_set_bitmap.h> |
23 | |
24 | #define IPSET_TYPE_REV_MIN 0 |
25 | /* 1 Counter support added */ |
26 | /* 2 Comment support added */ |
27 | #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */ |
28 | |
29 | MODULE_LICENSE("GPL" ); |
30 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>" ); |
31 | IP_SET_MODULE_DESC("bitmap:ip,mac" , IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
32 | MODULE_ALIAS("ip_set_bitmap:ip,mac" ); |
33 | |
34 | #define MTYPE bitmap_ipmac |
35 | #define HOST_MASK 32 |
36 | #define IP_SET_BITMAP_STORED_TIMEOUT |
37 | |
38 | enum { |
39 | MAC_UNSET, /* element is set, without MAC */ |
40 | MAC_FILLED, /* element is set with MAC */ |
41 | }; |
42 | |
43 | /* Type structure */ |
44 | struct bitmap_ipmac { |
45 | unsigned long *members; /* the set members */ |
46 | u32 first_ip; /* host byte order, included in range */ |
47 | u32 last_ip; /* host byte order, included in range */ |
48 | u32 elements; /* number of max elements in the set */ |
49 | size_t memsize; /* members size */ |
50 | struct timer_list gc; /* garbage collector */ |
51 | struct ip_set *set; /* attached to this ip_set */ |
52 | unsigned char extensions[] /* MAC + data extensions */ |
53 | __aligned(__alignof__(u64)); |
54 | }; |
55 | |
56 | /* ADT structure for generic function args */ |
57 | struct bitmap_ipmac_adt_elem { |
58 | unsigned char ether[ETH_ALEN] __aligned(2); |
59 | u16 id; |
60 | u16 add_mac; |
61 | }; |
62 | |
63 | struct bitmap_ipmac_elem { |
64 | unsigned char ether[ETH_ALEN]; |
65 | unsigned char filled; |
66 | } __aligned(__alignof__(u64)); |
67 | |
68 | static u32 |
69 | ip_to_id(const struct bitmap_ipmac *m, u32 ip) |
70 | { |
71 | return ip - m->first_ip; |
72 | } |
73 | |
74 | #define get_elem(extensions, id, dsize) \ |
75 | (struct bitmap_ipmac_elem *)(extensions + (id) * (dsize)) |
76 | |
77 | #define get_const_elem(extensions, id, dsize) \ |
78 | (const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize)) |
79 | |
80 | /* Common functions */ |
81 | |
82 | static int |
83 | bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, |
84 | const struct bitmap_ipmac *map, size_t dsize) |
85 | { |
86 | const struct bitmap_ipmac_elem *elem; |
87 | |
88 | if (!test_bit(e->id, map->members)) |
89 | return 0; |
90 | elem = get_const_elem(map->extensions, e->id, dsize); |
91 | if (e->add_mac && elem->filled == MAC_FILLED) |
92 | return ether_addr_equal(addr1: e->ether, addr2: elem->ether); |
93 | /* Trigger kernel to fill out the ethernet address */ |
94 | return -EAGAIN; |
95 | } |
96 | |
97 | static int |
98 | bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize) |
99 | { |
100 | const struct bitmap_ipmac_elem *elem; |
101 | |
102 | if (!test_bit(id, map->members)) |
103 | return 0; |
104 | elem = get_const_elem(map->extensions, id, dsize); |
105 | /* Timer not started for the incomplete elements */ |
106 | return elem->filled == MAC_FILLED; |
107 | } |
108 | |
109 | static int |
110 | bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem) |
111 | { |
112 | return elem->filled == MAC_FILLED; |
113 | } |
114 | |
115 | static int |
116 | bitmap_ipmac_add_timeout(unsigned long *timeout, |
117 | const struct bitmap_ipmac_adt_elem *e, |
118 | const struct ip_set_ext *ext, struct ip_set *set, |
119 | struct bitmap_ipmac *map, int mode) |
120 | { |
121 | u32 t = ext->timeout; |
122 | |
123 | if (mode == IPSET_ADD_START_STORED_TIMEOUT) { |
124 | if (t == set->timeout) |
125 | /* Timeout was not specified, get stored one */ |
126 | t = *timeout; |
127 | ip_set_timeout_set(timeout, value: t); |
128 | } else { |
129 | /* If MAC is unset yet, we store plain timeout value |
130 | * because the timer is not activated yet |
131 | * and we can reuse it later when MAC is filled out, |
132 | * possibly by the kernel |
133 | */ |
134 | if (e->add_mac) |
135 | ip_set_timeout_set(timeout, value: t); |
136 | else |
137 | *timeout = t; |
138 | } |
139 | return 0; |
140 | } |
141 | |
142 | static int |
143 | bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, |
144 | struct bitmap_ipmac *map, u32 flags, size_t dsize) |
145 | { |
146 | struct bitmap_ipmac_elem *elem; |
147 | |
148 | elem = get_elem(map->extensions, e->id, dsize); |
149 | if (test_bit(e->id, map->members)) { |
150 | if (elem->filled == MAC_FILLED) { |
151 | if (e->add_mac && |
152 | (flags & IPSET_FLAG_EXIST) && |
153 | !ether_addr_equal(addr1: e->ether, addr2: elem->ether)) { |
154 | /* memcpy isn't atomic */ |
155 | clear_bit(nr: e->id, addr: map->members); |
156 | smp_mb__after_atomic(); |
157 | ether_addr_copy(dst: elem->ether, src: e->ether); |
158 | } |
159 | return IPSET_ADD_FAILED; |
160 | } else if (!e->add_mac) |
161 | /* Already added without ethernet address */ |
162 | return IPSET_ADD_FAILED; |
163 | /* Fill the MAC address and trigger the timer activation */ |
164 | clear_bit(nr: e->id, addr: map->members); |
165 | smp_mb__after_atomic(); |
166 | ether_addr_copy(dst: elem->ether, src: e->ether); |
167 | elem->filled = MAC_FILLED; |
168 | return IPSET_ADD_START_STORED_TIMEOUT; |
169 | } else if (e->add_mac) { |
170 | /* We can store MAC too */ |
171 | ether_addr_copy(dst: elem->ether, src: e->ether); |
172 | elem->filled = MAC_FILLED; |
173 | return 0; |
174 | } |
175 | elem->filled = MAC_UNSET; |
176 | /* MAC is not stored yet, don't start timer */ |
177 | return IPSET_ADD_STORE_PLAIN_TIMEOUT; |
178 | } |
179 | |
180 | static int |
181 | bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e, |
182 | struct bitmap_ipmac *map) |
183 | { |
184 | return !test_and_clear_bit(nr: e->id, addr: map->members); |
185 | } |
186 | |
187 | static int |
188 | bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map, |
189 | u32 id, size_t dsize) |
190 | { |
191 | const struct bitmap_ipmac_elem *elem = |
192 | get_const_elem(map->extensions, id, dsize); |
193 | |
194 | return nla_put_ipaddr4(skb, type: IPSET_ATTR_IP, |
195 | htonl(map->first_ip + id)) || |
196 | (elem->filled == MAC_FILLED && |
197 | nla_put(skb, attrtype: IPSET_ATTR_ETHER, ETH_ALEN, data: elem->ether)); |
198 | } |
199 | |
200 | static int |
201 | bitmap_ipmac_do_head(struct sk_buff *skb, const struct bitmap_ipmac *map) |
202 | { |
203 | return nla_put_ipaddr4(skb, type: IPSET_ATTR_IP, htonl(map->first_ip)) || |
204 | nla_put_ipaddr4(skb, type: IPSET_ATTR_IP_TO, htonl(map->last_ip)); |
205 | } |
206 | |
207 | static int |
208 | bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, |
209 | const struct xt_action_param *par, |
210 | enum ipset_adt adt, struct ip_set_adt_opt *opt) |
211 | { |
212 | struct bitmap_ipmac *map = set->data; |
213 | ipset_adtfn adtfn = set->variant->adt[adt]; |
214 | struct bitmap_ipmac_adt_elem e = { .id = 0, .add_mac = 1 }; |
215 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
216 | u32 ip; |
217 | |
218 | ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC)); |
219 | if (ip < map->first_ip || ip > map->last_ip) |
220 | return -IPSET_ERR_BITMAP_RANGE; |
221 | |
222 | /* Backward compatibility: we don't check the second flag */ |
223 | if (skb_mac_header(skb) < skb->head || |
224 | (skb_mac_header(skb) + ETH_HLEN) > skb->data) |
225 | return -EINVAL; |
226 | |
227 | e.id = ip_to_id(m: map, ip); |
228 | |
229 | if (opt->flags & IPSET_DIM_TWO_SRC) |
230 | ether_addr_copy(dst: e.ether, src: eth_hdr(skb)->h_source); |
231 | else |
232 | ether_addr_copy(dst: e.ether, src: eth_hdr(skb)->h_dest); |
233 | |
234 | if (is_zero_ether_addr(addr: e.ether)) |
235 | return -EINVAL; |
236 | |
237 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); |
238 | } |
239 | |
240 | static int |
241 | bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], |
242 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
243 | { |
244 | const struct bitmap_ipmac *map = set->data; |
245 | ipset_adtfn adtfn = set->variant->adt[adt]; |
246 | struct bitmap_ipmac_adt_elem e = { .id = 0 }; |
247 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
248 | u32 ip = 0; |
249 | int ret = 0; |
250 | |
251 | if (tb[IPSET_ATTR_LINENO]) |
252 | *lineno = nla_get_u32(nla: tb[IPSET_ATTR_LINENO]); |
253 | |
254 | if (unlikely(!tb[IPSET_ATTR_IP])) |
255 | return -IPSET_ERR_PROTOCOL; |
256 | |
257 | ret = ip_set_get_hostipaddr4(nla: tb[IPSET_ATTR_IP], ipaddr: &ip); |
258 | if (ret) |
259 | return ret; |
260 | |
261 | ret = ip_set_get_extensions(set, tb, ext: &ext); |
262 | if (ret) |
263 | return ret; |
264 | |
265 | if (ip < map->first_ip || ip > map->last_ip) |
266 | return -IPSET_ERR_BITMAP_RANGE; |
267 | |
268 | e.id = ip_to_id(m: map, ip); |
269 | if (tb[IPSET_ATTR_ETHER]) { |
270 | if (nla_len(nla: tb[IPSET_ATTR_ETHER]) != ETH_ALEN) |
271 | return -IPSET_ERR_PROTOCOL; |
272 | memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN); |
273 | e.add_mac = 1; |
274 | } |
275 | ret = adtfn(set, &e, &ext, &ext, flags); |
276 | |
277 | return ip_set_eexist(ret, flags) ? 0 : ret; |
278 | } |
279 | |
280 | static bool |
281 | bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b) |
282 | { |
283 | const struct bitmap_ipmac *x = a->data; |
284 | const struct bitmap_ipmac *y = b->data; |
285 | |
286 | return x->first_ip == y->first_ip && |
287 | x->last_ip == y->last_ip && |
288 | a->timeout == b->timeout && |
289 | a->extensions == b->extensions; |
290 | } |
291 | |
292 | /* Plain variant */ |
293 | |
294 | #include "ip_set_bitmap_gen.h" |
295 | |
296 | /* Create bitmap:ip,mac type of sets */ |
297 | |
298 | static bool |
299 | init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, |
300 | u32 first_ip, u32 last_ip, u32 elements) |
301 | { |
302 | map->members = bitmap_zalloc(nbits: elements, GFP_KERNEL | __GFP_NOWARN); |
303 | if (!map->members) |
304 | return false; |
305 | map->first_ip = first_ip; |
306 | map->last_ip = last_ip; |
307 | map->elements = elements; |
308 | set->timeout = IPSET_NO_TIMEOUT; |
309 | |
310 | map->set = set; |
311 | set->data = map; |
312 | set->family = NFPROTO_IPV4; |
313 | |
314 | return true; |
315 | } |
316 | |
317 | static int |
318 | bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[], |
319 | u32 flags) |
320 | { |
321 | u32 first_ip = 0, last_ip = 0; |
322 | u64 elements; |
323 | struct bitmap_ipmac *map; |
324 | int ret; |
325 | |
326 | if (unlikely(!tb[IPSET_ATTR_IP] || |
327 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
328 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) |
329 | return -IPSET_ERR_PROTOCOL; |
330 | |
331 | ret = ip_set_get_hostipaddr4(nla: tb[IPSET_ATTR_IP], ipaddr: &first_ip); |
332 | if (ret) |
333 | return ret; |
334 | |
335 | if (tb[IPSET_ATTR_IP_TO]) { |
336 | ret = ip_set_get_hostipaddr4(nla: tb[IPSET_ATTR_IP_TO], ipaddr: &last_ip); |
337 | if (ret) |
338 | return ret; |
339 | if (first_ip > last_ip) |
340 | swap(first_ip, last_ip); |
341 | } else if (tb[IPSET_ATTR_CIDR]) { |
342 | u8 cidr = nla_get_u8(nla: tb[IPSET_ATTR_CIDR]); |
343 | |
344 | if (cidr >= HOST_MASK) |
345 | return -IPSET_ERR_INVALID_CIDR; |
346 | ip_set_mask_from_to(first_ip, last_ip, cidr); |
347 | } else { |
348 | return -IPSET_ERR_PROTOCOL; |
349 | } |
350 | |
351 | elements = (u64)last_ip - first_ip + 1; |
352 | |
353 | if (elements > IPSET_BITMAP_MAX_RANGE + 1) |
354 | return -IPSET_ERR_BITMAP_RANGE_SIZE; |
355 | |
356 | set->dsize = ip_set_elem_len(set, tb, |
357 | len: sizeof(struct bitmap_ipmac_elem), |
358 | align: __alignof__(struct bitmap_ipmac_elem)); |
359 | map = ip_set_alloc(size: sizeof(*map) + elements * set->dsize); |
360 | if (!map) |
361 | return -ENOMEM; |
362 | |
363 | map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); |
364 | set->variant = &bitmap_ipmac; |
365 | if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { |
366 | ip_set_free(members: map); |
367 | return -ENOMEM; |
368 | } |
369 | if (tb[IPSET_ATTR_TIMEOUT]) { |
370 | set->timeout = ip_set_timeout_uget(tb: tb[IPSET_ATTR_TIMEOUT]); |
371 | bitmap_ipmac_gc_init(set, gc: bitmap_ipmac_gc); |
372 | } |
373 | return 0; |
374 | } |
375 | |
376 | static struct ip_set_type bitmap_ipmac_type = { |
377 | .name = "bitmap:ip,mac" , |
378 | .protocol = IPSET_PROTOCOL, |
379 | .features = IPSET_TYPE_IP | IPSET_TYPE_MAC, |
380 | .dimension = IPSET_DIM_TWO, |
381 | .family = NFPROTO_IPV4, |
382 | .revision_min = IPSET_TYPE_REV_MIN, |
383 | .revision_max = IPSET_TYPE_REV_MAX, |
384 | .create = bitmap_ipmac_create, |
385 | .create_policy = { |
386 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
387 | [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, |
388 | [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, |
389 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
390 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, |
391 | }, |
392 | .adt_policy = { |
393 | [IPSET_ATTR_IP] = { .type = NLA_NESTED }, |
394 | [IPSET_ATTR_ETHER] = { .type = NLA_BINARY, |
395 | .len = ETH_ALEN }, |
396 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
397 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
398 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
399 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
400 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING, |
401 | .len = IPSET_MAX_COMMENT_SIZE }, |
402 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, |
403 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, |
404 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, |
405 | }, |
406 | .me = THIS_MODULE, |
407 | }; |
408 | |
409 | static int __init |
410 | bitmap_ipmac_init(void) |
411 | { |
412 | return ip_set_type_register(set_type: &bitmap_ipmac_type); |
413 | } |
414 | |
415 | static void __exit |
416 | bitmap_ipmac_fini(void) |
417 | { |
418 | rcu_barrier(); |
419 | ip_set_type_unregister(set_type: &bitmap_ipmac_type); |
420 | } |
421 | |
422 | module_init(bitmap_ipmac_init); |
423 | module_exit(bitmap_ipmac_fini); |
424 | |