~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netfilter/ipset/ip_set_hash_net.c

Version: ~ [ linux-6.6-rc1 ] ~ [ linux-6.5.2 ] ~ [ linux-6.4.15 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.52 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.131 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.194 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.256 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.294 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.325 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 hash:net type */
  5 
  6 #include <linux/jhash.h>
  7 #include <linux/module.h>
  8 #include <linux/ip.h>
  9 #include <linux/skbuff.h>
 10 #include <linux/errno.h>
 11 #include <linux/random.h>
 12 #include <net/ip.h>
 13 #include <net/ipv6.h>
 14 #include <net/netlink.h>
 15 
 16 #include <linux/netfilter.h>
 17 #include <linux/netfilter/ipset/pfxlen.h>
 18 #include <linux/netfilter/ipset/ip_set.h>
 19 #include <linux/netfilter/ipset/ip_set_hash.h>
 20 
 21 #define IPSET_TYPE_REV_MIN      0
 22 /*                              1    Range as input support for IPv4 added */
 23 /*                              2    nomatch flag support added */
 24 /*                              3    Counters support added */
 25 /*                              4    Comments support added */
 26 /*                              5    Forceadd support added */
 27 /*                              6    skbinfo support added */
 28 #define IPSET_TYPE_REV_MAX      7 /* bucketsize, initval support added */
 29 
 30 MODULE_LICENSE("GPL");
 31 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
 32 IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
 33 MODULE_ALIAS("ip_set_hash:net");
 34 
 35 /* Type specific function prefix */
 36 #define HTYPE           hash_net
 37 #define IP_SET_HASH_WITH_NETS
 38 
 39 /* IPv4 variant */
 40 
 41 /* Member elements  */
 42 struct hash_net4_elem {
 43         __be32 ip;
 44         u16 padding0;
 45         u8 nomatch;
 46         u8 cidr;
 47 };
 48 
 49 /* Common functions */
 50 
 51 static bool
 52 hash_net4_data_equal(const struct hash_net4_elem *ip1,
 53                      const struct hash_net4_elem *ip2,
 54                      u32 *multi)
 55 {
 56         return ip1->ip == ip2->ip &&
 57                ip1->cidr == ip2->cidr;
 58 }
 59 
 60 static int
 61 hash_net4_do_data_match(const struct hash_net4_elem *elem)
 62 {
 63         return elem->nomatch ? -ENOTEMPTY : 1;
 64 }
 65 
 66 static void
 67 hash_net4_data_set_flags(struct hash_net4_elem *elem, u32 flags)
 68 {
 69         elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
 70 }
 71 
 72 static void
 73 hash_net4_data_reset_flags(struct hash_net4_elem *elem, u8 *flags)
 74 {
 75         swap(*flags, elem->nomatch);
 76 }
 77 
 78 static void
 79 hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
 80 {
 81         elem->ip &= ip_set_netmask(cidr);
 82         elem->cidr = cidr;
 83 }
 84 
 85 static bool
 86 hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
 87 {
 88         u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
 89 
 90         if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip) ||
 91             nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
 92             (flags &&
 93              nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
 94                 goto nla_put_failure;
 95         return false;
 96 
 97 nla_put_failure:
 98         return true;
 99 }
100 
101 static void
102 hash_net4_data_next(struct hash_net4_elem *next,
103                     const struct hash_net4_elem *d)
104 {
105         next->ip = d->ip;
106 }
107 
108 #define MTYPE           hash_net4
109 #define HOST_MASK       32
110 #include "ip_set_hash_gen.h"
111 
112 static int
113 hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
114                const struct xt_action_param *par,
115                enum ipset_adt adt, struct ip_set_adt_opt *opt)
116 {
117         const struct hash_net4 *h = set->data;
118         ipset_adtfn adtfn = set->variant->adt[adt];
119         struct hash_net4_elem e = {
120                 .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
121         };
122         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
123 
124         if (e.cidr == 0)
125                 return -EINVAL;
126         if (adt == IPSET_TEST)
127                 e.cidr = HOST_MASK;
128 
129         ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
130         e.ip &= ip_set_netmask(e.cidr);
131 
132         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
133 }
134 
135 static int
136 hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
137                enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
138 {
139         const struct hash_net4 *h = set->data;
140         ipset_adtfn adtfn = set->variant->adt[adt];
141         struct hash_net4_elem e = { .cidr = HOST_MASK };
142         struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
143         u32 ip = 0, ip_to = 0, ipn, n = 0;
144         int ret;
145 
146         if (tb[IPSET_ATTR_LINENO])
147                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
148 
149         if (unlikely(!tb[IPSET_ATTR_IP] ||
150                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
151                 return -IPSET_ERR_PROTOCOL;
152 
153         ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
154         if (ret)
155                 return ret;
156 
157         ret = ip_set_get_extensions(set, tb, &ext);
158         if (ret)
159                 return ret;
160 
161         if (tb[IPSET_ATTR_CIDR]) {
162                 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
163                 if (!e.cidr || e.cidr > HOST_MASK)
164                         return -IPSET_ERR_INVALID_CIDR;
165         }
166 
167         if (tb[IPSET_ATTR_CADT_FLAGS]) {
168                 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
169 
170                 if (cadt_flags & IPSET_FLAG_NOMATCH)
171                         flags |= (IPSET_FLAG_NOMATCH << 16);
172         }
173 
174         if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
175                 e.ip = htonl(ip & ip_set_hostmask(e.cidr));
176                 ret = adtfn(set, &e, &ext, &ext, flags);
177                 return ip_set_enomatch(ret, flags, adt, set) ? -ret :
178                        ip_set_eexist(ret, flags) ? 0 : ret;
179         }
180 
181         ip_to = ip;
182         if (tb[IPSET_ATTR_IP_TO]) {
183                 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
184                 if (ret)
185                         return ret;
186                 if (ip_to < ip)
187                         swap(ip, ip_to);
188                 if (ip + UINT_MAX == ip_to)
189                         return -IPSET_ERR_HASH_RANGE;
190         }
191         ipn = ip;
192         do {
193                 ipn = ip_set_range_to_cidr(ipn, ip_to, &e.cidr);
194                 n++;
195         } while (ipn++ < ip_to);
196 
197         if (n > IPSET_MAX_RANGE)
198                 return -ERANGE;
199 
200         if (retried)
201                 ip = ntohl(h->next.ip);
202         do {
203                 e.ip = htonl(ip);
204                 ip = ip_set_range_to_cidr(ip, ip_to, &e.cidr);
205                 ret = adtfn(set, &e, &ext, &ext, flags);
206                 if (ret && !ip_set_eexist(ret, flags))
207                         return ret;
208 
209                 ret = 0;
210         } while (ip++ < ip_to);
211         return ret;
212 }
213 
214 /* IPv6 variant */
215 
216 struct hash_net6_elem {
217         union nf_inet_addr ip;
218         u16 padding0;
219         u8 nomatch;
220         u8 cidr;
221 };
222 
223 /* Common functions */
224 
225 static bool
226 hash_net6_data_equal(const struct hash_net6_elem *ip1,
227                      const struct hash_net6_elem *ip2,
228                      u32 *multi)
229 {
230         return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6) &&
231                ip1->cidr == ip2->cidr;
232 }
233 
234 static int
235 hash_net6_do_data_match(const struct hash_net6_elem *elem)
236 {
237         return elem->nomatch ? -ENOTEMPTY : 1;
238 }
239 
240 static void
241 hash_net6_data_set_flags(struct hash_net6_elem *elem, u32 flags)
242 {
243         elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
244 }
245 
246 static void
247 hash_net6_data_reset_flags(struct hash_net6_elem *elem, u8 *flags)
248 {
249         swap(*flags, elem->nomatch);
250 }
251 
252 static void
253 hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
254 {
255         ip6_netmask(&elem->ip, cidr);
256         elem->cidr = cidr;
257 }
258 
259 static bool
260 hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
261 {
262         u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
263 
264         if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip.in6) ||
265             nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr) ||
266             (flags &&
267              nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
268                 goto nla_put_failure;
269         return false;
270 
271 nla_put_failure:
272         return true;
273 }
274 
275 static void
276 hash_net6_data_next(struct hash_net6_elem *next,
277                     const struct hash_net6_elem *d)
278 {
279 }
280 
281 #undef MTYPE
282 #undef HOST_MASK
283 
284 #define MTYPE           hash_net6
285 #define HOST_MASK       128
286 #define IP_SET_EMIT_CREATE
287 #include "ip_set_hash_gen.h"
288 
289 static int
290 hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
291                const struct xt_action_param *par,
292                enum ipset_adt adt, struct ip_set_adt_opt *opt)
293 {
294         const struct hash_net6 *h = set->data;
295         ipset_adtfn adtfn = set->variant->adt[adt];
296         struct hash_net6_elem e = {
297                 .cidr = INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
298         };
299         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
300 
301         if (e.cidr == 0)
302                 return -EINVAL;
303         if (adt == IPSET_TEST)
304                 e.cidr = HOST_MASK;
305 
306         ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
307         ip6_netmask(&e.ip, e.cidr);
308 
309         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
310 }
311 
312 static int
313 hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
314                enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
315 {
316         ipset_adtfn adtfn = set->variant->adt[adt];
317         struct hash_net6_elem e = { .cidr = HOST_MASK };
318         struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
319         int ret;
320 
321         if (tb[IPSET_ATTR_LINENO])
322                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
323 
324         if (unlikely(!tb[IPSET_ATTR_IP] ||
325                      !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
326                 return -IPSET_ERR_PROTOCOL;
327         if (unlikely(tb[IPSET_ATTR_IP_TO]))
328                 return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
329 
330         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip);
331         if (ret)
332                 return ret;
333 
334         ret = ip_set_get_extensions(set, tb, &ext);
335         if (ret)
336                 return ret;
337 
338         if (tb[IPSET_ATTR_CIDR]) {
339                 e.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
340                 if (!e.cidr || e.cidr > HOST_MASK)
341                         return -IPSET_ERR_INVALID_CIDR;
342         }
343 
344         ip6_netmask(&e.ip, e.cidr);
345 
346         if (tb[IPSET_ATTR_CADT_FLAGS]) {
347                 u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
348 
349                 if (cadt_flags & IPSET_FLAG_NOMATCH)
350                         flags |= (IPSET_FLAG_NOMATCH << 16);
351         }
352 
353         ret = adtfn(set, &e, &ext, &ext, flags);
354 
355         return ip_set_enomatch(ret, flags, adt, set) ? -ret :
356                ip_set_eexist(ret, flags) ? 0 : ret;
357 }
358 
359 static struct ip_set_type hash_net_type __read_mostly = {
360         .name           = "hash:net",
361         .protocol       = IPSET_PROTOCOL,
362         .features       = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
363         .dimension      = IPSET_DIM_ONE,
364         .family         = NFPROTO_UNSPEC,
365         .revision_min   = IPSET_TYPE_REV_MIN,
366         .revision_max   = IPSET_TYPE_REV_MAX,
367         .create_flags[IPSET_TYPE_REV_MAX] = IPSET_CREATE_FLAG_BUCKETSIZE,
368         .create         = hash_net_create,
369         .create_policy  = {
370                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
371                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
372                 [IPSET_ATTR_INITVAL]    = { .type = NLA_U32 },
373                 [IPSET_ATTR_BUCKETSIZE] = { .type = NLA_U8 },
374                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
375                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
376                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
377         },
378         .adt_policy     = {
379                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
380                 [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
381                 [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
382                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
383                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
384                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
385                 [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
386                 [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
387                 [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING,
388                                             .len  = IPSET_MAX_COMMENT_SIZE },
389                 [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
390                 [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
391                 [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
392         },
393         .me             = THIS_MODULE,
394 };
395 
396 static int __init
397 hash_net_init(void)
398 {
399         return ip_set_type_register(&hash_net_type);
400 }
401 
402 static void __exit
403 hash_net_fini(void)
404 {
405         rcu_barrier();
406         ip_set_type_unregister(&hash_net_type);
407 }
408 
409 module_init(hash_net_init);
410 module_exit(hash_net_fini);
411 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp