1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@netfilter.org> */ |
3 | |
4 | /* Kernel module implementing an IP set type: the bitmap:port type */ |
5 | |
6 | #include <linux/module.h> |
7 | #include <linux/ip.h> |
8 | #include <linux/skbuff.h> |
9 | #include <linux/errno.h> |
10 | #include <linux/netlink.h> |
11 | #include <linux/jiffies.h> |
12 | #include <linux/timer.h> |
13 | #include <net/netlink.h> |
14 | |
15 | #include <linux/netfilter/ipset/ip_set.h> |
16 | #include <linux/netfilter/ipset/ip_set_bitmap.h> |
17 | #include <linux/netfilter/ipset/ip_set_getport.h> |
18 | |
19 | #define IPSET_TYPE_REV_MIN 0 |
20 | /* 1 Counter support added */ |
21 | /* 2 Comment support added */ |
22 | #define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */ |
23 | |
24 | MODULE_LICENSE("GPL" ); |
25 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>" ); |
26 | IP_SET_MODULE_DESC("bitmap:port" , IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); |
27 | MODULE_ALIAS("ip_set_bitmap:port" ); |
28 | |
29 | #define MTYPE bitmap_port |
30 | |
31 | /* Type structure */ |
32 | struct bitmap_port { |
33 | unsigned long *members; /* the set members */ |
34 | u16 first_port; /* host byte order, included in range */ |
35 | u16 last_port; /* host byte order, included in range */ |
36 | u32 elements; /* number of max elements in the set */ |
37 | size_t memsize; /* members size */ |
38 | struct timer_list gc; /* garbage collection */ |
39 | struct ip_set *set; /* attached to this ip_set */ |
40 | unsigned char extensions[] /* data extensions */ |
41 | __aligned(__alignof__(u64)); |
42 | }; |
43 | |
44 | /* ADT structure for generic function args */ |
45 | struct bitmap_port_adt_elem { |
46 | u16 id; |
47 | }; |
48 | |
49 | static u16 |
50 | port_to_id(const struct bitmap_port *m, u16 port) |
51 | { |
52 | return port - m->first_port; |
53 | } |
54 | |
55 | /* Common functions */ |
56 | |
57 | static int |
58 | bitmap_port_do_test(const struct bitmap_port_adt_elem *e, |
59 | const struct bitmap_port *map, size_t dsize) |
60 | { |
61 | return !!test_bit(e->id, map->members); |
62 | } |
63 | |
64 | static int |
65 | bitmap_port_gc_test(u16 id, const struct bitmap_port *map, size_t dsize) |
66 | { |
67 | return !!test_bit(id, map->members); |
68 | } |
69 | |
70 | static int |
71 | bitmap_port_do_add(const struct bitmap_port_adt_elem *e, |
72 | struct bitmap_port *map, u32 flags, size_t dsize) |
73 | { |
74 | return !!test_bit(e->id, map->members); |
75 | } |
76 | |
77 | static int |
78 | bitmap_port_do_del(const struct bitmap_port_adt_elem *e, |
79 | struct bitmap_port *map) |
80 | { |
81 | return !test_and_clear_bit(nr: e->id, addr: map->members); |
82 | } |
83 | |
84 | static int |
85 | bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id, |
86 | size_t dsize) |
87 | { |
88 | return nla_put_net16(skb, attrtype: IPSET_ATTR_PORT, |
89 | htons(map->first_port + id)); |
90 | } |
91 | |
92 | static int |
93 | bitmap_port_do_head(struct sk_buff *skb, const struct bitmap_port *map) |
94 | { |
95 | return nla_put_net16(skb, attrtype: IPSET_ATTR_PORT, htons(map->first_port)) || |
96 | nla_put_net16(skb, attrtype: IPSET_ATTR_PORT_TO, htons(map->last_port)); |
97 | } |
98 | |
99 | static bool |
100 | ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port) |
101 | { |
102 | bool ret; |
103 | u8 proto; |
104 | |
105 | switch (pf) { |
106 | case NFPROTO_IPV4: |
107 | ret = ip_set_get_ip4_port(skb, src, port, proto: &proto); |
108 | break; |
109 | case NFPROTO_IPV6: |
110 | ret = ip_set_get_ip6_port(skb, src, port, proto: &proto); |
111 | break; |
112 | default: |
113 | return false; |
114 | } |
115 | if (!ret) |
116 | return ret; |
117 | switch (proto) { |
118 | case IPPROTO_TCP: |
119 | case IPPROTO_UDP: |
120 | return true; |
121 | default: |
122 | return false; |
123 | } |
124 | } |
125 | |
126 | static int |
127 | bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb, |
128 | const struct xt_action_param *par, |
129 | enum ipset_adt adt, struct ip_set_adt_opt *opt) |
130 | { |
131 | struct bitmap_port *map = set->data; |
132 | ipset_adtfn adtfn = set->variant->adt[adt]; |
133 | struct bitmap_port_adt_elem e = { .id = 0 }; |
134 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); |
135 | __be16 __port; |
136 | u16 port = 0; |
137 | |
138 | if (!ip_set_get_ip_port(skb, pf: opt->family, |
139 | src: opt->flags & IPSET_DIM_ONE_SRC, port: &__port)) |
140 | return -EINVAL; |
141 | |
142 | port = ntohs(__port); |
143 | |
144 | if (port < map->first_port || port > map->last_port) |
145 | return -IPSET_ERR_BITMAP_RANGE; |
146 | |
147 | e.id = port_to_id(m: map, port); |
148 | |
149 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); |
150 | } |
151 | |
152 | static int |
153 | bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[], |
154 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) |
155 | { |
156 | struct bitmap_port *map = set->data; |
157 | ipset_adtfn adtfn = set->variant->adt[adt]; |
158 | struct bitmap_port_adt_elem e = { .id = 0 }; |
159 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); |
160 | u32 port; /* wraparound */ |
161 | u16 port_to; |
162 | int ret = 0; |
163 | |
164 | if (tb[IPSET_ATTR_LINENO]) |
165 | *lineno = nla_get_u32(nla: tb[IPSET_ATTR_LINENO]); |
166 | |
167 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || |
168 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO))) |
169 | return -IPSET_ERR_PROTOCOL; |
170 | |
171 | port = ip_set_get_h16(attr: tb[IPSET_ATTR_PORT]); |
172 | if (port < map->first_port || port > map->last_port) |
173 | return -IPSET_ERR_BITMAP_RANGE; |
174 | ret = ip_set_get_extensions(set, tb, ext: &ext); |
175 | if (ret) |
176 | return ret; |
177 | |
178 | if (adt == IPSET_TEST) { |
179 | e.id = port_to_id(m: map, port); |
180 | return adtfn(set, &e, &ext, &ext, flags); |
181 | } |
182 | |
183 | if (tb[IPSET_ATTR_PORT_TO]) { |
184 | port_to = ip_set_get_h16(attr: tb[IPSET_ATTR_PORT_TO]); |
185 | if (port > port_to) { |
186 | swap(port, port_to); |
187 | if (port < map->first_port) |
188 | return -IPSET_ERR_BITMAP_RANGE; |
189 | } |
190 | } else { |
191 | port_to = port; |
192 | } |
193 | |
194 | if (port_to > map->last_port) |
195 | return -IPSET_ERR_BITMAP_RANGE; |
196 | |
197 | for (; port <= port_to; port++) { |
198 | e.id = port_to_id(m: map, port); |
199 | ret = adtfn(set, &e, &ext, &ext, flags); |
200 | |
201 | if (ret && !ip_set_eexist(ret, flags)) |
202 | return ret; |
203 | |
204 | ret = 0; |
205 | } |
206 | return ret; |
207 | } |
208 | |
209 | static bool |
210 | bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b) |
211 | { |
212 | const struct bitmap_port *x = a->data; |
213 | const struct bitmap_port *y = b->data; |
214 | |
215 | return x->first_port == y->first_port && |
216 | x->last_port == y->last_port && |
217 | a->timeout == b->timeout && |
218 | a->extensions == b->extensions; |
219 | } |
220 | |
221 | /* Plain variant */ |
222 | |
223 | struct bitmap_port_elem { |
224 | }; |
225 | |
226 | #include "ip_set_bitmap_gen.h" |
227 | |
228 | /* Create bitmap:ip type of sets */ |
229 | |
230 | static bool |
231 | init_map_port(struct ip_set *set, struct bitmap_port *map, |
232 | u16 first_port, u16 last_port) |
233 | { |
234 | map->members = bitmap_zalloc(nbits: map->elements, GFP_KERNEL | __GFP_NOWARN); |
235 | if (!map->members) |
236 | return false; |
237 | map->first_port = first_port; |
238 | map->last_port = last_port; |
239 | set->timeout = IPSET_NO_TIMEOUT; |
240 | |
241 | map->set = set; |
242 | set->data = map; |
243 | set->family = NFPROTO_UNSPEC; |
244 | |
245 | return true; |
246 | } |
247 | |
248 | static int |
249 | bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[], |
250 | u32 flags) |
251 | { |
252 | struct bitmap_port *map; |
253 | u16 first_port, last_port; |
254 | u32 elements; |
255 | |
256 | if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || |
257 | !ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) || |
258 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || |
259 | !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) |
260 | return -IPSET_ERR_PROTOCOL; |
261 | |
262 | first_port = ip_set_get_h16(attr: tb[IPSET_ATTR_PORT]); |
263 | last_port = ip_set_get_h16(attr: tb[IPSET_ATTR_PORT_TO]); |
264 | if (first_port > last_port) |
265 | swap(first_port, last_port); |
266 | |
267 | elements = last_port - first_port + 1; |
268 | set->dsize = ip_set_elem_len(set, tb, len: 0, align: 0); |
269 | map = ip_set_alloc(size: sizeof(*map) + elements * set->dsize); |
270 | if (!map) |
271 | return -ENOMEM; |
272 | |
273 | map->elements = elements; |
274 | map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long); |
275 | set->variant = &bitmap_port; |
276 | if (!init_map_port(set, map, first_port, last_port)) { |
277 | ip_set_free(members: map); |
278 | return -ENOMEM; |
279 | } |
280 | if (tb[IPSET_ATTR_TIMEOUT]) { |
281 | set->timeout = ip_set_timeout_uget(tb: tb[IPSET_ATTR_TIMEOUT]); |
282 | bitmap_port_gc_init(set, gc: bitmap_port_gc); |
283 | } |
284 | return 0; |
285 | } |
286 | |
287 | static struct ip_set_type bitmap_port_type = { |
288 | .name = "bitmap:port" , |
289 | .protocol = IPSET_PROTOCOL, |
290 | .features = IPSET_TYPE_PORT, |
291 | .dimension = IPSET_DIM_ONE, |
292 | .family = NFPROTO_UNSPEC, |
293 | .revision_min = IPSET_TYPE_REV_MIN, |
294 | .revision_max = IPSET_TYPE_REV_MAX, |
295 | .create = bitmap_port_create, |
296 | .create_policy = { |
297 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, |
298 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, |
299 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
300 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, |
301 | }, |
302 | .adt_policy = { |
303 | [IPSET_ATTR_PORT] = { .type = NLA_U16 }, |
304 | [IPSET_ATTR_PORT_TO] = { .type = NLA_U16 }, |
305 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, |
306 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, |
307 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, |
308 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, |
309 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING, |
310 | .len = IPSET_MAX_COMMENT_SIZE }, |
311 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, |
312 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, |
313 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, |
314 | }, |
315 | .me = THIS_MODULE, |
316 | }; |
317 | |
318 | static int __init |
319 | bitmap_port_init(void) |
320 | { |
321 | return ip_set_type_register(set_type: &bitmap_port_type); |
322 | } |
323 | |
324 | static void __exit |
325 | bitmap_port_fini(void) |
326 | { |
327 | rcu_barrier(); |
328 | ip_set_type_unregister(set_type: &bitmap_port_type); |
329 | } |
330 | |
331 | module_init(bitmap_port_init); |
332 | module_exit(bitmap_port_fini); |
333 | |