1 /*
2 ** Copyright (C) 2008-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8
9 /*
10 ** skipset.c
11 **
12 ** skipset.c provides a data structure for maintaining IP
13 ** addresses. The implementation uses a Radix Tree (aka Patricia
14 ** Trie) to keep IP addresses and their prefixes. The
15 ** implementation can support IPv4 or IPv6 addresses, though each
16 ** instance of an IPset can only hold one type of IP address.
17 **
18 ** skipset.c is a replacement for the skIPTree_t data structure
19 ** defined in iptree.c.
20 **
21 ** Mark Thomas
22 ** Febrary 2011
23 */
24
25 #include <silk/silk.h>
26
27 RCSIDENT("$SiLK: skipset.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
28
29 #include <silk/rwrec.h>
30 #include <silk/skipaddr.h>
31 #include <silk/skipset.h>
32 #include <silk/sksite.h>
33 #include <silk/skstream.h>
34 #include <silk/skvector.h>
35 #include <silk/utils.h>
36 #include "skheader_priv.h"
37
38
39 /*
40 * IMPLEMENTATION
41 *
42 * The IPset code for to represent an IPv6 IPset in memory is
43 * implemented as a type of Radix Tree (aka Patricia Tree), where
44 * internal members of the tree are "nodes" and the terminal
45 * members are "leaves". Within an IPset instance, all nodes are
46 * allocated in one array, and all leaves are allocated in another
47 * array. The Radix Tree is not binary; each node points to
48 * IPSET_NUM_CHILDREN other nodes or leaves, and NUM_BITS is the
49 * number of bits of an IP address that must be examined to
50 * determine which branch to follow from a node.
51 *
52 * There is both an IPv4 and IPv6 version of the Radix Tree. The
53 * IPv4 Radix tree was used until SiLK 3.6.0; at that point the
54 * in-core IPv4 tree reverted the IPTree format. Using the IPv4
55 * Radix tree internally may be requested via an envvar.
56 *
57 * The IPv4 node structure is given here and described below:
58 *
59 * struct ipset_node_v4_st {
60 * uint32_t child[IPSET_NUM_CHILDREN];
61 *
62 * SET_BMAP_DECLARE(child_is_leaf, IPSET_NUM_CHILDREN);
63 *
64 * SET_BMAP_DECLARE(child_repeated, IPSET_NUM_CHILDREN);
65 *
66 * uint8_t prefix;
67 *
68 * // reserved/unsed bytes
69 * uint8_t reserved3;
70 * uint8_t reserved2;
71 * uint8_t reserved1;
72 *
73 * uint32_t ip;
74 * };
75 *
76 * Each node has an 'ip' member to hold a complete IP address; a
77 * 'prefix' value in the node says how many of the bits in that IP
78 * address are valid. The IP/prefix on a node provides the lower
79 * and upper bounds for the CIDR blocks of the children of the
80 * node. The prefix of a node will always be an even multiple of
81 * the NUM_BITS value of the IPset.
82 *
83 * IPv4 addresses are stored as uint32_t's in native byte order.
84 * IPv6 addresses are stored as an ipset_ipv6_t, which contains 2
85 * uint64_t's in native byte order. The 'ip' value appears at the
86 * bottom of the node, so that the layout of IPv4 nodes and IPv6
87 * nodes (ipset_node_v6_st) are identical except for the IP.
88 *
89 * Instead of nodes having pointers to other nodes or leaves, nodes
90 * contain the 'child[]' array of integer values that are indexes
91 * into either the array of nodes or the array of leaves. Since a
92 * given index may refer to either the node array or the leaf
93 * array, nodes also contain the 'child_is_leaf' bitmap that says
94 * which array the index references.
95 *
96 * If a node points to a leaf where the leaf's prefix is
97 * numerically less than (node->prefix + NUM_BITS), then more than
98 * one child[] entry will point to the same leaf index. When this
99 * occurs, the lowest entry in the child[] array that points to
100 * this leaf is considered the "real" entry, and the other indexes
101 * to this leaf in child[] will also have their bit set within the
102 * 'child_repeated' bitmap on the node.
103 *
104 * Assume an IPset where NUM_BITS is set to 4, so that each node
105 * points to 16 children. Also assume a node that contains
106 * 2.0.0.0/8. If the child[] array points to any nodes, the prefix
107 * on those nodes must not be larger than a /12 (that is, the value
108 * of the prefix must be 12 or numerically greater). Suppose the
109 * IPset contains the value 2.32.0.0/11. child[2] and child[3]
110 * will both contain the index of the leaf; bits 2 and 3 of the
111 * 'child_is_leaf' bitmap will be set, and bit 3 of the
112 * 'child_repeated' bitmap will be set.
113 *
114 * When a node is removed from the IPset such that it is no longer
115 * needed, the node is added to a 'free_list' of nodes, which is
116 * maintained by the IPset. The list is implemented as a stack,
117 * where child[0] of each node contains the index of the previous
118 * node in the stack. The index zero is reserved to mean the
119 * free_list is empty.
120 *
121 * The structure of the leaf for IPv4 is given here:
122 *
123 * struct ipset_leaf_v4_st {
124 * uint8_t prefix;
125 *
126 * // reserved/unsed bytes
127 * uint8_t reserved3;
128 * uint8_t reserved2;
129 * uint8_t reserved1;
130 *
131 * uint32_t ip;
132 * };
133 *
134 * The leaf contains only the IP and the prefix.
135 *
136 * The IPset also maintains a 'free_list' of leaves that is
137 * maintained as a stack. For leaves, the 'ip' member is used as
138 * the index to the previous leaf in the stack.
139 *
140 * If an IPset is marked as 'clean', the array of leaves contains
141 * the leaves in sorted order. This allows for fast iteration over
142 * the leaves of the IPset and allows streaming of the IPset.
143 * Additional properties of a 'clean' IPset are (a)Contiguous
144 * leaves have been combined to contain the largest possible CIDR
145 * block, (b)The leaves array contains no holes (that is, the
146 * 'free_list' of leaves is empty), and (c)The nodes array contains
147 * no holes.
148 *
149 * An IPset can be made clean by calling skIPSetClean(); some
150 * operations on the IPset require that the set be clean before it
151 * can be operated on.
152 *
153 * The root of the tree can be any node or leaf. The index of the
154 * root is specified in the skipset_t structure. The skipset_t
155 * structure also contains a flag denoting whether the index is a
156 * node or a leaf.
157 *
158 * The on-disk storage may match the in-core storage. This would
159 * allow us to mmap() the data section of the file when reading a
160 * set---as long as the set is in native byte order and the data
161 * section is not compressed.
162 *
163 *
164 * The IPset structure is currently optimized to hold large CIDR
165 * blocks. When a large number of widely spaced individual IPs are
166 * given, the size of the IPset will explode, since each IP is
167 * represented by an ipset_leaf_vX_t structure that is twice as
168 * large as the individual IP address. We need to allow some way
169 * for the leaves of the IPset to hold multiple IPs. For example,
170 * if the leaves held a bitmap of which IPs were set.
171 *
172 *
173 */
174
175
176 /* LOCAL DEFINES AND TYPEDEFS */
177
178 /*
179 * Set to non-zero to print a message to stderr whenever the
180 * radix-tree buffer is (re-)allocated.
181 */
182 /* #define TRACE_ALLOC 1 */
183 #ifndef TRACE_ALLOC
184 #define TRACE_ALLOC 0
185 #endif
186
187 /*
188 * The numeric id of the initial format of an IPset file. This
189 * format is only capable of holding IPv4 addresses.
190 *
191 * IPs are stored on disk in blocks of nine 32-bit words which
192 * represent a /24. The first uint32_t (position [0]) is the base
193 * IP of the /24 (a.b.c.0); the remaining eight uint32_t's are a
194 * 256-bit bitmap that represents the IPs in that /24. Each
195 * uint32_t is a /27. A high bit indicates the address is present.
196 * The least significant bit in position [1] is a.b.c.0, and the
197 * most significant bit in position [8] is a.b.c.255.
198 *
199 * The /24s in the file appear in sorted order. All values are
200 * written to the file in native byte order.
201 *
202 * No header entry is associated with this format.
203 *
204 * Note: Very early IPset files did not properly set the version,
205 * and pre-SiLK 1.0 files that have a version number of 0 or 1 are
206 * identical to version 2.
207 */
208 #define IPSET_REC_VERSION_CLASSC 2
209
210 /*
211 * The numeric id of the IPset file format introduced in SiLK-3.0.
212 * Files in this format may store either IPv4 or IPv6 addresses (a
213 * header entry specifies which).
214 *
215 * This version contains a dump of the radix-tree data structure
216 * that is used in-memory. The reasoning behind this was that the
217 * data could be mmap()ed directly from disk without having to read
218 * the file into memory. For this to work, the file's data must
219 * not be compressed, the byte-order of the file must match the
220 * machine's byte-order, and the stream must be seekable (not
221 * standard input).
222 *
223 * The radix data structure maintains the (interior) nodes separate
224 * from the leaves. In the output stream, all nodes are written
225 * first, then the leaves. The leaves are sorted by IP before
226 * being written, and the first leaf in the output stream does not
227 * contain data. An individual leaf is 8 octets for IPv4 and 24
228 * octets for IPv6. For IPv4, a leaf contains the CIDR prefix in
229 * the first octet, three empty octets, and the 32-bit IPv4 address
230 * in native byte order. For IPv6, a leaf contains the CIDR prefix
231 * in the first octet, seven(!) empty octets, followed by two
232 * unsigned 64-bit numbers is native byte order. The first 64-bit
233 * number contains the upper 8 octets of the IPv6 address, and the
234 * second number contains the lower 8 octets.
235 *
236 * The file has a header entry that may be used to determine
237 * whether the file contains IPv4 or IPv6 addresses. The contents
238 * of the header are the number of children per node, the number of
239 * leaves, the size of a leaf, the number of (interior) nodes, the
240 * size of a node, and the location of the root node. The leaf
241 * size is 8 for IPv4 and 24 for IPv6.
242 *
243 * All IPv4 IPsets were written in this format between SiLK 3.0.0
244 * and SiLK 3.5.1. SiLK 3.6.0 reverted to using
245 * IPSET_REC_VERSION_CLASSC files for IPv4 IPsets.
246 */
247 #define IPSET_REC_VERSION_RADIX 3
248
249 /*
250 * The numeric id of the IPset file format introduced in SiLK-3.7.
251 * The file may contain either IPv4 or IPv6 addresses (a header
252 * entry specifies which).
253 *
254 * This format is not the default in order that previous releases
255 * of the SiLK 3.x series may read IPsets created by the default
256 * configuration of this release.
257 *
258 * IP addresses are stored as "blocks". Each block starts with an
259 * IP address and a single unsigned octet value. If the single
260 * octet is less than or equal to 0x80, that is the end of the
261 * block. The IP address is the base address of a netblock and the
262 * single octet is the CIDR mask for the netblock.
263 *
264 * If the octet is strictly greater than 0x80, the address is the
265 * base address for a bitmap. The value of 0x81 means the bitmap
266 * has 256 bits containing a /24 in IPv4 or a /120 in IPv6. These
267 * bitmaps are similar to those in IPSET_REC_VERSION_CLASSC.
268 *
269 * The IPs in the file appear in sorted order. IPv4 addresses and
270 * values in the bitmap are written in native byte order. IPv6
271 * addresses are stored as an array of 16 uint8_t's in network byte
272 * order.
273 *
274 * The file has a header entry that may be used to determine
275 * whether the file contains IPv4 or IPv6 addresses. The header
276 * entry is identical with that used by IPSET_REC_VERSION_RADIX.
277 * All fields are 0 except for the leaf length field. The leaf
278 * length is 4 for files containing IPv4 addresses and 16 for files
279 * containing IPv6.
280 */
281 #define IPSET_REC_VERSION_CIDRBMAP 4
282
283 /*
284 * The numeric id of the IPset file format introduced in SiLK-3.14.
285 * The file may contain only IPv6 addresses.
286 *
287 * This format is not the default in order that previous releases
288 * of the SiLK 3.x series may read IPsets created by the default
289 * configuration of this release.
290 *
291 * IP addresses are split into two 64 bit values, and they may be
292 * viewed as being on a two level tree, where the upper 64 bits
293 * appear on one level and the lower 64 bits on the other. Each 64
294 * bit value is followed by a single byte. When the IP represents
295 * a /64 or larger (more IPs), the block is represented by a single
296 * 64 bit value and the prefix; all other IPs are represented by
297 * two 64 bit values. For IPs in the same /64, the upper 64 bit
298 * value appears once followed by 0x82. Next are the lower 64 bits
299 * of all the IPs in that /64. Each lower IP is followed either by
300 * a value between 0 and 0x80 indicating the prefix of the netblock
301 * or the value 0x81 indicating that a 256-bit bitmap follows for
302 * the IPs in that /120, similar to IPSET_REC_VERSION_CIDRBMAP and
303 * IPSET_REC_VERSION_CLASSC.
304 *
305 * The IPs appear in sorted order. All values are written in
306 * native byte order.
307 *
308 * Although the file format contains only IPv6 addresses, there is
309 * a header entry that confirms this. The header entry is
310 * identical to that used by IPSET_REC_VERSION_RADIX. All fields
311 * are 0 except for the leaf length field. The expected leaf
312 * length is 16.
313 */
314 #define IPSET_REC_VERSION_SLASH64 5
315
316 /*
317 * Ideas for the IPset file formats of the future:
318 *
319 * Separate IPv4 addresses from IPv6 to save 12 bytes per IPv4
320 * address.
321 *
322 * Instead of intermixing single IPs, bitmaps, and CIDR blocks in
323 * one list (with an extra byte per address to specify what type
324 * type of thing it is), separate the three types of things into
325 * three separate lists.
326 *
327 * Disadvantage of both of these changes is that the addresses in
328 * the file are no longer sorted.
329 */
330
331 /*
332 * This record version tells the writer to
333 * IPSET_REC_VERSION_DEFAULT_IPV4 for IPv4 IPsets and
334 * IPSET_REC_VERSION_DEFAULT_IPV6 for IPv6 IPsets.
335 */
336 #define IPSET_REC_VERSION_DEFAULT 0
337
338 /*
339 * When writing a IPset that contains IPv4 addresses, this is the
340 * default version file format to use.
341 */
342 #if !defined(SK_IPSET_DEFAULT_VERSION)
343 #define IPSET_REC_VERSION_DEFAULT_IPV4 IPSET_REC_VERSION_CLASSC
344 #elif SK_IPSET_DEFAULT_VERSION == 5
345 #define IPSET_REC_VERSION_DEFAULT_IPV4 IPSET_REC_VERSION_CIDRBMAP
346 #elif SK_IPSET_DEFAULT_VERSION == 4
347 #define IPSET_REC_VERSION_DEFAULT_IPV4 IPSET_REC_VERSION_CIDRBMAP
348 #else
349 #define IPSET_REC_VERSION_DEFAULT_IPV4 IPSET_REC_VERSION_CLASSC
350 #endif
351
352 /*
353 * When writing a IPset that contains IPv6 addresses, this is the
354 * default version file format to use.
355 */
356 #if !defined(SK_IPSET_DEFAULT_VERSION)
357 #define IPSET_REC_VERSION_DEFAULT_IPV6 IPSET_REC_VERSION_RADIX
358 #elif SK_IPSET_DEFAULT_VERSION == 5
359 #define IPSET_REC_VERSION_DEFAULT_IPV6 IPSET_REC_VERSION_SLASH64
360 #elif SK_IPSET_DEFAULT_VERSION == 4
361 #define IPSET_REC_VERSION_DEFAULT_IPV6 IPSET_REC_VERSION_CIDRBMAP
362 #else
363 #define IPSET_REC_VERSION_DEFAULT_IPV6 IPSET_REC_VERSION_RADIX
364 #endif
365
366 /*
367 * Minimum file version available
368 */
369 #define IPSET_REC_VERSION_MIN IPSET_REC_VERSION_DEFAULT
370
371 /*
372 * Maximum file version available
373 */
374 #define IPSET_REC_VERSION_MAX IPSET_REC_VERSION_SLASH64
375
376 /*
377 * Name of an environment variable that, when set, is used in place
378 * of IPSET_REC_VERSION_DEFAULT. This is advertised.
379 */
380 #define IPSET_REC_VERSION_ENVAR "SILK_IPSET_RECORD_VERSION"
381
382 /*
383 * Name of an environment variable used to determine how
384 * IPv4-IPsets are represented internally. Legal values are
385 * "iptree" for the SiLK-2 IPTree structure and "radix" for the
386 * Radix-Tree structure. Not intended for end users. Used by
387 * IPSET_USE_IPTREE and ipset_use_iptree.
388 */
389 #define IPSET_ENVAR_INCORE_FORMAT "SKIPSET_INCORE_FORMAT"
390
391 /*
392 * Name of an environment variable used to force the Radix-tree to
393 * print, to standard error, its structure when it is destoryed.
394 * Not intended for end users.
395 */
396 #define IPSET_ENVAR_DESTROY_PRINT "SKIPSET_DESTROY_PRINT"
397
398
399 /*
400 * Whether to use the IPTree or Radix-Tree data structure for
401 * in-memory IPv4-IPsets. Uses the environment variable specified
402 * by the IPSET_ENVAR_INCORE_FORMAT macro.
403 */
404 #define IPSET_USE_IPTREE \
405 (ipset_use_iptree >= 0 ? ipset_use_iptree : ipsetCheckFormatEnvar())
406
407 /*
408 * Default value for IPSET_USE_IPTREE if the envar is not set. See
409 * the 'ipset_use_iptree' variable below.
410 */
411 #define IPSET_USE_IPTREE_DEFAULT 1
412
413 /* Number of nodes/leaves to create initially in the radix tree */
414 #define IPSET_INITIAL_ENTRY_COUNT 2048
415
416 /* After the radix tree array contains this number of nodes/leaves,
417 * grow by adding this many more nodes/leaves to the current size. */
418 #define IPSET_GROW_LINEARLY 0x100000
419
420 /* Number of bits if IP to examine when branching at a node */
421 #define NUM_BITS 4
422
423 /* Number of children in each interior node */
424 #define IPSET_NUM_CHILDREN (1 << NUM_BITS)
425
426 /* Number of uint32_t's required to hold a bitmap of
427 * IPSET_NUM_CHILDREN bits */
428 #define BITMAP_SIZE_NUM_CHILDREN \
429 ((IPSET_NUM_CHILDREN + 31) >> 5)
430
431 /* Number of bytes in an IPv6 address */
432 #define IPSET_LEN_V6 16
433
434 /* Number of bytes in an IPv4 address */
435 #define IPSET_LEN_V4 4
436
437 /* The library uses recursion in few places, and instead maintains a
438 * stack of nodes; this constant is the required depth of the
439 * stack. */
440 #define IPSET_MAX_DEPTH_V4 \
441 (IPSET_NUM_CHILDREN * (1 + ((IPSET_LEN_V4 * CHAR_BIT) / NUM_BITS)))
442 #define IPSET_MAX_DEPTH_V6 \
443 (IPSET_NUM_CHILDREN * (1 + ((IPSET_LEN_V6 * CHAR_BIT) / NUM_BITS)))
444 #if SK_ENABLE_IPV6
445 # define IPSET_MAX_DEPTH IPSET_MAX_DEPTH_V6
446 #else
447 # define IPSET_MAX_DEPTH IPSET_MAX_DEPTH_V4
448 #endif /* SK_ENABLE_IPV6 */
449
450 /* Index of first leaf when iterating over the leaves in a clean IPset */
451 #define IPSET_LINK_LIST_ANCHOR 1
452 #define IPSET_ITER_FIRST_LEAF 1
453
454 /* Magic parent_idx value to denote that ipsetFindVx() returned the
455 * root of the tree */
456 #define IPSET_NO_PARENT UINT32_MAX
457
458 /* Return the root index for an IPset */
459 #define IPSET_ROOT_INDEX(iri_set) ((iri_set)->s.v3->root_idx)
460
461 /* Return a non-zero value if the root index references a leaf */
462 #define IPSET_ROOT_IS_LEAF(iril_set) ((iril_set)->s.v3->root_is_leaf)
463
464 /* Set the root index of the IPset */
465 #define IPSET_ROOT_INDEX_SET(iris_set, iris_index, iris_is_leaf) \
466 { \
467 ((iris_set)->s.v3->root_idx) = (iris_index); \
468 ((iris_set)->s.v3->root_is_leaf) = (iris_is_leaf); \
469 }
470
471 /* Is the IPset empty? */
472 #define IPSET_ISEMPTY(iie_ipset) \
473 (0 == (iie_ipset)->s.v3->nodes.entry_count)
474
475 /* Helper macro to get the node at 'ge_index' */
476 #define GET_ENTRY(ge_buf, ge_index) \
477 (&((ge_buf).buf[(ge_buf).entry_size * (ge_index)]))
478
479 /* Get the node at position 'np_index' and cast to correct type */
480 #define NODE_PTR(np_set, np_index) \
481 ((ipset_node_t*)GET_ENTRY((np_set)->s.v3->nodes, np_index))
482
483 #define NODE_PTR_V4(np_set, np_index) \
484 (&(((ipset_node_v4_t*)((np_set)->s.v3->nodes.buf))[(np_index)]))
485
486 #define NODE_PTR_V6(np_set, np_index) \
487 (&(((ipset_node_v6_t*)((np_set)->s.v3->nodes.buf))[(np_index)]))
488
489 /* Get the member of the node structure to use when handling nodes on
490 * the free list */
491 #define NODEPTR_FREE_LIST(npmfl_node) \
492 ((npmfl_node)->v4.child[0])
493 #define NODEIDX_FREE_LIST(nimfl_set, nimfl_nodeidx) \
494 NODEPTR_FREE_LIST(NODE_PTR((nimfl_set), (nimfl_nodeidx)))
495
496 /* "Free" the node at position 'nf_index' by pusing onto free list */
497 #define NODEIDX_FREE(nf_set, nf_index) \
498 { \
499 NODEIDX_FREE_LIST((nf_set), (nf_index)) \
500 = (nf_set)->s.v3->nodes.free_list; \
501 (nf_set)->s.v3->nodes.free_list = (nf_index); \
502 }
503
504 /* Get the leaf at position 'np_index' and cast to correct type */
505 #define LEAF_PTR(np_set, np_index) \
506 ((ipset_leaf_t*)GET_ENTRY((np_set)->s.v3->leaves, np_index))
507
508 #define LEAF_PTR_V4(np_set, np_index) \
509 (&(((ipset_leaf_v4_t*)((np_set)->s.v3->leaves.buf))[(np_index)]))
510
511 #define LEAF_PTR_V6(np_set, np_index) \
512 (&(((ipset_leaf_v6_t*)((np_set)->s.v3->leaves.buf))[(np_index)]))
513
514 /* Get the member of the leaf structure to use for handling leaves on
515 * the free list */
516 #define LEAFPTR_FREE_LIST(lpmfl_leaf) \
517 ((lpmfl_leaf)->v4.ip)
518 #define LEAFIDX_FREE_LIST(limfl_set, limfl_leafidx) \
519 LEAFPTR_FREE_LIST(LEAF_PTR((limfl_set), (limfl_leafidx)))
520
521 /* "Free" the leaf at position 'lf_index' by pushing onto free list */
522 #define LEAFIDX_FREE(lf_set, lf_index) \
523 { \
524 LEAFIDX_FREE_LIST((lf_set), (lf_index)) \
525 = (lf_set)->s.v3->leaves.free_list; \
526 (lf_set)->s.v3->leaves.free_list = (lf_index); \
527 }
528
529
530 /* Return a non-zero value if the child at index position 'ncil_pos'
531 * on the node 'ncil_node' is a leaf. 'ncil_node' must be an
532 * ipset_node_v{4,6}_t, not a generic ipset_node_t. */
533 #define NODEPTR_CHILD_IS_LEAF(ncil_node, ncil_pos) \
534 SET_BMAP_GET((ncil_node)->child_is_leaf, (ncil_pos))
535
536 /* Similar to NODEPTR_CHILD_IS_LEAF(), but specifies whether the child
537 * at 'ncir_pos' is a repeat of the child to its left---which may also
538 * be a repeat of the child to its left, etc. */
539 #define NODEPTR_CHILD_IS_REPEAT(ncir_node, ncir_pos) \
540 SET_BMAP_GET((ncir_node)->child_repeated, (ncir_pos))
541
542 /* Specify that the child at index position 'ncsl_pos' on the node
543 * 'ncsl_node' is a leaf not a node. 'ncsl_node' must an
544 * ipset_node_v{4,6}_t, not a generic ipset_node_t. */
545 #define NODEPTR_CHILD_SET_LEAF(ncsl_node, ncsl_pos) \
546 SET_BMAP_SET((ncsl_node)->child_is_leaf, (ncsl_pos))
547
548 /* Specify that the child at index position 'nccl_pos' on the node
549 * 'nccl_node' is NOT a leaf. 'nccl_node' must an
550 * ipset_node_v{4,6}_t, not a generic ipset_node_t. */
551 #define NODEPTR_CHILD_CLEAR_LEAF(nccl_node, nccl_pos) \
552 SET_BMAP_CLEAR((nccl_node)->child_is_leaf, (nccl_pos))
553
554 /* Specify that the children between index position 'ncsl_pos1' and
555 * 'ncsl_pos2' on the node 'ncsl_node' are leaves. 'ncsl_node' must
556 * an ipset_node_v{4,6}_t, not a generic ipset_node_t. */
557 #define NODEPTR_CHILD_SET_LEAF2(ncsl_node, ncsl_pos1, ncsl_pos2) \
558 SET_BMAP_RANGE_SET((ncsl_node)->child_is_leaf, (ncsl_pos1), (ncsl_pos2))
559
560 /* Specify that the children between index position 'nccl_pos1' and
561 * 'nccl_pos2' on the node 'nccl_node' are NOT leaves. 'nccl_node'
562 * must an ipset_node_v{4,6}_t, not a generic ipset_node_t. */
563 #define NODEPTR_CHILD_CLEAR_LEAF2(nccl_node, nccl_pos1, nccl_pos2) \
564 SET_BMAP_RANGE_CLEAR((nccl_node)->child_is_leaf, (nccl_pos1), (nccl_pos2))
565
566 /* Specify that the child at index position 'ncsr_pos' on the node
567 * 'ncsr_node' is a repeat of the child to its left. 'ncsr_node' must
568 * an ipset_node_v{4,6}_t, not a generic ipset_node_t. */
569 #define NODEPTR_CHILD_SET_REPEAT(ncsr_node, ncsr_pos) \
570 SET_BMAP_SET((ncsr_node)->child_repeated, (ncsr_pos))
571
572 /* Specify the the children between index position 'ncsr_pos1' and
573 * 'ncsr_pos2' on the node 'ncsr_node' are leaves. 'ncsr_node' must
574 * an ipset_node_v{4,6}_t, not a generic ipset_node_t. */
575 #define NODEPTR_CHILD_SET_REPEAT2(ncsr_node, ncsr_pos1, ncsr_pos2) \
576 SET_BMAP_RANGE_SET((ncsr_node)->child_repeated, (ncsr_pos1), (ncsr_pos2))
577
578 /* Specify that the child at index position 'nccr_pos' on the node
579 * 'nccr_node' is NOT a repeat. 'nccr_node' must an
580 * ipset_node_v{4,6}_t, not a generic ipset_node_t. */
581 #define NODEPTR_CHILD_CLEAR_REPEAT(nccr_node, nccr_pos) \
582 SET_BMAP_CLEAR((nccr_node)->child_repeated, (nccr_pos))
583
584 /* Specify that the children between index position 'nccr_pos1' and
585 * 'nccr_pos2' on the node 'nccr_node' are NOT repeats. 'nccr_node'
586 * must an ipset_node_v{4,6}_t, not a generic ipset_node_t. */
587 #define NODEPTR_CHILD_CLEAR_REPEAT2(nccr_node, nccr_pos1, nccr_pos2) \
588 SET_BMAP_RANGE_CLEAR((nccr_node)->child_repeated, (nccr_pos1), (nccr_pos2))
589
590
591
592 /* Ensure that an IPset is in-core. If required, it calls the
593 * function to change an mmap()ed IPset to an in-core IPset */
594 #define IPSET_COPY_ON_WRITE(cow_ipset) \
595 if (!(cow_ipset)->s.v3->mapped_file) { /* no-op */ } else { \
596 int cow_rv = ipsetCopyOnWrite(cow_ipset); \
597 if (cow_rv) { \
598 return cow_rv; \
599 } \
600 }
601
602 /* If the leaf buffer was reallocated, check to see if any leaves can
603 * be reclaimed by combining adjacent CIDR blocks */
604 #define IPSET_MAYBE_COMBINE(mc_ipset) \
605 if (!(mc_ipset)->s.v3->realloc_leaves) { /*no-op*/ } else { \
606 ipsetCombineAdjacentCIDR(mc_ipset); \
607 (mc_ipset)->s.v3->realloc_leaves = 0; \
608 }
609
610
611 /* Macros for checking and manipulating the bitmaps on the
612 * ipset_node_vX_t structures. */
613 #define SET_BMAP_DECLARE(sbd_map, sbd_size) \
614 BITMAP_DECLARE(sbd_map, sbd_size)
615
616 #define SET_BMAP_SET(sbs_map, sbs_pos) \
617 BITMAP_SETBIT(sbs_map, sbs_pos)
618
619 #define SET_BMAP_GET(sbg_map, sbg_pos) \
620 BITMAP_GETBIT(sbg_map, sbg_pos)
621
622 #define SET_BMAP_CLEAR(sbc_map, sbc_pos) \
623 BITMAP_CLEARBIT(sbc_map, sbc_pos)
624
625 #define SET_BMAP_CLEAR_ALL(sbca_map) \
626 BITMAP_INIT(sbca_map)
627
628 #if BITMAP_SIZE_NUM_CHILDREN == 1
629
630 #define SET_BMAP_RANGE_SET(sbrs_map, sbrs_beg, sbrs_end) \
631 SET_MASKED_BITS((sbrs_map)[_BMAP_INDEX(sbrs_beg)], UINT32_MAX, \
632 (sbrs_beg) & 0x1F, 1+(sbrs_end)-(sbrs_beg))
633
634 #define SET_BMAP_RANGE_CLEAR(sbrs_map, sbrs_beg, sbrs_end) \
635 SET_MASKED_BITS((sbrs_map)[_BMAP_INDEX(sbrs_beg)], 0, \
636 (sbrs_beg) & 0x1F, 1+(sbrs_end)-(sbrs_beg))
637
638 #else /* #if BITMAP_SIZE_NUM_CHILDREN == 1 */
639
640 #define SET_BMAP_RANGE_SET(sbrs_map, sbrs_beg, sbrs_end) \
641 do { \
642 uint32_t sbrs_i = _BMAP_INDEX(sbrs_beg); \
643 uint32_t sbrs_j = _BMAP_INDEX(sbrs_end); \
644 if (sbrs_i == sbrs_j) { \
645 /* single word */ \
646 SET_MASKED_BITS((sbrs_map)[sbrs_i], UINT32_MAX, \
647 (sbrs_beg) & 0x1F, 1+(sbrs_end)-(sbrs_beg)); \
648 } else { \
649 SET_MASKED_BITS((sbrs_map)[sbrs_i], UINT32_MAX, \
650 (sbrs_beg) & 0x1F, 32-((sbrs_beg) & 0x1F)); \
651 ++sbrs_i; \
652 memset(&(sbrs_map)[sbrs_i], 0xFF, \
653 (sbrs_j - sbrs_i) * sizeof(uint32_t)); \
654 SET_MASKED_BITS((sbrs_map)[sbrs_j], UINT32_MAX, \
655 0, 1 + ((sbrs_end) & 0x1F)); \
656 } \
657 } while(0)
658
659 #define SET_BMAP_RANGE_CLEAR(sbrs_map, sbrs_beg, sbrs_end) \
660 do { \
661 uint32_t sbrs_i = _BMAP_INDEX(sbrs_beg); \
662 uint32_t sbrs_j = _BMAP_INDEX(sbrs_end); \
663 if (sbrs_i == sbrs_j) { \
664 /* single word */ \
665 SET_MASKED_BITS((sbrs_map)[sbrs_i], 0, \
666 (sbrs_beg) & 0x1F, 1+(sbrs_end)-(sbrs_beg)); \
667 } else { \
668 SET_MASKED_BITS((sbrs_map)[sbrs_i], 0, \
669 (sbrs_beg) & 0x1F, 32-((sbrs_beg) & 0x1F)); \
670 ++sbrs_i; \
671 memset(&(sbrs_map)[sbrs_i], 0, \
672 (sbrs_j - sbrs_i) * sizeof(uint32_t)); \
673 SET_MASKED_BITS((sbrs_map)[sbrs_j], 0, \
674 0, 1 + ((sbrs_end) & 0x1F)); \
675 } \
676 } while(0)
677
678 #endif /* #else of BITMAP_SIZE_NUM_CHILDREN == 1 */
679
680
681 /* Given an IPv4 address of a child and the prefix of the node holding
682 * that child, return the index of child[] where the address
683 * belongs */
684 #define WHICH_CHILD_V4(wc_ip, wc_prefix) \
685 (((wc_ip) >> (32 - NUM_BITS - ((wc_prefix) & ~(NUM_BITS - 1)))) \
686 & ((1u << NUM_BITS) - 1))
687
688 #if NUM_BITS == 3
689 #elif NUM_BITS == 5
690 #elif NUM_BITS == 7
691 #else
692 #define WHICH_CHILD_V6(wc_ip, wc_prefix) \
693 (((wc_prefix) >= 64) \
694 ? (((wc_ip)->ip[1] \
695 >> (128 - NUM_BITS - ((wc_prefix) & ~(NUM_BITS - 1)))) \
696 & ((1u << NUM_BITS) - 1)) \
697 : (((wc_ip)->ip[0] \
698 >> (64 - NUM_BITS - ((wc_prefix) & ~(NUM_BITS - 1)))) \
699 & ((1u << NUM_BITS) - 1)))
700 #endif
701
702
703 /* Convert from an IPv6 skipaddr_t 'aviv_addr' to ipset_ipv6_t
704 * 'aviv_ip' */
705 #define IPSET_IPV6_FROM_ADDRV6(aviv_ip, aviv_addr6) \
706 { \
707 skipaddrGetV6((aviv_addr6), (aviv_ip)); \
708 (aviv_ip)->ip[0] = ntoh64((aviv_ip)->ip[0]); \
709 (aviv_ip)->ip[1] = ntoh64((aviv_ip)->ip[1]); \
710 }
711
712 /* Convert from an IPv4 skipaddr_t 'aviv_addr' to ipset_ipv6_t 'aviv_ip' */
713 #define IPSET_IPV6_FROM_ADDRV4(aviv_ip, aviv_addr4) \
714 { \
715 skipaddrGetAsV6((aviv_addr4), (aviv_ip)); \
716 (aviv_ip)->ip[0] = ntoh64((aviv_ip)->ip[0]); \
717 (aviv_ip)->ip[1] = ntoh64((aviv_ip)->ip[1]); \
718 }
719
720 /* Convert from ipset_ipv6_t 'aviv_ip' to an IPv6 skipaddr_t 'aviv_addr' */
721 #define IPSET_IPV6_TO_ADDR(aviv_ip, aviv_addr) \
722 { \
723 ipset_ipv6_t aviv_tmp; \
724 aviv_tmp.ip[0] = hton64((aviv_ip)->ip[0]); \
725 aviv_tmp.ip[1] = hton64((aviv_ip)->ip[1]); \
726 skipaddrSetV6((aviv_addr), &aviv_tmp); \
727 }
728
729 /* Convert from ipset_ipv6_t 'aviv_ip' to an IPv4 skipaddr_t 'aviv_addr' */
730 #define IPSET_IPV6_TO_ADDR_V4(aviv_ip, aviv_addr) \
731 { \
732 uint32_t aviv_ipv4; \
733 assert(0 == (aviv_ip)->ip[0]); \
734 assert(UINT64_C(0x0000ffff00000000) \
735 == (UINT64_C(0xffffffff00000000) & (aviv_ip)->ip[1])); \
736 aviv_ipv4 = (uint32_t)(UINT64_C(0x00000000ffffffff) \
737 & (aviv_ip)->ip[1]); \
738 skipaddrSetV4((aviv_addr), &aviv_ipv4); \
739 }
740
741 /* Convert from ipset_ipv6_t 'aviv_ip' to an array[16] of uint8_t
742 * 'aviv_array' */
743 #define IPSET_IPV6_TO_ARRAY(aviv_ip, aviv_array) \
744 { \
745 ipset_ipv6_t aviv_tmp; \
746 aviv_tmp.ip[0] = hton64((aviv_ip)->ip[0]); \
747 aviv_tmp.ip[1] = hton64((aviv_ip)->ip[1]); \
748 memcpy((aviv_array), &aviv_tmp, IPSET_LEN_V6); \
749 }
750
751 /* Convert from an array[16] of uint8_t 'aviv_array' to an
752 * ipset_ipv6_t 'aviv_ip' */
753 #define IPSET_IPV6_FROM_ARRAY(aviv_ip, aviv_array) \
754 { \
755 ipset_ipv6_t aviv_tmp; \
756 memcpy(&aviv_tmp, (aviv_array), IPSET_LEN_V6); \
757 (aviv_ip)->ip[0] = hton64(aviv_tmp.ip[0]); \
758 (aviv_ip)->ip[1] = hton64(aviv_tmp.ip[1]); \
759 }
760
761 /* Copy an 'ipset_ipv6_t' */
762 #define IPSET_IPV6_COPY(ipc_dest, ipc_src) \
763 memcpy(ipc_dest, ipc_src, IPSET_LEN_V6)
764
765 /* Apply netblock mask 'ipac_prefix' to the ipset_ipv6_t 'ipac_ip' */
766 #define IPSET_IPV6_APPLY_CIDR(ipac_ip, ipac_prefix) \
767 if ((ipac_prefix) > 64) { \
768 (ipac_ip)->ip[1] &= ~(UINT64_MAX >> ((ipac_prefix) - 64)); \
769 } else { \
770 (ipac_ip)->ip[1] = 0; \
771 if ((ipac_prefix) < 64) { \
772 (ipac_ip)->ip[0] &= ~(UINT64_MAX >> (ipac_prefix)); \
773 } \
774 }
775
776 /* Copy an 'ipset_ipv6_t' and apply the CIDR mask */
777 #define IPSET_IPV6_COPY_AND_MASK(ipcam_dest, ipcam_src, ipcam_prefix) \
778 if ((ipcam_prefix) > 64) { \
779 (ipcam_dest)->ip[0] = (ipcam_src)->ip[0]; \
780 (ipcam_dest)->ip[1] = ((ipcam_src)->ip[1] \
781 & ~(UINT64_MAX >> ((ipcam_prefix)-64))); \
782 } else if ((ipcam_prefix) == 64) { \
783 (ipcam_dest)->ip[0] = (ipcam_src)->ip[0]; \
784 (ipcam_dest)->ip[1] = 0; \
785 } else { \
786 (ipcam_dest)->ip[0] = ((ipcam_src)->ip[0] \
787 & ~(UINT64_MAX >> (ipcam_prefix))); \
788 (ipcam_dest)->ip[1] = 0; \
789 }
790
791 /* Return true if 'ipset_ipv6_t' is 0 */
792 #define IPSET_IPV6_IS_ZERO(ipiz) \
793 ((0 == (ipiz)->ip[0]) && (0 == (ipiz)->ip[1]))
794
795 /* Set 'mb_result_ptr' to the number of leading 0 bits in
796 * 'mb_expression', a 32 bit value */
797 #define COUNT_MATCHING_BITS32(mb_result_ptr, mb_expression) \
798 { \
799 uint32_t t1, t2; \
800 t1 = (mb_expression); \
801 t2 = t1 >> 16; \
802 if (t2) { \
803 t1 = t2 >> 8; \
804 *(mb_result_ptr) = (t1 \
805 ? bit_diff_offset[t1] \
806 : (8 + bit_diff_offset[t2])); \
807 } else { \
808 t2 = t1 >> 8; \
809 *(mb_result_ptr) = (t2 \
810 ? (16 + bit_diff_offset[t2]) \
811 : (24 + bit_diff_offset[t1])); \
812 } \
813 }
814
815 /* Set 'mb_result_ptr' to the number of leading 0 bits in
816 * 'mb_expression', a 64 bit value */
817 #define COUNT_MATCHING_BITS64(mb_result_ptr, mb_expression) \
818 { \
819 uint64_t t1, t2; \
820 t2 = (mb_expression); \
821 t1 = t2 >> 32; \
822 if (t1) { \
823 t2 = t1 >> 16; \
824 if (t2) { \
825 t1 = t2 >> 8; \
826 *(mb_result_ptr) = (t1 \
827 ? bit_diff_offset[t1] \
828 : (8 + bit_diff_offset[t2])); \
829 } else { \
830 t2 = t1 >> 8; \
831 *(mb_result_ptr) = (t2 \
832 ? (16 + bit_diff_offset[t2]) \
833 : (24 + bit_diff_offset[t1])); \
834 } \
835 } else { \
836 t1 = t2 >> 16; \
837 if (t1) { \
838 t2 = t1 >> 8; \
839 *(mb_result_ptr) = (t2 \
840 ? (32 + bit_diff_offset[t2]) \
841 : (40 + bit_diff_offset[t1])); \
842 } else { \
843 t1 = t2 >> 8; \
844 *(mb_result_ptr) = (t1 \
845 ? (48 + bit_diff_offset[t1]) \
846 : (56 + bit_diff_offset[t2])); \
847 } \
848 } \
849 }
850
851
852 /* In IPSET_REC_VERSION_CIDRBMAP and IPSET_REC_VERSION_SLASH64 files,
853 * mapping from the 'prefix' byte to size of the bitmap */
854 #define SET_CIDRBMAP_MAP256 0x81
855
856 /* In IPSET_REC_VERSION_SLASH64, value that indicates this 64bit value
857 * starts a new /64. */
858 #define SET_SLASH64_IS_SLASH64 0x82
859
860
861 #if !defined(NUM_BITS)
862 # error "NUM_BITS must be defined"
863 #elif NUM_BITS <= 0
864 # errror "NUM_BITS must be > 0"
865 #endif
866
867
868 /* Macros used by the SiLK-2 (IPTree) version of IPsets */
869
870 /* The number of uint32_t values for each /24. Value is computed by
871 * ((1 << 8) / (1 << 5)) ==> (1 << 3) ==> 8 */
872 #define IPTREE_WORDS_PER_SLASH24 8
873
874 /*
875 * NOTE: Must be called on the IPTree pointer, not the IPset.
876 *
877 * NOTE: May cause the function that uses it to return.
878 *
879 * If the IPTree 'iptree' has a node for 'high16' where 'high16'
880 * are the 16 most significant bits of an IPv4 address, do nothing.
881 * Otherwise, attempt to allocate the node and position the node in
882 * the tree. If the allocation fail, this macro causes the
883 * function return SKIPSET_ERR_ALLOC to the caller.
884 */
885 #define IPTREE_NODE_ALLOC(iptree, high16) \
886 if ((iptree)->nodes[(high16)]) { /*no-op*/ } else { \
887 (iptree)->nodes[(high16)] \
888 = (skIPNode_t*)calloc(1, sizeof(skIPNode_t)); \
889 if (NULL == (iptree)->nodes[(high16)]) { \
890 return SKIPSET_ERR_ALLOC; \
891 } \
892 }
893
894 #ifdef NDEBUG
895 #define ASSERT_OK(func_call) func_call
896 #else
897 #define ASSERT_OK(func_call) \
898 { \
899 int assert_ok = func_call; \
900 assert(0 == assert_ok); \
901 }
902 #endif
903
904
905 /* define an ipv6 address type */
906 typedef struct ipset_ipv6_st {
907 uint64_t ip[2];
908 } ipset_ipv6_t;
909
910 /* Forward declare the node types */
911 typedef struct ipset_node_v4_st ipset_node_v4_t;
912 typedef struct ipset_node_v6_st ipset_node_v6_t;
913 typedef union ipset_node_un ipset_node_t;
914
915 typedef struct ipset_leaf_v4_st ipset_leaf_v4_t;
916 typedef struct ipset_leaf_v6_st ipset_leaf_v6_t;
917 typedef union ipset_leaf_un ipset_leaf_t;
918
919 typedef struct ipset_buffer_st {
920 uint8_t *buf;
921 /* the size of an entry in the array */
922 size_t entry_size;
923 /* the number of nodes in the array of entries. bytes allocated is
924 * given by (entry_capacity * entry_size). */
925 uint32_t entry_capacity;
926 /* maximum index used in the array. this is not the number of
927 * valid entries since it also includes nodes on the free-list. */
928 uint32_t entry_count;
929 /* location of first available element in free-list, or 0 if empty */
930 uint32_t free_list;
931 } ipset_buffer_t;
932
933
934 /* THE IPSET Structure as of SiLK 3 */
935 typedef struct skipset_v3_st {
936 /* pointer to mmap()ed file */
937 void *mapped_file;
938 /* the size of the mmap()ed space */
939 size_t mapped_size;
940 /* structures to hold the nodes and leaves */
941 ipset_buffer_t nodes;
942 ipset_buffer_t leaves;
943 /* location of the root of tree; may be a node or a leaf; which it
944 * is is given by the root_is_leaf member below */
945 uint32_t root_idx;
946 /* whether root_idx is a leaf or a node */
947 unsigned root_is_leaf :1;
948 /* whether changes to tree caused the "leaves" buffer to be
949 * reallocated */
950 unsigned realloc_leaves :1;
951 } skipset_v3_t;
952
953 /* A COMMON IPSET Structure */
954 struct skipset_st {
955 /* options used when writing an IPset */
956 const skipset_options_t *options;
957 /* which pointer to use in this union depends on the setting of
958 * the 'is_iptree' member */
959 union body_un {
960 skipset_v3_t *v3;
961 skIPTree_t *v2;
962 } s;
963 /* whether the 's' member holds a SiLK-3 IPset (==0) or a SiLK-2
964 * IPTree (==1). See also 'is_ipv6'. */
965 unsigned is_iptree :1;
966 /* whether the SiLK-3 IPset holds IPv6 addresses. When this is 1,
967 * the 'is_iptree' member must be 0. */
968 unsigned is_ipv6 :1;
969 /* whether the tree has changed since last call to skIPSetClean() */
970 unsigned is_dirty:1;
971 /* whether an attempt to insert an IPv6 address into an IPv4 tree
972 * should returnan error. when this is 0, the tree will
973 * automatically be converted to IPv6. */
974 unsigned no_autoconvert :1;
975 };
976
977
978
979 /* IPSET NODE */
980
981 /* The nodes of a tree hold either IPv4 or IPv6 addresses. The
982 * structures are indentical except for the IP address, which allows
983 * safe access to all non-IP elements. */
984
985 struct ipset_node_v4_st {
986 /* index of the children, which may be nodes or leaves. for a node
987 * on free_list, child[0] is the next of the next node on the
988 * free_list */
989 uint32_t child[IPSET_NUM_CHILDREN];
990
991 /* bitmap that specifies whether a child[] refers to another node
992 * or to a leaf. */
993 SET_BMAP_DECLARE(child_is_leaf, IPSET_NUM_CHILDREN);
994
995 /* bitmap that specifies whether a child[] is a repeat of the
996 * child to its left. this is used when a leaf's prefix is larger
997 * (holds more IPs) than node->prefix + NUM_BITS. */
998 SET_BMAP_DECLARE(child_repeated, IPSET_NUM_CHILDREN);
999
1000 /* prefix is number of significant bits in the IP; on the nodes,
1001 * prefix is the number of bits to compare before deciding which
1002 * child[] to branch to. */
1003 uint8_t prefix;
1004
1005 /* reserved/unsed bytes */
1006 uint8_t reserved3;
1007 uint8_t reserved2;
1008 uint8_t reserved1;
1009
1010 /* IP address */
1011 uint32_t ip;
1012 };
1013
1014 struct ipset_node_v6_st {
1015 uint32_t child[IPSET_NUM_CHILDREN];
1016
1017 SET_BMAP_DECLARE(child_is_leaf, IPSET_NUM_CHILDREN);
1018 SET_BMAP_DECLARE(child_repeated, IPSET_NUM_CHILDREN);
1019
1020 uint8_t prefix;
1021 uint8_t reserved3;
1022 uint8_t reserved2;
1023 uint8_t reserved1;
1024
1025 #if SK_ENABLE_IPV6
1026 uint32_t pad_align;
1027 ipset_ipv6_t ip;
1028 #else
1029 uint32_t ip;
1030 #endif /* SK_ENABLE_IPV6 */
1031 };
1032
1033 /* A generic "node" pointer */
1034 /* from above: typedef union ipset_node_un ipset_node_t; */
1035 union ipset_node_un {
1036 ipset_node_v6_t v6;
1037 ipset_node_v4_t v4;
1038 };
1039
1040
1041 /* IPSET LEAF */
1042
1043 struct ipset_leaf_v4_st {
1044 /* prefix is number of significant bits in the IP. */
1045 uint8_t prefix;
1046 /* reserved/unused bytes */
1047 uint8_t reserved3;
1048 uint8_t reserved2;
1049 uint8_t reserved1;
1050
1051 /* IP address */
1052 uint32_t ip;
1053 };
1054
1055 struct ipset_leaf_v6_st {
1056 uint8_t prefix;
1057 uint8_t reserved3;
1058 uint8_t reserved2;
1059 uint8_t reserved1;
1060
1061 #if SK_ENABLE_IPV6
1062 uint32_t pad_align;
1063 ipset_ipv6_t ip;
1064 #else
1065 uint32_t ip;
1066 #endif
1067 };
1068
1069 /* A generic "leaf" pointer */
1070 /* from above: typedef union ipset_leaf_un ipset_leaf_t; */
1071 union ipset_leaf_un {
1072 ipset_leaf_v6_t v6;
1073 ipset_leaf_v4_t v4;
1074 };
1075
1076 /* Support structure for counting the IPs in an IPset, used by
1077 * skIPSetCount() and ipsetCountCallbackV*() */
1078 typedef struct ipset_count_st {
1079 uint64_t lower;
1080 uint64_t upper;
1081 uint64_t full;
1082 } ipset_count_t;
1083
1084 /* Support structure for ipsetFind() */
1085 typedef struct ipset_find_st {
1086 uint32_t parent_idx;
1087 uint32_t node_idx;
1088 uint32_t parents_child;
1089 int result;
1090 uint8_t bitpos;
1091 uint8_t node_is_leaf;
1092 } ipset_find_t;
1093
1094 /* Support structure for intersecting two IPsets; used by
1095 * skIPSetIntersect() and ipsetIntersectCallback() */
1096 typedef struct ipset_intersect_st {
1097 skipaddr_t addr[2];
1098 sk_vector_t *vec_add;
1099 skipset_iterator_t iter;
1100 } ipset_intersect_t;
1101
1102 /* Support structure for printing the IPs in an IPset, used by
1103 * skIPSetPrint() and ipsetPrintCallback() */
1104 typedef struct ipset_print_st {
1105 const skipset_t *ipset;
1106 skstream_t *stream;
1107 skipaddr_flags_t ip_format;
1108 } ipset_print_t;
1109
1110 typedef int (ipset_walk_v4_fn_t)(
1111 uint32_t ipv4,
1112 uint32_t prefix,
1113 void *cb_data);
1114
1115 typedef int (ipset_walk_v6_fn_t)(
1116 const ipset_ipv6_t *ipv6,
1117 uint32_t prefix,
1118 void *cb_data);
1119
1120
1121 /* Support structure for walking over the IPset */
1122 typedef struct ipset_walk_st {
1123 /* user function to invoke for each IP/CIDR block */
1124 skipset_walk_fn_t callback;
1125 /* user-provided data to pass to the callback */
1126 void *cb_data;
1127 /* how to handle IP addresses */
1128 sk_ipv6policy_t v6policy;
1129 /* whether to return CIDR blocks (1) or individual IPs (0). (This
1130 * may eventually become the maximum size block to return.) */
1131 uint8_t cidr_blocks;
1132 } ipset_walk_t;
1133
1134 /* Support strucuture for writing a SiLK-3 IPset in the SiLK-2 file
1135 * format; used by ipsetWriteClasscFromRadix() and
1136 * ipsetWriteClasscFromRadixCallback(). */
1137 typedef struct ipset_write_silk2_st {
1138 /* the stream to write to */
1139 skstream_t *stream;
1140 /* the current /24 is in buffer[0]; remaining values are a bitmap
1141 * of addresses for that /24. */
1142 uint32_t buffer[1+IPTREE_WORDS_PER_SLASH24];
1143 /* true when the buffer contains valid data */
1144 unsigned buffer_is_dirty :1;
1145 } ipset_write_silk2_t;
1146
1147
1148 /* SILK-2 IPTREE FORMAT */
1149
1150 /*
1151 * Prior to SiLK 3.0.0, the in-memory structure used to represent
1152 * IPsets was the skIPTree_t. This structure is still used to
1153 * represent IPsets that contain only IPv4 addresses.
1154 *
1155 * The skIPTree_t consists of a 64k pointers, each of which is
1156 * either NULL or a pointer to a node, the skIPNode_t. A node
1157 * contains 64k bits for marking the addresses in an IPset. The
1158 * bitmap is represented as an array of uint32_t, where each
1159 * uint32_t maps to a /27. Dividing 64k by 32 means there are 2k
1160 * uint32_t's.
1161 */
1162 typedef struct skIPNode_st skIPNode_t;
1163
1164 /*
1165 * Number of skIPNode_t's in an skIPTree_t.
1166 */
1167 #define SKIP_BBLOCK_COUNT 65536
1168
1169 /*
1170 * Number of uint32_t's in an skIPNode_t.
1171 */
1172 #define SKIP_BBLOCK_SIZE 2048
1173
1174 /* skIPTree_t */
1175 struct skIPTree_st {
1176 skIPNode_t *nodes[SKIP_BBLOCK_COUNT];
1177 };
1178 /* typedef struct skIPTree_st skIPTree_t; // skipset.h */
1179
1180 /* skIPNode_t */
1181 struct skIPNode_st {
1182 uint32_t addressBlock[SKIP_BBLOCK_SIZE];
1183 };
1184
1185 /*
1186 * Check for bit 'lower16' in 'node'. The value in 'lower16' must
1187 * be the 16 least significant bits of an address; 'node' is the
1188 * skIPNode_t for the 16 most significant bits of the address.
1189 */
1190 #define IPTREE_NODE_CHECK_BIT(m_node, m_lower16) \
1191 ((m_node)->addressBlock[(m_lower16) >> 5] & (1 << ((m_lower16) & 0x1F)))
1192
1193 /*
1194 * Return TRUE if 'addr' is set on tree 'iptree'; FALSE otherwise
1195 */
1196 #define IPTREE_CHECK_ADDRESS(m_iptree, m_addr) \
1197 ((m_iptree)->nodes[(m_addr) >> 16] \
1198 && IPTREE_NODE_CHECK_BIT((m_iptree)->nodes[(m_addr)>>16], \
1199 ((m_addr) & 0xFFFF)))
1200
1201
1202 /* HEADER ENTRY */
1203
1204 /*
1205 * sk_hentry_ipset_t is an in-memory representation of a streams's
1206 * header entry that describes the IPset data structure. It is
1207 * present in IPset version 3, version 4, and version 5 files.
1208 */
1209 struct sk_hentry_ipset_st {
1210 sk_header_entry_spec_t he_spec;
1211 uint32_t child_node;
1212 uint32_t leaf_count;
1213 uint32_t leaf_size;
1214 uint32_t node_count;
1215 uint32_t node_size;
1216 uint32_t root_idx;
1217 };
1218 typedef struct sk_hentry_ipset_st sk_hentry_ipset_t;
1219
1220
1221 /* IPSET OPTIONS */
1222
1223 enum ipset_options_en {
1224 OPT_IPSET_INVOCATION_STRIP,
1225 /* record-version is handled separately; it must be last */
1226 OPT_IPSET_RECORD_VERSION
1227 };
1228 static const struct option ipset_options[] = {
1229 {"invocation-strip", NO_ARG, 0, OPT_IPSET_INVOCATION_STRIP},
1230 {0, 0, 0, 0} /* sentinel entry */
1231 };
1232 static const char *ipset_options_help[] = {
1233 "Strip invocation history from the IPset file. Def. no",
1234 (char*)NULL
1235 };
1236
1237 static const char *ipset_options_record_version_default_name =
1238 "record-version";
1239
1240 static struct option ipset_options_record_version[] = {
1241 {NULL, REQUIRED_ARG, 0, OPT_IPSET_RECORD_VERSION},
1242 {0, 0, 0, 0} /* sentinel entry */
1243 };
1244
1245
1246 /* LOCAL VARIABLE DEFINITIONS */
1247
1248 /*
1249 * Whether to use the IPTree or Radix-Tree data structure for
1250 * in-memory IPv4-IPsets. Used by IPSET_USE_IPTREE. This is -1 if
1251 * the value has not been initialized; 0 for RADIX, and 1 for
1252 * IPTREE. See ipsetCheckFormatEnvar().
1253 */
1254 static int ipset_use_iptree = -1;
1255
1256 /* for handling IPset files Version 2 and Version 4 */
1257 static const uint32_t bmap256_zero[IPTREE_WORDS_PER_SLASH24] =
1258 {0, 0, 0, 0, 0, 0, 0, 0};
1259 static const uint32_t bmap256_full[IPTREE_WORDS_PER_SLASH24] =
1260 {UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX,
1261 UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX};
1262
1263 /* this is used to find which bit of two uint8_t's differ. */
1264 static const uint8_t bit_diff_offset[256] =
1265 {
1266 /* 0- 15 */ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
1267 /* 16- 31 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1268 /* 32- 47 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1269 /* 48- 63 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1270 /* 64- 79 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1271 /* 80- 95 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1272 /* 96-111 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1273 /* 112-127 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1274 /* 128-143 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1275 /* 144-159 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1276 /* 160-175 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1277 /* 176-191 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1278 /* 192-207 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1279 /* 208-223 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1280 /* 224-239 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1281 /* 240-255 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1282 };
1283
1284
1285 /* LOCAL FUNCTION PROTOTYPES */
1286
1287 static int
1288 ipsetCheckFormatEnvar(
1289 void);
1290 static int
1291 ipsetCreate(
1292 skipset_t **ipset_out,
1293 int support_ipv6,
1294 int force_radix);
1295 static void
1296 ipsetDestroySubtree(
1297 skipset_t *ipset,
1298 uint32_t destroy_node_idx,
1299 int destroy_self);
1300 static int
1301 ipsetFindV4(
1302 const skipset_t *ipset,
1303 const uint32_t ipv4,
1304 const uint32_t prefix,
1305 ipset_find_t *find_state);
1306 #if SK_ENABLE_IPV6
1307 static int
1308 ipsetFindV6(
1309 const skipset_t *ipset,
1310 const ipset_ipv6_t *ipv6,
1311 const uint32_t prefix,
1312 ipset_find_t *find_state);
1313 #endif
1314 static sk_header_entry_t *
1315 ipsetHentryCreate(
1316 uint32_t child_node,
1317 uint32_t leaf_count,
1318 uint32_t leaf_size,
1319 uint32_t node_count,
1320 uint32_t node_size,
1321 uint32_t root_idx);
1322 static void
1323 ipsetHentryFree(
1324 sk_header_entry_t *hentry);
1325 static int
1326 ipsetNewEntries(
1327 skipset_t *ipset,
1328 uint32_t num_nodes,
1329 uint32_t num_leaves,
1330 uint32_t *node_indexes,
1331 uint32_t *leaf_indexes);
1332 static int
1333 ipsetProcessStreamCallback(
1334 const ipset_ipv6_t *v6_start,
1335 const uint32_t *v4_start,
1336 uint32_t prefix,
1337 ipset_walk_t *proc_stream_state);
1338 static void
1339 ipsetReadStrerrror(
1340 skstream_t *stream,
1341 const char *format,
1342 ...)
1343 SK_CHECK_PRINTF(2, 3);
1344 static uint32_t
1345 ipsetReplaceNodeWithLeaf(
1346 skipset_t *ipset,
1347 ipset_node_t *parent,
1348 uint32_t which_child);
1349 static int
1350 ipsetVerify(
1351 const skipset_t *ipset);
1352
1353
1354 /* FUNCTION DEFINITIONS */
1355
1356 /*
1357 * status = ipsetAllocEntries(ibuf, new_cap);
1358 *
1359 * Grow or shink the entries list in 'ibuf' to hold 'new_cap'
1360 * nodes. If 'new_cap' is 0, the size of the current array is
1361 * doubled unless the current array size is IPSET_GROW_LINEARLY or
1362 * greater in which case an additional IPSET_GROW_LINEARLY elements
1363 * are added. If no memory is currently allocated, an array of
1364 * IPSET_INITIAL_ENTRY_COUNT nodes is allocated.
1365 *
1366 * Return 0 on success, or SKIPSET_ERR_ALLOC if memory cannot be
1367 * allocated.
1368 */
1369 static int
ipsetAllocEntries(ipset_buffer_t * ibuf,size_t new_cap)1370 ipsetAllocEntries(
1371 ipset_buffer_t *ibuf,
1372 size_t new_cap)
1373 {
1374 size_t old_cap;
1375 uint8_t *old_entries;
1376
1377 #if !defined(TRACE_ALLOC) || !TRACE_ALLOC
1378 #define ALLOC_TRACEMSG(old_size, new_size)
1379 #else
1380 #define ALLOC_TRACEMSG(old_size, new_size) \
1381 fprintf(stderr, ("%s:%d: growing memory capacity from" \
1382 " %" SK_PRIuZ " to %" SK_PRIuZ "\n"), \
1383 __FILE__, __LINE__, (old_size), (new_size))
1384 #endif
1385
1386 assert(ibuf);
1387
1388 /* the current capacity of the tree */
1389 old_cap = ibuf->entry_capacity;
1390
1391 /* handle empty tree */
1392 if (0 == old_cap) {
1393 if (0 == new_cap) {
1394 new_cap = IPSET_INITIAL_ENTRY_COUNT;
1395 }
1396 /* allocate new memory */
1397 ALLOC_TRACEMSG((size_t)0, new_cap);
1398 ibuf->buf = (uint8_t*)calloc(new_cap, ibuf->entry_size);
1399 if (NULL == ibuf->buf) {
1400 return SKIPSET_ERR_ALLOC;
1401 }
1402 ibuf->entry_capacity = new_cap;
1403 return 0;
1404 }
1405
1406 /* handle case where no new capacity is specified */
1407 if (new_cap) {
1408 ALLOC_TRACEMSG(old_cap, new_cap);
1409 } else {
1410 if (old_cap >= IPSET_GROW_LINEARLY) {
1411 new_cap = old_cap + IPSET_GROW_LINEARLY;
1412 ALLOC_TRACEMSG(old_cap, new_cap);
1413 } else if (old_cap < (IPSET_INITIAL_ENTRY_COUNT >> 1)) {
1414 new_cap = IPSET_INITIAL_ENTRY_COUNT;
1415 ALLOC_TRACEMSG(old_cap, new_cap);
1416 } else {
1417 new_cap = 2 * old_cap;
1418 ALLOC_TRACEMSG(old_cap, new_cap);
1419 }
1420 }
1421
1422 if (new_cap > SIZE_MAX / ibuf->entry_size) {
1423 return SKIPSET_ERR_ALLOC;
1424 }
1425
1426 /* realloc */
1427 old_entries = ibuf->buf;
1428 ibuf->buf = (uint8_t*)realloc(old_entries, (new_cap * ibuf->entry_size));
1429 /* handle failure */
1430 if (NULL == ibuf->buf) {
1431 ibuf->buf = old_entries;
1432 return SKIPSET_ERR_ALLOC;
1433 }
1434
1435 /* bzero the new memory */
1436 if (old_cap < new_cap) {
1437 memset((ibuf->buf + (old_cap * ibuf->entry_size)),
1438 0, ((new_cap - old_cap) * ibuf->entry_size));
1439 }
1440
1441 ibuf->entry_capacity = new_cap;
1442 return 0;
1443 }
1444
1445
1446 /*
1447 * use_iptree = ipsetCheckFormatEnvar();
1448 *
1449 * Check the value of the environment variable specified by the
1450 * IPSET_ENVAR_INCORE_FORMAT macro and set the global
1451 * 'ipset_use_iptree' variable appropriately. If the envar is not
1452 * set, set 'ipset_use_iptree' to the default structure specified
1453 * by IPSET_USE_IPTREE_DEFAULT.
1454 */
1455 static int
ipsetCheckFormatEnvar(void)1456 ipsetCheckFormatEnvar(
1457 void)
1458 {
1459 const char *envar;
1460
1461 if (ipset_use_iptree >= 0) {
1462 return ipset_use_iptree;
1463 }
1464 envar = getenv(IPSET_ENVAR_INCORE_FORMAT);
1465 if (envar) {
1466 if (0 == strcasecmp("iptree", envar)) {
1467 ipset_use_iptree = 1;
1468 return ipset_use_iptree;
1469 }
1470 if (0 == strcasecmp("radix", envar)) {
1471 ipset_use_iptree = 0;
1472 return ipset_use_iptree;
1473 }
1474 }
1475 ipset_use_iptree = IPSET_USE_IPTREE_DEFAULT;
1476 return ipset_use_iptree;
1477 }
1478
1479
1480 /*
1481 * status = ipsetCheckIPSetCallbackV4(ipaddr, prefix, ipset);
1482 * status = ipsetCheckIPSetCallbackV6(ipaddr, prefix, ipset);
1483 *
1484 * Callback functions used by skIPSetCheckIPSet().
1485 *
1486 * Check whether the 'ipaddr'/'prefix' is in 'ipset'. If it is
1487 * not, return SKIPSET_OK so iteration continues. Otherwise,
1488 * return SKIPSET_ERR_SUBSET so iteration stops.
1489 */
1490 static int
ipsetCheckIPSetCallbackV4(skipaddr_t * ipaddr,uint32_t prefix,void * v_search_set)1491 ipsetCheckIPSetCallbackV4(
1492 skipaddr_t *ipaddr,
1493 uint32_t prefix,
1494 void *v_search_set)
1495 {
1496 uint32_t ipv4;
1497
1498 if (skipaddrGetAsV4(ipaddr, &ipv4)) {
1499 return SKIPSET_OK;
1500 }
1501 switch (ipsetFindV4((const skipset_t*)v_search_set, ipv4, prefix, NULL)) {
1502 case SKIPSET_OK:
1503 case SKIPSET_ERR_SUBSET:
1504 return SKIPSET_ERR_SUBSET;
1505 default:
1506 break;
1507 }
1508 return SKIPSET_OK;
1509 }
1510
1511 #if SK_ENABLE_IPV6
1512 static int
ipsetCheckIPSetCallbackV6(skipaddr_t * ipaddr,uint32_t prefix,void * v_search_set)1513 ipsetCheckIPSetCallbackV6(
1514 skipaddr_t *ipaddr,
1515 uint32_t prefix,
1516 void *v_search_set)
1517 {
1518 ipset_ipv6_t ipv6;
1519
1520 IPSET_IPV6_FROM_ADDRV6(&ipv6, ipaddr);
1521
1522 switch (ipsetFindV6((const skipset_t*)v_search_set, &ipv6, prefix, NULL)) {
1523 case SKIPSET_OK:
1524 case SKIPSET_ERR_SUBSET:
1525 return SKIPSET_ERR_SUBSET;
1526 default:
1527 break;
1528 }
1529 return SKIPSET_OK;
1530 }
1531 #endif /* SK_ENABLE_IPV6 */
1532
1533
1534 /*
1535 * Helper function for skIPSetCheckIPSet() when both IPsets are
1536 * implmented by a SiLK-2 IPTree.
1537 *
1538 * Also a helper function for legacy skIPTreeCheckIntersectIPTree().
1539 */
1540 static int
ipsetCheckIPSetIPTree(const skIPTree_t * ipset1,const skIPTree_t * ipset2)1541 ipsetCheckIPSetIPTree(
1542 const skIPTree_t *ipset1,
1543 const skIPTree_t *ipset2)
1544 {
1545 unsigned int i, j;
1546
1547 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
1548 /* check for intersection at the /16 level */
1549 if ((NULL == ipset1->nodes[i]) || (NULL == ipset2->nodes[i])) {
1550 /* do nothing */
1551
1552 } else {
1553 /* Need to intersect the bits in the /16 */
1554 for (j = 0; j < SKIP_BBLOCK_SIZE; ++j) {
1555 if (ipset1->nodes[i]->addressBlock[j]
1556 & ipset2->nodes[i]->addressBlock[j])
1557 {
1558 return 1;
1559 }
1560 }
1561 }
1562 }
1563
1564 /* no intersesction */
1565 return 0;
1566 }
1567
1568
1569 /*
1570 * Helper function for skIPSetCheckIPWildcard() when the IPset is
1571 * implmented by a SiLK-2 IPTree.
1572 *
1573 * Also a helper function for legacy skIPTreeCheckIntersectIPWildcard().
1574 */
1575 static int
ipsetCheckWildcardIPTree(const skIPTree_t * ipset,const skIPWildcard_t * ipwild)1576 ipsetCheckWildcardIPTree(
1577 const skIPTree_t *ipset,
1578 const skIPWildcard_t *ipwild)
1579 {
1580 /* for a description of 'prefix_as_bits', see
1581 * ipsetInsertAddressIPTree() */
1582 const uint32_t prefix_as_bits[] = {
1583 0xFFFFFFFF, 0xFFFF, 0xFF, 0xF, 0x3, 0x1
1584 };
1585 skIPWildcardIterator_t iter;
1586 skipaddr_t ipaddr;
1587 uint32_t ipv4;
1588 uint32_t ipv4_end;
1589 uint32_t prefix;
1590 skIPNode_t empty_node;
1591
1592 memset(&empty_node, 0, sizeof(empty_node));
1593
1594 /* Iterate over the IPs from the wildcard */
1595 skIPWildcardIteratorBindV4(&iter, ipwild);
1596 while (skIPWildcardIteratorNextCidr(&iter, &ipaddr, &prefix)
1597 == SK_ITERATOR_OK)
1598 {
1599 assert(prefix <= 32);
1600 ipv4 = skipaddrGetV4(&ipaddr);
1601
1602 if (prefix <= 16) {
1603 ipv4_end = ((UINT32_MAX >> prefix) | ipv4) >> 16;
1604 ipv4 >>= 16;
1605 do {
1606 if (ipset->nodes[ipv4]) {
1607 /* assumes any non-NULL IPTree node contains at
1608 * least one high bit */
1609 return 1;
1610 }
1611 } while (ipv4++ < ipv4_end);
1612
1613 } else if (NULL == ipset->nodes[ipv4 >> 16]) {
1614 /* no intersection */
1615
1616 } else if (prefix >= 27) {
1617 if (ipset->nodes[ipv4 >> 16]->addressBlock[(ipv4 & 0xFFFF)>>5]
1618 & (prefix_as_bits[prefix - 27] << ((ipv4) & 0x1F)))
1619 {
1620 return 1;
1621 }
1622
1623 } else {
1624 /* 16 < prefix < 27 */
1625 if (memcmp(&ipset->nodes[ipv4>>16]->addressBlock[(ipv4&0xFFFF)>>5],
1626 &empty_node, (sizeof(skIPNode_t) >> (prefix - 16))))
1627 {
1628 return 1;
1629 }
1630 }
1631 }
1632
1633 /* no intersesction */
1634 return 0;
1635 }
1636
1637
1638 /*
1639 * ipsetCombineSubtreeV4(ipset, parent_idx, node_idx, which_child);
1640 * ipsetCombineSubtreeV6(ipset, parent_idx, node_idx, which_child);
1641 *
1642 * Helper function for ipsetCombineAdjacentCIDR().
1643 *
1644 * Reduce the number of nodes used in the 'ipset' by combining
1645 * nodes that form a contiguous block into a larger block and by
1646 * removing nodes that contain a single leaf.
1647 *
1648 * The algorithm uses a recursive, depth first traversal from
1649 * 'node_idx'.
1650 *
1651 * The 'node_idx' passed into this function must not be a leaf
1652 * node.
1653 */
1654 static void
ipsetCombineSubtreeV4(skipset_t * ipset,uint32_t parent_idx,uint32_t node_idx,uint32_t which_child)1655 ipsetCombineSubtreeV4(
1656 skipset_t *ipset,
1657 uint32_t parent_idx,
1658 uint32_t node_idx,
1659 uint32_t which_child)
1660 {
1661 ipset_node_v4_t *parent;
1662 ipset_node_v4_t *node;
1663 ipset_leaf_v4_t *leaf1;
1664 ipset_leaf_v4_t *leaf2;
1665 uint32_t first_child;
1666 uint32_t last_child;
1667 uint32_t child[IPSET_NUM_CHILDREN];
1668 uint32_t depth;
1669 uint32_t i;
1670 uint32_t j;
1671
1672 #ifndef NDEBUG
1673 assert(node_idx < ipset->s.v3->nodes.entry_count);
1674 if (parent_idx != IPSET_NO_PARENT) {
1675 node = NODE_PTR_V4(ipset, parent_idx);
1676 assert(which_child < IPSET_NUM_CHILDREN);
1677 assert(node->child[which_child] == node_idx);
1678 assert(!NODEPTR_CHILD_IS_LEAF(node, which_child));
1679 }
1680 #endif /* NDEBUG */
1681
1682 /* note the position of the first and last child on the node so we
1683 * can later determine whether all children on this node point to
1684 * the same leaf. */
1685 first_child = IPSET_NUM_CHILDREN;
1686 last_child = IPSET_NUM_CHILDREN;
1687
1688 /* the child[] array is a stack of child positions waiting to be
1689 * merged into a larger contiguous block if possible. depth is
1690 * the index into the child[] array. */
1691 depth = 0;
1692
1693 node = NODE_PTR_V4(ipset, node_idx);
1694
1695 /* find child in highest position */
1696 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
1697 --i;
1698 if (node->child[i]) {
1699 last_child = i;
1700 break;
1701 }
1702 }
1703
1704 if (IPSET_NUM_CHILDREN == last_child) {
1705 /* node has no children!! */
1706 if (IPSET_NO_PARENT == parent_idx) {
1707 skIPSetRemoveAll(ipset);
1708 } else {
1709 assert(which_child < IPSET_NUM_CHILDREN);
1710 parent = NODE_PTR_V4(ipset, parent_idx);
1711 parent->child[which_child] = 0;
1712 }
1713 return;
1714 }
1715
1716 do {
1717 if (0 == node->child[i]) {
1718 /* not contiguous */
1719 depth = 0;
1720 continue;
1721 }
1722 assert(NODEPTR_CHILD_IS_LEAF(node, i)
1723 ? (node->child[i] < ipset->s.v3->leaves.entry_count)
1724 : (node->child[i] < ipset->s.v3->nodes.entry_count));
1725 if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
1726 continue;
1727 }
1728 first_child = i;
1729 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
1730 ipsetCombineSubtreeV4(ipset, node_idx, node->child[i], i);
1731 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
1732 depth = 0;
1733 continue;
1734 }
1735 }
1736 if ((0 == depth) || (i & 0x1)) {
1737 child[depth++] = i;
1738 continue;
1739 }
1740 while (depth) {
1741 /* for two leaves to be joinable, they must have the same
1742 * prefix and the XOR of their values must be less than
1743 * the IP range covered by the proposed prefix, which is
1744 * one less than the current prefix. */
1745 leaf1 = LEAF_PTR_V4(ipset, node->child[i]);
1746 leaf2 = LEAF_PTR_V4(ipset, node->child[child[depth-1]]);
1747 assert(leaf1->prefix > 0);
1748 assert(leaf1->prefix <= 32);
1749 if (leaf1->prefix != leaf2->prefix
1750 || ((leaf1->ip ^ leaf2->ip) >= (1u << (33 - leaf1->prefix))))
1751 {
1752 /* cannot be joined */
1753 break;
1754 }
1755
1756 /* combine these two leaves */
1757 --leaf1->prefix;
1758 leaf1->ip &= ~(UINT32_MAX >> leaf1->prefix);
1759 j = child[depth-1];
1760 LEAFIDX_FREE(ipset, node->child[j]);
1761 NODEPTR_CHILD_SET_REPEAT2(node, i+1, j);
1762 do {
1763 node->child[j] = node->child[i];
1764 ++j;
1765 } while (j < IPSET_NUM_CHILDREN
1766 && NODEPTR_CHILD_IS_REPEAT(node, j));
1767 --depth;
1768 }
1769 child[depth++] = i;
1770
1771 } while (i-- > 0);
1772
1773 if (node->child[first_child] != node->child[last_child]
1774 || !NODEPTR_CHILD_IS_LEAF(node, first_child)
1775 || !NODEPTR_CHILD_IS_LEAF(node, last_child))
1776 {
1777 return;
1778 }
1779
1780 /* replace the node with the leaf */
1781 if (IPSET_NO_PARENT == parent_idx) {
1782 IPSET_ROOT_INDEX_SET(ipset, node->child[first_child], 1);
1783 } else {
1784 assert(which_child < IPSET_NUM_CHILDREN);
1785 parent = NODE_PTR_V4(ipset, parent_idx);
1786 parent->child[which_child] = node->child[first_child];
1787 SET_BMAP_SET(parent->child_is_leaf, which_child);
1788 }
1789 NODEIDX_FREE(ipset, node_idx);
1790 }
1791
1792 #if SK_ENABLE_IPV6
1793 static void
ipsetCombineSubtreeV6(skipset_t * ipset,uint32_t parent_idx,uint32_t node_idx,uint32_t which_child)1794 ipsetCombineSubtreeV6(
1795 skipset_t *ipset,
1796 uint32_t parent_idx,
1797 uint32_t node_idx,
1798 uint32_t which_child)
1799 {
1800 ipset_node_v6_t *parent;
1801 ipset_node_v6_t *node;
1802 ipset_leaf_v6_t *leaf1;
1803 ipset_leaf_v6_t *leaf2;
1804 uint32_t first_child;
1805 uint32_t last_child;
1806 uint32_t child[IPSET_NUM_CHILDREN];
1807 uint32_t depth;
1808 uint32_t i;
1809 uint32_t j;
1810
1811 #ifndef NDEBUG
1812 assert(node_idx < ipset->s.v3->nodes.entry_count);
1813 if (parent_idx != IPSET_NO_PARENT) {
1814 node = NODE_PTR_V6(ipset, parent_idx);
1815 assert(which_child < IPSET_NUM_CHILDREN);
1816 assert(node->child[which_child] == node_idx);
1817 assert(!NODEPTR_CHILD_IS_LEAF(node, which_child));
1818 }
1819 #endif /* NDEBUG */
1820
1821 /* note the position of the first and last child on the node so we
1822 * can later determine whether all children on this node point to
1823 * the same leaf. */
1824 first_child = IPSET_NUM_CHILDREN;
1825 last_child = IPSET_NUM_CHILDREN;
1826
1827 /* the child[] array is a stack of child positions waiting to be
1828 * merged into a larger contiguous block if possible. depth is
1829 * the index into the child[] array. */
1830 depth = 0;
1831
1832 node = NODE_PTR_V6(ipset, node_idx);
1833
1834 /* find child in highest position */
1835 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
1836 --i;
1837 if (node->child[i]) {
1838 last_child = i;
1839 break;
1840 }
1841 }
1842
1843 if (IPSET_NUM_CHILDREN == last_child) {
1844 /* node has no children!! */
1845 if (IPSET_NO_PARENT == parent_idx) {
1846 skIPSetRemoveAll(ipset);
1847 } else {
1848 assert(which_child < IPSET_NUM_CHILDREN);
1849 parent = NODE_PTR_V6(ipset, parent_idx);
1850 parent->child[which_child] = 0;
1851 }
1852 return;
1853 }
1854
1855 do {
1856 if (0 == node->child[i]) {
1857 depth = 0;
1858 continue;
1859 }
1860 assert(NODEPTR_CHILD_IS_LEAF(node, i)
1861 ? (node->child[i] < ipset->s.v3->leaves.entry_count)
1862 : (node->child[i] < ipset->s.v3->nodes.entry_count));
1863 if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
1864 continue;
1865 }
1866 first_child = i;
1867 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
1868 ipsetCombineSubtreeV6(ipset, node_idx, node->child[i], i);
1869 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
1870 depth = 0;
1871 continue;
1872 }
1873 }
1874 if ((0 == depth) || (i & 0x1)) {
1875 child[depth++] = i;
1876 continue;
1877 }
1878 while (depth) {
1879 /* for two leaves to be joinable, the must have the same
1880 * prefix and the XOR of their values must be less than 1
1881 * shifted by the proposed prefix subtracted from 32,
1882 * where the proposed prefix is one less than the current
1883 * prefix. */
1884 leaf1 = LEAF_PTR_V6(ipset, node->child[i]);
1885 leaf2 = LEAF_PTR_V6(ipset, node->child[child[depth-1]]);
1886 if (leaf1->prefix != leaf2->prefix) {
1887 break;
1888 }
1889 assert(leaf1->prefix > 0);
1890 assert(leaf1->prefix <= 128);
1891 if (leaf1->prefix <= 64) {
1892 /* this change affects the most significant 64 bits */
1893 if ((leaf1->ip.ip[0] ^ leaf2->ip.ip[0])
1894 >= (UINT64_C(1) << (65 - leaf1->prefix)))
1895 {
1896 /* cannot be joined */
1897 break;
1898 }
1899 /* combine these two leaves */
1900 --leaf1->prefix;
1901 leaf1->ip.ip[0] &= ~(UINT64_MAX >> leaf1->prefix);
1902 } else if (leaf1->prefix == 65) {
1903 /* this change affects the least significant 64 bits */
1904 if (leaf1->ip.ip[0] != leaf2->ip.ip[0]) {
1905 /* cannot be joined. */
1906 break;
1907 }
1908 /* a prefix of 65 must succeed, since the ranges must
1909 * be W:X:Y:Z:0::/65 and W:X:Y:Z:8000::/65 */
1910 --leaf1->prefix;
1911 leaf1->ip.ip[1] = 0;
1912 } else {
1913 /* this change affects the least significant 64 bits */
1914 if ((leaf1->ip.ip[0] != leaf2->ip.ip[0])
1915 || ((leaf1->ip.ip[1] ^ leaf2->ip.ip[1])
1916 >= (UINT64_C(1) << (129 - leaf1->prefix))))
1917 {
1918 /* cannot be joined. */
1919 break;
1920 }
1921 --leaf1->prefix;
1922 leaf1->ip.ip[1] &= ~(UINT64_MAX >> (leaf1->prefix - 64));
1923 }
1924
1925 j = child[depth-1];
1926 LEAFIDX_FREE(ipset, node->child[j]);
1927 NODEPTR_CHILD_SET_REPEAT2(node, i+1, j);
1928 do {
1929 node->child[j] = node->child[i];
1930 ++j;
1931 } while (j < IPSET_NUM_CHILDREN
1932 && NODEPTR_CHILD_IS_REPEAT(node, j));
1933 --depth;
1934 }
1935 child[depth++] = i;
1936
1937 } while (i-- > 0);
1938
1939 if (node->child[first_child] != node->child[last_child]
1940 || !NODEPTR_CHILD_IS_LEAF(node, first_child)
1941 || !NODEPTR_CHILD_IS_LEAF(node, last_child))
1942 {
1943 return;
1944 }
1945
1946 /* replace the node with the leaf */
1947 if (IPSET_NO_PARENT == parent_idx) {
1948 IPSET_ROOT_INDEX_SET(ipset, node->child[first_child], 1);
1949 } else {
1950 assert(which_child < IPSET_NUM_CHILDREN);
1951 parent = NODE_PTR_V6(ipset, parent_idx);
1952 parent->child[which_child] = node->child[first_child];
1953 NODEPTR_CHILD_SET_LEAF(parent, which_child);
1954 }
1955 NODEIDX_FREE(ipset, node_idx);
1956 }
1957 #endif /* SK_ENABLE_IPV6 */
1958
1959
1960 /*
1961 * ipsetCombineAdjacentCIDR(ipset);
1962 *
1963 * Visit the nodes in the tree looking for leaves that form a
1964 * contiguous block of IPs. When found, combine the leaves into a
1965 * single leaf. This will make reduce the size required by the
1966 * tree.
1967 */
1968 static void
ipsetCombineAdjacentCIDR(skipset_t * ipset)1969 ipsetCombineAdjacentCIDR(
1970 skipset_t *ipset)
1971 {
1972 if (!IPSET_ROOT_IS_LEAF(ipset)) {
1973 #if SK_ENABLE_IPV6
1974 if (ipset->is_ipv6) {
1975 ipsetCombineSubtreeV6(ipset, IPSET_NO_PARENT,
1976 IPSET_ROOT_INDEX(ipset), IPSET_NUM_CHILDREN);
1977 } else
1978 #endif /* SK_ENABLE_IPV6 */
1979 {
1980 ipsetCombineSubtreeV4(ipset, IPSET_NO_PARENT,
1981 IPSET_ROOT_INDEX(ipset), IPSET_NUM_CHILDREN);
1982 }
1983 }
1984 }
1985
1986
1987 /*
1988 * ipsetCompact(ipset);
1989 *
1990 * Make the nodes and leaves arrays in the 'ipset' use contiguous
1991 * blocks of memory. Any holes in the arrays---represented by
1992 * nodes/leaves in the free-list---will become occupied. When this
1993 * function returns, the memory will be contiguous and the free
1994 * list will be empty.
1995 */
1996 static void
ipsetCompact(skipset_t * ipset)1997 ipsetCompact(
1998 skipset_t *ipset)
1999 {
2000 ipset_node_t *node;
2001 ipset_leaf_t *leaf;
2002 uint32_t nodes_in_use;
2003 uint32_t nodes_free_idx;
2004 uint32_t leaves_in_use;
2005 uint32_t leaves_free_idx;
2006 uint32_t to_visit[IPSET_MAX_DEPTH];
2007 uint32_t depth;
2008 int i;
2009
2010 /* if the free lists are empty, the tree is compact */
2011 if (0 == ipset->s.v3->nodes.free_list
2012 && 0 == ipset->s.v3->leaves.free_list)
2013 {
2014 return;
2015 }
2016
2017 /* handle a leaf at the root as a special case */
2018 if (IPSET_ROOT_IS_LEAF(ipset)) {
2019 /* values 1 and 2 due to node#0 and leaf#0 never used */
2020 nodes_in_use = 1;
2021 leaves_in_use = 2;
2022 if (IPSET_ROOT_INDEX(ipset) >= leaves_in_use) {
2023 leaves_free_idx = 1;
2024 /* copy the child to this location */
2025 memcpy(LEAF_PTR(ipset, leaves_free_idx),
2026 LEAF_PTR(ipset, IPSET_ROOT_INDEX(ipset)),
2027 ipset->s.v3->leaves.entry_size);
2028 /* update the root's pointer to the child */
2029 IPSET_ROOT_INDEX_SET(ipset, leaves_free_idx, 1);
2030 }
2031 goto CLEAR_MEMORY;
2032 }
2033
2034 /* determine the number of nodes currently in use by subtracting
2035 * the nodes on the free list from the total number of nodes */
2036 nodes_in_use = ipset->s.v3->nodes.entry_count;
2037 for (nodes_free_idx = ipset->s.v3->nodes.free_list;
2038 0 != nodes_free_idx;
2039 nodes_free_idx = NODEPTR_FREE_LIST(node))
2040 {
2041 assert(nodes_free_idx < ipset->s.v3->nodes.entry_count);
2042 --nodes_in_use;
2043 node = NODE_PTR(ipset, nodes_free_idx);
2044 }
2045 if (ipset->s.v3->nodes.entry_count < nodes_in_use) {
2046 /* the only way for this to happen is for the nodes_in_use
2047 * value to underflow 0 */
2048 skAbort();
2049 }
2050
2051 /* repeat the process for the leaves */
2052 leaves_in_use = ipset->s.v3->leaves.entry_count;
2053 for (leaves_free_idx = ipset->s.v3->leaves.free_list;
2054 0 != leaves_free_idx;
2055 leaves_free_idx = LEAFPTR_FREE_LIST(leaf))
2056 {
2057 assert(leaves_free_idx < ipset->s.v3->leaves.entry_count);
2058 --leaves_in_use;
2059 leaf = LEAF_PTR(ipset, leaves_free_idx);
2060 }
2061 if (ipset->s.v3->leaves.entry_count < leaves_in_use) {
2062 skAbort();
2063 }
2064
2065 /* Since Node#0 and Leaf#0 are never used, nodes_in_use and
2066 * leaves_in_use can be 0 or they can be a value >= 2, but they
2067 * should never be 1. */
2068 /* However, I am leary of enabling these asserts.
2069 * assert(nodes_in_use != 1);
2070 * assert(leaves_in_use != 1);
2071 */
2072
2073 /* handle the root */
2074 assert(0 == IPSET_ROOT_IS_LEAF(ipset));
2075 if (IPSET_ROOT_INDEX(ipset) >= nodes_in_use) {
2076 /* pop nodes from the free list until we find one smaller
2077 * than nodes_in_use. */
2078 do {
2079 nodes_free_idx = ipset->s.v3->nodes.free_list;
2080 ipset->s.v3->nodes.free_list
2081 = NODEIDX_FREE_LIST(ipset, nodes_free_idx);
2082 } while (nodes_free_idx >= nodes_in_use);
2083 assert(nodes_free_idx != 0);
2084
2085 /* copy the child to the location we just popped
2086 * from the free_list */
2087 memcpy(NODE_PTR(ipset, nodes_free_idx),
2088 NODE_PTR(ipset, IPSET_ROOT_INDEX(ipset)),
2089 ipset->s.v3->nodes.entry_size);
2090
2091 /* update the root's pointer to the child */
2092 IPSET_ROOT_INDEX_SET(ipset, nodes_free_idx, 0);
2093 }
2094
2095 /* visit the nodes in the tree. */
2096 depth = 0;
2097 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
2098
2099 while (depth) {
2100 node = NODE_PTR(ipset, to_visit[--depth]);
2101
2102 /* if the indexes of the children of this node are larger than
2103 * 'nodes_in_use' or leaves_in_use', pop an entry from
2104 * the appropriate free-list and copy that child to the new
2105 * location. handled just like the root. */
2106 for (i = 0; i < IPSET_NUM_CHILDREN; ++i) {
2107 if (node->v4.child[i]) {
2108 if (!NODEPTR_CHILD_IS_LEAF(&node->v4, i)) {
2109 /* this is a node */
2110 if (node->v4.child[i] >= nodes_in_use) {
2111 do {
2112 nodes_free_idx = ipset->s.v3->nodes.free_list;
2113 ipset->s.v3->nodes.free_list
2114 = NODEIDX_FREE_LIST(ipset, nodes_free_idx);
2115 } while (nodes_free_idx >= nodes_in_use);
2116 assert(nodes_free_idx != 0);
2117 memcpy(NODE_PTR(ipset, nodes_free_idx),
2118 NODE_PTR(ipset, node->v4.child[i]),
2119 ipset->s.v3->nodes.entry_size);
2120 node->v4.child[i] = nodes_free_idx;
2121 }
2122 /* we must visit this child */
2123 assert(depth < IPSET_MAX_DEPTH - 1);
2124 to_visit[depth++] = node->v4.child[i];
2125
2126 } else {
2127 /* this is a leaf: it is handled just slightly
2128 * differently than a node */
2129 if (node->v4.child[i] >= leaves_in_use) {
2130 do {
2131 leaves_free_idx = ipset->s.v3->leaves.free_list;
2132 ipset->s.v3->leaves.free_list
2133 = LEAFIDX_FREE_LIST(ipset, leaves_free_idx);
2134 } while (leaves_free_idx >= leaves_in_use);
2135 assert(leaves_free_idx != 0);
2136 memcpy(LEAF_PTR(ipset, leaves_free_idx),
2137 LEAF_PTR(ipset, node->v4.child[i]),
2138 ipset->s.v3->leaves.entry_size);
2139 node->v4.child[i] = leaves_free_idx;
2140
2141 /* handle repeated leaf */
2142 while ((i < (IPSET_NUM_CHILDREN - 1))
2143 && NODEPTR_CHILD_IS_REPEAT(&node->v4, i+1))
2144 {
2145 ++i;
2146 node->v4.child[i] = leaves_free_idx;
2147 }
2148 }
2149 }
2150 }
2151 }
2152 }
2153
2154 CLEAR_MEMORY:
2155 /* we have compacted the tree. bzero the memory we just cleared,
2156 * set the entry_counts to the number of active entries, and reset
2157 * the free lists. */
2158 memset((ipset->s.v3->nodes.buf
2159 + (nodes_in_use * ipset->s.v3->nodes.entry_size)),
2160 0, ((ipset->s.v3->nodes.entry_count - nodes_in_use)
2161 * ipset->s.v3->nodes.entry_size));
2162 ipset->s.v3->nodes.entry_count = nodes_in_use;
2163 ipset->s.v3->nodes.free_list = 0;
2164
2165 memset((ipset->s.v3->leaves.buf
2166 + (leaves_in_use * ipset->s.v3->leaves.entry_size)),
2167 0, ((ipset->s.v3->leaves.entry_count - leaves_in_use)
2168 * ipset->s.v3->leaves.entry_size));
2169 ipset->s.v3->leaves.entry_count = leaves_in_use;
2170 ipset->s.v3->leaves.free_list = 0;
2171 }
2172
2173
2174 #if SK_ENABLE_IPV6
2175 /*
2176 * status = ipsetConvertIPTreetoV6(ipset);
2177 *
2178 * Convert the contents of a SiLK-2 based IPset (IPTree) to a
2179 * SiLK-3 based IPv6 IPset. The IPv4 addresses in the IPset will
2180 * be mapped into the "::ffff:0.0.0.0/96" address space. Return
2181 * SKIPSET_OK on success, or SKIPSET_ERR_ALLOC if memory cannot be
2182 * allocated to hold the IPv6 addresses.
2183 */
2184 static int
ipsetConvertIPTreetoV6(skipset_t * ipset)2185 ipsetConvertIPTreetoV6(
2186 skipset_t *ipset)
2187 {
2188 skIPTree_t *iptree;
2189 skipset_t *v6ipset;
2190 skipset_iterator_t iter;
2191 skipaddr_t ipaddr;
2192 uint32_t prefix;
2193 int rv;
2194
2195 assert(ipset);
2196 assert(1 == ipset->is_iptree);
2197 assert(0 == ipset->is_ipv6);
2198 assert(0 == ipset->no_autoconvert);
2199
2200 rv = ipsetCreate(&v6ipset, 1, 1);
2201 if (rv) {
2202 return rv;
2203 }
2204
2205 skIPSetClean(ipset);
2206
2207 ASSERT_OK(skIPSetIteratorBind(&iter, ipset, 1, SK_IPV6POLICY_FORCE));
2208 while (skIPSetIteratorNext(&iter, &ipaddr, &prefix) == SK_ITERATOR_OK) {
2209 rv = skIPSetInsertAddress(v6ipset, &ipaddr, prefix);
2210 if (rv) {
2211 skIPSetDestroy(&v6ipset);
2212 return rv;
2213 }
2214 }
2215
2216 /* swap the IPsets */
2217 iptree = ipset->s.v2;
2218 ipset->s.v3 = v6ipset->s.v3;
2219 ipset->is_iptree = 0;
2220 ipset->is_ipv6 = 1;
2221
2222 v6ipset->is_ipv6 = 0;
2223 v6ipset->is_iptree = 1;
2224 v6ipset->s.v2 = iptree;
2225
2226 skIPSetDestroy(&v6ipset);
2227
2228 skIPSetClean(ipset);
2229
2230 return SKIPSET_OK;
2231 }
2232
2233
2234 /*
2235 * status = ipsetConvertV4toV6(ipset);
2236 *
2237 * Helper function for skIPSetConvert();
2238 *
2239 * Convert the contents of a Radix-Tree based 'ipset' so it
2240 * contains IPv6 addresses.
2241 *
2242 * The IPv4 addresses in the IPset will be mapped into the
2243 * "::ffff:0.0.0.0/96" address space. Return SKIPSET_OK on
2244 * success, or SKIPSET_ERR_ALLOC if memory cannot be allocated to
2245 * hold the IPv6 addresses.
2246 */
2247 static int
ipsetConvertV4toV6(skipset_t * ipset)2248 ipsetConvertV4toV6(
2249 skipset_t *ipset)
2250 {
2251 ipset_node_v6_t *node6;
2252 ipset_node_v4_t *node4;
2253 ipset_leaf_v6_t *leaf6;
2254 ipset_leaf_v4_t *leaf4;
2255 size_t num_entries;
2256 size_t ip_offset;
2257 uint32_t i;
2258 int rv;
2259
2260 assert(ipset);
2261 assert(0 == ipset->is_iptree);
2262 assert(sizeof(ipset_node_v4_t) == ipset->s.v3->nodes.entry_size);
2263
2264 if (IPSET_ISEMPTY(ipset)) {
2265 goto SET_ATTRIBUTES;
2266 }
2267
2268 /* compute the number of bytes required to hold the nodes once
2269 * they are converted to IPv6, then divide by the IPv4 node size
2270 * to get the number of IPv4 nodes to request. The -1/+1 handle a
2271 * partial node. */
2272 num_entries
2273 = (((ipset->s.v3->nodes.entry_count * sizeof(ipset_node_v6_t) - 1)
2274 / sizeof(ipset_node_v4_t)) + 1);
2275 if (num_entries > ipset->s.v3->nodes.entry_capacity) {
2276 rv = ipsetAllocEntries(&ipset->s.v3->nodes, num_entries);
2277 if (rv) {
2278 return rv;
2279 }
2280 }
2281
2282 /* repeat for the leaves */
2283 num_entries
2284 = (((ipset->s.v3->leaves.entry_count * sizeof(ipset_leaf_v6_t) - 1)
2285 / sizeof(ipset_leaf_v4_t)) + 1);
2286 if (num_entries > ipset->s.v3->leaves.entry_capacity) {
2287 rv = ipsetAllocEntries(&ipset->s.v3->leaves, num_entries);
2288 if (rv) {
2289 return rv;
2290 }
2291 }
2292
2293 /* modify the nodes */
2294
2295 ip_offset = offsetof(ipset_node_v4_t, ip);
2296 assert(offsetof(ipset_node_v6_t, ip) >= ip_offset);
2297
2298 /* break the NODE_PTR() abstraction here. Count from
2299 * 'entry_count' down to 1, converting each node from a V4 node to
2300 * a V6 node. */
2301 node4 = &(((ipset_node_v4_t*)ipset->s.v3->nodes.buf)
2302 [ipset->s.v3->nodes.entry_count-1]);
2303 node6 = &(((ipset_node_v6_t*)ipset->s.v3->nodes.buf)
2304 [ipset->s.v3->nodes.entry_count-1]);
2305
2306 for (i = ipset->s.v3->nodes.entry_count - 1; i > 0; --i, --node4, --node6){
2307 /* copy and convert the IP; must do the IP first, since its
2308 * location is overwritten by the memmove() call */
2309 node6->ip.ip[1] = UINT64_C(0xffff00000000) | node4->ip;
2310 node6->ip.ip[0] = 0;
2311 /* use memmove to copy the node except for the IP; must use
2312 * memmove() since the nodes overlap */
2313 memmove(node6, node4, ip_offset);
2314 node6->prefix += 96;
2315 /* node6->pad_align = 0 */
2316 }
2317 assert(0 == i);
2318 assert((void*)node4 == (void*)ipset->s.v3->nodes.buf);
2319 assert((void*)node6 == (void*)ipset->s.v3->nodes.buf);
2320
2321 /* node-0 is unused; clear out the IP address */
2322 node6->ip.ip[0] = 0;
2323 node6->ip.ip[1] = 0;
2324
2325 /* repeat for the leaves */
2326
2327 ip_offset = offsetof(ipset_leaf_v4_t, ip);
2328 assert(offsetof(ipset_leaf_v6_t, ip) >= ip_offset);
2329
2330 /* break the LEAF_PTR() abstraction here. Count from
2331 * 'entry_count' down to 0, converting each leaf from a V4 leaf to
2332 * a V6 leaf. */
2333 leaf4 = &(((ipset_leaf_v4_t*)ipset->s.v3->leaves.buf)
2334 [ipset->s.v3->leaves.entry_count-1]);
2335 leaf6 = &(((ipset_leaf_v6_t*)ipset->s.v3->leaves.buf)
2336 [ipset->s.v3->leaves.entry_count-1]);
2337
2338 for (i = ipset->s.v3->leaves.entry_count - 1; i > 0; --i, --leaf4, --leaf6)
2339 {
2340 /* use memcpy to copy the leaf; can use memcpy, since leaf6 is
2341 * twice the size of leaf4 */
2342 memcpy(leaf6, leaf4, ip_offset);
2343 leaf6->prefix += 96;
2344 /* copy and convert the IP */
2345 leaf6->ip.ip[1] = UINT64_C(0xffff00000000) | leaf4->ip;
2346 leaf6->ip.ip[0] = 0;
2347 }
2348 assert(0 == i);
2349 assert((void*)leaf4 == (void*)ipset->s.v3->leaves.buf);
2350 assert((void*)leaf6 == (void*)ipset->s.v3->leaves.buf);
2351
2352 /* clear the IP address in leaf-0 */
2353 leaf6->ip.ip[0] = 0;
2354 leaf6->ip.ip[1] = 0;
2355
2356 SET_ATTRIBUTES:
2357 /* set the IPset attributes for IPv6 */
2358 ipset->s.v3->nodes.entry_size = sizeof(ipset_node_v6_t);
2359 ipset->s.v3->leaves.entry_size = sizeof(ipset_leaf_v6_t);
2360 ipset->is_ipv6 = 1;
2361 ipset->is_dirty = 1;
2362
2363 /* adjust the capacities. this may result in a few wasted bytes
2364 * until the next realloc() */
2365 ipset->s.v3->nodes.entry_capacity
2366 = (ipset->s.v3->nodes.entry_capacity
2367 * sizeof(ipset_node_v4_t) / sizeof(ipset_node_v6_t));
2368 assert(ipset->s.v3->nodes.entry_capacity >= ipset->s.v3->nodes.entry_count);
2369 ipset->s.v3->leaves.entry_capacity
2370 = (ipset->s.v3->leaves.entry_capacity
2371 * sizeof(ipset_leaf_v4_t) / sizeof(ipset_leaf_v6_t));
2372 assert(ipset->s.v3->leaves.entry_capacity
2373 >= ipset->s.v3->leaves.entry_count);
2374
2375 return SKIPSET_OK;
2376 }
2377
2378
2379 /*
2380 * status = ipsetConvertV6toV4(ipset);
2381 *
2382 * Helper function for skIPSetConvert();
2383 *
2384 * Convert the contents of 'ipset' so it contains only IPv4
2385 * addresses. This function should not be called on IPsets that
2386 * contain IPv6 addresses outside of "::ffff:0.0.0.0/96".
2387 */
2388 static int
ipsetConvertV6toV4(skipset_t * ipset)2389 ipsetConvertV6toV4(
2390 skipset_t *ipset)
2391 {
2392 ipset_node_v6_t *node6;
2393 ipset_node_v4_t *node4;
2394 ipset_leaf_v6_t *leaf6;
2395 ipset_leaf_v4_t *leaf4;
2396 size_t ip_offset;
2397 uint32_t i;
2398
2399 assert(ipset);
2400 assert(0 == ipset->is_iptree);
2401 assert(sizeof(ipset_node_v6_t) == ipset->s.v3->nodes.entry_size);
2402 assert(sizeof(ipset_leaf_v6_t) == ipset->s.v3->leaves.entry_size);
2403 assert(0 == skIPSetContainsV6(ipset));
2404
2405 if (IPSET_ISEMPTY(ipset)) {
2406 goto SET_ATTRIBUTES;
2407 }
2408
2409 ip_offset = offsetof(ipset_node_v4_t, ip);
2410 assert(offsetof(ipset_node_v6_t, ip) >= ip_offset);
2411
2412 /* break the NODE_PTR() abstraction here. Count from 0 to
2413 * 'entry_count', converting each node from a V6 node to a V4
2414 * node. */
2415 node4 = (ipset_node_v4_t*)ipset->s.v3->nodes.buf;
2416 node6 = (ipset_node_v6_t*)ipset->s.v3->nodes.buf;
2417
2418 /* just need to set the IP to 0 for node 0 */
2419 node4->ip = 0;
2420
2421 for (i = 1, ++node4, ++node6;
2422 i < ipset->s.v3->nodes.entry_count;
2423 ++i, ++node4, ++node6)
2424 {
2425 memmove(node4, node6, ip_offset);
2426 node4->ip = (uint32_t)(node6->ip.ip[1] & UINT32_MAX);
2427 node4->prefix -= 96;
2428 }
2429
2430
2431 /* Repeat the same process for the leaves */
2432
2433 ip_offset = offsetof(ipset_leaf_v4_t, ip);
2434 assert(offsetof(ipset_leaf_v6_t, ip) >= ip_offset);
2435
2436 leaf4 = (ipset_leaf_v4_t*)ipset->s.v3->leaves.buf;
2437 leaf6 = (ipset_leaf_v6_t*)ipset->s.v3->leaves.buf;
2438
2439 leaf4->ip = 0;
2440
2441 for (i = 1, ++leaf4, ++leaf6;
2442 i < ipset->s.v3->leaves.entry_count;
2443 ++i, ++leaf4, ++leaf6)
2444 {
2445 memcpy(leaf4, leaf6, ip_offset);
2446 leaf4->ip = (uint32_t)(leaf6->ip.ip[1] & UINT32_MAX);
2447 leaf4->prefix -= 96;
2448 }
2449
2450 SET_ATTRIBUTES:
2451 /* set the IPset attributes for IPv4 */
2452 ipset->s.v3->nodes.entry_size = sizeof(ipset_node_v4_t);
2453 ipset->s.v3->leaves.entry_size = sizeof(ipset_leaf_v4_t);
2454 ipset->is_ipv6 = 0;
2455 ipset->is_dirty = 1;
2456
2457 /* adjust the capacities. this may result in a waste of a few
2458 * bytes */
2459 ipset->s.v3->nodes.entry_capacity
2460 = (ipset->s.v3->nodes.entry_capacity
2461 * sizeof(ipset_node_v6_t) / sizeof(ipset_node_v4_t));
2462 ipset->s.v3->leaves.entry_capacity
2463 = (ipset->s.v3->leaves.entry_capacity
2464 * sizeof(ipset_leaf_v6_t) / sizeof(ipset_leaf_v4_t));
2465
2466 return SKIPSET_OK;
2467 }
2468 #endif /* SK_ENABLE_IPV6 */
2469
2470
2471 /*
2472 * status = ipsetCopyOnWrite(ipset);
2473 *
2474 * Use the IPSET_COPY_ON_WRITE() macro to invoke this function,
2475 * which only calls this function when necessary.
2476 *
2477 * Change the IPset 'ipset' so that it uses in-core memory to hold
2478 * its nodes instead of using mmap()ed data. Return 0 on success,
2479 * or SKIPSET_ERR_ALLOC if memory cannot be allocated.
2480 */
2481 static int
ipsetCopyOnWrite(skipset_t * ipset)2482 ipsetCopyOnWrite(
2483 skipset_t *ipset)
2484 {
2485 uint8_t *node_buf;
2486 uint8_t *leaf_buf;
2487 int rv;
2488
2489 assert(ipset->s.v3->mapped_file && ipset->s.v3->mapped_size);
2490
2491 /* cache the current buffer values in case the allocation fails */
2492 node_buf = ipset->s.v3->nodes.buf;
2493 leaf_buf = ipset->s.v3->leaves.buf;
2494
2495 /* clear the values so we can allocate the space */
2496 ipset->s.v3->nodes.buf = NULL;
2497 ipset->s.v3->nodes.entry_capacity = 0;
2498 ipset->s.v3->leaves.buf = NULL;
2499 ipset->s.v3->leaves.entry_capacity = 0;
2500
2501 rv = ipsetAllocEntries(&ipset->s.v3->nodes, ipset->s.v3->nodes.entry_count);
2502 if (rv) {
2503 ipset->s.v3->nodes.buf = node_buf;
2504 ipset->s.v3->nodes.entry_capacity = ipset->s.v3->nodes.entry_count;
2505 ipset->s.v3->leaves.buf = leaf_buf;
2506 ipset->s.v3->leaves.entry_capacity = ipset->s.v3->leaves.entry_count;
2507 return rv;
2508 }
2509 rv = ipsetAllocEntries(&ipset->s.v3->leaves,
2510 ipset->s.v3->leaves.entry_count);
2511 if (rv) {
2512 free(ipset->s.v3->nodes.buf);
2513 ipset->s.v3->nodes.buf = node_buf;
2514 ipset->s.v3->nodes.entry_capacity = ipset->s.v3->nodes.entry_count;
2515 ipset->s.v3->leaves.buf = leaf_buf;
2516 ipset->s.v3->leaves.entry_capacity = ipset->s.v3->leaves.entry_count;
2517 return rv;
2518 }
2519
2520 /* copy the mmap()ed data into the newly allocated space */
2521 memcpy(ipset->s.v3->nodes.buf, node_buf,
2522 (ipset->s.v3->nodes.entry_count * ipset->s.v3->nodes.entry_size));
2523 memcpy(ipset->s.v3->leaves.buf, leaf_buf,
2524 (ipset->s.v3->leaves.entry_count * ipset->s.v3->leaves.entry_size));
2525
2526 /* unmap the space */
2527 munmap(ipset->s.v3->mapped_file, ipset->s.v3->mapped_size);
2528
2529 ipset->s.v3->mapped_file = NULL;
2530 ipset->s.v3->mapped_size = 0;
2531
2532 return SKIPSET_OK;
2533 }
2534
2535
2536 /*
2537 * status = ipsetCountCallbackV4(ipv4, prefix, &count_state)
2538 * status = ipsetCountCallbackV6(ipv6, prefix, &count_state)
2539 *
2540 * Helper function for skIPSetCount().
2541 *
2542 * Compute (1 << 'prefix') to get the number of IPs in this block
2543 * and update the count in 'count_state'.
2544 */
2545 static int
ipsetCountCallbackV4(uint32_t UNUSED (ipv4),uint32_t prefix,void * v_count_state)2546 ipsetCountCallbackV4(
2547 uint32_t UNUSED(ipv4),
2548 uint32_t prefix,
2549 void *v_count_state)
2550 {
2551 ipset_count_t *count_state = (ipset_count_t*)v_count_state;
2552
2553 if (prefix > 32) {
2554 skAppPrintErr("Invalid prefix %u\n", prefix);
2555 skAbort();
2556 }
2557 count_state->lower += UINT64_C(1) << (32 - prefix);
2558 return 0;
2559 }
2560
2561 #if SK_ENABLE_IPV6
2562 static int
ipsetCountCallbackV6(const ipset_ipv6_t UNUSED (* ipv6),uint32_t prefix,void * v_count_state)2563 ipsetCountCallbackV6(
2564 const ipset_ipv6_t UNUSED(*ipv6),
2565 uint32_t prefix,
2566 void *v_count_state)
2567 {
2568 ipset_count_t *count_state = (ipset_count_t*)v_count_state;
2569 uint64_t tmp;
2570
2571 if (prefix == 0) {
2572 ++count_state->full;
2573 } else if (prefix <= 64) {
2574 tmp = UINT64_C(1) << (64 - prefix);
2575 if ((UINT64_MAX - count_state->upper) >= tmp) {
2576 count_state->upper += tmp;
2577 } else {
2578 ++count_state->full;
2579 count_state->upper -= ((UINT64_MAX - tmp) + 1);
2580 }
2581 } else if (prefix <= 128) {
2582 tmp = UINT64_C(1) << (128 - prefix);
2583 if ((UINT64_MAX - count_state->lower) >= tmp) {
2584 count_state->lower += tmp;
2585 } else {
2586 ++count_state->upper;
2587 count_state->lower -= ((UINT64_MAX - tmp) + 1);
2588 }
2589 } else {
2590 skAppPrintErr("Invalid prefix %u\n", prefix);
2591 skAbort();
2592 }
2593 return 0;
2594 }
2595 #endif /* SK_ENABLE_IPV6 */
2596
2597
2598 /*
2599 * Helper function for skIPSetCount() when the IPsets is implmented
2600 * by a SiLK-2 IPTree.
2601 *
2602 * Also a helper function for legacy skIPTreeCountIPs().
2603 */
2604 static uint64_t
ipsetCountIPTree(const skIPTree_t * iptree)2605 ipsetCountIPTree(
2606 const skIPTree_t *iptree)
2607 {
2608 unsigned int i, j;
2609 uint64_t count = 0;
2610 uint32_t bits;
2611
2612 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
2613 if (NULL != iptree->nodes[i]) {
2614 for (j = 0; j < SKIP_BBLOCK_SIZE; ++j) {
2615 if (iptree->nodes[i]->addressBlock[j]) {
2616 BITS_IN_WORD32(&bits, iptree->nodes[i]->addressBlock[j]);
2617 count += bits;
2618 }
2619 }
2620 }
2621 }
2622
2623 return count;
2624 }
2625
2626
2627 /*
2628 * occupied = ipsetCountOccupiedLeaves(ipset);
2629 *
2630 * Return the number of occupied leaves in 'ipset'.
2631 */
2632 static uint32_t
ipsetCountOccupiedLeaves(const skipset_t * ipset)2633 ipsetCountOccupiedLeaves(
2634 const skipset_t *ipset)
2635 {
2636 const ipset_leaf_t *leaf;
2637 uint32_t leaves_in_use;
2638 uint32_t leaves_free_idx;
2639
2640 /* handle a leaf at the root as a special case */
2641 if (IPSET_ROOT_IS_LEAF(ipset)) {
2642 return 1;
2643 }
2644
2645 /* determine the number of leaves currently in use by subtracting
2646 * the leaves on the free list from the total number of leaves */
2647 leaves_in_use = ipset->s.v3->leaves.entry_count;
2648 for (leaves_free_idx = ipset->s.v3->leaves.free_list;
2649 0 != leaves_free_idx;
2650 leaves_free_idx = LEAFPTR_FREE_LIST(leaf))
2651 {
2652 assert(leaves_free_idx < ipset->s.v3->leaves.entry_count);
2653 --leaves_in_use;
2654 leaf = LEAF_PTR(ipset, leaves_free_idx);
2655 }
2656
2657 if (ipset->s.v3->leaves.entry_count < leaves_in_use) {
2658 skAbort();
2659 }
2660
2661 return leaves_in_use;
2662 }
2663
2664
2665 /*
2666 * status = ipsetCountStreamCallbackV4(ipaddr, prefix, count_state);
2667 * status = ipsetCountStreamCallbackV6(ipaddr, prefix, count_state);
2668 *
2669 * Helper functions for skIPSetProcessStreamCountIPs().
2670 *
2671 * Compute (1 << 'prefix') to get the number of IPs in this block
2672 * and update the count in 'count_state'.
2673 */
2674 static int
ipsetCountStreamCallbackV4(skipaddr_t UNUSED (* ipaddr),uint32_t prefix,void * v_count_state)2675 ipsetCountStreamCallbackV4(
2676 skipaddr_t UNUSED(*ipaddr),
2677 uint32_t prefix,
2678 void *v_count_state)
2679 {
2680 return ipsetCountCallbackV4(0, prefix, v_count_state);
2681 }
2682
2683 #if SK_ENABLE_IPV6
2684 static int
ipsetCountStreamCallbackV6(skipaddr_t UNUSED (* ipaddr),uint32_t prefix,void * v_count_state)2685 ipsetCountStreamCallbackV6(
2686 skipaddr_t UNUSED(*ipaddr),
2687 uint32_t prefix,
2688 void *v_count_state)
2689 {
2690 return ipsetCountCallbackV6(NULL, prefix, v_count_state);
2691 }
2692 #endif /* SK_ENABLE_IPV6 */
2693
2694
2695 /*
2696 * Convert the value in 'count_state' to a decimal number.
2697 *
2698 * Helper function for skIPSetCountIPsString() and
2699 * skIPSetProcessStreamCountIPs().
2700 */
2701 static char *
ipsetCountToString(const ipset_count_t * count_state,char * buf,size_t buflen)2702 ipsetCountToString(
2703 const ipset_count_t *count_state,
2704 char *buf,
2705 size_t buflen)
2706 {
2707 const uint64_t lim = UINT64_C(10000000000);
2708 const uint64_t map_ipv6_to_dec[][4] = {
2709 { UINT64_C(1), 0, 0, 0}, /* 1 << 0 */
2710 { UINT64_C(4294967296), 0, 0, 0}, /* 1 << 32 */
2711 { UINT64_C(3709551616), UINT64_C(1844674407), 0, 0}, /* 1 << 64 */
2712 { UINT64_C(3543950336), UINT64_C(1426433759), UINT64_C(792281625),
2713 0}, /* 1 << 96 */
2714 };
2715 /* the decimal value being calculated */
2716 uint64_t decimal[5] = {0, 0, 0, 0, 0};
2717 uint64_t tmp;
2718 uint64_t tmp2 = 0;
2719 ssize_t sz;
2720 int i, j;
2721
2722 if (count_state->full) {
2723 sz = snprintf(buf, buflen, "340282366920938463463374607431768211456");
2724 goto END;
2725 }
2726 if (0 == count_state->upper) {
2727 sz = snprintf(buf, buflen, ("%" PRIu64), count_state->lower);
2728 goto END;
2729 }
2730 for (i = 0; i < 4; ++i) {
2731 switch (i) {
2732 case 0: tmp2 = (count_state->lower & UINT32_MAX); break;
2733 case 1: tmp2 = ((count_state->lower >> 32) & UINT32_MAX); break;
2734 case 2: tmp2 = (count_state->upper & UINT32_MAX); break;
2735 case 3: tmp2 = ((count_state->upper >> 32) & UINT32_MAX); break;
2736 }
2737 if (tmp2) {
2738 for (j = 0; j < 4 && map_ipv6_to_dec[i][j] > 0; ++j) {
2739 tmp = tmp2 * map_ipv6_to_dec[i][j];
2740 if (tmp < lim) {
2741 decimal[j] += tmp;
2742 } else {
2743 /* handle overflow */
2744 decimal[j] += tmp % lim;
2745 decimal[j+1] += tmp / lim;
2746 }
2747 }
2748 }
2749 }
2750 /* Final check for overflow and determine number of 'decimal'
2751 * elements that have a value */
2752 i = 0;
2753 for (j = 0; j < 4; ++j) {
2754 if (decimal[j] >= lim) {
2755 i = j;
2756 tmp = decimal[j];
2757 decimal[j] %= lim;
2758 decimal[j+1] += tmp / lim;
2759 } else if (decimal[j] > 0) {
2760 i = j;
2761 }
2762 }
2763 switch (i) {
2764 case 0:
2765 sz = snprintf(buf, buflen, "%" PRIu64, decimal[0]);
2766 break;
2767 case 1:
2768 sz = snprintf(buf, buflen, "%" PRIu64 "%010" PRIu64,
2769 decimal[1], decimal[0]);
2770 break;
2771 case 2:
2772 sz = snprintf(buf, buflen, "%" PRIu64 "%010" PRIu64 "%010" PRIu64,
2773 decimal[2], decimal[1], decimal[0]);
2774 break;
2775 case 3:
2776 sz = snprintf(buf, buflen,
2777 "%" PRIu64 "%010" PRIu64 "%010" PRIu64 "%010" PRIu64,
2778 decimal[3], decimal[2], decimal[1], decimal[0]);
2779 break;
2780 case 4:
2781 sz = snprintf(buf, buflen,
2782 ("%" PRIu64 "%010" PRIu64 "%010" PRIu64
2783 "%010" PRIu64 "%010" PRIu64),
2784 decimal[4], decimal[3], decimal[2],
2785 decimal[1], decimal[0]);
2786 break;
2787 default:
2788 skAbortBadCase(i);
2789 }
2790
2791 END:
2792 if ((size_t)sz >= buflen) {
2793 return NULL;
2794 }
2795 return buf;
2796 }
2797
2798
2799 /*
2800 * Return the number of trailing zeros in the bit representation of
2801 * 'v'. NB return 31 when 'v' is 0.
2802 *
2803 * From
2804 * http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightBinSearch
2805 */
2806 static uint32_t
ipsetCountTrailingZeros(uint32_t v)2807 ipsetCountTrailingZeros(
2808 uint32_t v)
2809 {
2810 uint32_t c;
2811
2812 if (v & 0x1) {
2813 /* shortcut for odd 'v' */
2814 c = 0;
2815 } else {
2816 /* set c to one then subtract at the end */
2817 c = 1;
2818 if ((v & 0xFFFF) == 0) {
2819 v >>= 16;
2820 c += 16;
2821 }
2822 if ((v & 0xFF) == 0) {
2823 v >>= 8;
2824 c += 8;
2825 }
2826 if ((v & 0xF) == 0) {
2827 v >>= 4;
2828 c += 4;
2829 }
2830 if ((v & 0x3) == 0) {
2831 v >>= 2;
2832 c += 2;
2833 }
2834 c -= (v & 0x1);
2835 }
2836 return c;
2837 }
2838
2839
2840 /*
2841 * status = ipsetCreate(ipset, support_ipv6, force_radix);
2842 *
2843 * Helper function for skIPSetCreate() and used internally.
2844 *
2845 * Allocates and initializes a new IPset at the space specified by
2846 * '*ipset'. The set is initially empty. When 'support_ipv6' is
2847 * non-zero, the IPset will be initialized to store IPv6 addresses;
2848 * otherwise it will be initialized to hold IPv4 addresses. When
2849 * creating an IPv4 IPset, the IPTree format from SiLK-2 will be
2850 * used unless the 'force_radix' parameter has a non-zero value.
2851 */
2852 static int
ipsetCreate(skipset_t ** ipset_out,int support_ipv6,int force_radix)2853 ipsetCreate(
2854 skipset_t **ipset_out,
2855 int support_ipv6,
2856 int force_radix)
2857 {
2858 skipset_t *set;
2859
2860 assert(ipset_out);
2861
2862 set = (skipset_t*)calloc(1, sizeof(skipset_t));
2863 if (!set) {
2864 return SKIPSET_ERR_ALLOC;
2865 }
2866
2867 if (support_ipv6) {
2868 set->s.v3 = (skipset_v3_t*)calloc(1, sizeof(skipset_v3_t));
2869 if (!set->s.v3) {
2870 free(set);
2871 return SKIPSET_ERR_ALLOC;
2872 }
2873 set->s.v3->nodes.entry_size = sizeof(ipset_node_v6_t);
2874 set->s.v3->leaves.entry_size = sizeof(ipset_leaf_v6_t);
2875 set->is_ipv6 = 1;
2876 set->is_iptree = 0;
2877 } else if (force_radix) {
2878 set->s.v3 = (skipset_v3_t*)calloc(1, sizeof(skipset_v3_t));
2879 if (!set->s.v3) {
2880 free(set);
2881 return SKIPSET_ERR_ALLOC;
2882 }
2883 set->s.v3->nodes.entry_size = sizeof(ipset_node_v4_t);
2884 set->s.v3->leaves.entry_size = sizeof(ipset_leaf_v4_t);
2885 set->is_ipv6 = 0;
2886 set->is_iptree = 0;
2887 } else {
2888 set->s.v2 = (skIPTree_t*)calloc(1, sizeof(skIPTree_t));
2889 if (!set->s.v2) {
2890 free(set);
2891 return SKIPSET_ERR_ALLOC;
2892 }
2893 set->is_ipv6 = 0;
2894 set->is_iptree = 1;
2895 }
2896
2897 *ipset_out = set;
2898 return SKIPSET_OK;
2899 }
2900
2901
2902 /*
2903 * status = ipsetDestroyIPTree(iptree);
2904 *
2905 * Helper function for skIPSetDestroy().
2906 *
2907 * Also a helper function for legacy skIPTreeDelete().
2908 *
2909 * Destroy the skIPTree_t 'iptree'.
2910 */
2911 static void
ipsetDestroyIPTree(skIPTree_t * iptree)2912 ipsetDestroyIPTree(
2913 skIPTree_t *iptree)
2914 {
2915 unsigned int i;
2916
2917 if (iptree) {
2918 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
2919 if (iptree->nodes[i]) {
2920 free(iptree->nodes[i]);
2921 }
2922 }
2923 free(iptree);
2924 }
2925 }
2926
2927
2928 /*
2929 * ipsetDestroySubtree(ipset, node_idx, destroy_self);
2930 *
2931 * Puts all the child nodes of 'node_idx' onto the free list. If
2932 * 'destroy_self' is non-zero, the 'node_idx' node is also added to
2933 * the free list. If 'destroy_self' is zero, the child indexes on
2934 * 'node_idx' are set to 0.
2935 */
2936 static void
ipsetDestroySubtree(skipset_t * ipset,uint32_t node_idx,int destroy_self)2937 ipsetDestroySubtree(
2938 skipset_t *ipset,
2939 uint32_t node_idx,
2940 int destroy_self)
2941 {
2942 uint32_t to_visit[IPSET_MAX_DEPTH];
2943 uint32_t depth = 0;
2944 ipset_node_t *node;
2945 int i;
2946
2947 if (destroy_self) {
2948 /* add this node to the list of nodes to destroy */
2949 to_visit[depth++] = node_idx;
2950 } else {
2951 /* destroy any leaves off of this node; add this node's child
2952 * nodes to the list of nodes to destroy */
2953 node = NODE_PTR(ipset, node_idx);
2954 for (i = 0; i < IPSET_NUM_CHILDREN; ++i) {
2955 if (node->v4.child[i]
2956 && !NODEPTR_CHILD_IS_REPEAT(&node->v4, i))
2957 {
2958 if (NODEPTR_CHILD_IS_LEAF(&node->v4, i)) {
2959 LEAFIDX_FREE(ipset, node->v4.child[i]);
2960 } else {
2961 to_visit[depth++] = node->v4.child[i];
2962 }
2963 }
2964 }
2965 /* clear the child array and bitmaps */
2966 memset(node->v4.child, 0, sizeof(node->v4.child));
2967 SET_BMAP_CLEAR_ALL(node->v4.child_is_leaf);
2968 SET_BMAP_CLEAR_ALL(node->v4.child_repeated);
2969 }
2970
2971 while (depth) {
2972 node_idx = to_visit[--depth];
2973 node = NODE_PTR(ipset, node_idx);
2974 for (i = 0; i < IPSET_NUM_CHILDREN; ++i) {
2975 if (node->v4.child[i]
2976 && !NODEPTR_CHILD_IS_REPEAT(&node->v4, i))
2977 {
2978 if (NODEPTR_CHILD_IS_LEAF(&node->v4, i)) {
2979 LEAFIDX_FREE(ipset, node->v4.child[i]);
2980 } else {
2981 to_visit[depth++] = node->v4.child[i];
2982 }
2983 }
2984 }
2985 NODEIDX_FREE(ipset, node_idx);
2986 }
2987 }
2988
2989
2990 /*
2991 * status = ipsetFindV4(ipset, ip, prefix, &find_state);
2992 * status = ipsetFindV6(ipset, ip, prefix, &find_state);
2993 *
2994 * Searches for 'ip'/'prefix' in the Radix-tree based 'ipset'.
2995 * 'ip' is an integer presentation of the IP address in native byte
2996 * order.
2997 *
2998 * Returns SKIPSET_OK if it is found exactly or if a CIDR block
2999 * containing it is found: searching for 10.0.0.2 and find
3000 * 10.0.0.0/24.
3001 *
3002 * Returns SKIPSET_ERR_SUBSET when a subset of target is found:
3003 * search for 10.0.0.0/24 and find 10.0.0.2.
3004 *
3005 * Returns SKIPSET_ERR_EMPTY if the IPset is empty.
3006 *
3007 * Returns SKIPSET_ERR_MULTILEAF if it is not found but the search
3008 * failed at a position where a leaf can be inserted.
3009 *
3010 * Returns SKIPSET_ERR_NOTFOUND if it is not found and the
3011 * SKIPSET_ERR_MULTILEAF case does not apply.
3012 *
3013 * When 'find_state' is non-NULL, its fields will be set to the
3014 * final location visited in the tree. Specifically, 'node_idx' is
3015 * set to the index of the node where the search terminated;
3016 * 'bitpos' is set to the number of bits of the IP address that
3017 * were searched; 'parent_idx' is set to the index of the parent of
3018 * the node in 'node_idx'. If 'node_idx' is the root of the tree,
3019 * 'parent_idx' will be UINT32_MAX; 'result' will be the same as
3020 * the return status of the function.
3021 */
3022 static int
ipsetFindV4(const skipset_t * ipset,const uint32_t ipv4,const uint32_t prefix,ipset_find_t * find_state)3023 ipsetFindV4(
3024 const skipset_t *ipset,
3025 const uint32_t ipv4,
3026 const uint32_t prefix,
3027 ipset_find_t *find_state)
3028 {
3029 const ipset_node_v4_t *node;
3030 const ipset_leaf_v4_t *leaf = NULL;
3031 uint32_t parent_idx;
3032 uint32_t node_idx;
3033 uint32_t which_child;
3034 uint32_t j;
3035 uint8_t bitpos;
3036 int rv;
3037
3038 /*
3039 * The 'bitpos' value specifies the number of bits that match
3040 * between the IP on the current node/leaf and the search IP
3041 * (starting from the most significant bit).
3042 *
3043 * On a node at any level in the tree, if bitpos is less than the
3044 * prefix on that node, we cannot descend to the next level in
3045 * the tree. Otherwise, before descending, we check to see
3046 * whether the node's prefix is greater than the search prefix;
3047 * if it is, there is no need to continue and the function
3048 * returns SUBSET.
3049 *
3050 * Whether the descent into the tree stops due to reaching a leaf
3051 * or due to not matching enough bits on a node, the return
3052 * status depends on three values: (1)the number of bits that
3053 * were matched, (2)the prefix on the node/leaf, and (3)the
3054 * search prefix. If bitpos is less than the search prefix, the
3055 * search failed and NOTFOUND is returned. If both bitpos and
3056 * the search prefix are at least equal to the prefix on the
3057 * node/leaf, the search returns OK. For any other combination,
3058 * the search returns SUBSET.
3059 *
3060 * If the search is on the node and wants to descend into the
3061 * tree but there is no child at that position, the search either
3062 * returns SUBSET or MULTILEAF. The search returns SUBSET if the
3063 * search prefix covers multiple children on the node and at
3064 * least one of those children is occupied. Otherwise, the
3065 * search returns MULTILEAF, denoting that a leaf can be safely
3066 * added at this position.
3067 */
3068
3069 assert(ipset);
3070 assert(prefix > 0 || ipv4 == 0);
3071 assert(prefix <= 32);
3072 assert(0 == ipset->is_iptree);
3073 assert(0 == ipset->is_ipv6);
3074
3075 parent_idx = IPSET_NO_PARENT;
3076 node_idx = IPSET_ROOT_INDEX(ipset);
3077 which_child = IPSET_NUM_CHILDREN;
3078 bitpos = 0;
3079 rv = SKIPSET_ERR_SUBSET;
3080
3081 if (IPSET_ISEMPTY(ipset)) {
3082 rv = SKIPSET_ERR_EMPTY;
3083 goto END;
3084 }
3085
3086 if (IPSET_ROOT_IS_LEAF(ipset)) {
3087 leaf = LEAF_PTR_V4(ipset, node_idx);
3088 /* find number of bits this leaf's IP and the search IP have
3089 * in common */
3090 COUNT_MATCHING_BITS32(&bitpos, (ipv4 ^ (leaf->ip)));
3091 if (bitpos < leaf->prefix) {
3092 if (bitpos < prefix) {
3093 /* not found */
3094 rv = SKIPSET_ERR_NOTFOUND;
3095 } else {
3096 bitpos = prefix;
3097 /* rv = SKIPSET_ERR_SUBSET; */
3098 }
3099 } else {
3100 /* make certain bitpos is not greater than this leaf's
3101 * prefix */
3102 bitpos = leaf->prefix;
3103 if (prefix >= leaf->prefix) {
3104 rv = SKIPSET_OK;
3105 }
3106 /* else rv = SKIPSET_ERR_SUBSET; */
3107 }
3108 goto END;
3109 }
3110
3111 do {
3112 assert(node_idx < ipset->s.v3->nodes.entry_count);
3113 node = NODE_PTR_V4(ipset, node_idx);
3114 if (bitpos < node->prefix) {
3115 COUNT_MATCHING_BITS32(&bitpos, (ipv4 ^ (node->ip)));
3116 if (bitpos < node->prefix) {
3117 /* cannot descend any farther into tree */
3118 if (bitpos < prefix) {
3119 /* not found */
3120 rv = SKIPSET_ERR_NOTFOUND;
3121 goto END;
3122 }
3123 bitpos = prefix;
3124 /* rv = SKIPSET_ERR_SUBSET; */
3125 goto END;
3126 }
3127 /* else bitpos >= node->prefix */
3128 if (prefix <= node->prefix) {
3129 bitpos = prefix;
3130 /* rv = SKIPSET_ERR_SUBSET; */
3131 goto END;
3132 }
3133 /* else descend to next level */
3134 }
3135
3136 /* go to the appropriate child */
3137 parent_idx = node_idx;
3138 which_child = WHICH_CHILD_V4(ipv4, node->prefix);
3139 node_idx = node->child[which_child];
3140 if (0 == node_idx) {
3141 if (NUM_BITS > prefix - node->prefix) {
3142 /* the 'prefix' covers multiple child[] entries; see
3143 * if any others are occupied */
3144 for (j = 1;
3145 ((j < (1u << (NUM_BITS - (prefix - node->prefix))))
3146 && ((which_child + j) < IPSET_NUM_CHILDREN));
3147 ++j)
3148 {
3149 if (node->child[which_child + j]) {
3150 /* rv = SKIPSET_ERR_SUBSET; */
3151 goto END;
3152 }
3153 }
3154 }
3155 node_idx = which_child;
3156 rv = SKIPSET_ERR_MULTILEAF;
3157 goto END;
3158 }
3159 if (BITMAP_GETBIT(node->child_is_leaf, which_child)) {
3160 leaf = LEAF_PTR_V4(ipset, node_idx);
3161 COUNT_MATCHING_BITS32(&bitpos, (ipv4 ^ (leaf->ip)));
3162 if (bitpos < leaf->prefix) {
3163 if (bitpos < prefix) {
3164 /* not found */
3165 rv = SKIPSET_ERR_NOTFOUND;
3166 } else {
3167 bitpos = prefix;
3168 /* rv = SKIPSET_ERR_SUBSET; */
3169 }
3170 } else {
3171 bitpos = leaf->prefix;
3172 if (prefix >= leaf->prefix) {
3173 rv = SKIPSET_OK;
3174 }
3175 /* else rv = SKIPSET_ERR_SUBSET; */
3176 }
3177 goto END;
3178 }
3179
3180 bitpos = node->prefix + NUM_BITS;
3181
3182 } while (bitpos < prefix);
3183
3184 END:
3185 if (find_state) {
3186 find_state->parent_idx = parent_idx;
3187 find_state->node_idx = node_idx;
3188 find_state->parents_child = which_child;
3189 find_state->bitpos = bitpos;
3190 find_state->result = rv;
3191 find_state->node_is_leaf = (leaf != NULL);
3192 }
3193 return rv;
3194 }
3195
3196 #if SK_ENABLE_IPV6
3197 static int
ipsetFindV6(const skipset_t * ipset,const ipset_ipv6_t * ipv6,const uint32_t prefix,ipset_find_t * find_state)3198 ipsetFindV6(
3199 const skipset_t *ipset,
3200 const ipset_ipv6_t *ipv6,
3201 const uint32_t prefix,
3202 ipset_find_t *find_state)
3203 {
3204 const ipset_node_v6_t *node;
3205 const ipset_leaf_v6_t *leaf = NULL;
3206 uint32_t parent_idx;
3207 uint32_t node_idx;
3208 uint32_t which_child;
3209 uint8_t bitpos;
3210 uint32_t j;
3211 int ip_idx;
3212 int rv;
3213
3214 assert(ipset);
3215 assert(ipv6);
3216 assert(0 < prefix && prefix <= 128);
3217 assert(0 == ipset->is_iptree);
3218 assert(1 == ipset->is_ipv6);
3219
3220 parent_idx = IPSET_NO_PARENT;
3221 node_idx = IPSET_ROOT_INDEX(ipset);
3222 which_child = IPSET_NUM_CHILDREN;
3223 bitpos = 0;
3224 ip_idx = 0;
3225 rv = SKIPSET_ERR_SUBSET;
3226
3227 if (IPSET_ISEMPTY(ipset)) {
3228 rv = SKIPSET_ERR_EMPTY;
3229 goto END;
3230 }
3231
3232 if (IPSET_ROOT_IS_LEAF(ipset)) {
3233 leaf = LEAF_PTR_V6(ipset, node_idx);
3234 /* find number of bits this leaf's IP and the search IP have
3235 * in common */
3236 if (ipv6->ip[0] == leaf->ip.ip[0]) {
3237 COUNT_MATCHING_BITS64(&bitpos, (ipv6->ip[1] ^ leaf->ip.ip[1]));
3238 bitpos += 64;
3239 } else {
3240 COUNT_MATCHING_BITS64(&bitpos, (ipv6->ip[0] ^ leaf->ip.ip[0]));
3241 }
3242 if (bitpos < leaf->prefix) {
3243 if (bitpos < prefix) {
3244 /* not found */
3245 rv = SKIPSET_ERR_NOTFOUND;
3246 } else {
3247 bitpos = prefix;
3248 /* rv = SKIPSET_ERR_SUBSET; */
3249 }
3250 } else {
3251 /* make certain bitpos is not greater than this leaf's
3252 * prefix */
3253 bitpos = leaf->prefix;
3254 if (prefix >= leaf->prefix) {
3255 rv = SKIPSET_OK;
3256 }
3257 /* else rv = SKIPSET_ERR_SUBSET; */
3258 }
3259 goto END;
3260 }
3261
3262 do {
3263 assert(node_idx < ipset->s.v3->nodes.entry_count);
3264 node = NODE_PTR_V6(ipset, node_idx);
3265 if (bitpos < node->prefix) {
3266 COUNT_MATCHING_BITS64(&bitpos,
3267 (ipv6->ip[ip_idx] ^ node->ip.ip[ip_idx]));
3268 bitpos += (ip_idx * 64);
3269 if (bitpos < node->prefix) {
3270 if (64 == bitpos && 0 == ip_idx) {
3271 ++ip_idx;
3272 continue;
3273 }
3274 /* cannot descend any farther into tree */
3275 if (bitpos < prefix) {
3276 /* not found */
3277 rv = SKIPSET_ERR_NOTFOUND;
3278 goto END;
3279 }
3280 bitpos = prefix;
3281 /* rv = SKIPSET_ERR_SUBSET; */
3282 goto END;
3283 }
3284 /* else bitpos >= node->prefix */
3285 if (prefix <= node->prefix) {
3286 bitpos = prefix;
3287 /* rv = SKIPSET_ERR_SUBSET; */
3288 goto END;
3289 }
3290 }
3291
3292 /* go to the appropriate child */
3293 parent_idx = node_idx;
3294 which_child = WHICH_CHILD_V6(ipv6, node->prefix);
3295 node_idx = node->child[which_child];
3296 if (0 == node_idx) {
3297 if (NUM_BITS > prefix - node->prefix) {
3298 /* the 'prefix' covers multiple child[] entries; see
3299 * if any others are occupied */
3300 for (j = 1;
3301 ((j < (1u << (NUM_BITS - (prefix - node->prefix))))
3302 && ((which_child + j) < IPSET_NUM_CHILDREN));
3303 ++j)
3304 {
3305 if (node->child[which_child + j]) {
3306 /* rv = SKIPSET_ERR_SUBSET; */
3307 goto END;
3308 }
3309 }
3310 }
3311 node_idx = which_child;
3312 rv = SKIPSET_ERR_MULTILEAF;
3313 goto END;
3314 }
3315 if (BITMAP_GETBIT(node->child_is_leaf, which_child)) {
3316 leaf = LEAF_PTR_V6(ipset, node_idx);
3317 if ((1 == ip_idx) || (ipv6->ip[0] == leaf->ip.ip[0])) {
3318 COUNT_MATCHING_BITS64(&bitpos, (ipv6->ip[1] ^ leaf->ip.ip[1]));
3319 bitpos += 64;
3320 } else {
3321 COUNT_MATCHING_BITS64(&bitpos, (ipv6->ip[0] ^ leaf->ip.ip[0]));
3322 }
3323 if (bitpos < leaf->prefix) {
3324 if (bitpos < prefix) {
3325 /* not found */
3326 rv = SKIPSET_ERR_NOTFOUND;
3327 } else {
3328 bitpos = prefix;
3329 /* rv = SKIPSET_ERR_SUBSET; */
3330 }
3331 } else {
3332 bitpos = leaf->prefix;
3333 if (prefix >= leaf->prefix) {
3334 rv = SKIPSET_OK;
3335 }
3336 /* else rv = SKIPSET_ERR_SUBSET; */
3337 }
3338 goto END;
3339 }
3340
3341 bitpos = node->prefix + NUM_BITS;
3342
3343 } while (bitpos < prefix);
3344
3345 END:
3346 if (find_state) {
3347 find_state->parent_idx = parent_idx;
3348 find_state->node_idx = node_idx;
3349 find_state->parents_child = which_child;
3350 find_state->bitpos = bitpos;
3351 find_state->result = rv;
3352 find_state->node_is_leaf = (leaf != NULL);
3353 }
3354 return rv;
3355 }
3356 #endif /* SK_ENABLE_IPV6 */
3357
3358
3359 /*
3360 * remove_count = ipsetFixNodeSingleChild(ipset, node_idx, non_recursive);
3361 *
3362 * Determine if the node specified by 'node_idx' has multiple
3363 * children. If it does, do not modify 'ipset' and return 0.
3364 *
3365 * If the node specified by 'node_idx' as one child---which may be
3366 * a leaf or another node---modify the node's parent to replace the
3367 * node with node's child and return 1.
3368 *
3369 * If the node specified by 'node_idx' has no children, remove the
3370 * node from the node's parent. If 'non_recursive' is non-zero, do
3371 * no further processing and return 1. If 'non_recursive' is 0,
3372 * repeat the process using the parent of the node that was just
3373 * removed. For this final case, the return status will be a count
3374 * of the number of nodes removed.
3375 *
3376 * I do not believe anything uses the return value; this function
3377 * could be changed to "return" void.
3378 */
3379 static int
ipsetFixNodeSingleChild(skipset_t * ipset,uint32_t node_idx,int non_recursive)3380 ipsetFixNodeSingleChild(
3381 skipset_t *ipset,
3382 uint32_t node_idx,
3383 int non_recursive)
3384 {
3385 ipset_find_t find_state;
3386 ipset_node_t *parent;
3387 ipset_node_t *node;
3388 uint32_t which_child;
3389 uint32_t child_idx = 0;
3390 uint32_t i;
3391 int remove_count = 0;
3392
3393 assert(ipset);
3394 assert(0 == ipset->is_iptree);
3395 assert(node_idx > 0 && node_idx < ipset->s.v3->nodes.entry_count);
3396
3397 node = NODE_PTR(ipset, node_idx);
3398
3399 for (;;) {
3400 which_child = IPSET_NUM_CHILDREN;
3401 for (i = 0; i < IPSET_NUM_CHILDREN; ++i) {
3402 if ((node->v4.child[i])
3403 && !NODEPTR_CHILD_IS_REPEAT(&node->v4, i))
3404 {
3405 if (which_child != IPSET_NUM_CHILDREN) {
3406 /* more than one child; we are done. */
3407 return remove_count;
3408 }
3409 which_child = i;
3410 }
3411 }
3412
3413 if (which_child < IPSET_NUM_CHILDREN) {
3414 /* the node has a single child; modify the node's parent
3415 * to replace the node with the node's child */
3416 if (!NODEPTR_CHILD_IS_LEAF(&node->v4, which_child)) {
3417 /* the single child is another node; the easiest way
3418 * to handle this case is to copy the child over the
3419 * node, and leave the parent untouched */
3420 node_idx = node->v4.child[which_child];
3421 memcpy(node, NODE_PTR(ipset, node_idx),
3422 ipset->s.v3->nodes.entry_size);
3423 break;
3424 }
3425
3426 child_idx = node->v4.child[which_child];
3427 }
3428
3429 /* find the node in order to get a handle to the node's
3430 * parent */
3431 if (0 == node->v4.prefix) {
3432 /* cannot call ipsetFindVx() with a prefix of 0, but that
3433 * can only happen at the root */
3434 find_state.parent_idx = IPSET_NO_PARENT;
3435 #if SK_ENABLE_IPV6
3436 } else if (ipset->is_ipv6) {
3437 #ifndef NDEBUG
3438 int rv =
3439 #endif
3440 ipsetFindV6(ipset, &node->v6.ip, node->v6.prefix, &find_state);
3441 assert(SKIPSET_OK == rv || SKIPSET_ERR_SUBSET == rv);
3442 assert(find_state.node_idx == node_idx && !find_state.node_is_leaf);
3443 #endif /* SK_ENABLE_IPV6 */
3444 } else {
3445 #ifndef NDEBUG
3446 int rv =
3447 #endif
3448 ipsetFindV4(ipset, node->v4.ip, node->v4.prefix, &find_state);
3449 assert(SKIPSET_OK == rv || SKIPSET_ERR_SUBSET == rv);
3450 assert(find_state.node_idx == node_idx && !find_state.node_is_leaf);
3451 }
3452
3453 if (which_child < IPSET_NUM_CHILDREN) {
3454 /* wire the nodes's parent to the child (which is a leaf),
3455 * then free the node */
3456 if (IPSET_NO_PARENT == find_state.parent_idx) {
3457 /* this node was the root */
3458 IPSET_ROOT_INDEX_SET(ipset, child_idx, 1);
3459 } else {
3460 parent = NODE_PTR(ipset, find_state.parent_idx);
3461 parent->v4.child[find_state.parents_child] = child_idx;
3462 SET_BMAP_SET(parent->v4.child_is_leaf,
3463 find_state.parents_child);
3464 }
3465 break;
3466 }
3467 /* delete the node from the parent */
3468 if (IPSET_NO_PARENT == find_state.parent_idx) {
3469 /* this node was the root */
3470 skIPSetRemoveAll(ipset);
3471 ++remove_count;
3472 return remove_count;
3473 }
3474
3475 parent = NODE_PTR(ipset, find_state.parent_idx);
3476 parent->v4.child[find_state.parents_child] = 0;
3477 if (non_recursive) {
3478 break;
3479 }
3480
3481 /* we have deleted the node from the parent. see if the
3482 * parent now has a single child */
3483 NODEIDX_FREE(ipset, node_idx);
3484 ++remove_count;
3485 node_idx = find_state.parent_idx;
3486 node = parent;
3487 }
3488
3489 NODEIDX_FREE(ipset, node_idx);
3490 ++remove_count;
3491 return remove_count;
3492 }
3493
3494
3495 /*
3496 * Call ipsetHentryCreate() (which see) to a new SiLK stream header
3497 * entry for an IPset and add that header entry to the file's
3498 * headers in 'hdr'. Return an SKHEADER error code on failure.
3499 */
3500 static int
ipsetHentryAddToFile(sk_file_header_t * hdr,uint32_t child_node,uint32_t leaf_count,uint32_t leaf_size,uint32_t node_count,uint32_t node_size,uint32_t root_idx)3501 ipsetHentryAddToFile(
3502 sk_file_header_t *hdr,
3503 uint32_t child_node,
3504 uint32_t leaf_count,
3505 uint32_t leaf_size,
3506 uint32_t node_count,
3507 uint32_t node_size,
3508 uint32_t root_idx)
3509 {
3510 int rv;
3511 sk_header_entry_t *ipset_hdr = NULL;
3512
3513 ipset_hdr = ipsetHentryCreate(child_node, leaf_count, leaf_size,
3514 node_count, node_size, root_idx);
3515 if (NULL == ipset_hdr) {
3516 return SKHEADER_ERR_ALLOC;
3517 }
3518
3519 rv = skHeaderAddEntry(hdr, ipset_hdr);
3520 if (rv) {
3521 ipsetHentryFree(ipset_hdr);
3522 }
3523 return rv;
3524 }
3525
3526
3527 /*
3528 * hentry = ipsetHentryCopy(hentry);
3529 *
3530 * Create and return a new header entry for IPset files that is a
3531 * copy of the header entry 'hentry'.
3532 *
3533 * This is the 'copy_fn' callback for skHentryTypeRegister().
3534 */
3535 static sk_header_entry_t *
ipsetHentryCopy(const sk_header_entry_t * hentry)3536 ipsetHentryCopy(
3537 const sk_header_entry_t *hentry)
3538 {
3539 const sk_hentry_ipset_t *ipset_hdr = (sk_hentry_ipset_t*)hentry;
3540
3541 return ipsetHentryCreate(ipset_hdr->child_node, ipset_hdr->leaf_count,
3542 ipset_hdr->leaf_size, ipset_hdr->node_count,
3543 ipset_hdr->node_size, ipset_hdr->root_idx);
3544 }
3545
3546
3547 /*
3548 * Create and return a new header entry for IPset files.
3549 * 'child_node' is the number of children per node, 'leaf_count' is
3550 * the number of leaves, 'leaf_size' is the size of an individual
3551 * leaf, 'node_count' is the number of (internal) nodes,
3552 * 'node_size' is the size of an individual node, and
3553 * 'root_index'is the index of the root of the tree.
3554 */
3555 static sk_header_entry_t *
ipsetHentryCreate(uint32_t child_node,uint32_t leaf_count,uint32_t leaf_size,uint32_t node_count,uint32_t node_size,uint32_t root_idx)3556 ipsetHentryCreate(
3557 uint32_t child_node,
3558 uint32_t leaf_count,
3559 uint32_t leaf_size,
3560 uint32_t node_count,
3561 uint32_t node_size,
3562 uint32_t root_idx)
3563 {
3564 sk_hentry_ipset_t *ipset_hdr;
3565
3566 ipset_hdr = (sk_hentry_ipset_t*)calloc(1, sizeof(sk_hentry_ipset_t));
3567 if (NULL == ipset_hdr) {
3568 return NULL;
3569 }
3570 ipset_hdr->he_spec.hes_id = SK_HENTRY_IPSET_ID;
3571 ipset_hdr->he_spec.hes_len = sizeof(sk_hentry_ipset_t);
3572 ipset_hdr->child_node = child_node;
3573 ipset_hdr->leaf_count = leaf_count;
3574 ipset_hdr->leaf_size = leaf_size;
3575 ipset_hdr->node_count = node_count;
3576 ipset_hdr->node_size = node_size;
3577 ipset_hdr->root_idx = root_idx;
3578
3579 return (sk_header_entry_t*)ipset_hdr;
3580 }
3581
3582
3583 /*
3584 * ipsetHentryFree(hentry);
3585 *
3586 * Release any memory that is used by the in-memory representation
3587 * of the file header for IPset files.
3588 *
3589 * This is the 'free_fn' callback for skHentryTypeRegister().
3590 */
3591 static void
ipsetHentryFree(sk_header_entry_t * hentry)3592 ipsetHentryFree(
3593 sk_header_entry_t *hentry)
3594 {
3595 if (hentry) {
3596 assert(skHeaderEntryGetTypeId(hentry) == SK_HENTRY_IPSET_ID);
3597 hentry->he_spec.hes_id = UINT32_MAX;
3598 free(hentry);
3599 }
3600 }
3601
3602
3603 #define ipsetHentryGetChildPerNode(hentry) \
3604 (((sk_hentry_ipset_t*)(hentry))->child_node)
3605
3606 #define ipsetHentryGetLeafCount(hentry) \
3607 (((sk_hentry_ipset_t*)(hentry))->leaf_count)
3608
3609 #define ipsetHentryGetLeafSize(hentry) \
3610 (((sk_hentry_ipset_t*)(hentry))->leaf_size)
3611
3612 #define ipsetHentryGetNodeCount(hentry) \
3613 (((sk_hentry_ipset_t*)(hentry))->node_count)
3614
3615 #define ipsetHentryGetNodeSize(hentry) \
3616 (((sk_hentry_ipset_t*)(hentry))->node_size)
3617
3618 #define ipsetHentryGetRootIndex(hentry) \
3619 (((sk_hentry_ipset_t*)(hentry))->root_idx)
3620
3621
3622 /*
3623 * size = ipsetHentryPacker(hentry, buf, bufsiz);
3624 *
3625 * Pack the contents of the header entry for IPset files, 'hentry'
3626 * into the buffer 'buf', whose size is 'bufsiz', for writing the
3627 * file to disk.
3628 *
3629 * This the 'pack_fn' callback for skHentryTypeRegister().
3630 */
3631 static ssize_t
ipsetHentryPacker(const sk_header_entry_t * in_hentry,uint8_t * out_packed,size_t bufsize)3632 ipsetHentryPacker(
3633 const sk_header_entry_t *in_hentry,
3634 uint8_t *out_packed,
3635 size_t bufsize)
3636 {
3637 sk_hentry_ipset_t *ipset_hdr = (sk_hentry_ipset_t*)in_hentry;
3638 sk_hentry_ipset_t tmp_hdr;
3639
3640 assert(in_hentry);
3641 assert(out_packed);
3642 assert(skHeaderEntryGetTypeId(ipset_hdr) == SK_HENTRY_IPSET_ID);
3643
3644 if (bufsize >= sizeof(sk_hentry_ipset_t)) {
3645 skHeaderEntrySpecPack(&(ipset_hdr->he_spec), (uint8_t *)&tmp_hdr,
3646 sizeof(tmp_hdr));
3647 tmp_hdr.child_node = htonl(ipset_hdr->child_node);
3648 tmp_hdr.leaf_count = htonl(ipset_hdr->leaf_count);
3649 tmp_hdr.leaf_size = htonl(ipset_hdr->leaf_size);
3650 tmp_hdr.node_count = htonl(ipset_hdr->node_count);
3651 tmp_hdr.node_size = htonl(ipset_hdr->node_size);
3652 tmp_hdr.root_idx = htonl(ipset_hdr->root_idx);
3653
3654 memcpy(out_packed, &tmp_hdr, sizeof(sk_hentry_ipset_t));
3655 }
3656
3657 return sizeof(sk_hentry_ipset_t);
3658 }
3659
3660
3661 /*
3662 * ipsetHentryPrint(hentry, fh);
3663 *
3664 * Print a textual representation of a file's IPset header entry in
3665 * 'hentry' to the FILE pointer 'fh'.
3666 *
3667 * This is the 'print_fn' callback for skHentryTypeRegister().
3668 */
3669 static void
ipsetHentryPrint(const sk_header_entry_t * hentry,FILE * fh)3670 ipsetHentryPrint(
3671 const sk_header_entry_t *hentry,
3672 FILE *fh)
3673 {
3674 sk_hentry_ipset_t *ipset_hdr = (sk_hentry_ipset_t*)hentry;
3675
3676 assert(skHeaderEntryGetTypeId(ipset_hdr) == SK_HENTRY_IPSET_ID);
3677 if ((0 == ipset_hdr->child_node) && (0 == ipset_hdr->root_idx)) {
3678 /* assume this is a RecordVersion 4 file */
3679 fprintf(fh, "IPv%d",
3680 ((sizeof(uint32_t) == ipset_hdr->leaf_size) ? 4 : 6));
3681 } else {
3682 fprintf(fh, ("%" PRIu32 "-way branch, root@%" PRIu32 ", "
3683 "%" PRIu32 " x %" PRIu32 "b node%s, "
3684 "%" PRIu32 " x %" PRIu32 "b leaves"),
3685 ipset_hdr->child_node, ipset_hdr->root_idx,
3686 ipset_hdr->node_count, ipset_hdr->node_size,
3687 ((ipset_hdr->node_count > 1) ? "s" : ""),
3688 ipset_hdr->leaf_count, ipset_hdr->leaf_size);
3689 }
3690 }
3691
3692
3693 /*
3694 * hentry = ipsetHentryUnpacker(buf);
3695 *
3696 * Unpack the data in 'buf' to create an in-memory representation
3697 * of a file's IPset header entry.
3698 *
3699 * This is the 'unpack_fn' callback for skHentryTypeRegister().
3700 */
3701 static sk_header_entry_t *
ipsetHentryUnpacker(uint8_t * in_packed)3702 ipsetHentryUnpacker(
3703 uint8_t *in_packed)
3704 {
3705 sk_hentry_ipset_t *ipset_hdr;
3706
3707 assert(in_packed);
3708
3709 /* create space for new header */
3710 ipset_hdr = (sk_hentry_ipset_t*)calloc(1, sizeof(sk_hentry_ipset_t));
3711 if (NULL == ipset_hdr) {
3712 return NULL;
3713 }
3714
3715 /* copy the spec */
3716 skHeaderEntrySpecUnpack(&(ipset_hdr->he_spec), in_packed);
3717 assert(skHeaderEntryGetTypeId(ipset_hdr) == SK_HENTRY_IPSET_ID);
3718
3719 /* copy the data */
3720 if (ipset_hdr->he_spec.hes_len != sizeof(sk_hentry_ipset_t)) {
3721 free(ipset_hdr);
3722 return NULL;
3723 }
3724 memcpy(&(ipset_hdr->child_node),
3725 &(in_packed[sizeof(sk_header_entry_spec_t)]),
3726 sizeof(sk_hentry_ipset_t) - sizeof(sk_header_entry_spec_t));
3727 ipset_hdr->child_node = htonl(ipset_hdr->child_node);
3728 ipset_hdr->leaf_count = htonl(ipset_hdr->leaf_count);
3729 ipset_hdr->leaf_size = htonl(ipset_hdr->leaf_size);
3730 ipset_hdr->node_count = htonl(ipset_hdr->node_count);
3731 ipset_hdr->node_size = htonl(ipset_hdr->node_size);
3732 ipset_hdr->root_idx = htonl(ipset_hdr->root_idx);
3733
3734 return (sk_header_entry_t*)ipset_hdr;
3735 }
3736
3737
3738 /*
3739 * status = ipsetInsertAddressIPTree(ipset, ip, prefix);
3740 *
3741 * Helper function for skIPSetInsertAddress(); may also be called
3742 * by other internal functions.
3743 *
3744 * Also a helper function for legacy skIPTreeAddAddress().
3745 *
3746 * Insert the CIDR block 'ip'/'prefix' into 'ipset'.
3747 */
3748 static int
ipsetInsertAddressIPTree(skIPTree_t * iptree,uint32_t ipv4,uint32_t prefix)3749 ipsetInsertAddressIPTree(
3750 skIPTree_t *iptree,
3751 uint32_t ipv4,
3752 uint32_t prefix)
3753 {
3754 /*
3755 * The skIPNode_t contains an array of uint32_t's, where each
3756 * uint32_t is treated as a bitmap for a /27.
3757 *
3758 * This array contains the bits that correspond a CIDR prefix
3759 * for one of these uint32_t values. Prefix must be between 27
3760 * and 32 inclusive. The key to this array is (prefix - 27).
3761 */
3762 const uint32_t prefix_as_bits[] = {
3763 0xFFFFFFFF, 0xFFFF, 0xFF, 0xF, 0x3, 0x1
3764 };
3765 uint32_t ipv4_end;
3766
3767 assert(iptree);
3768 assert(prefix > 0 || ipv4 == 0);
3769 assert(prefix <= 32);
3770
3771 if (prefix <= 16) {
3772 ipv4_end = ((UINT32_MAX >> prefix) | ipv4) >> 16;
3773 ipv4 >>= 16;
3774 do {
3775 IPTREE_NODE_ALLOC(iptree, ipv4);
3776 memset(iptree->nodes[ipv4], 0xFF, sizeof(skIPNode_t));
3777 } while (ipv4++ < ipv4_end);
3778
3779 } else {
3780 IPTREE_NODE_ALLOC(iptree, ipv4 >> 16);
3781
3782 if (prefix >= 27) {
3783 iptree->nodes[ipv4 >> 16]->addressBlock[(ipv4 & 0xFFFF) >> 5]
3784 |= (prefix_as_bits[prefix - 27] << ((ipv4) & 0x1F));
3785
3786 } else {
3787 /* 16 < prefix < 27 */
3788 memset(&iptree->nodes[ipv4>>16]->addressBlock[(ipv4 & 0xFFFF)>>5],
3789 0xFF, (sizeof(skIPNode_t) >> (prefix - 16)));
3790 }
3791 }
3792
3793 return SKIPSET_OK;
3794 }
3795
3796
3797 /*
3798 * status = ipsetInsertAddressV4(ipset, ip, prefix, find_state);
3799 * status = ipsetInsertAddressV6(ipset, ip, prefix, find_state);
3800 *
3801 * Helper function for skIPSetInsertAddress(); may also be called
3802 * by other internal functions.
3803 *
3804 * Insert the CIDR block 'ip'/'prefix' into the Radix-Tree based
3805 * 'ipset'. 'find_state' may be NULL. If not NULL, 'find_state'
3806 * should be the result of calling ipsetFindVx() for the
3807 * 'ip'/'prefix'. Do not call this function with a non-NULL
3808 * 'find_state' if ipsetFindVx() found the IP address.
3809 *
3810 * Return SKIPSET_OK when the IP was successfully inserted, or
3811 * SKIPSET_ERR_ALLOC if there is not enough memory to insert the
3812 * IP.
3813 */
3814 static int
ipsetInsertAddressV4(skipset_t * ipset,const uint32_t ipv4,const uint32_t prefix,const ipset_find_t * find_state)3815 ipsetInsertAddressV4(
3816 skipset_t *ipset,
3817 const uint32_t ipv4,
3818 const uint32_t prefix,
3819 const ipset_find_t *find_state)
3820 {
3821 ipset_find_t find_state_local;
3822 ipset_node_v4_t *parent = NULL;
3823 ipset_leaf_v4_t *leaf = NULL;
3824 ipset_node_v4_t *new_node;
3825 uint32_t new_node_idx;
3826 uint32_t new_leaf_idx[IPSET_NUM_CHILDREN];
3827 uint32_t which_child;
3828 uint32_t bitpos;
3829 uint32_t i;
3830 uint32_t j;
3831 int rv;
3832
3833 assert(ipset);
3834 assert(prefix > 0 || ipv4 == 0);
3835 assert(prefix <= 32);
3836 assert(0 == ipset->is_iptree);
3837 assert(0 == ipset->is_ipv6);
3838
3839 /* use the passed in 'find_state' if given */
3840 if (find_state) {
3841 rv = find_state->result;
3842 } else {
3843 rv = ipsetFindV4(ipset, ipv4, prefix, &find_state_local);
3844 /* if IP was found, we can return */
3845 if (SKIPSET_OK == rv) {
3846 return SKIPSET_OK;
3847 }
3848 find_state = &find_state_local;
3849 }
3850 ipset->is_dirty = 1;
3851
3852 if (SKIPSET_ERR_EMPTY == rv) {
3853 /* tree was previously empty */
3854 /* create a new leaf to hold the IP. create an extra node and
3855 * extra leaf since node#0 and leaf#0 are always empty */
3856 if (ipsetNewEntries(ipset, 1, 2, &new_node_idx, new_leaf_idx)) {
3857 return SKIPSET_ERR_ALLOC;
3858 }
3859 assert(0 == new_node_idx);
3860 assert(0 == new_leaf_idx[0]);
3861 assert(1 == new_leaf_idx[1]);
3862 IPSET_ROOT_INDEX_SET(ipset, new_leaf_idx[1], 1);
3863 leaf = LEAF_PTR_V4(ipset, new_leaf_idx[IPSET_ROOT_INDEX(ipset)]);
3864 leaf->ip = ipv4;
3865 leaf->prefix = prefix;
3866 return SKIPSET_OK;
3867 }
3868
3869 if (SKIPSET_ERR_SUBSET == rv) {
3870 /* we're adding an IP/PREFIX where part of the IP space
3871 * already exists in the IPSet. Modify this node's values to
3872 * hold the larger block, and remove any nodes below here. */
3873 if (IPSET_NO_PARENT == find_state->parent_idx) {
3874 if (IPSET_ROOT_IS_LEAF(ipset)) {
3875 leaf = LEAF_PTR_V4(ipset, find_state->node_idx);
3876 } else {
3877 new_leaf_idx[0] = ipsetReplaceNodeWithLeaf(ipset, NULL, 0);
3878 leaf = LEAF_PTR_V4(ipset, new_leaf_idx[0]);
3879 }
3880 leaf->ip = ipv4;
3881 leaf->prefix = prefix;
3882 return SKIPSET_OK;
3883 }
3884
3885 /* get a handle to the parent */
3886 parent = NODE_PTR_V4(ipset, find_state->parent_idx);
3887
3888 if (NUM_BITS <= prefix - parent->prefix) {
3889 /* leaf has a single child[] entry on the parent */
3890 if (find_state->node_is_leaf) {
3891 /* we can modify the leaf and be done */
3892 leaf = LEAF_PTR_V4(ipset, find_state->node_idx);
3893 } else {
3894 /* need to replace the node with a leaf */
3895 new_leaf_idx[0]
3896 = ipsetReplaceNodeWithLeaf(ipset, (ipset_node_t*)parent,
3897 find_state->parents_child);
3898 leaf = LEAF_PTR_V4(ipset, new_leaf_idx[0]);
3899 }
3900 leaf->ip = ipv4;
3901 leaf->prefix = prefix;
3902 return SKIPSET_OK;
3903 }
3904
3905 /* this leaf will cover several child[] entries on the parent.
3906 * destroy any existing children and attempt to find a leaf on
3907 * this level to use */
3908 new_leaf_idx[0] = 0;
3909 for (i = find_state->parents_child, j = 0;
3910 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
3911 ++i, ++j)
3912 {
3913 if (parent->child[i]
3914 && !NODEPTR_CHILD_IS_REPEAT(parent, i))
3915 {
3916 if (!NODEPTR_CHILD_IS_LEAF(parent, i)) {
3917 /* delete this subtree */
3918 ipsetDestroySubtree(ipset, parent->child[i], 1);
3919 } else if (0 == new_leaf_idx[0]) {
3920 /* found a leaf to use */
3921 new_leaf_idx[0] = parent->child[i];
3922 } else {
3923 /* do not need this leaf */
3924 LEAFIDX_FREE(ipset, parent->child[i]);
3925 }
3926 }
3927 }
3928
3929 if (0 == new_leaf_idx[0]) {
3930 /* no leaves available, need to allocate one */
3931 if (ipsetNewEntries(ipset, 0, 1, NULL, new_leaf_idx)) {
3932 return SKIPSET_ERR_ALLOC;
3933 }
3934 }
3935
3936 leaf = LEAF_PTR_V4(ipset, new_leaf_idx[0]);
3937 leaf->ip = ipv4;
3938 leaf->prefix = prefix;
3939
3940 /* set child[] entries on 'parent' to point at the new leaf */
3941 /* set additional child[]s to also point at the leaf */
3942 for (i = find_state->parents_child, j = 0;
3943 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
3944 ++i, ++j)
3945 {
3946 parent->child[i] = new_leaf_idx[0];
3947 }
3948 NODEPTR_CHILD_SET_LEAF2(parent, find_state->parents_child, i - 1);
3949 NODEPTR_CHILD_SET_REPEAT2(parent, 1+find_state->parents_child, i - 1);
3950 return SKIPSET_OK;
3951 }
3952
3953 if (SKIPSET_ERR_MULTILEAF == rv) {
3954 /* get a handle to the current node */
3955 parent = NODE_PTR_V4(ipset, find_state->parent_idx);
3956
3957 if (NUM_BITS <= prefix - parent->prefix) {
3958 /* need to add a single leaf and have a single child[]
3959 * entry on 'parent' point to that leaf */
3960 if (ipsetNewEntries(ipset, 0, 1, NULL, new_leaf_idx)) {
3961 return SKIPSET_ERR_ALLOC;
3962 }
3963 /* get a handle to the newly created leaf and copy the new
3964 * IP there */
3965 leaf = LEAF_PTR_V4(ipset, new_leaf_idx[0]);
3966 leaf->ip = ipv4;
3967 leaf->prefix = prefix;
3968
3969 /* set pointer on 'parent' to point at the new leaf */
3970 parent->child[find_state->parents_child] = new_leaf_idx[0];
3971 NODEPTR_CHILD_SET_LEAF(parent, find_state->parents_child);
3972 return SKIPSET_OK;
3973 }
3974
3975 /* this leaf will cover several child[] entries on the parent.
3976 * see if any are occupied. */
3977 new_leaf_idx[0] = 0;
3978 for (i = find_state->parents_child + 1, j = 1u;
3979 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
3980 ++i, ++j)
3981 {
3982 if (parent->child[i] && NODEPTR_CHILD_IS_LEAF(parent, i)) {
3983 new_leaf_idx[0] = parent->child[i];
3984 break;
3985 }
3986 }
3987 if (new_leaf_idx[0] == 0) {
3988 /* no leaves available, need to allocate one */
3989 if (ipsetNewEntries(ipset, 0, 1, NULL, new_leaf_idx)) {
3990 return SKIPSET_ERR_ALLOC;
3991 }
3992 }
3993
3994 leaf = LEAF_PTR_V4(ipset, new_leaf_idx[0]);
3995 leaf->ip = ipv4;
3996 leaf->prefix = prefix;
3997
3998 /* set child[] on 'parent' to point at the new leaf */
3999 parent->child[find_state->parents_child] = new_leaf_idx[0];
4000
4001 /* set additional child[]s to also point at the leaf */
4002 for (i = find_state->parents_child + 1, j = 1u;
4003 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
4004 ++i, ++j)
4005 {
4006 if (parent->child[i]) {
4007 if (!NODEPTR_CHILD_IS_LEAF(parent, i)) {
4008 /* delete this subtree */
4009 ipsetDestroySubtree(ipset, parent->child[i], 1);
4010 } else if (parent->child[i] != new_leaf_idx[0]) {
4011 /* do not need this leaf */
4012 LEAFIDX_FREE(ipset, parent->child[i]);
4013 }
4014 }
4015 parent->child[i] = new_leaf_idx[0];
4016 }
4017 NODEPTR_CHILD_SET_LEAF2(parent, find_state->parents_child, i - 1);
4018 if (j > 1) {
4019 NODEPTR_CHILD_SET_REPEAT2(parent, 1 + find_state->parents_child,
4020 i - 1);
4021 }
4022 return SKIPSET_OK;
4023 }
4024
4025 /* we must add a new node and a new leaf to the tree. The leaf
4026 * holds the IP being inserted. The node holds the CIDR block
4027 * containing the leaf and our current node---that is, it becomes
4028 * a new parent; we must also update the index on the current
4029 * node's parent to point to the new parent. */
4030
4031 /* create the two new entries */
4032 if (ipsetNewEntries(ipset, 1, 1, &new_node_idx, new_leaf_idx)) {
4033 return SKIPSET_ERR_ALLOC;
4034 }
4035
4036 /* get a handle to the newly created node */
4037 new_node = NODE_PTR_V4(ipset, new_node_idx);
4038
4039 bitpos = find_state->bitpos & ~(NUM_BITS - 1);
4040
4041 /* get a handle to the newly created leaf, copy the inserted IP
4042 * there, and link it to the new_node. */
4043 leaf = LEAF_PTR_V4(ipset, new_leaf_idx[0]);
4044 leaf->ip = ipv4;
4045 leaf->prefix = prefix;
4046 which_child = WHICH_CHILD_V4(ipv4, bitpos);
4047 if (NUM_BITS <= prefix - bitpos) {
4048 /* adding a single child[] entry */
4049 new_node->child[which_child] = new_leaf_idx[0];
4050 NODEPTR_CHILD_SET_LEAF(new_node, which_child);
4051
4052 } else {
4053 /* this leaf will cover several child[] values on the node. */
4054 for (i = which_child, j = 0;
4055 j < (1u << (NUM_BITS - (prefix - bitpos)));
4056 ++i, ++j)
4057 {
4058 new_node->child[i] = new_leaf_idx[0];
4059 }
4060 NODEPTR_CHILD_SET_LEAF2(new_node, which_child, i - 1);
4061 NODEPTR_CHILD_SET_REPEAT2(new_node, 1 + which_child, i - 1);
4062 }
4063
4064 /* the following code is slightly different depending on whether
4065 * search stopped on a node or on a leaf */
4066 if (find_state->node_is_leaf) {
4067 /* get a handle to the current leaf that is being moved down
4068 * the tree */
4069 leaf = LEAF_PTR_V4(ipset, find_state->node_idx);
4070
4071 /* copy the leaf's IP to the new parent, masking off the lower
4072 * bits */
4073 new_node->prefix = bitpos;
4074 new_node->ip = leaf->ip & ~(UINT32_MAX >> new_node->prefix);
4075
4076 /* put the leaf under new_node */
4077 which_child = WHICH_CHILD_V4(leaf->ip, new_node->prefix);
4078 if (NUM_BITS <= leaf->prefix - new_node->prefix) {
4079 /* leaf occupies a single child[] entry */
4080 new_node->child[which_child] = find_state->node_idx;
4081 NODEPTR_CHILD_SET_LEAF(new_node, which_child);
4082
4083 } else {
4084 for (i = which_child, j = 0;
4085 j < (1u << (NUM_BITS - (leaf->prefix - new_node->prefix)));
4086 ++i, ++j)
4087 {
4088 new_node->child[i] = find_state->node_idx;
4089 }
4090 NODEPTR_CHILD_SET_LEAF2(new_node, which_child, i - 1);
4091 NODEPTR_CHILD_SET_REPEAT2(new_node, 1 + which_child, i - 1);
4092 }
4093
4094 /* get a handle to the parent, and update the child pointer on
4095 * the parent */
4096 if (find_state->parent_idx == IPSET_NO_PARENT) {
4097 IPSET_ROOT_INDEX_SET(ipset, new_node_idx, 0);
4098 } else {
4099 parent = NODE_PTR_V4(ipset, find_state->parent_idx);
4100 which_child = WHICH_CHILD_V4(leaf->ip, parent->prefix);
4101 assert(parent->child[which_child] == find_state->node_idx);
4102 parent->child[which_child] = new_node_idx;
4103 NODEPTR_CHILD_CLEAR_LEAF(parent, which_child);
4104 }
4105
4106 } else {
4107 /* get a handle to the current node that is being moved down
4108 * the tree */
4109 ipset_node_v4_t *node = NODE_PTR_V4(ipset, find_state->node_idx);
4110
4111 /* copy the current node's IP to the new parent, masking off
4112 * the lower bits */
4113 new_node->prefix = bitpos;
4114 new_node->ip = node->ip & ~(UINT32_MAX >> bitpos);
4115
4116 /* put the current node under new_node */
4117 which_child = WHICH_CHILD_V4(node->ip, new_node->prefix);
4118 new_node->child[which_child] = find_state->node_idx;
4119
4120 /* get a handle to the parent, and update the child pointer on
4121 * the parent */
4122 if (find_state->parent_idx == IPSET_NO_PARENT) {
4123 IPSET_ROOT_INDEX_SET(ipset, new_node_idx, 0);
4124 } else {
4125 parent = NODE_PTR_V4(ipset, find_state->parent_idx);
4126 which_child = WHICH_CHILD_V4(node->ip, parent->prefix);
4127 assert(parent->child[which_child] == find_state->node_idx);
4128 parent->child[which_child] = new_node_idx;
4129 }
4130 }
4131
4132 return SKIPSET_OK;
4133 }
4134
4135 #if SK_ENABLE_IPV6
4136 static int
ipsetInsertAddressV6(skipset_t * ipset,const ipset_ipv6_t * ipv6,const uint32_t prefix,const ipset_find_t * find_state)4137 ipsetInsertAddressV6(
4138 skipset_t *ipset,
4139 const ipset_ipv6_t *ipv6,
4140 const uint32_t prefix,
4141 const ipset_find_t *find_state)
4142 {
4143 ipset_find_t find_state_local;
4144 ipset_node_v6_t *parent = NULL;
4145 ipset_leaf_v6_t *leaf = NULL;
4146 ipset_node_v6_t *new_node;
4147 uint32_t new_node_idx;
4148 uint32_t new_leaf_idx[IPSET_NUM_CHILDREN];
4149 uint32_t which_child;
4150 uint32_t bitpos;
4151 uint32_t i;
4152 uint32_t j;
4153 int rv;
4154
4155 assert(ipset);
4156 assert(ipv6);
4157 assert(0 < prefix && prefix <= 128);
4158 assert(0 == ipset->is_iptree);
4159 assert(1 == ipset->is_ipv6);
4160
4161 if (find_state) {
4162 rv = find_state->result;
4163 } else {
4164 rv = ipsetFindV6(ipset, ipv6, prefix, &find_state_local);
4165 /* if IP was found, we can return */
4166 if (SKIPSET_OK == rv) {
4167 return SKIPSET_OK;
4168 }
4169 find_state = &find_state_local;
4170 }
4171 ipset->is_dirty = 1;
4172
4173 if (SKIPSET_ERR_EMPTY == rv) {
4174 /* tree was previously empty */
4175 /* create a new node to hold the IP */
4176 if (ipsetNewEntries(ipset, 1, 2, &new_node_idx, new_leaf_idx)) {
4177 return SKIPSET_ERR_ALLOC;
4178 }
4179 assert(0 == new_node_idx);
4180 assert(0 == new_leaf_idx[0]);
4181 assert(1 == new_leaf_idx[1]);
4182 IPSET_ROOT_INDEX_SET(ipset, new_leaf_idx[1], 1);
4183 leaf = LEAF_PTR_V6(ipset, new_leaf_idx[IPSET_ROOT_INDEX(ipset)]);
4184 IPSET_IPV6_COPY(&leaf->ip, ipv6);
4185 leaf->prefix = prefix;
4186 return SKIPSET_OK;
4187 }
4188
4189 if (SKIPSET_ERR_SUBSET == rv) {
4190 /* we're adding an IP/PREFIX where part of the IP space
4191 * already exists in the IPSet. Modify this node's values to
4192 * hold the larger block, and remove any nodes below here. */
4193 if (IPSET_NO_PARENT == find_state->parent_idx) {
4194 if (IPSET_ROOT_IS_LEAF(ipset)) {
4195 leaf = LEAF_PTR_V6(ipset, find_state->node_idx);
4196 } else {
4197 new_leaf_idx[0] = ipsetReplaceNodeWithLeaf(ipset, NULL, 0);
4198 leaf = LEAF_PTR_V6(ipset, new_leaf_idx[0]);
4199 }
4200 IPSET_IPV6_COPY(&leaf->ip, ipv6);
4201 leaf->prefix = prefix;
4202 return SKIPSET_OK;
4203 }
4204
4205 /* get a handle to the parent */
4206 parent = NODE_PTR_V6(ipset, find_state->parent_idx);
4207
4208 if (NUM_BITS <= prefix - parent->prefix) {
4209 /* leaf has a single child[] entry on the parent */
4210 if (find_state->node_is_leaf) {
4211 /* we can modify the leaf and be done */
4212 leaf = LEAF_PTR_V6(ipset, find_state->node_idx);
4213 } else {
4214 /* need to replace the node with a leaf */
4215 new_leaf_idx[0]
4216 = ipsetReplaceNodeWithLeaf(ipset, (ipset_node_t*)parent,
4217 find_state->parents_child);
4218 leaf = LEAF_PTR_V6(ipset, new_leaf_idx[0]);
4219 }
4220 IPSET_IPV6_COPY(&leaf->ip, ipv6);
4221 leaf->prefix = prefix;
4222 return SKIPSET_OK;
4223 }
4224
4225 /* this leaf will cover several child[] entries on the parent.
4226 * destroy any existing children and attempt to find a leaf on
4227 * this level to use */
4228 new_leaf_idx[0] = 0;
4229 for (i = find_state->parents_child, j = 0;
4230 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
4231 ++i, ++j)
4232 {
4233 if (parent->child[i]
4234 && !NODEPTR_CHILD_IS_REPEAT(parent, i))
4235 {
4236 if (!NODEPTR_CHILD_IS_LEAF(parent, i)) {
4237 /* delete this subtree */
4238 ipsetDestroySubtree(ipset, parent->child[i], 1);
4239 } else if (0 == new_leaf_idx[0]) {
4240 /* found a leaf to use */
4241 new_leaf_idx[0] = parent->child[i];
4242 } else {
4243 /* do not need this leaf */
4244 LEAFIDX_FREE(ipset, parent->child[i]);
4245 }
4246 }
4247 }
4248
4249 if (0 == new_leaf_idx[0]) {
4250 /* no leaves available, need to allocate one */
4251 if (ipsetNewEntries(ipset, 0, 1, NULL, new_leaf_idx)) {
4252 return SKIPSET_ERR_ALLOC;
4253 }
4254 }
4255
4256 leaf = LEAF_PTR_V6(ipset, new_leaf_idx[0]);
4257 IPSET_IPV6_COPY(&leaf->ip, ipv6);
4258 leaf->prefix = prefix;
4259
4260 /* set child[] entries on 'parent' to point at the new leaf */
4261 /* set additional child[]s to also point at the leaf */
4262 for (i = find_state->parents_child, j = 0;
4263 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
4264 ++i, ++j)
4265 {
4266 parent->child[i] = new_leaf_idx[0];
4267 }
4268 NODEPTR_CHILD_SET_LEAF2(parent, find_state->parents_child, i - 1);
4269 NODEPTR_CHILD_SET_REPEAT2(parent, 1+find_state->parents_child, i - 1);
4270 return SKIPSET_OK;
4271 }
4272
4273 if (SKIPSET_ERR_MULTILEAF == rv) {
4274 /* get a handle to the current node */
4275 parent = NODE_PTR_V6(ipset, find_state->parent_idx);
4276
4277 if (NUM_BITS <= prefix - parent->prefix) {
4278 /* need to add a single leaf and have a single child[]
4279 * entry on 'parent' point to that leaf */
4280 if (ipsetNewEntries(ipset, 0, 1, NULL, new_leaf_idx)) {
4281 return SKIPSET_ERR_ALLOC;
4282 }
4283 /* get a handle to the newly created leaf and copy the new
4284 * IP there */
4285 leaf = LEAF_PTR_V6(ipset, new_leaf_idx[0]);
4286 IPSET_IPV6_COPY(&leaf->ip, ipv6);
4287 leaf->prefix = prefix;
4288
4289 /* set pointer on 'parent' to point at the new leaf */
4290 parent->child[find_state->parents_child] = new_leaf_idx[0];
4291 NODEPTR_CHILD_SET_LEAF(parent, find_state->parents_child);
4292 return SKIPSET_OK;
4293 }
4294
4295 /* this leaf will cover several child[] entries on the parent.
4296 * see if any are occupied. */
4297 new_leaf_idx[0] = 0;
4298 for (i = find_state->parents_child + 1, j = 1u;
4299 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
4300 ++i, ++j)
4301 {
4302 if (parent->child[i] && NODEPTR_CHILD_IS_LEAF(parent, i)) {
4303 new_leaf_idx[0] = parent->child[i];
4304 break;
4305 }
4306 }
4307 if (new_leaf_idx[0] == 0) {
4308 /* no leaves available, need to allocate one */
4309 if (ipsetNewEntries(ipset, 0, 1, NULL, new_leaf_idx)) {
4310 return SKIPSET_ERR_ALLOC;
4311 }
4312 }
4313
4314 leaf = LEAF_PTR_V6(ipset, new_leaf_idx[0]);
4315 IPSET_IPV6_COPY(&leaf->ip, ipv6);
4316 leaf->prefix = prefix;
4317
4318 /* set child[] on 'parent' to point at the new leaf */
4319 parent->child[find_state->parents_child] = new_leaf_idx[0];
4320
4321 /* set additional child[]s to also point at the leaf */
4322 for (i = find_state->parents_child + 1, j = 1u;
4323 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
4324 ++i, ++j)
4325 {
4326 if (parent->child[i]) {
4327 if (!NODEPTR_CHILD_IS_LEAF(parent, i)) {
4328 /* delete this subtree */
4329 ipsetDestroySubtree(ipset, parent->child[i], 1);
4330 } else if (parent->child[i] != new_leaf_idx[0]) {
4331 /* do not need this leaf */
4332 LEAFIDX_FREE(ipset, parent->child[i]);
4333 }
4334 }
4335 parent->child[i] = new_leaf_idx[0];
4336 }
4337 NODEPTR_CHILD_SET_LEAF2(parent, find_state->parents_child, i - 1);
4338 if (j > 1) {
4339 NODEPTR_CHILD_SET_REPEAT2(parent, 1 + find_state->parents_child,
4340 i - 1);
4341 }
4342 return SKIPSET_OK;
4343 }
4344
4345 /* we must add a new node and a new leaf to the tree. The leaf
4346 * holds the IP being inserted. The node holds the CIDR block
4347 * containing the leaf and our current node---that is, it becomes
4348 * a new parent; we must also update the index on the current
4349 * node's parent to point to the new parent. */
4350
4351 /* create the two new entries */
4352 if (ipsetNewEntries(ipset, 1, 1, &new_node_idx, new_leaf_idx)) {
4353 return SKIPSET_ERR_ALLOC;
4354 }
4355
4356 /* get a handle to the newly created node */
4357 new_node = NODE_PTR_V6(ipset, new_node_idx);
4358
4359 bitpos = find_state->bitpos & ~(NUM_BITS - 1);
4360
4361 /* get a handle to the newly created leaf, copy the inserted IP
4362 * there, and link it to the new_node */
4363 leaf = LEAF_PTR_V6(ipset, new_leaf_idx[0]);
4364 IPSET_IPV6_COPY(&leaf->ip, ipv6);
4365 leaf->prefix = prefix;
4366 which_child = WHICH_CHILD_V6(ipv6, bitpos);
4367 if (NUM_BITS <= prefix - bitpos) {
4368 /* adding a single child[] entry */
4369 new_node->child[which_child] = new_leaf_idx[0];
4370 NODEPTR_CHILD_SET_LEAF(new_node, which_child);
4371
4372 } else {
4373 /* this leaf will cover several child[] values on the node. */
4374 for (i = which_child, j = 0;
4375 j < (1u << (NUM_BITS - (prefix - bitpos)));
4376 ++i, ++j)
4377 {
4378 new_node->child[i] = new_leaf_idx[0];
4379 }
4380 NODEPTR_CHILD_SET_LEAF2(new_node, which_child, i - 1);
4381 NODEPTR_CHILD_SET_REPEAT2(new_node, 1 + which_child, i - 1);
4382 }
4383
4384 /* the following code is slightly different depending on whether
4385 * search stopped on a node or on a leaf */
4386 if (find_state->node_is_leaf) {
4387 /* get a handle to the current leaf that is being moved down
4388 * the tree */
4389 leaf = LEAF_PTR_V6(ipset, find_state->node_idx);
4390
4391 /* copy the leaf's IP to the new parent, masking off the lower
4392 * bits */
4393 new_node->prefix = bitpos;
4394 IPSET_IPV6_COPY_AND_MASK(&new_node->ip, &leaf->ip, bitpos);
4395
4396 /* put the leaf under new_node */
4397 which_child = WHICH_CHILD_V6(&leaf->ip, new_node->prefix);
4398 if (NUM_BITS <= leaf->prefix - new_node->prefix) {
4399 /* leaf occupies a single child[] entry */
4400 new_node->child[which_child] = find_state->node_idx;
4401 NODEPTR_CHILD_SET_LEAF(new_node, which_child);
4402
4403 } else {
4404 for (i = which_child, j = 0;
4405 j < (1u << (NUM_BITS - (leaf->prefix - new_node->prefix)));
4406 ++i, ++j)
4407 {
4408 new_node->child[i] = find_state->node_idx;
4409 }
4410 NODEPTR_CHILD_SET_LEAF2(new_node, which_child, i - 1);
4411 NODEPTR_CHILD_SET_REPEAT2(new_node, 1 + which_child, i - 1);
4412 }
4413
4414 /* get a handle to the parent, and update the child pointer on
4415 * the parent */
4416 if (find_state->parent_idx == IPSET_NO_PARENT) {
4417 IPSET_ROOT_INDEX_SET(ipset, new_node_idx, 0);
4418 } else {
4419 parent = NODE_PTR_V6(ipset, find_state->parent_idx);
4420 which_child = WHICH_CHILD_V6(&leaf->ip, parent->prefix);
4421 assert(parent->child[which_child] == find_state->node_idx);
4422 parent->child[which_child] = new_node_idx;
4423 NODEPTR_CHILD_CLEAR_LEAF(parent, which_child);
4424 }
4425
4426 } else {
4427 /* get a handle to the current node that is being moved down
4428 * the tree */
4429 ipset_node_v6_t *node = NODE_PTR_V6(ipset, find_state->node_idx);
4430
4431 /* copy the current node's IP to the new parent, masking off
4432 * the lower bits */
4433 new_node->prefix = bitpos;
4434 IPSET_IPV6_COPY_AND_MASK(&new_node->ip, &node->ip, bitpos);
4435
4436 /* put the current node under new_node */
4437 which_child = WHICH_CHILD_V6(&node->ip, new_node->prefix);
4438 new_node->child[which_child] = find_state->node_idx;
4439
4440 /* get a handle to the parent, and update the child pointer on
4441 * the parent */
4442 if (find_state->parent_idx == IPSET_NO_PARENT) {
4443 IPSET_ROOT_INDEX_SET(ipset, new_node_idx, 0);
4444 } else {
4445 parent = NODE_PTR_V6(ipset, find_state->parent_idx);
4446 which_child = WHICH_CHILD_V6(&node->ip, parent->prefix);
4447 assert(parent->child[which_child] == find_state->node_idx);
4448 parent->child[which_child] = new_node_idx;
4449 }
4450 }
4451
4452 return SKIPSET_OK;
4453 }
4454 #endif /* SK_ENABLE_IPV6 */
4455
4456 /*
4457 * status = ipsetInsertIPAddrIPTree(ipaddr, prefix, ipset);
4458 * status = ipsetInsertIPAddrV4(ipaddr, prefix, ipset);
4459 * status = ipsetInsertIPAddrV6(ipaddr, prefix, ipset);
4460 *
4461 * Helper callback functions for the helpers of skIPSetRead() that
4462 * use ipsetProcessStream...(). These callbacks are similar to
4463 * ipsetUnionCallback*(), but these take an skipaddr_t.
4464 *
4465 * Add the CIDR block specified by 'ipaddr'/'prefix' to 'ipset'.
4466 */
4467 static int
ipsetInsertIPAddrIPTree(skipaddr_t * ipaddr,uint32_t prefix,void * v_ipset)4468 ipsetInsertIPAddrIPTree(
4469 skipaddr_t *ipaddr,
4470 uint32_t prefix,
4471 void *v_ipset)
4472 {
4473 return ipsetInsertAddressIPTree(((skipset_t*)v_ipset)->s.v2,
4474 skipaddrGetV4(ipaddr), prefix);
4475 }
4476
4477 static int
ipsetInsertIPAddrV4(skipaddr_t * ipaddr,uint32_t prefix,void * v_ipset)4478 ipsetInsertIPAddrV4(
4479 skipaddr_t *ipaddr,
4480 uint32_t prefix,
4481 void *v_ipset)
4482 {
4483 return ipsetInsertAddressV4((skipset_t*)v_ipset, skipaddrGetV4(ipaddr),
4484 prefix, NULL);
4485 }
4486
4487 #if SK_ENABLE_IPV6
4488 static int
ipsetInsertIPAddrV6(skipaddr_t * ipaddr,uint32_t prefix,void * v_ipset)4489 ipsetInsertIPAddrV6(
4490 skipaddr_t *ipaddr,
4491 uint32_t prefix,
4492 void *v_ipset)
4493 {
4494 ipset_ipv6_t ipv6;
4495 IPSET_IPV6_FROM_ADDRV6(&ipv6, ipaddr);
4496 return ipsetInsertAddressV6((skipset_t*)v_ipset, &ipv6, prefix, NULL);
4497 }
4498 #endif /* SK_ENABLE_IPV6 */
4499
4500
4501 /*
4502 * status = ipsetInsertRangeIPTree(ipset, ipaddr_start, ipaddr_end);
4503 *
4504 * Insert all IPv4 addresses from ipaddr_start to ipaddr_end
4505 * inclusive into the IPset 'ipset'.
4506 */
4507 static int
ipsetInsertRangeIPTree(skipset_t * ipset,const skipaddr_t * ipaddr_start,const skipaddr_t * ipaddr_end)4508 ipsetInsertRangeIPTree(
4509 skipset_t *ipset,
4510 const skipaddr_t *ipaddr_start,
4511 const skipaddr_t *ipaddr_end)
4512 {
4513 skipaddr_t ipaddr4_start;
4514 skipaddr_t ipaddr4_end;
4515 skipaddr_t ipaddr4_next;
4516 uint32_t prefix;
4517 int rv = SKIPSET_OK;
4518
4519 assert(ipset);
4520 assert(1 == ipset->is_iptree);
4521 assert(0 == ipset->is_ipv6);
4522
4523 /* must be a valid range of IPv4 addresses containing two or more
4524 * IP addresses */
4525 assert(skipaddrCompare(ipaddr_start, ipaddr_end) < 0);
4526 assert(!skipaddrIsV6(ipaddr_start) && !skipaddrIsV6(ipaddr_end));
4527
4528 #if SK_ENABLE_IPV6
4529 if (skipaddrIsV6(ipaddr_start)) {
4530 if (skipaddrV6toV4(ipaddr_start, &ipaddr4_start)) {
4531 return SKIPSET_ERR_IPV6;
4532 }
4533 } else
4534 #endif /* SK_ENABLE_IPV6 */
4535 {
4536 skipaddrCopy(&ipaddr4_start, ipaddr_start);
4537 }
4538
4539 #if SK_ENABLE_IPV6
4540 if (skipaddrIsV6(ipaddr_end)) {
4541 if (skipaddrV6toV4(ipaddr_end, &ipaddr4_end)) {
4542 return SKIPSET_ERR_IPV6;
4543 }
4544 } else
4545 #endif /* SK_ENABLE_IPV6 */
4546 {
4547 skipaddrCopy(&ipaddr4_end, ipaddr_end);
4548 }
4549
4550 ipset->is_dirty = 1;
4551
4552 do {
4553 prefix = skCIDRComputePrefix(&ipaddr4_start, &ipaddr4_end,
4554 &ipaddr4_next);
4555 rv = ipsetInsertAddressIPTree(
4556 ipset->s.v2, skipaddrGetV4(&ipaddr4_start), prefix);
4557 skipaddrCopy(&ipaddr4_start, &ipaddr4_next);
4558 } while (SKIPSET_OK == rv && !skipaddrIsZero(&ipaddr4_start));
4559
4560 return rv;
4561 }
4562
4563
4564 /*
4565 * status = ipsetIntersectCallback(ipaddr, prefix, state);
4566 *
4567 * Callback function used by skIPSetIntersect().
4568 *
4569 * This function will return SKIPSET_OK to continue walking over
4570 * the IPs, SKIPSET_ERR_ALLOC for an allocation error, or
4571 * SKIPSET_ERR_SUBSET when the iterator runs out of IPs to
4572 * visit---which will stop the skIPSetWalk().
4573 */
4574 static int
ipsetIntersectCallback(skipaddr_t * start_addr,uint32_t prefix,void * v_state)4575 ipsetIntersectCallback(
4576 skipaddr_t *start_addr,
4577 uint32_t prefix,
4578 void *v_state)
4579 {
4580 ipset_intersect_t *state = (ipset_intersect_t*)v_state;
4581 skipaddr_t walk_addr[2];
4582 int walk_next = 0;
4583
4584 /* get the start and end IPs for the CIDR block */
4585 skCIDR2IPRange(start_addr, prefix, &walk_addr[0], &walk_addr[1]);
4586
4587 for (;;) {
4588 /* test (iter.final <= walk.final) */
4589 if (skipaddrCompare(&state->addr[1], &walk_addr[1]) <= 0) {
4590
4591 /* test (iter.begin >= walk.begin) */
4592 if (skipaddrCompare(&state->addr[0], &walk_addr[0]) >= 0) {
4593 /* The iter block is completely contained in---or
4594 * identical to---the walk block. Add the iter
4595 * block to the vector.
4596 *
4597 * iter block: |---------|
4598 * walk block: |---------------------------------|
4599 */
4600 if (skVectorAppendValue(state->vec_add, state->addr)) {
4601 return SKIPSET_ERR_ALLOC;
4602 }
4603
4604 /* test (iter.final >= walk.begin) */
4605 } else if (skipaddrCompare(&state->addr[1], &walk_addr[0]) >= 0) {
4606 /* Add the IPs between walk.begin and iter.final.
4607 *
4608 * iter block: |---------|
4609 * walk block: |---------|
4610 */
4611 skipaddrCopy(&state->addr[0], &walk_addr[0]);
4612 if (skVectorAppendValue(state->vec_add, state->addr)) {
4613 return SKIPSET_ERR_ALLOC;
4614 }
4615 }
4616
4617 /* Else, the iter block is completely below the current walk
4618 * block; and there is nothing to do.
4619 *
4620 * iter block: |---------|
4621 * walk block: |---------|
4622 */
4623
4624 /* If the end IPs are identical, refresh both blocks; else
4625 * go to next iter block */
4626 if (skipaddrCompare(&state->addr[1], &walk_addr[1]) == 0) {
4627 walk_next = 1;
4628 }
4629
4630 if (skIPSetIteratorNext(&state->iter, &state->addr[0], &prefix)) {
4631 /* return some value so we stop walking over the IPs */
4632 return SKIPSET_ERR_SUBSET;
4633 }
4634 skCIDR2IPRange(&state->addr[0], prefix,
4635 &state->addr[0], &state->addr[1]);
4636 if (walk_next) {
4637 break;
4638 }
4639
4640 } else {
4641
4642 /* test (iter.begin <= walk.begin) */
4643 if (skipaddrCompare(&state->addr[0], &walk_addr[0]) <= 0) {
4644 /* The walk is completely contained in the iter block.
4645 * Add the walk block to the vector.
4646 *
4647 * iter block: |---------|
4648 * walk block: |-----|
4649 */
4650 if (skVectorAppendValue(state->vec_add, walk_addr)) {
4651 return SKIPSET_ERR_ALLOC;
4652 }
4653
4654 /* test (iter.begin <= walk.final) */
4655 } else if (skipaddrCompare(&state->addr[0], &walk_addr[1]) <= 0) {
4656 /* Add the IPs between iter.begin and walk.final.
4657 *
4658 * iter block: |---------|
4659 * walk block: |---------|
4660 */
4661 skipaddrCopy(&walk_addr[0], &state->addr[0]);
4662 if (skVectorAppendValue(state->vec_add, walk_addr)) {
4663 return SKIPSET_ERR_ALLOC;
4664 }
4665 }
4666
4667 /* Else, the iter block is completely above the walk block,
4668 * and there is nothing to do.
4669 *
4670 * iter block: |---------|
4671 * walk block: |---------|
4672 */
4673
4674 /* Go to next walk block */
4675 break;
4676 }
4677 }
4678 return SKIPSET_OK;
4679 }
4680
4681
4682 /*
4683 * status = ipsetInsertWildcardIPTree(ipset, wildcard);
4684 *
4685 * Helper function for skIPSetInsertIPWildcard() when the IPset is
4686 * represented by a SiLK-2 IPTree.
4687 *
4688 * Also a helper function for legacy skIPTreeAddIPWildcard().
4689 *
4690 * Insert the IPs in the IPWildcard 'wildcard' into 'ipset'.
4691 */
4692 static int
ipsetInsertWildcardIPTree(skIPTree_t * ipset,const skIPWildcard_t * ipwild)4693 ipsetInsertWildcardIPTree(
4694 skIPTree_t *ipset,
4695 const skIPWildcard_t *ipwild)
4696 {
4697 skIPWildcardIterator_t iter;
4698 skipaddr_t ipaddr;
4699 uint32_t ipv4;
4700 uint32_t prefix;
4701 int rv;
4702
4703 assert(ipset);
4704 assert(ipwild);
4705
4706 /* Iterate over the IPs from the wildcard */
4707 skIPWildcardIteratorBindV4(&iter, ipwild);
4708 while (skIPWildcardIteratorNextCidr(&iter, &ipaddr, &prefix)
4709 == SK_ITERATOR_OK)
4710 {
4711 assert(prefix <= 32);
4712 ipv4 = skipaddrGetV4(&ipaddr);
4713 rv = ipsetInsertAddressIPTree(ipset, ipv4, prefix);
4714 if (rv) {
4715 return rv;
4716 }
4717 }
4718 return SKIPSET_OK;
4719 }
4720
4721
4722 /*
4723 * Helper function for skIPSetIntersect() when both IPsets are
4724 * implmented by SiLK-2 IPTrees.
4725 *
4726 * Also a helper function for legacy skIPTreeIntersect().
4727 */
4728 static int
ipsetIntersectIPTree(skIPTree_t * result_ipset,const skIPTree_t * ipset)4729 ipsetIntersectIPTree(
4730 skIPTree_t *result_ipset,
4731 const skIPTree_t *ipset)
4732 {
4733 unsigned int i, j;
4734
4735 assert(result_ipset);
4736 assert(ipset);
4737
4738 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
4739 if (NULL == result_ipset->nodes[i]) {
4740 /* This /16 is completely off in 'result_ipset; no changes
4741 * necessary */
4742
4743 } else if (NULL == ipset->nodes[i]) {
4744 /* Turn off this node in 'result_ipset' */
4745 free(result_ipset->nodes[i]);
4746 result_ipset->nodes[i] = NULL;
4747
4748 } else {
4749 uint32_t keep_node = 0;
4750 /* Need to intersect the bits in the /16 */
4751 for (j = 0; keep_node == 0 && j < SKIP_BBLOCK_SIZE; ++j) {
4752 result_ipset->nodes[i]->addressBlock[j]
4753 &= ipset->nodes[i]->addressBlock[j];
4754 keep_node = result_ipset->nodes[i]->addressBlock[j];
4755 }
4756 if (keep_node) {
4757 for ( ; j < SKIP_BBLOCK_SIZE; ++j) {
4758 result_ipset->nodes[i]->addressBlock[j]
4759 &= ipset->nodes[i]->addressBlock[j];
4760 }
4761 } else {
4762 free(result_ipset->nodes[i]);
4763 result_ipset->nodes[i] = NULL;
4764 }
4765 }
4766 }
4767
4768 return SKIPSET_OK;
4769 }
4770
4771
4772 /*
4773 * Modify the IPTree iterator values on 'iter' to point to the next
4774 * /27-bitmap that has any bits set.
4775 *
4776 * The search starts from the CURRENT values of the 'top_16' and
4777 * 'mid_11' members of the iterator.
4778 */
4779 static void
ipsetIteratorIPTreeNextSlash27(skipset_iterator_t * iter)4780 ipsetIteratorIPTreeNextSlash27(
4781 skipset_iterator_t *iter)
4782 {
4783 for ( ; iter->it.v2.top_16 < SKIP_BBLOCK_COUNT; ++iter->it.v2.top_16) {
4784 if (iter->it.v2.tree->nodes[iter->it.v2.top_16]) {
4785 for (; iter->it.v2.mid_11 < SKIP_BBLOCK_SIZE; ++iter->it.v2.mid_11)
4786 {
4787 if (iter->it.v2.tree->nodes[iter->it.v2.top_16]
4788 ->addressBlock[iter->it.v2.mid_11])
4789 {
4790 return;
4791 }
4792 }
4793 iter->it.v2.mid_11 = 0;
4794 }
4795 }
4796 }
4797
4798
4799 /*
4800 * ipsetIteratorNextIPTree(iter, ipaddr, prefix);
4801 *
4802 * Helper function for skIPSetIteratorNext() when the IPset is a
4803 * SiLK-2 style IPTree.
4804 */
4805 static int
ipsetIteratorNextIPTree(skipset_iterator_t * iter,skipaddr_t * ipaddr,uint32_t * prefix)4806 ipsetIteratorNextIPTree(
4807 skipset_iterator_t *iter,
4808 skipaddr_t *ipaddr,
4809 uint32_t *prefix)
4810 {
4811 uint32_t ipv4;
4812 uint32_t bmap;
4813 uint32_t max_slash27;
4814 uint32_t trail_zero;
4815
4816 assert(1 == iter->is_iptree);
4817
4818 if (iter->it.v2.count) {
4819 /* if the iterator already contains a CIDR block, return it */
4820 assert(1 == iter->cidr_blocks);
4821 goto END;
4822 }
4823
4824 /* check stopping condition */
4825 if (iter->it.v2.top_16 >= SKIP_BBLOCK_COUNT) {
4826 return SK_ITERATOR_NO_MORE_ENTRIES;
4827 }
4828
4829 /* iterator should always be on a /27-bitmap with data */
4830 assert(iter->it.v2.mid_11 < SKIP_BBLOCK_SIZE);
4831 assert(iter->it.v2.bot_5 < 32);
4832 assert(iter->it.v2.tree->nodes[iter->it.v2.top_16]
4833 ->addressBlock[iter->it.v2.mid_11]);
4834
4835 /* find position of least significant high bit in this /27-bitmap,
4836 * ignoring bits we have already checked */
4837 bmap = ((iter->it.v2.tree->nodes[iter->it.v2.top_16]
4838 ->addressBlock[iter->it.v2.mid_11])
4839 >> iter->it.v2.bot_5);
4840 assert(0 != bmap);
4841 trail_zero = ipsetCountTrailingZeros(bmap);
4842 bmap >>= trail_zero;
4843 iter->it.v2.bot_5 += trail_zero;
4844 /* Generate the IP address */
4845 ipv4 = (((iter->it.v2.top_16) << 16)
4846 | (iter->it.v2.mid_11 << 5)
4847 | iter->it.v2.bot_5);
4848
4849 if (!iter->cidr_blocks || (ipv4 & 0x1)) {
4850 *prefix = 32;
4851 if ((bmap >> 1) && iter->it.v2.bot_5 < 31) {
4852 /* there are additional IPs in this /27-bitmap; no need to
4853 * search for the next valid /27 */
4854 ++iter->it.v2.bot_5;
4855 goto END;
4856 }
4857 /* reset bottom counter and increment middle counter; drop
4858 * into code below to find next valid /27-bitmap */
4859 iter->it.v2.bot_5 = 0;
4860 ++iter->it.v2.mid_11;
4861
4862 } else if (UINT32_MAX != bmap) {
4863 /* this /27-bitmap is only partially filled */
4864
4865 /* find number of consecutive high bits in 'bmap' that map
4866 * into a CIDR block */
4867 switch (iter->it.v2.bot_5) {
4868 case 0: case 16:
4869 if ((bmap & 0xFFFF) == 0xFFFF) {
4870 *prefix = 28;
4871 iter->it.v2.bot_5 += 16;
4872 bmap >>= 16;
4873 break;
4874 }
4875 /* FALLTHROUGH */
4876 case 8: case 24:
4877 if ((bmap & 0xFF) == 0xFF) {
4878 *prefix = 29;
4879 iter->it.v2.bot_5 += 8;
4880 bmap >>= 8;
4881 break;
4882 }
4883 /* FALLTHROUGH */
4884 case 4: case 12: case 20: case 28:
4885 if ((bmap & 0xF) == 0xF) {
4886 *prefix = 30;
4887 iter->it.v2.bot_5 += 4;
4888 bmap >>= 4;
4889 break;
4890 }
4891 /* FALLTHROUGH */
4892 case 2: case 6: case 10: case 14:
4893 case 18: case 22: case 26: case 30:
4894 if ((bmap & 0x3) == 0x3) {
4895 *prefix = 31;
4896 iter->it.v2.bot_5 += 2;
4897 bmap >>= 2;
4898 break;
4899 }
4900 /* FALLTHROUGH */
4901 default:
4902 *prefix = 32;
4903 ++iter->it.v2.bot_5;
4904 bmap >>= 1;
4905 break;
4906 }
4907
4908 if (bmap && iter->it.v2.bot_5 < 32) {
4909 /* there are additional IPs in this /27-bitmap; no need to
4910 * search for the next valid /27 */
4911 goto END;
4912 }
4913 /* reset bottom counter and increment middle counter; drop
4914 * into code below to find next valid /27-bitmap */
4915 iter->it.v2.bot_5 = 0;
4916 ++iter->it.v2.mid_11;
4917
4918 } else if (iter->it.v2.mid_11 & 0x1) {
4919 /* this /27 is full and the base IP is odd so it cannot grow;
4920 * increment counts and search for next /27-bitmap */
4921 assert(0 == iter->it.v2.bot_5);
4922 *prefix = 27;
4923 ++iter->it.v2.mid_11;
4924
4925 } else {
4926 /* this /27 is full; attempt to join it with additional /27s
4927 * to make a larger CIDR block */
4928 assert(0 == iter->it.v2.bot_5);
4929
4930 iter->it.v2.base_ip = ipv4;
4931
4932 /* compute the maximum number of /27s that can be joined with
4933 * this one by counting the number of trailing zero bits on
4934 * the IP */
4935 if (0 == ipv4) {
4936 iter->it.v2.trail_zero = 32;
4937 } else {
4938 iter->it.v2.trail_zero = ipsetCountTrailingZeros(ipv4);
4939 }
4940
4941 /* compute the maximum number of /27's that can be in this
4942 * CIDR block if it is completely full; the 'count' value on
4943 * the iterator maintains the number we actually see. */
4944 max_slash27 = (1 << (iter->it.v2.trail_zero - 5));
4945 iter->it.v2.count = 0;
4946
4947 if (max_slash27 >= SKIP_BBLOCK_SIZE) {
4948 /* handle completely full nodes if we can */
4949 skIPNode_t full_node;
4950
4951 assert(0 == iter->it.v2.mid_11);
4952 memset(&full_node, 0xFF, sizeof(full_node));
4953 do {
4954 if (memcmp(iter->it.v2.tree->nodes[iter->it.v2.top_16],
4955 &full_node, sizeof(full_node)))
4956 {
4957 /* node is not full */
4958 break;
4959 }
4960 /* node is full */
4961 iter->it.v2.count += SKIP_BBLOCK_SIZE;
4962 ++iter->it.v2.top_16;
4963 assert(iter->it.v2.top_16 < SKIP_BBLOCK_COUNT
4964 || iter->it.v2.count == max_slash27);
4965 } while (iter->it.v2.count < max_slash27
4966 && iter->it.v2.tree->nodes[iter->it.v2.top_16]);
4967 }
4968
4969 if (0 == iter->it.v2.count) {
4970 iter->it.v2.count = 1;
4971 ++iter->it.v2.mid_11;
4972
4973 for (;;) {
4974 assert(iter->it.v2.mid_11 < SKIP_BBLOCK_SIZE);
4975 if (UINT32_MAX
4976 != (iter->it.v2.tree->nodes[iter->it.v2.top_16]
4977 ->addressBlock[iter->it.v2.mid_11]))
4978 {
4979 /* cannot extend the CIDR block */
4980 break;
4981 }
4982 ++iter->it.v2.count;
4983 ++iter->it.v2.mid_11;
4984 if (iter->it.v2.mid_11 == SKIP_BBLOCK_SIZE) {
4985 /* cannot grow any more---a full node would have
4986 * been found above; move to the next node and
4987 * drop into the code below */
4988 iter->it.v2.mid_11 = 0;
4989 ++iter->it.v2.top_16;
4990 break;
4991 }
4992 if (iter->it.v2.count == max_slash27) {
4993 /* the CIDR block is at its maximum size; find the
4994 * next /27-bitmap that has data */
4995 break;
4996 }
4997 /* else keep growing the current CIDR block */
4998 }
4999 }
5000 }
5001
5002 ipsetIteratorIPTreeNextSlash27(iter);
5003
5004 END:
5005 if (iter->it.v2.count) {
5006 assert(1 == iter->cidr_blocks);
5007 assert(iter->it.v2.trail_zero >= 5);
5008 while (iter->it.v2.count < (1u << (iter->it.v2.trail_zero - 5))) {
5009 --iter->it.v2.trail_zero;
5010 }
5011 ipv4 = iter->it.v2.base_ip;
5012 *prefix = (32 - iter->it.v2.trail_zero);
5013 iter->it.v2.count -= (1 << (iter->it.v2.trail_zero - 5));
5014 iter->it.v2.base_ip |= (0x20u << (iter->it.v2.trail_zero - 5));
5015 --iter->it.v2.trail_zero;
5016 }
5017
5018 switch (iter->v6policy) {
5019 case SK_IPV6POLICY_ONLY:
5020 /* since we do not support IPv6 addresses in the IPTree data
5021 * structure, there is nothing to return */
5022 skAbortBadCase(iter->v6policy);
5023
5024 case SK_IPV6POLICY_FORCE:
5025 #if SK_ENABLE_IPV6
5026 skipaddrSetV6FromUint32(ipaddr, &ipv4);
5027 *prefix += 96;
5028 #endif /* #if SK_ENABLE_IPV6 */
5029 break;
5030
5031 case SK_IPV6POLICY_MIX:
5032 case SK_IPV6POLICY_ASV4:
5033 case SK_IPV6POLICY_IGNORE:
5034 skipaddrSetV4(ipaddr, &ipv4);
5035 break;
5036 }
5037 return SK_ITERATOR_OK;
5038 }
5039
5040
5041 /*
5042 * ipsetIteratorNextRangeV4(iter);
5043 * ipsetIteratorNextRangeV6(iter);
5044 *
5045 * Helper functions for skIPSetIteratorNext().
5046 *
5047 * Update the IPset iterator 'iter' to contain the starting and
5048 * stopping IPs values for the CIDR block on the current leaf.
5049 * Assumes the 'cur' field on the iterator is pointing at a valid
5050 * leaf.
5051 */
5052 static void
ipsetIteratorNextRangeV4(skipset_iterator_t * iter)5053 ipsetIteratorNextRangeV4(
5054 skipset_iterator_t *iter)
5055 {
5056 ipset_leaf_v4_t *leaf = LEAF_PTR_V4(iter->ipset, iter->it.v3.cur);
5057
5058 if (32 == leaf->prefix) {
5059 iter->it.v3.data[0] = iter->it.v3.data[2] = leaf->ip;
5060 } else {
5061 iter->it.v3.data[0] = leaf->ip;
5062 iter->it.v3.data[2] = (leaf->ip | (UINT32_MAX >> leaf->prefix));
5063 }
5064 }
5065
5066 #if SK_ENABLE_IPV6
5067 static void
ipsetIteratorNextRangeV6(skipset_iterator_t * iter)5068 ipsetIteratorNextRangeV6(
5069 skipset_iterator_t *iter)
5070 {
5071 /*
5072 * The data[4] array on the interator contains:
5073 *
5074 * 0, 1: Start of range, upper-64 and lower-64 bits
5075 * 2, 3: End of range, upper-64 and lower-64 bits
5076 */
5077 ipset_leaf_v6_t *leaf = LEAF_PTR_V6(iter->ipset, iter->it.v3.cur);
5078
5079 if (SK_IPV6POLICY_ASV4 == iter->v6policy) {
5080 /* check stopping condition */
5081 if (leaf->ip.ip[0] != 0
5082 || ((UINT64_C(0xffffffff00000000) & leaf->ip.ip[1])
5083 != UINT64_C(0x0000ffff00000000)))
5084 {
5085 iter->it.v3.cur = iter->ipset->s.v3->leaves.entry_count;
5086 return;
5087 }
5088 }
5089
5090 if (leaf->prefix > 64) {
5091 if (leaf->prefix == 128) {
5092 iter->it.v3.data[0] = iter->it.v3.data[2] = leaf->ip.ip[0];
5093 iter->it.v3.data[1] = iter->it.v3.data[3] = leaf->ip.ip[1];
5094 } else {
5095 iter->it.v3.data[0] = iter->it.v3.data[2] = leaf->ip.ip[0];
5096 iter->it.v3.data[1] = leaf->ip.ip[1];
5097 iter->it.v3.data[3] = (leaf->ip.ip[1]
5098 | (UINT64_MAX >> (leaf->prefix - 64)));
5099 }
5100 } else if (leaf->prefix == 64) {
5101 iter->it.v3.data[0] = iter->it.v3.data[2] = leaf->ip.ip[0];
5102 iter->it.v3.data[1] = 0;
5103 iter->it.v3.data[3] = UINT64_MAX;
5104 } else {
5105 iter->it.v3.data[0] = leaf->ip.ip[0];
5106 iter->it.v3.data[2] = (leaf->ip.ip[0] | (UINT64_MAX >> leaf->prefix));
5107 iter->it.v3.data[1] = 0;
5108 iter->it.v3.data[3] = UINT64_MAX;
5109 }
5110 }
5111 #endif /* SK_ENABLE_IPV6 */
5112
5113
5114 /*
5115 * cmp = ipsetLeafCompareV4(leaf_a, leaf_b);
5116 * cmp = ipsetLeafCompareV6(leaf_a, leaf_b);
5117 *
5118 * Return -1, 0, 1 depending on whether the IP on leaf_a is less
5119 * than, equal to, or greater than the IP on leaf_b.
5120 *
5121 * This function compares the first IP in each leaf; it does not
5122 * consider the case where one leaf contains a netblock that is a
5123 * subset of the netblock on another leaf.
5124 */
5125 static int
ipsetLeafCompareV4(const void * va,const void * vb)5126 ipsetLeafCompareV4(
5127 const void *va,
5128 const void *vb)
5129 {
5130 const uint32_t a = ((const ipset_leaf_v4_t *)va)->ip;
5131 const uint32_t b = ((const ipset_leaf_v4_t *)vb)->ip;
5132 if (a < b) {
5133 return -1;
5134 }
5135 return (a > b);
5136 }
5137
5138 #if SK_ENABLE_IPV6
5139 static int
ipsetLeafCompareV6(const void * va,const void * vb)5140 ipsetLeafCompareV6(
5141 const void *va,
5142 const void *vb)
5143 {
5144 const ipset_ipv6_t *a = &((const ipset_leaf_v6_t *)va)->ip;
5145 const ipset_ipv6_t *b = &((const ipset_leaf_v6_t *)vb)->ip;
5146 if (a->ip[0] < b->ip[0]) {
5147 return -1;
5148 }
5149 if (a->ip[0] > b->ip[0]) {
5150 return 1;
5151 }
5152 if (a->ip[1] < b->ip[1]) {
5153 return -1;
5154 }
5155 return (a->ip[1] > b->ip[1]);
5156 }
5157 #endif /* SK_ENABLE_IPV6 */
5158
5159
5160 /*
5161 * status = ipsetMaskAddLeavesV4(ipset, mask_prefix, leaf);
5162 * status = ipsetMaskAddLeavesV6(ipset, mask_prefix, leaf);
5163 *
5164 * Helper function for ipsetMaskVx().
5165 *
5166 * Given 'leaf' that contains a CIDR block, remove 'leaf' from the
5167 * 'ipset' and add new leaves, where each new leaf is a single IP
5168 * address (a /32 or /128), and the step size between the IPs is
5169 * 1<<(32-mask_prefix) or 1<<(128-mask_prefix).
5170 *
5171 * Return SKIPSET_OK or SKIPSET_ERR_ALLOC.
5172 */
5173 static int
ipsetMaskAddLeavesV4(skipset_t * ipset,const uint32_t mask_prefix,ipset_leaf_v4_t * leaf)5174 ipsetMaskAddLeavesV4(
5175 skipset_t *ipset,
5176 const uint32_t mask_prefix,
5177 ipset_leaf_v4_t *leaf)
5178 {
5179 const uint32_t step = 1u << (32 - mask_prefix);
5180 uint32_t ipv4;
5181 uint32_t final;
5182 int rv;
5183
5184 /* get the ip address */
5185 ipv4 = leaf->ip;
5186
5187 /* compute the final ip address for our stopping condition */
5188 final = ((ipv4 | (UINT32_MAX >> leaf->prefix))
5189 & ~(UINT32_MAX >> mask_prefix));
5190
5191 /* set the prefix so this leaf is a single IP */
5192 leaf->prefix = 32;
5193
5194 while (ipv4 < final) {
5195 ipv4 += step;
5196 rv = ipsetInsertAddressV4(ipset, ipv4, 32, NULL);
5197 if (rv) {
5198 return rv;
5199 }
5200 }
5201 return SKIPSET_OK;
5202 }
5203
5204 #if SK_ENABLE_IPV6
5205 static int
ipsetMaskAddLeavesV6(skipset_t * ipset,const uint32_t mask_prefix,ipset_leaf_v6_t * leaf)5206 ipsetMaskAddLeavesV6(
5207 skipset_t *ipset,
5208 const uint32_t mask_prefix,
5209 ipset_leaf_v6_t *leaf)
5210 {
5211 ipset_ipv6_t ipv6;
5212 ipset_ipv6_t final;
5213 ipset_ipv6_t step;
5214 int rv;
5215
5216 /* get the first address in this block */
5217 ipv6.ip[0] = leaf->ip.ip[0];
5218 ipv6.ip[1] = leaf->ip.ip[1];
5219
5220 /* code in the bodies of the following if/else differ by size of
5221 * prefix */
5222 if (mask_prefix <= 64) {
5223 /* this affects only the most significant 64 bits */
5224 assert(leaf->prefix < 64);
5225
5226 /* determine the final address in this block */
5227 final.ip[0] = ((ipv6.ip[0] | (UINT64_MAX >> leaf->prefix))
5228 & ((mask_prefix < 64)
5229 ? ~(UINT64_MAX >> mask_prefix)
5230 : UINT64_MAX));
5231
5232 /* get the step size */
5233 step.ip[0] = UINT64_C(1) << (64 - mask_prefix);
5234
5235 /* modify starting leaf to be a single IP */
5236 leaf->prefix = 128;
5237
5238 while (ipv6.ip[0] < final.ip[0]) {
5239 ipv6.ip[0] += step.ip[0];
5240 rv = ipsetInsertAddressV6(ipset, &ipv6, 128, NULL);
5241 if (rv) { return rv; }
5242 }
5243
5244 } else if (leaf->prefix > 64) {
5245 /* this affects only the least significant 64 bits */
5246 assert(mask_prefix > 64);
5247
5248 /* determine the final address in this block */
5249 final.ip[1] = ((ipv6.ip[1] | (UINT64_MAX >> (leaf->prefix - 64)))
5250 & ~(UINT64_MAX >> (mask_prefix - 64)));
5251
5252 /* get the step size */
5253 step.ip[1] = UINT64_C(1) << (128 - mask_prefix);
5254
5255 /* modify starting leaf to be a single IP */
5256 leaf->prefix = 128;
5257
5258 while (ipv6.ip[1] < final.ip[1]) {
5259 ipv6.ip[1] += step.ip[1];
5260 rv = ipsetInsertAddressV6(ipset, &ipv6, 128, NULL);
5261 if (rv) { return rv; }
5262 }
5263
5264 } else {
5265 assert(mask_prefix > 64);
5266 assert(leaf->prefix <= 64);
5267
5268 /* determine the final address in this block */
5269 final.ip[0] = ipv6.ip[0] | ((leaf->prefix < 64)
5270 ? (UINT64_MAX >> leaf->prefix)
5271 : 0);
5272 final.ip[1] = ~(UINT64_MAX >> (mask_prefix - 64));
5273
5274 /* get the step size */
5275 step.ip[1] = UINT64_C(1) << (128 - mask_prefix);
5276
5277 /* modify starting leaf to be a single IP */
5278 leaf->prefix = 128;
5279
5280 while (ipv6.ip[0] < final.ip[0]) {
5281 if (ipv6.ip[1] <= UINT64_MAX - step.ip[1]) {
5282 ipv6.ip[1] += step.ip[1];
5283 } else {
5284 /* handle rollover */
5285 ++ipv6.ip[0];
5286 ipv6.ip[1] -= (UINT64_MAX - step.ip[1]) + 1;
5287 }
5288 rv = ipsetInsertAddressV6(ipset, &ipv6, 128, NULL);
5289 if (rv) { return rv; }
5290 }
5291 while (ipv6.ip[1] < final.ip[1]) {
5292 ipv6.ip[1] += step.ip[1];
5293 rv = ipsetInsertAddressV6(ipset, &ipv6, 128, NULL);
5294 if (rv) { return rv; }
5295 }
5296 }
5297
5298 return SKIPSET_OK;
5299 }
5300 #endif /* SK_ENABLE_IPV6 */
5301
5302
5303 /*
5304 * Helper function for skIPSetMask() when the IPset is implmented
5305 * by a SiLK-2 IPTree.
5306 *
5307 * Also a helper function for legacy skIPTreeMask().
5308 */
5309 static int
ipsetMaskIPTree(skIPTree_t * ipset,uint32_t mask)5310 ipsetMaskIPTree(
5311 skIPTree_t *ipset,
5312 uint32_t mask)
5313 {
5314 unsigned int i, j, k;
5315
5316 assert(ipset);
5317
5318 if (mask <= 16) {
5319 /* operate on multiple blocks */
5320 const unsigned int step = 1 << (16 - mask);
5321
5322 if (0 == mask) {
5323 /* no op */
5324 return SKIPSET_OK;
5325 }
5326 for (i = 0; i < SKIP_BBLOCK_COUNT; i += step) {
5327 /* use 'k' to visit each /16 in this /N (stored in 'i')
5328 * until we find one that contains data. if data is found,
5329 * set the first bit in 'i' to 1 and delete all blocks 'k'
5330 * where 'k' > 'i'. */
5331 for (k = i; k < i + step; ++k) {
5332 if (NULL != ipset->nodes[k]) {
5333 /* assumes any non-NULL IPTree node contains at
5334 * least one high bit */
5335 if (k > i) {
5336 ipset->nodes[i] = ipset->nodes[k];
5337 ipset->nodes[k] = NULL;
5338 }
5339 memset(ipset->nodes[i], 0, sizeof(skIPNode_t));
5340 ipset->nodes[i]->addressBlock[0] = 1;
5341 break;
5342 }
5343 }
5344 /* handle any remaining /16s in this /N */
5345 for (++k; k < i + step; ++k) {
5346 if (NULL != ipset->nodes[k]) {
5347 free(ipset->nodes[k]);
5348 ipset->nodes[k] = NULL;
5349 }
5350 }
5351 }
5352
5353 } else if (mask <= 27) {
5354 /* operate on multiple uint32_t's in each block */
5355 const unsigned int step = 1 << (27 - mask);
5356 const size_t len = sizeof(skIPNode_t) >> (mask - 16);
5357 skIPNode_t empty;
5358 memset(&empty, 0, len);
5359
5360 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
5361 if (NULL == ipset->nodes[i]) {
5362 /* no change */
5363
5364 } else {
5365 for (j = 0; j < SKIP_BBLOCK_SIZE; j += step) {
5366 if (memcmp(&ipset->nodes[i]->addressBlock[j], &empty, len))
5367 {
5368 memset(&ipset->nodes[i]->addressBlock[j], 0, len);
5369 ipset->nodes[i]->addressBlock[j] = 1;
5370 }
5371 }
5372 }
5373 }
5374
5375 } else if (mask < 32) {
5376 /* operate on bits within each uint32_t */
5377 const unsigned int step = 1 << (32 - mask);
5378 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
5379 if (NULL == ipset->nodes[i]) {
5380 /* no change */
5381
5382 } else {
5383 for (j = 0; j < SKIP_BBLOCK_SIZE; ++j) {
5384 for (k = 0; k < 32; k += step) {
5385 if (GET_MASKED_BITS(
5386 ipset->nodes[i]->addressBlock[j], k, step))
5387 {
5388 SET_MASKED_BITS(
5389 ipset->nodes[i]->addressBlock[j], 1, k, step);
5390 }
5391 }
5392 }
5393 }
5394 }
5395 }
5396
5397 return SKIPSET_OK;
5398 }
5399
5400 /*
5401 * status = ipsetMaskV4(ipset, mask_prefix)
5402 * status = ipsetMaskV6(ipset, mask_prefix)
5403 *
5404 * Helper function for skIPSetMask().
5405 *
5406 * For each block of size 'mask_prefix', if any IPs in that block
5407 * are set, remove all IPs in the block and replace with with a
5408 * single IP.
5409 */
5410 static int
ipsetMaskV4(skipset_t * ipset,const uint32_t mask_prefix)5411 ipsetMaskV4(
5412 skipset_t *ipset,
5413 const uint32_t mask_prefix)
5414 {
5415 ipset_node_v4_t *node;
5416 ipset_leaf_v4_t *leaf;
5417 uint32_t child_idx;
5418 uint32_t node_idx;
5419 uint32_t new_leaf_idx;
5420 uint32_t children_per_leaf;
5421 uint32_t ipv4;
5422 uint32_t i;
5423 uint32_t j;
5424 uint32_t depth;
5425 uint32_t to_visit[IPSET_MAX_DEPTH_V4];
5426 int rv = SKIPSET_OK;
5427
5428 ipset->is_dirty = 1;
5429
5430 /* handle case where root is a leaf */
5431 if (IPSET_ROOT_IS_LEAF(ipset)) {
5432 leaf = LEAF_PTR_V4(ipset, IPSET_ROOT_INDEX(ipset));
5433 if (leaf->prefix >= mask_prefix) {
5434 /* leaf spans fewer IPs than specified by 'mask_prefix'.
5435 * Modify the leaf's IP and prefix and return */
5436 leaf->ip &= ~(UINT32_MAX >> mask_prefix);
5437 leaf->prefix = 32;
5438 return SKIPSET_OK;
5439 }
5440 /* else, this leaf's prefix is more course (holds more IPs)
5441 * than what we want; we must split the leaf into multiple
5442 * nodes and leaves */
5443 return ipsetMaskAddLeavesV4(ipset, mask_prefix, leaf);
5444 }
5445
5446 /* handle case where root contains a node whose prefix is
5447 * more-precise than the 'mask_prefix' */
5448 node = NODE_PTR_V4(ipset, IPSET_ROOT_INDEX(ipset));
5449 if (node->prefix >= mask_prefix) {
5450 ipv4 = node->ip;
5451 new_leaf_idx = ipsetReplaceNodeWithLeaf(ipset, NULL, 0);
5452 leaf = LEAF_PTR_V4(ipset, new_leaf_idx);
5453 leaf->ip = ipv4 & ~(UINT32_MAX >> mask_prefix);
5454 leaf->prefix = 32;
5455 return SKIPSET_OK;
5456 }
5457
5458 /* visit the nodes in the tree */
5459 depth = 0;
5460 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
5461
5462 while (depth) {
5463 node_idx = to_visit[--depth];
5464 node = NODE_PTR_V4(ipset, node_idx);
5465
5466 if (mask_prefix - node->prefix > NUM_BITS) {
5467 /* this node is not at the bottom level of the tree; add
5468 * child nodes of this node to the 'to_visit' list. modify
5469 * any leaves to hold a single IP */
5470 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
5471 --i;
5472 if ((0 == node->child[i])
5473 || NODEPTR_CHILD_IS_REPEAT(node, i))
5474 {
5475 /* no-op */
5476 } else if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
5477 /* node; add to vist list unless its prefix is
5478 * larger than the mask, in which case replace
5479 * with a leaf */
5480 if (NODE_PTR_V4(ipset, node->child[i])->prefix
5481 <= mask_prefix)
5482 {
5483 to_visit[depth++] = node->child[i];
5484 } else {
5485 ipv4 = NODE_PTR_V4(ipset,node->child[i])->ip;
5486 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
5487 leaf = LEAF_PTR_V4(ipset, node->child[i]);
5488 leaf->ip = ipv4 & ~(UINT32_MAX >> mask_prefix);
5489 leaf->prefix = 32;
5490 }
5491 } else {
5492 leaf = LEAF_PTR_V4(ipset, node->child[i]);
5493 if (leaf->prefix >= mask_prefix) {
5494 leaf->ip &= ~(UINT32_MAX >> mask_prefix);
5495 leaf->prefix = 32;
5496 } else {
5497 /* this leaf's prefix is more course (holds
5498 * more IPs) than what we want; similar to
5499 * code above that handle leaf at the root */
5500
5501 if (NUM_BITS > leaf->prefix - node->prefix) {
5502 /* leaf occupies multiple child[] entries;
5503 * clear all but the current one */
5504 for (j = 1;
5505 ((j < (1u << (NUM_BITS -
5506 (leaf->prefix - node->prefix))))
5507 && ((i + j) < IPSET_NUM_CHILDREN));
5508 ++j)
5509 {
5510 node->child[i+j] = 0;
5511 }
5512 NODEPTR_CHILD_CLEAR_LEAF2(node, i + 1, i + j - 1);
5513 NODEPTR_CHILD_CLEAR_REPEAT2(node, i + 1, i + j - 1);
5514 }
5515 rv = ipsetMaskAddLeavesV4(ipset, mask_prefix, leaf);
5516 if (rv) { return rv; }
5517 node = NODE_PTR_V4(ipset, node_idx);
5518 }
5519 }
5520 }
5521
5522 } else if (mask_prefix - node->prefix == NUM_BITS) {
5523 /* this node is on the bottom level of the tree, and every
5524 * occupied child[] will become an independent leaf */
5525 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
5526 --i;
5527 if (node->child[i]) {
5528 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
5529 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
5530 } else if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
5531 if (ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx)){
5532 return SKIPSET_ERR_ALLOC;
5533 }
5534 node->child[i] = new_leaf_idx;
5535 NODEPTR_CHILD_CLEAR_REPEAT(node, i);
5536 }
5537 leaf = LEAF_PTR_V4(ipset, node->child[i]);
5538 leaf->ip = ((node->ip
5539 | (i << (32 - NUM_BITS - node->prefix)))
5540 & ~(UINT32_MAX >> mask_prefix));
5541 leaf->prefix = 32;
5542 }
5543 }
5544
5545 /* if node has a single child, we need to replace the node
5546 * with the child on the node's parent */
5547 ipsetFixNodeSingleChild(ipset, node_idx, 1);
5548
5549 } else {
5550 /* this node is on the bottom level of the tree. multiple
5551 * child[] entries will become a single leaf */
5552 children_per_leaf = 1u << (NUM_BITS- (mask_prefix - node->prefix));
5553 child_idx = UINT32_MAX;
5554 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
5555 for (j = 0; j < children_per_leaf; ++j) {
5556 --i;
5557 if (node->child[i]) {
5558 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
5559 if (UINT32_MAX == child_idx) {
5560 child_idx = IPSET_NUM_CHILDREN;
5561 }
5562 ipsetDestroySubtree(ipset, node->child[i], 1);
5563 node->child[i] = 0;
5564 } else if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
5565 if (UINT32_MAX == child_idx) {
5566 child_idx = IPSET_NUM_CHILDREN;
5567 }
5568 node->child[i] = 0;
5569 } else if (child_idx >= IPSET_NUM_CHILDREN) {
5570 child_idx = i;
5571 } else {
5572 LEAFIDX_FREE(ipset, node->child[child_idx]);
5573 NODEPTR_CHILD_CLEAR_LEAF(node, child_idx);
5574 node->child[child_idx] = 0;
5575 child_idx = i;
5576 }
5577 }
5578 }
5579
5580 /* the if() is entered when 'i' is looking at the
5581 * start of a group of child[] entries and any of the
5582 * child[] entries for this group of entries was
5583 * occupied. */
5584 if (child_idx != UINT32_MAX) {
5585 if (IPSET_NUM_CHILDREN == child_idx) {
5586 if (ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx)){
5587 return SKIPSET_ERR_ALLOC;
5588 }
5589 node->child[i] = new_leaf_idx;
5590 } else if (child_idx != i) {
5591 node->child[i] = node->child[child_idx];
5592 node->child[child_idx] = 0;
5593 }
5594 leaf = LEAF_PTR_V4(ipset, node->child[i]);
5595 leaf->ip = ((node->ip
5596 | (i << (32 - NUM_BITS - node->prefix)))
5597 & ~(UINT32_MAX >> mask_prefix));
5598 leaf->prefix = 32;
5599 NODEPTR_CHILD_SET_LEAF(node, i);
5600 NODEPTR_CHILD_CLEAR_LEAF2(node, i+1,
5601 i + children_per_leaf - 1);
5602 NODEPTR_CHILD_CLEAR_REPEAT2(node, i,
5603 i + children_per_leaf - 1);
5604
5605 /* reset for next group */
5606 child_idx = UINT32_MAX;
5607 }
5608 }
5609
5610 /* if node has a single child, we need to replace the node
5611 * with the child on the node's parent */
5612 ipsetFixNodeSingleChild(ipset, node_idx, 1);
5613 }
5614 }
5615
5616 return SKIPSET_OK;
5617 }
5618
5619 #if SK_ENABLE_IPV6
5620 static int
ipsetMaskV6(skipset_t * ipset,const uint32_t mask_prefix)5621 ipsetMaskV6(
5622 skipset_t *ipset,
5623 const uint32_t mask_prefix)
5624 {
5625 ipset_node_v6_t *node;
5626 ipset_leaf_v6_t *leaf;
5627 uint32_t child_idx;
5628 uint32_t node_idx;
5629 uint32_t new_leaf_idx;
5630 uint32_t children_per_leaf;
5631 ipset_ipv6_t ipv6;
5632 uint32_t i;
5633 uint32_t j;
5634 uint32_t depth;
5635 uint32_t to_visit[IPSET_MAX_DEPTH_V6];
5636 int rv = SKIPSET_OK;
5637
5638 ipset->is_dirty = 1;
5639
5640 /* handle case where root is a leaf */
5641 if (IPSET_ROOT_IS_LEAF(ipset)) {
5642 leaf = LEAF_PTR_V6(ipset, IPSET_ROOT_INDEX(ipset));
5643 if (leaf->prefix >= mask_prefix) {
5644 /* leaf spans fewer IPs than specified by 'mask_prefix'.
5645 * Modify the leaf's IP and prefix and return */
5646 IPSET_IPV6_APPLY_CIDR(&leaf->ip, mask_prefix);
5647 leaf->prefix = 128;
5648 return SKIPSET_OK;
5649 }
5650 /* else, this leaf's prefix is more course (holds more IPs)
5651 * than what we want; we must split the leaf into multiple
5652 * nodes and leaves */
5653 return ipsetMaskAddLeavesV6(ipset, mask_prefix, leaf);
5654 }
5655
5656 /* handle case where root contains a node whose prefix is
5657 * more-precise than the 'mask_prefix' */
5658 node = NODE_PTR_V6(ipset, IPSET_ROOT_INDEX(ipset));
5659 if (node->prefix >= mask_prefix) {
5660 IPSET_IPV6_COPY(&ipv6, &node->ip);
5661 new_leaf_idx = ipsetReplaceNodeWithLeaf(ipset, NULL, 0);
5662 leaf = LEAF_PTR_V6(ipset, new_leaf_idx);
5663 IPSET_IPV6_COPY_AND_MASK(&leaf->ip, &ipv6, mask_prefix);
5664 leaf->prefix = 128;
5665 return SKIPSET_OK;
5666 }
5667
5668 /* visit the nodes in the tree */
5669 depth = 0;
5670 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
5671
5672 while (depth) {
5673 node_idx = to_visit[--depth];
5674 node = NODE_PTR_V6(ipset, node_idx);
5675
5676 if (mask_prefix - node->prefix > NUM_BITS) {
5677 /* this node is not at the bottom level of the tree; add
5678 * child nodes of this node to the 'to_visit' list. modify
5679 * any leaves to hold a single IP. */
5680 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
5681 --i;
5682 if ((0 == node->child[i])
5683 || NODEPTR_CHILD_IS_REPEAT(node, i))
5684 {
5685 /* no-op */
5686 } else if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
5687 /* node; add to vist list unless its prefix is
5688 * larger than the mask, in which case replace
5689 * with a leaf */
5690 if (NODE_PTR_V6(ipset, node->child[i])->prefix
5691 <= mask_prefix)
5692 {
5693 to_visit[depth++] = node->child[i];
5694 } else {
5695 IPSET_IPV6_COPY(&ipv6,
5696 &NODE_PTR_V6(ipset,node->child[i])->ip);
5697 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
5698 leaf = LEAF_PTR_V6(ipset, node->child[i]);
5699 IPSET_IPV6_COPY_AND_MASK(&leaf->ip, &ipv6, mask_prefix);
5700 leaf->prefix = 128;
5701 }
5702 } else {
5703 leaf = LEAF_PTR_V6(ipset, node->child[i]);
5704 if (leaf->prefix >= mask_prefix) {
5705 IPSET_IPV6_APPLY_CIDR(&leaf->ip, mask_prefix);
5706 leaf->prefix = 128;
5707 } else {
5708 /* this leaf's prefix is more course (holds
5709 * more IPs) than what we want; similar to
5710 * code above that handle leaf at the root */
5711
5712 if (NUM_BITS > leaf->prefix - node->prefix) {
5713 /* leaf occupies multiple child[] entries;
5714 * clear all but the current one */
5715 for (j = 1;
5716 ((j < (1u << (NUM_BITS -
5717 (leaf->prefix - node->prefix))))
5718 && ((i + j) < IPSET_NUM_CHILDREN));
5719 ++j)
5720 {
5721 node->child[i+j] = 0;
5722 }
5723 NODEPTR_CHILD_CLEAR_LEAF2(node, i + 1, i + j - 1);
5724 NODEPTR_CHILD_CLEAR_REPEAT2(node, i + 1, i + j - 1);
5725 }
5726 rv = ipsetMaskAddLeavesV6(ipset, mask_prefix, leaf);
5727 if (rv) { return rv; }
5728 node = NODE_PTR_V6(ipset, node_idx);
5729 }
5730 }
5731 }
5732
5733 } else if (mask_prefix - node->prefix == NUM_BITS) {
5734 /* this node is on the bottom level of the tree, and every
5735 * occupied child[] will become an independent leaf */
5736 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
5737 --i;
5738 if (node->child[i]) {
5739 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
5740 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
5741 } else if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
5742 if (ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx)){
5743 return SKIPSET_ERR_ALLOC;
5744 }
5745 node->child[i] = new_leaf_idx;
5746 NODEPTR_CHILD_CLEAR_REPEAT(node, i);
5747 }
5748 leaf = LEAF_PTR_V6(ipset, node->child[i]);
5749 leaf->prefix = 128;
5750 if (node->prefix <= 64 - NUM_BITS) {
5751 leaf->ip.ip[0] = ((node->ip.ip[0]
5752 | (((uint64_t)i)
5753 << (64-NUM_BITS- node->prefix)))
5754 & ((mask_prefix < 64)
5755 ? ~(UINT64_MAX >> mask_prefix)
5756 : UINT64_MAX));
5757 leaf->ip.ip[1] = 0;
5758 } else {
5759 leaf->ip.ip[0] = node->ip.ip[0];
5760 leaf->ip.ip[1] = ((node->ip.ip[1]
5761 | (((uint64_t)i)
5762 << (128-NUM_BITS- node->prefix)))
5763 & ~(UINT64_MAX >> (mask_prefix-64)));
5764 }
5765 }
5766 }
5767
5768 /* if node has a single child, we need to replace the node
5769 * with the child on the node's parent */
5770 ipsetFixNodeSingleChild(ipset, node_idx, 1);
5771
5772 } else {
5773 /* this node is on the bottom level of the tree. multiple
5774 * child[] entries will become a single leaf */
5775 children_per_leaf = 1u << (NUM_BITS- (mask_prefix - node->prefix));
5776 child_idx = UINT32_MAX;
5777 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
5778 for (j = 0; j < children_per_leaf; ++j) {
5779 --i;
5780 if (node->child[i]) {
5781 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
5782 if (UINT32_MAX == child_idx) {
5783 child_idx = IPSET_NUM_CHILDREN;
5784 }
5785 ipsetDestroySubtree(ipset, node->child[i], 1);
5786 node->child[i] = 0;
5787 } else if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
5788 if (UINT32_MAX == child_idx) {
5789 child_idx = IPSET_NUM_CHILDREN;
5790 }
5791 node->child[i] = 0;
5792 } else if (child_idx >= IPSET_NUM_CHILDREN) {
5793 child_idx = i;
5794 } else {
5795 LEAFIDX_FREE(ipset, node->child[child_idx]);
5796 NODEPTR_CHILD_CLEAR_LEAF(node, child_idx);
5797 node->child[child_idx] = 0;
5798 child_idx = i;
5799 }
5800 }
5801 }
5802
5803 /* the if() is entered when 'i' is looking at the
5804 * start of a group of child[] entries and any of the
5805 * child[] entries for this group of entries was
5806 * occupied. */
5807 if (child_idx != UINT32_MAX) {
5808 if (IPSET_NUM_CHILDREN == child_idx) {
5809 if (ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx)){
5810 return SKIPSET_ERR_ALLOC;
5811 }
5812 node->child[i] = new_leaf_idx;
5813 } else if (child_idx != i) {
5814 node->child[i] = node->child[child_idx];
5815 node->child[child_idx] = 0;
5816 }
5817 leaf = LEAF_PTR_V6(ipset, node->child[i]);
5818 leaf->prefix = 128;
5819 if (node->prefix <= 64 - NUM_BITS) {
5820 leaf->ip.ip[0] = ((node->ip.ip[0]
5821 | (((uint64_t)i)
5822 << (64-NUM_BITS- node->prefix)))
5823 & ((mask_prefix < 64)
5824 ? ~(UINT64_MAX >> mask_prefix)
5825 : UINT64_MAX));
5826 leaf->ip.ip[1] = 0;
5827 } else {
5828 leaf->ip.ip[0] = node->ip.ip[0];
5829 leaf->ip.ip[1] = ((node->ip.ip[1]
5830 | (((uint64_t)i)
5831 << (128-NUM_BITS- node->prefix)))
5832 & ~(UINT64_MAX >> (mask_prefix-64)));
5833 }
5834 NODEPTR_CHILD_SET_LEAF(node, i);
5835 NODEPTR_CHILD_CLEAR_LEAF2(node, i+1,
5836 i + children_per_leaf - 1);
5837 NODEPTR_CHILD_CLEAR_REPEAT2(node, i,
5838 i + children_per_leaf - 1);
5839
5840 child_idx = UINT32_MAX;
5841 }
5842 }
5843
5844 /* if node has a single child, we need to replace the node
5845 * with the child on the node's parent */
5846 ipsetFixNodeSingleChild(ipset, node_idx, 1);
5847 }
5848 }
5849
5850 return SKIPSET_OK;
5851 }
5852 #endif /* SK_ENABLE_IPV6 */
5853
5854
5855 /*
5856 * status = ipsetMaskAndFillIPTree(ipset, mask_prefix)
5857 *
5858 * Helper function for skIPSetMaskAndFill().
5859 *
5860 * For each block of size 'mask_prefix', if any IPs in that block
5861 * are set, fill the entire block.
5862 */
5863 static int
ipsetMaskAndFillIPTree(skipset_t * ipset,const uint32_t mask_prefix)5864 ipsetMaskAndFillIPTree(
5865 skipset_t *ipset,
5866 const uint32_t mask_prefix)
5867 {
5868 unsigned int i, j, k;
5869 skIPTree_t *iptree;
5870
5871 assert(ipset);
5872 assert(1 == ipset->is_iptree);
5873 assert(0 == ipset->is_ipv6);
5874 assert(mask_prefix < 32 && mask_prefix > 0);
5875
5876 ipset->is_dirty = 1;
5877
5878 iptree = ipset->s.v2;
5879
5880 if (mask_prefix <= 16) {
5881 /* operate on multiple blocks */
5882 const unsigned int step = 1 << (16 - mask_prefix);
5883
5884 if (0 == mask_prefix) {
5885 /* no op */
5886 return SKIPSET_OK;
5887 }
5888 for (i = 0; i < SKIP_BBLOCK_COUNT; i += step) {
5889 /* use 'k' to visit each /16 in this /N (stored in 'i')
5890 * until we find one that contains data. if data is found,
5891 * set each /16 to a completely full node. */
5892
5893 /* assumes any non-NULL IPTree node contains at least one
5894 * high bit */
5895 for (k = i; (k < i + step) && (NULL == iptree->nodes[k]); ++k)
5896 ; /* empty */
5897 if (k < i + step) {
5898 for (k = i; k < i + step; ++k) {
5899 IPTREE_NODE_ALLOC(iptree, k);
5900 memset(iptree->nodes[k]->addressBlock, 0xff,
5901 sizeof(iptree->nodes[k]->addressBlock));
5902 }
5903 }
5904 }
5905
5906 } else if (mask_prefix <= 27) {
5907 /* operate on multiple uint32_t's in each block */
5908 const unsigned int step = 1 << (27 - mask_prefix);
5909 const size_t len = sizeof(skIPNode_t) >> (mask_prefix - 16);
5910 skIPNode_t empty;
5911 memset(&empty, 0, len);
5912
5913 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
5914 if (NULL == iptree->nodes[i]) {
5915 /* no change */
5916
5917 } else {
5918 for (j = 0; j < SKIP_BBLOCK_SIZE; j += step) {
5919 if (memcmp(&iptree->nodes[i]->addressBlock[j], &empty,len))
5920 {
5921 memset(&iptree->nodes[i]->addressBlock[j], 0xFF, len);
5922 }
5923 }
5924 }
5925 }
5926
5927 } else if (mask_prefix < 32) {
5928 /* operate on bits within each uint32_t */
5929 const unsigned int step = 1 << (32 - mask_prefix);
5930 const int32_t full = UINT32_MAX >> (32 - step);
5931
5932 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
5933 if (NULL == iptree->nodes[i]) {
5934 /* no change */
5935
5936 } else {
5937 for (j = 0; j < SKIP_BBLOCK_SIZE; ++j) {
5938 for (k = 0; k < 32; k += step) {
5939 if (GET_MASKED_BITS(iptree->nodes[i]->addressBlock[j],
5940 k, step))
5941 {
5942 SET_MASKED_BITS(iptree->nodes[i]->addressBlock[j],
5943 full, k, step);
5944 }
5945 }
5946 }
5947 }
5948 }
5949 }
5950
5951 return SKIPSET_OK;
5952 }
5953
5954
5955 /*
5956 * status = ipsetMaskAndFillV4(ipset, mask_prefix)
5957 * status = ipsetMaskAndFillV6(ipset, mask_prefix)
5958 *
5959 * Helper function for skIPSetMaskAndFill().
5960 *
5961 * For each block of size 'mask_prefix', if any IPs in that block
5962 * are set, fill the entire block.
5963 */
5964 static int
ipsetMaskAndFillV4(skipset_t * ipset,const uint32_t mask_prefix)5965 ipsetMaskAndFillV4(
5966 skipset_t *ipset,
5967 const uint32_t mask_prefix)
5968 {
5969 ipset_node_v4_t *node;
5970 ipset_leaf_v4_t *leaf;
5971 uint32_t child_idx;
5972 uint32_t node_idx;
5973 uint32_t new_leaf_idx;
5974 uint32_t children_per_leaf;
5975 uint32_t ipv4;
5976 uint32_t i;
5977 uint32_t j;
5978 uint32_t depth;
5979 uint32_t to_visit[IPSET_MAX_DEPTH_V4];
5980
5981 ipset->is_dirty = 1;
5982
5983 /* handle case where root is a leaf */
5984 if (IPSET_ROOT_IS_LEAF(ipset)) {
5985 leaf = LEAF_PTR_V4(ipset, IPSET_ROOT_INDEX(ipset));
5986 if (leaf->prefix > mask_prefix) {
5987 /* leaf spans fewer IPs than specified by 'mask_prefix'.
5988 * Modify the leaf's IP and prefix and return */
5989 leaf->ip &= ~(UINT32_MAX >> mask_prefix);
5990 leaf->prefix = mask_prefix;
5991 return SKIPSET_OK;
5992 }
5993 /* else, this leaf's prefix is more course (holds more IPs)
5994 * than the mask_prefix, and there is no need to change it. */
5995 return SKIPSET_OK;
5996 }
5997
5998 /* handle case where root contains a node whose prefix is
5999 * more-precise than the 'mask_prefix' */
6000 node = NODE_PTR_V4(ipset, IPSET_ROOT_INDEX(ipset));
6001 if (node->prefix >= mask_prefix) {
6002 ipv4 = node->ip;
6003 new_leaf_idx = ipsetReplaceNodeWithLeaf(ipset, NULL, 0);
6004 leaf = LEAF_PTR_V4(ipset, new_leaf_idx);
6005 leaf->ip = ipv4 & ~(UINT32_MAX >> mask_prefix);
6006 leaf->prefix = mask_prefix;
6007 return SKIPSET_OK;
6008 }
6009
6010 /* visit the nodes in the tree */
6011 depth = 0;
6012 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
6013
6014 while (depth) {
6015 node_idx = to_visit[--depth];
6016 node = NODE_PTR_V4(ipset, node_idx);
6017
6018 if (mask_prefix - node->prefix > NUM_BITS) {
6019 /* this node is not at the bottom level of the tree; add
6020 * child nodes of this node to the 'to_visit' list. modify
6021 * any leaves to hold a single block */
6022 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
6023 --i;
6024 if ((0 == node->child[i])
6025 || NODEPTR_CHILD_IS_REPEAT(node, i))
6026 {
6027 /* no-op */
6028 } else if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
6029 /* node; add to vist list unless its prefix is
6030 * larger than or equal to the mask, in which case
6031 * replace with a leaf */
6032 if (NODE_PTR_V4(ipset, node->child[i])->prefix
6033 < mask_prefix)
6034 {
6035 to_visit[depth++] = node->child[i];
6036 } else {
6037 ipv4 = NODE_PTR_V4(ipset,node->child[i])->ip;
6038 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
6039 leaf = LEAF_PTR_V4(ipset, node->child[i]);
6040 leaf->ip = ipv4 & ~(UINT32_MAX >> mask_prefix);
6041 leaf->prefix = mask_prefix;
6042 }
6043 } else {
6044 leaf = LEAF_PTR_V4(ipset, node->child[i]);
6045 if (leaf->prefix > mask_prefix) {
6046 leaf->ip &= ~(UINT32_MAX >> mask_prefix);
6047 leaf->prefix = mask_prefix;
6048 }
6049 }
6050 }
6051
6052 } else if (mask_prefix - node->prefix == NUM_BITS) {
6053 /* this node is on the bottom level of the tree, and every
6054 * occupied child[] will become an independent leaf */
6055 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
6056 --i;
6057 if (node->child[i]
6058 && !NODEPTR_CHILD_IS_REPEAT(node, i))
6059 {
6060 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
6061 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
6062 leaf = LEAF_PTR_V4(ipset, node->child[i]);
6063 } else {
6064 leaf = LEAF_PTR_V4(ipset, node->child[i]);
6065 if (leaf->prefix <= mask_prefix) {
6066 continue;
6067 }
6068 }
6069 leaf->ip = ((node->ip
6070 | (i << (32 - NUM_BITS - node->prefix)))
6071 & ~(UINT32_MAX >> mask_prefix));
6072 leaf->prefix = mask_prefix;
6073 }
6074 }
6075
6076 } else {
6077 /* this node is on the bottom level of the tree. multiple
6078 * child[] entries will become a single leaf */
6079 children_per_leaf = 1u << (NUM_BITS- (mask_prefix - node->prefix));
6080 child_idx = UINT32_MAX;
6081 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
6082 for (j = 0; j < children_per_leaf; ++j) {
6083 --i;
6084 if (node->child[i]) {
6085 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
6086 if (UINT32_MAX == child_idx) {
6087 child_idx = IPSET_NUM_CHILDREN;
6088 }
6089 ipsetDestroySubtree(ipset, node->child[i], 1);
6090 } else if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
6091 leaf = LEAF_PTR_V4(ipset, node->child[i]);
6092 if (leaf->prefix <= mask_prefix) {
6093 assert(0 == j);
6094 i -= children_per_leaf - 1;
6095 break;
6096 }
6097 if (UINT32_MAX == child_idx) {
6098 child_idx = IPSET_NUM_CHILDREN;
6099 }
6100 node->child[i] = 0;
6101 } else if (child_idx >= IPSET_NUM_CHILDREN) {
6102 child_idx = i;
6103 } else {
6104 LEAFIDX_FREE(ipset, node->child[child_idx]);
6105 node->child[child_idx] = 0;
6106 child_idx = i;
6107 }
6108 }
6109 }
6110
6111 /* the if() is entered when 'i' is looking at the
6112 * start of a group of child[] entries and any of the
6113 * child[] entries for this group of entries was
6114 * occupied. */
6115 if (child_idx != UINT32_MAX) {
6116 if (IPSET_NUM_CHILDREN == child_idx) {
6117 if (ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx)){
6118 return SKIPSET_ERR_ALLOC;
6119 }
6120 node->child[i] = new_leaf_idx;
6121 } else if (child_idx != i) {
6122 node->child[i] = node->child[child_idx];
6123 }
6124 leaf = LEAF_PTR_V4(ipset, node->child[i]);
6125 leaf->ip = ((node->ip
6126 | (i << (32 - NUM_BITS - node->prefix)))
6127 & ~(UINT32_MAX >> mask_prefix));
6128 leaf->prefix = mask_prefix;
6129 NODEPTR_CHILD_SET_LEAF2(node, i,
6130 i + children_per_leaf - 1);
6131 NODEPTR_CHILD_SET_REPEAT2(node, i+1,
6132 i + children_per_leaf - 1);
6133 for (j = 1; j < children_per_leaf; ++j) {
6134 node->child[i + j] = node->child[i];
6135 }
6136 /* reset for next group */
6137 child_idx = UINT32_MAX;
6138 }
6139 }
6140 }
6141 }
6142
6143 return SKIPSET_OK;
6144 }
6145
6146 #if SK_ENABLE_IPV6
6147 static int
ipsetMaskAndFillV6(skipset_t * ipset,const uint32_t mask_prefix)6148 ipsetMaskAndFillV6(
6149 skipset_t *ipset,
6150 const uint32_t mask_prefix)
6151 {
6152 ipset_node_v6_t *node;
6153 ipset_leaf_v6_t *leaf;
6154 uint32_t child_idx;
6155 uint32_t node_idx;
6156 uint32_t new_leaf_idx;
6157 uint32_t children_per_leaf;
6158 ipset_ipv6_t ipv6;
6159 uint32_t i;
6160 uint32_t j;
6161 uint32_t depth;
6162 uint32_t to_visit[IPSET_MAX_DEPTH_V6];
6163
6164 ipset->is_dirty = 1;
6165
6166 /* handle case where root is a leaf */
6167 if (IPSET_ROOT_IS_LEAF(ipset)) {
6168 leaf = LEAF_PTR_V6(ipset, IPSET_ROOT_INDEX(ipset));
6169 if (leaf->prefix > mask_prefix) {
6170 /* leaf spans fewer IPs than specified by 'mask_prefix'.
6171 * Modify the leaf's IP and prefix and return */
6172 IPSET_IPV6_APPLY_CIDR(&leaf->ip, mask_prefix);
6173 leaf->prefix = mask_prefix;
6174 return SKIPSET_OK;
6175 }
6176 /* else, this leaf's prefix is more course (holds more IPs)
6177 * than the mask_prefix, and there is no need to change it */
6178 return SKIPSET_OK;
6179 }
6180
6181 /* handle case where root contains a node whose prefix is
6182 * more-precise than the 'mask_prefix' */
6183 node = NODE_PTR_V6(ipset, IPSET_ROOT_INDEX(ipset));
6184 if (node->prefix >= mask_prefix) {
6185 IPSET_IPV6_COPY(&ipv6, &node->ip);
6186 new_leaf_idx = ipsetReplaceNodeWithLeaf(ipset, NULL, 0);
6187 leaf = LEAF_PTR_V6(ipset, new_leaf_idx);
6188 IPSET_IPV6_COPY_AND_MASK(&leaf->ip, &ipv6, mask_prefix);
6189 leaf->prefix = mask_prefix;
6190 return SKIPSET_OK;
6191 }
6192
6193 /* visit the nodes in the tree */
6194 depth = 0;
6195 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
6196
6197 while (depth) {
6198 node_idx = to_visit[--depth];
6199 node = NODE_PTR_V6(ipset, node_idx);
6200
6201 if (mask_prefix - node->prefix > NUM_BITS) {
6202 /* this node is not at the bottom level of the tree; add
6203 * child nodes of this node to the 'to_visit' list. modify
6204 * any leaves to hold a single block. */
6205 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
6206 --i;
6207 if ((0 == node->child[i])
6208 || NODEPTR_CHILD_IS_REPEAT(node, i))
6209 {
6210 /* no-op */
6211 } else if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
6212 /* node; add to vist list unless its prefix is
6213 * larger than or equal to the mask, in which case
6214 * replace with a leaf */
6215 if (NODE_PTR_V6(ipset, node->child[i])->prefix
6216 < mask_prefix)
6217 {
6218 to_visit[depth++] = node->child[i];
6219 } else {
6220 IPSET_IPV6_COPY(&ipv6,
6221 &NODE_PTR_V6(ipset,node->child[i])->ip);
6222 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
6223 leaf = LEAF_PTR_V6(ipset, node->child[i]);
6224 IPSET_IPV6_COPY_AND_MASK(&leaf->ip, &ipv6, mask_prefix);
6225 leaf->prefix = mask_prefix;
6226 }
6227 } else {
6228 leaf = LEAF_PTR_V6(ipset, node->child[i]);
6229 if (leaf->prefix > mask_prefix) {
6230 IPSET_IPV6_APPLY_CIDR(&leaf->ip, mask_prefix);
6231 leaf->prefix = mask_prefix;
6232 }
6233 }
6234 }
6235
6236 } else if (mask_prefix - node->prefix == NUM_BITS) {
6237 /* this node is on the bottom level of the tree, and every
6238 * occupied child[] will become an independent leaf */
6239 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
6240 --i;
6241 if (node->child[i]
6242 && !NODEPTR_CHILD_IS_REPEAT(node, i))
6243 {
6244 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
6245 ipsetReplaceNodeWithLeaf(ipset,(ipset_node_t*)node,i);
6246 leaf = LEAF_PTR_V6(ipset, node->child[i]);
6247 } else {
6248 leaf = LEAF_PTR_V6(ipset, node->child[i]);
6249 if (leaf->prefix <= mask_prefix) {
6250 continue;
6251 }
6252 }
6253 leaf->prefix = mask_prefix;
6254 if (node->prefix <= 64 - NUM_BITS) {
6255 leaf->ip.ip[0] = ((node->ip.ip[0]
6256 | (((uint64_t)i)
6257 << (64-NUM_BITS- node->prefix)))
6258 & ((mask_prefix < 64)
6259 ? ~(UINT64_MAX >> mask_prefix)
6260 : UINT64_MAX));
6261 leaf->ip.ip[1] = 0;
6262 } else {
6263 leaf->ip.ip[0] = node->ip.ip[0];
6264 leaf->ip.ip[1] = ((node->ip.ip[1]
6265 | (((uint64_t)i)
6266 << (128-NUM_BITS- node->prefix)))
6267 & ~(UINT64_MAX >> (mask_prefix-64)));
6268 }
6269 }
6270 }
6271
6272 } else {
6273 /* this node is on the bottom level of the tree. multiple
6274 * child[] entries will become a single leaf */
6275 children_per_leaf = 1u << (NUM_BITS- (mask_prefix - node->prefix));
6276 child_idx = UINT32_MAX;
6277 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
6278 for (j = 0; j < children_per_leaf; ++j) {
6279 --i;
6280 if (node->child[i]) {
6281 if (!NODEPTR_CHILD_IS_LEAF(node, i)) {
6282 if (UINT32_MAX == child_idx) {
6283 child_idx = IPSET_NUM_CHILDREN;
6284 }
6285 ipsetDestroySubtree(ipset, node->child[i], 1);
6286 } else if (NODEPTR_CHILD_IS_REPEAT(node, i)) {
6287 leaf = LEAF_PTR_V6(ipset, node->child[i]);
6288 if (leaf->prefix <= mask_prefix) {
6289 assert(0 == j);
6290 i -= children_per_leaf - 1;
6291 break;
6292 }
6293 if (UINT32_MAX == child_idx) {
6294 child_idx = IPSET_NUM_CHILDREN;
6295 }
6296 } else if (child_idx >= IPSET_NUM_CHILDREN) {
6297 child_idx = i;
6298 } else {
6299 LEAFIDX_FREE(ipset, node->child[child_idx]);
6300 NODEPTR_CHILD_CLEAR_LEAF(node, child_idx);
6301 child_idx = i;
6302 }
6303 }
6304 }
6305
6306 /* the if() is entered when 'i' is looking at the
6307 * start of a group of child[] entries and any of the
6308 * child[] entries for this group of entries was
6309 * occupied. */
6310 if (child_idx != UINT32_MAX) {
6311 if (IPSET_NUM_CHILDREN == child_idx) {
6312 if (ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx)){
6313 return SKIPSET_ERR_ALLOC;
6314 }
6315 node->child[i] = new_leaf_idx;
6316 } else if (child_idx != i) {
6317 node->child[i] = node->child[child_idx];
6318 }
6319 leaf = LEAF_PTR_V6(ipset, node->child[i]);
6320 leaf->prefix = mask_prefix;
6321 if (node->prefix <= 64 - NUM_BITS) {
6322 leaf->ip.ip[0] = ((node->ip.ip[0]
6323 | (((uint64_t)i)
6324 << (64-NUM_BITS- node->prefix)))
6325 & ((mask_prefix < 64)
6326 ? ~(UINT64_MAX >> mask_prefix)
6327 : UINT64_MAX));
6328 leaf->ip.ip[1] = 0;
6329 } else {
6330 leaf->ip.ip[0] = node->ip.ip[0];
6331 leaf->ip.ip[1] = ((node->ip.ip[1]
6332 | (((uint64_t)i)
6333 << (128-NUM_BITS- node->prefix)))
6334 & ~(UINT64_MAX >> (mask_prefix-64)));
6335 }
6336 NODEPTR_CHILD_SET_LEAF2(node, i,
6337 i + children_per_leaf - 1);
6338 NODEPTR_CHILD_SET_REPEAT2(node, i+1,
6339 i + children_per_leaf - 1);
6340 for (j = 1; j < children_per_leaf; ++j) {
6341 node->child[i + j] = node->child[i];
6342 }
6343
6344 child_idx = UINT32_MAX;
6345 }
6346 }
6347 }
6348 }
6349
6350 return SKIPSET_OK;
6351 }
6352 #endif /* SK_ENABLE_IPV6 */
6353
6354
6355 /*
6356 * status = ipsetNewEntries(ipset, num_nodes, num_leaves, node_indexes, leaf_indexes);
6357 *
6358 * Determine where 'num_nodes' new nodes and 'num_leaves' new
6359 * leaves can be stored and return the index(es) to that/those
6360 * location(s) in the arrays specified by the 'node_indexes' and
6361 * 'leaf_indexes' parameters. The new nodes and leaves will be
6362 * zeroed before returning.
6363 *
6364 * When a size value is 0, its corresponding array may be NULL.
6365 *
6366 * If a value is 0, its array will not be modified, so any pointers
6367 * into that array remain valid. Specifically, if you have a
6368 * handle to a node and request new leaves, the handle to the node
6369 * remains valid.
6370 *
6371 * Uses space at the end of the currently allocated arrays first,
6372 * then returns entries from the free list. Finally, calls
6373 * ipsetAllocEntries() if no nodes or leaves are available. Return
6374 * 0 on success, or SKIPSET_ERR_ALLOC on failure.
6375 *
6376 * If the leaves buffer is reallocated, this function sets the
6377 * 'realloc_leaves' bit on the 'ipset'.
6378 */
6379 static int
ipsetNewEntries(skipset_t * ipset,uint32_t num_nodes,uint32_t num_leaves,uint32_t * node_indexes,uint32_t * leaf_indexes)6380 ipsetNewEntries(
6381 skipset_t *ipset,
6382 uint32_t num_nodes,
6383 uint32_t num_leaves,
6384 uint32_t *node_indexes,
6385 uint32_t *leaf_indexes)
6386 #ifndef IPSET_DEBUG_MEMORY
6387 {
6388 /* this is the normal function defintion of ipsetNewEntries() */
6389
6390 assert(ipset);
6391 assert(ipset->s.v3->nodes.entry_capacity >= ipset->s.v3->nodes.entry_count);
6392 assert(ipset->s.v3->leaves.entry_capacity
6393 >= ipset->s.v3->leaves.entry_count);
6394
6395 if (num_leaves <= (ipset->s.v3->leaves.entry_capacity
6396 - ipset->s.v3->leaves.entry_count))
6397 {
6398 /* grab leaves from end of the "fresh" memory */
6399 while (num_leaves) {
6400 *leaf_indexes = ipset->s.v3->leaves.entry_count;
6401 ++ipset->s.v3->leaves.entry_count;
6402 ++leaf_indexes;
6403 --num_leaves;
6404 }
6405 if (num_nodes) {
6406 goto ALLOC_NODES;
6407 }
6408 return SKIPSET_OK;
6409 }
6410 while (num_leaves && (ipset->s.v3->leaves.entry_count
6411 < ipset->s.v3->leaves.entry_capacity))
6412 {
6413 /* grab as many leaves from end of the "fresh" memory as we can */
6414 *leaf_indexes = ipset->s.v3->leaves.entry_count;
6415 ++ipset->s.v3->leaves.entry_count;
6416 ++leaf_indexes;
6417 --num_leaves;
6418 }
6419 while (num_leaves && ipset->s.v3->leaves.free_list) {
6420 /* grab as many leaves from the free list as we can */
6421 ipset_leaf_t *leaf;
6422 *leaf_indexes = ipset->s.v3->leaves.free_list;
6423 leaf = LEAF_PTR(ipset, *leaf_indexes);
6424 ipset->s.v3->leaves.free_list = LEAFPTR_FREE_LIST(leaf);
6425 memset(leaf, 0, ipset->s.v3->leaves.entry_size);
6426 ++leaf_indexes;
6427 --num_leaves;
6428 }
6429 if (num_leaves) {
6430 /* allocate new memory and use it; set the flag to denote that
6431 * new leaves have been allocated. */
6432 if (ipset->s.v3->leaves.entry_capacity > 0) {
6433 ipset->s.v3->realloc_leaves = 1;
6434 }
6435 do {
6436 if (ipsetAllocEntries(&ipset->s.v3->leaves, 0)) {
6437 return SKIPSET_ERR_ALLOC;
6438 }
6439 while (num_leaves && (ipset->s.v3->leaves.entry_count
6440 < ipset->s.v3->leaves.entry_capacity))
6441 {
6442 *leaf_indexes = ipset->s.v3->leaves.entry_count;
6443 ++ipset->s.v3->leaves.entry_count;
6444 ++leaf_indexes;
6445 --num_leaves;
6446 }
6447 } while (num_leaves);
6448 }
6449
6450 ALLOC_NODES:
6451 if (num_nodes
6452 <= (ipset->s.v3->nodes.entry_capacity - ipset->s.v3->nodes.entry_count))
6453 {
6454 /* grab nodes from end of the "fresh" memory */
6455 while (num_nodes) {
6456 *node_indexes = ipset->s.v3->nodes.entry_count;
6457 ++ipset->s.v3->nodes.entry_count;
6458 ++node_indexes;
6459 --num_nodes;
6460 }
6461 return SKIPSET_OK;
6462 }
6463 while (num_nodes && (ipset->s.v3->nodes.entry_count
6464 < ipset->s.v3->nodes.entry_capacity))
6465 {
6466 /* grab as many nodes from end of the "fresh" memory as we can */
6467 *node_indexes = ipset->s.v3->nodes.entry_count;
6468 ++ipset->s.v3->nodes.entry_count;
6469 ++node_indexes;
6470 --num_nodes;
6471 }
6472 while (num_nodes && ipset->s.v3->nodes.free_list) {
6473 /* grab as many nodes from the free list as we can */
6474 ipset_node_t *node;
6475 *node_indexes = ipset->s.v3->nodes.free_list;
6476 node = NODE_PTR(ipset, *node_indexes);
6477 ipset->s.v3->nodes.free_list = NODEPTR_FREE_LIST(node);
6478 memset(node, 0, ipset->s.v3->nodes.entry_size);
6479 ++node_indexes;
6480 --num_nodes;
6481 }
6482 while (num_nodes) {
6483 /* allocate new memory and use it */
6484 if (ipsetAllocEntries(&ipset->s.v3->nodes, 0)) {
6485 return SKIPSET_ERR_ALLOC;
6486 }
6487 while (num_nodes && (ipset->s.v3->nodes.entry_count
6488 < ipset->s.v3->nodes.entry_capacity))
6489 {
6490 *node_indexes = ipset->s.v3->nodes.entry_count;
6491 ++ipset->s.v3->nodes.entry_count;
6492 ++node_indexes;
6493 --num_nodes;
6494 }
6495 }
6496
6497 return SKIPSET_OK;
6498 }
6499 #else /* #ifndef IPSET_DEBUG_MEMORY */
6500 {
6501 /*
6502 * This is a debugging defintion of ipsetNewEntries().
6503 *
6504 * This definition uses the free list first, so we properly
6505 * handle cases where a call to ipsetNewEntries() follows a call
6506 * to ipsetDestroySubtree(). (The calling code does not expect
6507 * the ipsetNewEntries() call to fail in this case.)
6508 *
6509 * If additional nodes and/or leaves are required, the function
6510 * moves the location of the nodes and/or leaves array(s). The
6511 * objective is to find places the in code that are holding a
6512 * stale pointer---that is, places that do not properly handle
6513 * the case where a realloc may occur.
6514 *
6515 * In addition, the function allocates only as many nodes/leaves
6516 * as are requested, so writing beyond the array can be detected
6517 * by memory checkers.
6518 */
6519
6520 void *new_mem;
6521 uint32_t new_size;
6522
6523 assert(ipset);
6524 assert(ipset->s.v3->nodes.entry_capacity >= ipset->s.v3->nodes.entry_count);
6525 assert(ipset->s.v3->leaves.entry_capacity
6526 >= ipset->s.v3->leaves.entry_count);
6527
6528 if (num_leaves) {
6529 while (num_leaves && ipset->s.v3->leaves.free_list) {
6530 ipset_leaf_t *leaf;
6531 *leaf_indexes = ipset->s.v3->leaves.free_list;
6532 leaf = LEAF_PTR(ipset, *leaf_indexes);
6533 ipset->s.v3->leaves.free_list = LEAFPTR_FREE_LIST(leaf);
6534 memset(leaf, 0, ipset->s.v3->leaves.entry_size);
6535 ++leaf_indexes;
6536 --num_leaves;
6537 }
6538 if (num_leaves) {
6539 if (ipset->s.v3->leaves.entry_capacity
6540 && ((ipset->s.v3->leaves.entry_capacity + num_leaves)
6541 % IPSET_INITIAL_ENTRY_COUNT) < num_leaves)
6542 {
6543 ipset->s.v3->realloc_leaves = 1;
6544 }
6545 new_size = ipset->s.v3->leaves.entry_capacity + num_leaves;
6546 if (new_size > SIZE_MAX / ipset->s.v3->leaves.entry_size) {
6547 return SKIPSET_ERR_ALLOC;
6548 }
6549 new_mem = malloc(new_size * ipset->s.v3->leaves.entry_size);
6550 if (!new_mem) {
6551 return SKIPSET_ERR_ALLOC;
6552 }
6553 if (ipset->s.v3->leaves.buf) {
6554 memcpy(new_mem, ipset->s.v3->leaves.buf,
6555 (ipset->s.v3->leaves.entry_count
6556 * ipset->s.v3->leaves.entry_size));
6557 free(ipset->s.v3->leaves.buf);
6558 }
6559 ipset->s.v3->leaves.buf = new_mem;
6560 ipset->s.v3->leaves.entry_capacity = new_size;
6561 do {
6562 *leaf_indexes = ipset->s.v3->leaves.entry_count;
6563 memset(LEAF_PTR(ipset, *leaf_indexes), 0,
6564 ipset->s.v3->leaves.entry_size);
6565 ++ipset->s.v3->leaves.entry_count;
6566 ++leaf_indexes;
6567 --num_leaves;
6568 assert(ipset->s.v3->leaves.entry_capacity
6569 >= ipset->s.v3->leaves.entry_count);
6570 } while (num_leaves);
6571 }
6572 }
6573
6574 if (num_nodes) {
6575 while (num_nodes && ipset->s.v3->nodes.free_list) {
6576 ipset_node_t *node;
6577 *node_indexes = ipset->s.v3->nodes.free_list;
6578 node = NODE_PTR(ipset, *node_indexes);
6579 ipset->s.v3->nodes.free_list = NODEPTR_FREE_LIST(node);
6580 memset(node, 0, ipset->s.v3->nodes.entry_size);
6581 ++node_indexes;
6582 --num_nodes;
6583 }
6584 if (num_nodes) {
6585 new_size = ipset->s.v3->nodes.entry_capacity + num_nodes;
6586 if (new_size > SIZE_MAX / ipset->s.v3->nodes.entry_size) {
6587 return SKIPSET_ERR_ALLOC;
6588 }
6589 new_mem = malloc(new_size * ipset->s.v3->nodes.entry_size);
6590 if (!new_mem) {
6591 return SKIPSET_ERR_ALLOC;
6592 }
6593 if (ipset->s.v3->nodes.buf) {
6594 memcpy(new_mem, ipset->s.v3->nodes.buf,
6595 (ipset->s.v3->nodes.entry_count
6596 * ipset->s.v3->nodes.entry_size));
6597 free(ipset->s.v3->nodes.buf);
6598 }
6599 ipset->s.v3->nodes.buf = new_mem;
6600 ipset->s.v3->nodes.entry_capacity = new_size;
6601 do {
6602 *node_indexes = ipset->s.v3->nodes.entry_count;
6603 memset(NODE_PTR(ipset, *node_indexes), 0,
6604 ipset->s.v3->nodes.entry_size);
6605 ++ipset->s.v3->nodes.entry_count;
6606 ++node_indexes;
6607 --num_nodes;
6608 assert(ipset->s.v3->nodes.entry_capacity
6609 >= ipset->s.v3->nodes.entry_count);
6610 } while (num_nodes);
6611 }
6612 }
6613
6614 return SKIPSET_OK;
6615 }
6616 #endif /* #else of #ifndef IPSET_DEBUG_MEMORY */
6617
6618
6619 /*
6620 * status = ipsetOptionsHandler(cData, opt_index, opt_arg);
6621 *
6622 * Parse an option that was registered by skIPSetOptionsRegister().
6623 * Return 0 on success, or non-zero on failure.
6624 */
6625 static int
ipsetOptionsHandler(clientData cData,int opt_index,char * opt_arg)6626 ipsetOptionsHandler(
6627 clientData cData,
6628 int opt_index,
6629 char *opt_arg)
6630 {
6631 skipset_options_t *ipset_opts = (skipset_options_t*)cData;
6632 uint32_t tmp32;
6633 int rv;
6634
6635 assert(ipset_options_record_version[0].name);
6636
6637 switch (opt_index) {
6638 case OPT_IPSET_RECORD_VERSION:
6639 rv = skStringParseUint32(&tmp32, opt_arg, IPSET_REC_VERSION_MIN,
6640 IPSET_REC_VERSION_MAX);
6641 if (rv) {
6642 skAppPrintErr("Invalid %s '%s': %s",
6643 ipset_options_record_version[0].name, opt_arg,
6644 skStringParseStrerror(rv));
6645 return -1;
6646 }
6647 if (1 == tmp32) {
6648 skAppPrintErr("Invalid %s '%s': Illegal version number",
6649 ipset_options_record_version[0].name,
6650 opt_arg);
6651 return -1;
6652 }
6653 ipset_opts->record_version = (uint16_t)tmp32;
6654 break;
6655
6656 case OPT_IPSET_INVOCATION_STRIP:
6657 ipset_opts->invocation_strip = 1;
6658 break;
6659
6660 default:
6661 skAbortBadCase(opt_index);
6662 }
6663
6664 return 0;
6665 }
6666
6667
6668 /*
6669 * status = ipsetPrintCallback(ip, prefix, &print_state);
6670 *
6671 * Helper function for skIPSetPrint().
6672 *
6673 * Print a textual representation of the 'ip' and 'prefix'. The
6674 * stream to print to and the format to use are present in the
6675 * 'print_state' argument.
6676 */
6677 static int
ipsetPrintCallback(skipaddr_t * ip,uint32_t prefix,void * v_print_state)6678 ipsetPrintCallback(
6679 skipaddr_t *ip,
6680 uint32_t prefix,
6681 void *v_print_state)
6682 {
6683 ipset_print_t *print_state = (ipset_print_t*)v_print_state;
6684 char ipbuf[SKIPADDR_STRLEN+1];
6685 int rv = SKIPSET_OK;
6686
6687 /* print ip and its prefix, then return */
6688 skipaddrString(ipbuf, ip, print_state->ip_format);
6689 if (skipaddrIsV6(ip) ? (prefix == 128) : (prefix == 32)) {
6690 if (skStreamPrint(print_state->stream, "%s\n", ipbuf)) {
6691 rv = SKIPSET_ERR_FILEIO;
6692 }
6693 } else {
6694 if (skStreamPrint(print_state->stream, ("%s/%" PRIu32 "\n"),
6695 ipbuf, prefix))
6696 {
6697 rv = SKIPSET_ERR_FILEIO;
6698 }
6699 }
6700
6701 return rv;
6702 }
6703
6704
6705 /*
6706 * status = ipsetProcessStreamBmapSlash24(baseip, bmap, swap_flag,proc_state);
6707 * status = ipsetProcessStreamBmapSlash120(baseip, bmap,swap_flag,proc_state);
6708 *
6709 * Helper function for ipsetProcessStreamClassc(),
6710 * ipsetProcessStreamCidrbmapV4(), ipsetProcessStreamCidrbmapV6(),
6711 * and ipsetProcessStreamSlash64().
6712 *
6713 * Process the bitmap of 256 bits in 'bmap' that represents the
6714 * IPv4 /24 or the IPv6 /120 in 'baseip'. For each address or CIDR
6715 * block in the bitmap, use ipsetProcessStreamCallback() to invoke
6716 * the callback function specified in 'proc_state'. When the
6717 * 'swap_flag' parameter is true, the values in 'bmap' are not in
6718 * native byte order.
6719 */
6720 static int
ipsetProcessStreamBmapSlash24(uint32_t slash24,uint32_t bmap[8],int swap_flag,ipset_walk_t * proc_stream_state)6721 ipsetProcessStreamBmapSlash24(
6722 uint32_t slash24,
6723 uint32_t bmap[8],
6724 int swap_flag,
6725 ipset_walk_t *proc_stream_state)
6726 {
6727 uint32_t ipv4;
6728 uint32_t trail_zero;
6729 uint32_t i;
6730 int rv = SKIPSET_OK;
6731
6732 /* loop over the uint32_t in this block */
6733 i = 0;
6734 while (i < 8) {
6735 if (0 == bmap[i]) {
6736 ++i;
6737 continue;
6738 }
6739 ipv4 = slash24 | (i << 5);
6740 if (UINT32_MAX == bmap[i]) {
6741 /* Check for a longer run of high bits by checking the
6742 * value in adjacent uint32_t's. */
6743 if ((i & 0x1) || (UINT32_MAX != bmap[i+1])) {
6744 /* either i is odd or cannot create a run of 64 */
6745 rv = (ipsetProcessStreamCallback(
6746 NULL, &ipv4, 27, proc_stream_state));
6747 ++i;
6748 } else if ((i & 0x3)
6749 || memcmp(&bmap[i+2], bmap256_full, sizeof(uint32_t)*2))
6750 {
6751 /* either i is 2 or 6 or cannot create a run of 128 */
6752 rv = (ipsetProcessStreamCallback(
6753 NULL, &ipv4, 26, proc_stream_state));
6754 i += 2;
6755 } else {
6756 rv = (ipsetProcessStreamCallback(
6757 NULL, &ipv4, 25, proc_stream_state));
6758 i += 4;
6759 }
6760 if (rv) { goto END; }
6761 } else {
6762 if (swap_flag) {
6763 bmap[i] = BSWAP32(bmap[i]);
6764 }
6765 while (bmap[i]) {
6766 /* find position of least significant bit */
6767 trail_zero = ipsetCountTrailingZeros(bmap[i]);
6768 ipv4 += trail_zero;
6769 bmap[i] >>= trail_zero;
6770 /* find number of consecutive high bits that map into a
6771 * CIDR block */
6772 switch (ipv4 & 0x1F) {
6773 case 0: case 16:
6774 if ((bmap[i] & 0xFFFF) == 0xFFFF) {
6775 rv = (ipsetProcessStreamCallback(
6776 NULL, &ipv4, 28, proc_stream_state));
6777 bmap[i] >>= 16;
6778 ipv4 += 16;
6779 break;
6780 }
6781 /* FALLTHROUGH */
6782 case 8: case 24:
6783 if ((bmap[i] & 0xFF) == 0xFF) {
6784 rv = (ipsetProcessStreamCallback(
6785 NULL, &ipv4, 29, proc_stream_state));
6786 bmap[i] >>= 8;
6787 ipv4 += 8;
6788 break;
6789 }
6790 /* FALLTHROUGH */
6791 case 4: case 12: case 20: case 28:
6792 if ((bmap[i] & 0xF) == 0xF) {
6793 rv = (ipsetProcessStreamCallback(
6794 NULL, &ipv4, 30, proc_stream_state));
6795 bmap[i] >>= 4;
6796 ipv4 += 4;
6797 break;
6798 }
6799 /* FALLTHROUGH */
6800 case 2: case 6: case 10: case 14:
6801 case 18: case 22: case 26: case 30:
6802 if ((bmap[i] & 0x3) == 0x3) {
6803 rv = (ipsetProcessStreamCallback(
6804 NULL, &ipv4, 31, proc_stream_state));
6805 bmap[i] >>= 2;
6806 ipv4 += 2;
6807 break;
6808 }
6809 /* FALLTHROUGH */
6810 default:
6811 rv = (ipsetProcessStreamCallback(
6812 NULL, &ipv4, 32, proc_stream_state));
6813 bmap[i] >>= 1;
6814 ++ipv4;
6815 break;
6816 }
6817 if (rv) { goto END; }
6818 }
6819 }
6820 }
6821 END:
6822 return rv;
6823 }
6824
6825 #if SK_ENABLE_IPV6
6826 /* an IPv6 version of previous function */
6827 static int
ipsetProcessStreamBmapSlash120(const ipset_ipv6_t * slash120,uint32_t bmap[8],int swap_flag,ipset_walk_t * proc_stream_state)6828 ipsetProcessStreamBmapSlash120(
6829 const ipset_ipv6_t *slash120,
6830 uint32_t bmap[8],
6831 int swap_flag,
6832 ipset_walk_t *proc_stream_state)
6833 {
6834 ipset_ipv6_t ipv6;
6835 uint32_t trail_zero;
6836 uint32_t i;
6837 int rv = SKIPSET_OK;
6838
6839 ipv6.ip[0] = slash120->ip[0];
6840
6841 i = 0;
6842 while (i < 8) {
6843 if (0 == bmap[i]) {
6844 ++i;
6845 continue;
6846 }
6847 ipv6.ip[1] = slash120->ip[1] | (i << 5);
6848 if (UINT32_MAX == bmap[i]) {
6849 if ((i & 0x1) || (UINT32_MAX != bmap[i+1])) {
6850 rv = (ipsetProcessStreamCallback(
6851 &ipv6, NULL, 123, proc_stream_state));
6852 ++i;
6853 } else if ((i & 0x3)
6854 || memcmp(&bmap[i+2], bmap256_full,
6855 sizeof(uint32_t)*2))
6856 {
6857 rv = (ipsetProcessStreamCallback(
6858 &ipv6, NULL, 122, proc_stream_state));
6859 i += 2;
6860 } else {
6861 rv = (ipsetProcessStreamCallback(
6862 &ipv6, NULL, 121, proc_stream_state));
6863 i += 4;
6864 }
6865 if (rv) { goto END; }
6866 } else {
6867 if (swap_flag) {
6868 bmap[i] = BSWAP32(bmap[i]);
6869 }
6870 while (bmap[i]) {
6871 trail_zero = ipsetCountTrailingZeros(bmap[i]);
6872 ipv6.ip[1] += trail_zero;
6873 bmap[i] >>= trail_zero;
6874 switch (ipv6.ip[1] & 0x1F) {
6875 case 0: case 16:
6876 if ((bmap[i] & 0xFFFF) == 0xFFFF) {
6877 rv = (ipsetProcessStreamCallback(
6878 &ipv6, NULL, 124, proc_stream_state));
6879 bmap[i] >>= 16;
6880 ipv6.ip[1] += 16;
6881 break;
6882 }
6883 /* FALLTHROUGH */
6884 case 8: case 24:
6885 if ((bmap[i] & 0xFF) == 0xFF) {
6886 rv = (ipsetProcessStreamCallback(
6887 &ipv6, NULL, 125, proc_stream_state));
6888 bmap[i] >>= 8;
6889 ipv6.ip[1] += 8;
6890 break;
6891 }
6892 /* FALLTHROUGH */
6893 case 4: case 12: case 20: case 28:
6894 if ((bmap[i] & 0xF) == 0xF) {
6895 rv = (ipsetProcessStreamCallback(
6896 &ipv6, NULL, 126, proc_stream_state));
6897 bmap[i] >>= 4;
6898 ipv6.ip[1] += 4;
6899 break;
6900 }
6901 /* FALLTHROUGH */
6902 case 2: case 6: case 10: case 14:
6903 case 18: case 22: case 26: case 30:
6904 if ((bmap[i] & 0x3) == 0x3) {
6905 rv = (ipsetProcessStreamCallback(
6906 &ipv6, NULL, 127, proc_stream_state));
6907 bmap[i] >>= 2;
6908 ipv6.ip[1] += 2;
6909 break;
6910 }
6911 /* FALLTHROUGH */
6912 default:
6913 rv = (ipsetProcessStreamCallback(
6914 &ipv6, NULL, 128, proc_stream_state));
6915 bmap[i] >>= 1;
6916 ++ipv6.ip[1];
6917 break;
6918 }
6919 if (rv) { goto END; }
6920 }
6921 }
6922 }
6923 END:
6924 return rv;
6925 }
6926 #endif /* SK_ENABLE_IPV6 */
6927
6928
6929 /*
6930 * status = ipsetProcessStreamCallback(ipv6, ipv4, prefix, proc_stream_state);
6931 *
6932 * Helper function for ipsetProcessStreamClassc(),
6933 * ipsetProcessStreamRadix(), ipsetProcessStreamCallbackV4(), and
6934 * ipsetProcessStreamCidrbmapV6().
6935 *
6936 * Convert the IP address in 'ipv4' or 'ipv6' to an skipaddr_t and
6937 * invoke the callback function specified in 'proc_stream_state'.
6938 *
6939 * The 'cidr_block' member of 'proc_stream_state' determines
6940 * whether the callback is invoked for the entire CIDR block or for
6941 * each IP in the block. In addition, the 'v6policy' member
6942 * controls how to represent the IP address.
6943 *
6944 * The code in assert()s that 'ipv6' is in the ::ffff:0:0/96
6945 * netblock when 'v6policy' is SK_IPV6POLICY_ASV4.
6946 */
6947 static int
ipsetProcessStreamCallback(const ipset_ipv6_t * v6_start,const uint32_t * v4_start,uint32_t prefix,ipset_walk_t * proc_stream_state)6948 ipsetProcessStreamCallback(
6949 const ipset_ipv6_t *v6_start,
6950 const uint32_t *v4_start,
6951 uint32_t prefix,
6952 ipset_walk_t *proc_stream_state)
6953 {
6954 #if SK_ENABLE_IPV6
6955 ipset_ipv6_t tmp_ipv6;
6956 uint32_t tmp_ipv4;
6957 #endif
6958 skipaddr_t ipaddr;
6959 int rv;
6960
6961 assert((v6_start && !v4_start)
6962 || (!v6_start && v4_start));
6963 assert(proc_stream_state);
6964
6965 if ((proc_stream_state->cidr_blocks)
6966 || (v4_start && 32 == prefix)
6967 || (v6_start && 128 == prefix))
6968 {
6969 #if SK_ENABLE_IPV6
6970 if (v6_start) {
6971 assert(prefix <= 128);
6972 assert(NULL == v4_start);
6973 if (proc_stream_state->v6policy >= SK_IPV6POLICY_MIX) {
6974 IPSET_IPV6_TO_ADDR(v6_start, &ipaddr);
6975 } else {
6976 assert(SK_IPV6POLICY_ASV4 == proc_stream_state->v6policy);
6977 IPSET_IPV6_TO_ADDR_V4(v6_start, &ipaddr);
6978 assert(prefix >= 96);
6979 prefix -= 96;
6980 }
6981 } else if (SK_IPV6POLICY_FORCE == proc_stream_state->v6policy) {
6982 assert(prefix <= 32);
6983 assert(NULL == v6_start);
6984 assert(v4_start);
6985 skipaddrSetV6FromUint32(&ipaddr, v4_start);
6986 prefix += 96;
6987 } else
6988 #endif /* SK_ENABLE_IPV6 */
6989 {
6990 assert(prefix <= 32);
6991 assert(NULL == v6_start);
6992 assert(v4_start);
6993 assert(proc_stream_state->v6policy <= SK_IPV6POLICY_MIX);
6994 skipaddrSetV4(&ipaddr, v4_start);
6995 }
6996 /* invoke the callback */
6997 return proc_stream_state->callback(&ipaddr, prefix,
6998 proc_stream_state->cb_data);
6999 }
7000 /* else we must invoke the callback on every IP */
7001
7002 /* first adjust the IP address according to the ipv6-policy */
7003 switch (proc_stream_state->v6policy) {
7004 case SK_IPV6POLICY_MIX:
7005 break;
7006
7007 case SK_IPV6POLICY_IGNORE:
7008 assert(NULL == v6_start);
7009 #if SK_ENABLE_IPV6
7010 skAbort();
7011 #endif
7012 break;
7013
7014 case SK_IPV6POLICY_ONLY:
7015 assert(NULL == v4_start);
7016 #if !SK_ENABLE_IPV6
7017 skAbort();
7018 #endif
7019 break;
7020
7021 case SK_IPV6POLICY_ASV4:
7022 #if SK_ENABLE_IPV6
7023 if (v6_start) {
7024 assert(prefix >= 96 && prefix <= 128);
7025 prefix -= 96;
7026 IPSET_IPV6_TO_ADDR_V4(v6_start, &ipaddr);
7027 tmp_ipv4 = skipaddrGetV4(&ipaddr);
7028 v4_start = &tmp_ipv4;
7029 v6_start = NULL;
7030 }
7031 #endif /* SK_ENABLE_IPV6 */
7032 break;
7033
7034 case SK_IPV6POLICY_FORCE:
7035 #if !SK_ENABLE_IPV6
7036 skAbort();
7037 #else
7038 if (v4_start) {
7039 assert(prefix <= 32);
7040 skipaddrSetV4(&ipaddr, v4_start);
7041 IPSET_IPV6_FROM_ADDRV4(&tmp_ipv6, &ipaddr);
7042 v6_start = &tmp_ipv6;
7043 v4_start = NULL;
7044 }
7045 #endif /* SK_ENABLE_IPV6 */
7046 break;
7047 }
7048
7049 #if SK_ENABLE_IPV6
7050 if (v6_start) {
7051 ipset_ipv6_t ipv6;
7052 ipset_ipv6_t fin6;
7053
7054 assert(NULL == v4_start);
7055
7056 /* convert CIDR block to start (ipv6) and final (fin6) */
7057 if (prefix > 64) {
7058 assert(prefix <= 128);
7059 ipv6.ip[0] = fin6.ip[0] = v6_start->ip[0];
7060 ipv6.ip[1] = v6_start->ip[1];
7061 fin6.ip[1] = (v6_start->ip[1] | (UINT64_MAX >> (prefix - 64)));
7062 } else if (prefix == 64) {
7063 ipv6.ip[0] = fin6.ip[0] = v6_start->ip[0];
7064 ipv6.ip[1] = 0;
7065 fin6.ip[1] = UINT64_MAX;
7066 } else {
7067 ipv6.ip[0] = v6_start->ip[0];
7068 fin6.ip[0] = (v6_start->ip[0] | (UINT64_MAX >> prefix));
7069 ipv6.ip[1] = 0;
7070 fin6.ip[1] = UINT64_MAX;
7071 }
7072 for (;;) {
7073 IPSET_IPV6_TO_ADDR(&ipv6, &ipaddr);
7074 rv = proc_stream_state->callback(&ipaddr, 128,
7075 proc_stream_state->cb_data);
7076 if (rv) {
7077 break;
7078 }
7079 if (ipv6.ip[0] < fin6.ip[0]) {
7080 if (ipv6.ip[1] < UINT64_MAX) {
7081 ++ipv6.ip[1];
7082 } else {
7083 ++ipv6.ip[0];
7084 ipv6.ip[1] = 0;
7085 }
7086 } else if (ipv6.ip[1] < fin6.ip[1]) {
7087 ++ipv6.ip[1];
7088 } else {
7089 break;
7090 }
7091 }
7092 } else
7093 #endif /* SK_ENABLE_IPV6 */
7094 {
7095 uint64_t num_ips;
7096
7097 assert(prefix <= 32);
7098 assert(NULL == v6_start);
7099 assert(v4_start);
7100
7101 num_ips = UINT64_C(1) << (32 - prefix);
7102
7103 skipaddrSetV4(&ipaddr, v4_start);
7104 do {
7105 rv = proc_stream_state->callback(&ipaddr, 32,
7106 proc_stream_state->cb_data);
7107 skipaddrIncrement(&ipaddr);
7108 } while (0 == rv && --num_ips > 0);
7109 }
7110 return rv;
7111 }
7112
7113
7114 /*
7115 * status = ipsetProcessStreamCidrbmapV4(stream, hdr, proc_stream_state);
7116 * status = ipsetProcessStreamCidrbmapV6(stream, hdr, proc_stream_state);
7117 *
7118 * Helper function for skIPSetProcessStream() and
7119 * ipsetReadCidrbmapInto...().
7120 *
7121 * Treat 'stream' as an IPset in the IPSET_REC_VERSION_CIDRBMAP
7122 * format and process all the IPs and CIDR blocks it contains
7123 * without reading the entire IPset into memory. The header of the
7124 * stream is in 'hdr'. The callback to invoke is available in
7125 * 'proc_stream_state'.
7126 *
7127 * See '#define IPSET_REC_VERSION_CIDRBMAP' for description of the
7128 * file format.
7129 */
7130 static int
ipsetProcessStreamCidrbmapV4(skstream_t * stream,sk_file_header_t * hdr,ipset_walk_t * proc_stream_state)7131 ipsetProcessStreamCidrbmapV4(
7132 skstream_t *stream,
7133 sk_file_header_t *hdr,
7134 ipset_walk_t *proc_stream_state)
7135 {
7136 sk_header_entry_t *hentry;
7137 uint8_t read_buf[sizeof(uint32_t) + sizeof(uint8_t)];
7138 uint32_t bmap[IPTREE_WORDS_PER_SLASH24];
7139 int swap_flag;
7140 uint32_t slash24;
7141 ssize_t b;
7142 int rv;
7143
7144 /* sanity check input */
7145 assert(stream);
7146 assert(hdr);
7147 assert(proc_stream_state);
7148 if (skStreamCheckSilkHeader(stream, FT_IPSET, IPSET_REC_VERSION_CIDRBMAP,
7149 IPSET_REC_VERSION_CIDRBMAP, NULL))
7150 {
7151 skAbort();
7152 }
7153 if (skHeaderGetRecordLength(hdr) != 1) {
7154 skAbort();
7155 }
7156 hentry = skHeaderGetFirstMatch(hdr, SK_HENTRY_IPSET_ID);
7157 if (NULL == hentry) {
7158 skAbort();
7159 }
7160 if (sizeof(uint32_t) != ipsetHentryGetLeafSize(hentry)) {
7161 skAbort();
7162 }
7163
7164 swap_flag = !skHeaderIsNativeByteOrder(hdr);
7165
7166 while ((b = skStreamRead(stream, read_buf, sizeof(read_buf)))
7167 == sizeof(read_buf))
7168 {
7169 if (swap_flag) {
7170 slash24 = BSWAP32(*(uint32_t*)read_buf);
7171 } else {
7172 slash24 = *(uint32_t*)read_buf;
7173 }
7174 /* handle the prefix bit */
7175 if (read_buf[sizeof(uint32_t)] <= 32) {
7176 /* IPv4 and one byte that is CIDR block */
7177 rv = ipsetProcessStreamCallback(NULL, &slash24,
7178 read_buf[sizeof(uint32_t)],
7179 proc_stream_state);
7180 if (rv) { goto END; }
7181 } else if (read_buf[sizeof(uint32_t)] != SET_CIDRBMAP_MAP256) {
7182 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7183 read_buf[sizeof(uint32_t)]);
7184 rv = SKIPSET_ERR_FILEIO;
7185 goto END;
7186 } else {
7187 /* IPv4 base address and 256-bit bitmap */
7188 if ((b = skStreamRead(stream, bmap, sizeof(bmap)))
7189 != sizeof(bmap))
7190 {
7191 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
7192 " bytes returned %" SK_PRIdZ),
7193 sizeof(bmap), b);
7194 rv = SKIPSET_ERR_FILEIO;
7195 goto END;
7196 }
7197 /* handle the block */
7198 rv = ipsetProcessStreamBmapSlash24(slash24, bmap, swap_flag,
7199 proc_stream_state);
7200 if (rv) { goto END; }
7201 }
7202 }
7203 if (b != 0) {
7204 /* read error */
7205 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
7206 " bytes returned %" SK_PRIdZ),
7207 sizeof(read_buf), b);
7208 rv = SKIPSET_ERR_FILEIO;
7209 goto END;
7210 }
7211
7212 /* Success */
7213 rv = SKIPSET_OK;
7214
7215 END:
7216 return rv;
7217 }
7218
7219 #if SK_ENABLE_IPV6
7220 static int
ipsetProcessStreamCidrbmapV6(skstream_t * stream,sk_file_header_t * hdr,ipset_walk_t * proc_stream_state)7221 ipsetProcessStreamCidrbmapV6(
7222 skstream_t *stream,
7223 sk_file_header_t *hdr,
7224 ipset_walk_t *proc_stream_state)
7225 {
7226 sk_header_entry_t *hentry;
7227 uint8_t read_buf[IPSET_LEN_V6 + sizeof(uint8_t)];
7228 uint32_t bmap[IPTREE_WORDS_PER_SLASH24];
7229 int swap_flag;
7230 ipset_ipv6_t slash120;
7231 ssize_t b;
7232 int no_more_ipv4 = 0;
7233 int rv;
7234
7235 /* sanity check input */
7236 assert(stream);
7237 assert(hdr);
7238 assert(proc_stream_state);
7239 if (skStreamCheckSilkHeader(stream, FT_IPSET, IPSET_REC_VERSION_CIDRBMAP,
7240 IPSET_REC_VERSION_CIDRBMAP, NULL))
7241 {
7242 skAbort();
7243 }
7244 if (skHeaderGetRecordLength(hdr) != 1) {
7245 skAbort();
7246 }
7247 hentry = skHeaderGetFirstMatch(hdr, SK_HENTRY_IPSET_ID);
7248 if (NULL == hentry) {
7249 skAbort();
7250 }
7251 if (IPSET_LEN_V6 != ipsetHentryGetLeafSize(hentry)) {
7252 skAbort();
7253 }
7254
7255 swap_flag = !skHeaderIsNativeByteOrder(hdr);
7256
7257 while ((b = skStreamRead(stream, read_buf, sizeof(read_buf)))
7258 == sizeof(read_buf))
7259 {
7260 IPSET_IPV6_FROM_ARRAY(&slash120, read_buf);
7261
7262 if (SK_IPV6POLICY_ASV4 == proc_stream_state->v6policy) {
7263 if (0 == read_buf[IPSET_LEN_V6]
7264 || read_buf[IPSET_LEN_V6] > SET_CIDRBMAP_MAP256)
7265 {
7266 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7267 read_buf[IPSET_LEN_V6]);
7268 rv = SKIPSET_ERR_FILEIO;
7269 goto END;
7270 }
7271 if (slash120.ip[0] > 0
7272 || slash120.ip[1] > UINT64_C(0x0000ffffffffffff))
7273 {
7274 no_more_ipv4 = 1;
7275 break;
7276 }
7277 if (slash120.ip[1] < UINT64_C(0x0000ffff00000000)) {
7278 /* IP is below ::ffff:0:0 */
7279 if (read_buf[IPSET_LEN_V6] == SET_CIDRBMAP_MAP256) {
7280 /* Read and skip the 256-bit bitmap */
7281 if ((b = skStreamRead(stream, bmap, sizeof(bmap)))
7282 != sizeof(bmap))
7283 {
7284 ipsetReadStrerrror(stream,
7285 ("Attempting to read %" SK_PRIuZ
7286 " bytes returned %" SK_PRIdZ),
7287 sizeof(bmap), b);
7288 rv = SKIPSET_ERR_FILEIO;
7289 goto END;
7290 }
7291 }
7292 continue;
7293 }
7294 }
7295 /* handle the prefix bit */
7296 if (read_buf[IPSET_LEN_V6] <= 128) {
7297 if (0 == read_buf[IPSET_LEN_V6]) {
7298 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7299 read_buf[IPSET_LEN_V6]);
7300 rv = SKIPSET_ERR_FILEIO;
7301 goto END;
7302 }
7303 /* IPv6 and one byte CIDR prefix */
7304 rv = ipsetProcessStreamCallback(&slash120, NULL,
7305 read_buf[IPSET_LEN_V6],
7306 proc_stream_state);
7307 if (rv) { goto END; }
7308 } else if (read_buf[IPSET_LEN_V6] != SET_CIDRBMAP_MAP256) {
7309 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7310 read_buf[IPSET_LEN_V6]);
7311 rv = SKIPSET_ERR_FILEIO;
7312 goto END;
7313 } else {
7314 /* IPv6 base address and 256-bit bitmap */
7315 if ((b = skStreamRead(stream, bmap, sizeof(bmap)))
7316 != sizeof(bmap))
7317 {
7318 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
7319 " bytes returned %" SK_PRIdZ),
7320 sizeof(bmap), b);
7321 rv = SKIPSET_ERR_FILEIO;
7322 goto END;
7323 }
7324 /* handle the block */
7325 rv = ipsetProcessStreamBmapSlash120(&slash120, bmap, swap_flag,
7326 proc_stream_state);
7327 if (rv) { goto END; }
7328 }
7329 }
7330 if (b != 0) {
7331 if (no_more_ipv4 && b == sizeof(read_buf)) {
7332 /* not an error; we exited the loop via a break; */
7333 } else {
7334 /* read error */
7335 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
7336 " bytes returned %" SK_PRIdZ),
7337 sizeof(read_buf), b);
7338 rv = SKIPSET_ERR_FILEIO;
7339 goto END;
7340 }
7341 }
7342
7343 /* Success */
7344 rv = SKIPSET_OK;
7345
7346 END:
7347 return rv;
7348 }
7349 #endif /* SK_ENABLE_IPV6 */
7350
7351
7352 /*
7353 * status = ipsetProcessStreamCidrbmap(stream, hdr, proc_stream_state);
7354 *
7355 * Helper function for skIPSetProcessStream().
7356 *
7357 * Treat 'stream' as an IPset in the IPSET_REC_VERSION_CIDRBMAP
7358 * format and process all the IPs and CIDR blocks it contains
7359 * without reading the entire IPset into memory. The header of the
7360 * stream is in 'hdr'. The callback to invoke is available in
7361 * 'proc_stream_state'.
7362 *
7363 * See '#define IPSET_REC_VERSION_CIDRBMAP' for description of the
7364 * file format.
7365 */
7366 static int
ipsetProcessStreamCidrbmap(skstream_t * stream,sk_file_header_t * hdr,ipset_walk_t * proc_stream_state)7367 ipsetProcessStreamCidrbmap(
7368 skstream_t *stream,
7369 sk_file_header_t *hdr,
7370 ipset_walk_t *proc_stream_state)
7371 {
7372 sk_header_entry_t *hentry;
7373
7374 /* sanity check input */
7375 assert(stream);
7376 assert(hdr);
7377 assert(proc_stream_state);
7378 if (skStreamCheckSilkHeader(stream, FT_IPSET, IPSET_REC_VERSION_CIDRBMAP,
7379 IPSET_REC_VERSION_CIDRBMAP, NULL))
7380 {
7381 skAbort();
7382 }
7383 if (skHeaderGetRecordLength(hdr) != 1) {
7384 skAbort();
7385 }
7386
7387 /* read and verify the header */
7388 hentry = skHeaderGetFirstMatch(hdr, SK_HENTRY_IPSET_ID);
7389 if (NULL == hentry) {
7390 skAbort();
7391 }
7392 /* most sizes are zero */
7393 if (0 != ipsetHentryGetChildPerNode(hentry)
7394 || 0 != ipsetHentryGetRootIndex(hentry)
7395 || 0 != ipsetHentryGetNodeCount(hentry)
7396 || 0 != ipsetHentryGetNodeSize(hentry)
7397 || 0 != ipsetHentryGetLeafCount(hentry))
7398 {
7399 skAbort();
7400 }
7401 if (sizeof(uint32_t) == ipsetHentryGetLeafSize(hentry)) {
7402 return ipsetProcessStreamCidrbmapV4(stream, hdr, proc_stream_state);
7403 }
7404 #if SK_ENABLE_IPV6
7405 if (IPSET_LEN_V6 == ipsetHentryGetLeafSize(hentry)) {
7406 return ipsetProcessStreamCidrbmapV6(stream, hdr, proc_stream_state);
7407 }
7408 #endif
7409
7410 /* Unrecognized record size */
7411 skAbort();
7412 }
7413
7414
7415 /*
7416 * status = ipsetProcessStreamClassc(stream, hdr, proc_stream_state);
7417 *
7418 * Helper function for skIPSetProcessStream() and
7419 * ipsetReadClasscIntoRadix()
7420 *
7421 * Treat 'stream' as an IPset in the IPSET_REC_VERSION_CLASSC
7422 * format and process all the IPs and CIDR blocks it contains
7423 * without reading the entire IPset into memory. The header of the
7424 * stream is in 'hdr'. The callback to invoke is available in
7425 * 'proc_stream_state'.
7426 *
7427 * See '#define IPSET_REC_VERSION_CLASSC' for description of the
7428 * file format.
7429 */
7430 static int
ipsetProcessStreamClassc(skstream_t * stream,sk_file_header_t * hdr,ipset_walk_t * proc_stream_state)7431 ipsetProcessStreamClassc(
7432 skstream_t *stream,
7433 sk_file_header_t *hdr,
7434 ipset_walk_t *proc_stream_state)
7435 {
7436 int swap_flag;
7437 uint32_t contig_start;
7438 uint32_t contig_length;
7439 uint32_t contig_max;
7440 uint32_t contig_cidr;
7441 uint32_t block24[1+IPTREE_WORDS_PER_SLASH24];
7442 uint32_t trail_zero;
7443 uint32_t slash24;
7444 uint32_t msb;
7445 ssize_t b;
7446 int isfull;
7447 int rv;
7448
7449 /* sanity check input */
7450 assert(stream);
7451 assert(hdr);
7452 assert(proc_stream_state);
7453 if (skStreamCheckSilkHeader(stream, FT_IPSET, 0,
7454 IPSET_REC_VERSION_CLASSC, NULL))
7455 {
7456 skAbort();
7457 }
7458 if (skHeaderGetRecordLength(hdr) != 1) {
7459 skAbort();
7460 }
7461
7462 contig_start = contig_length = contig_max = contig_cidr = 0;
7463
7464 swap_flag = !skHeaderIsNativeByteOrder(hdr);
7465
7466 while ((b = skStreamRead(stream, block24, sizeof(block24)))
7467 == sizeof(block24))
7468 {
7469 /* the /24 value is the first value in the array */
7470 slash24 = (((swap_flag) ? BSWAP32(block24[0]) : block24[0])
7471 & 0xFFFFFF00);
7472
7473 /* determine whether the is block full (all ones) */
7474 isfull = !memcmp(&block24[1], bmap256_full, sizeof(bmap256_full));
7475
7476 if (contig_length) {
7477 /* we handling a contiguous run of full /24s */
7478 if (isfull && ((contig_start + 256 * contig_length) == slash24)) {
7479 /* grow the number of /24s */
7480 ++contig_length;
7481 if (contig_length == contig_max) {
7482 /* cannot grow this block any more */
7483 rv = (ipsetProcessStreamCallback(
7484 NULL, &contig_start, contig_cidr,
7485 proc_stream_state));
7486 if (rv) { goto END; }
7487 contig_length = 0;
7488 }
7489 continue;
7490 }
7491
7492 /* either blocks are not contigous or current block is not
7493 * full; before we handle the current block, handle the
7494 * previous block of contiguous IPS */
7495 do {
7496 /* get position of most significant bit of the number
7497 * of /24s in the range, and subtract that from 24 to
7498 * get the CIDR block */
7499 msb = skIntegerLog2(contig_length);
7500 rv = (ipsetProcessStreamCallback(
7501 NULL, &contig_start, 24 - msb, proc_stream_state));
7502 if (rv) { goto END; }
7503 /* compute the start of the next CIDR block and the
7504 * number of /24s yet to process */
7505 contig_start += (1u << (8 + msb));
7506 contig_length -= (1u << msb);
7507 } while (contig_length);
7508 /* drop into code below to handle this new block */
7509 }
7510
7511 if (isfull) {
7512 /* start a new run of contiguous IPs */
7513 contig_start = slash24;
7514 contig_length = 1;
7515 /* determine largest block that can be created */
7516 /* if slash24 is 0 then the max number of /24s is 1<<24,
7517 * but we use 1<<23 to ensure the prefix value is not 0 */
7518 trail_zero = ipsetCountTrailingZeros(slash24);
7519 if (trail_zero > 8) {
7520 contig_max = (1u << (trail_zero - 8));
7521 contig_cidr = 32 - trail_zero;
7522 } else {
7523 /* the third octet is odd, so this /24 cannot be made
7524 * any larger */
7525 assert(trail_zero == 8);
7526 rv = (ipsetProcessStreamCallback(
7527 NULL, &slash24, 24, proc_stream_state));
7528 if (rv) { goto END; }
7529 contig_length = 0;
7530 }
7531 continue;
7532 }
7533
7534 /* handle the block */
7535 rv = ipsetProcessStreamBmapSlash24(slash24, &block24[1], swap_flag,
7536 proc_stream_state);
7537 }
7538 if (b == -1) {
7539 /* read error */
7540 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
7541 " bytes returned %" SK_PRIdZ),
7542 sizeof(block24), b);
7543 rv = SKIPSET_ERR_FILEIO;
7544 goto END;
7545 }
7546
7547 /* close any partial CIDR block */
7548 while (contig_length) {
7549 /* get position of most significant bit of the number of /24s
7550 * in the range, and subtract that from 24 to get the CIDR
7551 * block */
7552 msb = skIntegerLog2(contig_length);
7553 rv = (ipsetProcessStreamCallback(
7554 NULL, &contig_start, 24 - msb, proc_stream_state));
7555 if (rv) { goto END; }
7556 /* compute the start of the next CIDR block and the number of
7557 * /24s yet to process */
7558 contig_start += (1u << (8 + msb));
7559 contig_length -= (1u << msb);
7560 }
7561
7562 rv = SKIPSET_OK;
7563
7564 END:
7565 return rv;
7566 }
7567
7568
7569 /*
7570 * status = ipsetProcessStreamRadix(stream, hdr, proc_stream_state);
7571 *
7572 * Helper function for skIPSetProcessStream() and
7573 * ipsetReadRadixIntoIPTree().
7574 *
7575 * Treat 'stream' as an IPset in the IPSET_REC_VERSION_RADIX
7576 * format and process all the IPs and CIDR blocks it contains
7577 * without reading the entire IPset into memory. The header of the
7578 * stream is in 'hdr'. The callback to invoke is available in
7579 * 'proc_stream_state'.
7580 *
7581 * See '#define IPSET_REC_VERSION_RADIX' for description of the
7582 * file format.
7583 */
7584 static int
ipsetProcessStreamRadix(skstream_t * stream,sk_file_header_t * hdr,ipset_walk_t * proc_stream_state)7585 ipsetProcessStreamRadix(
7586 skstream_t *stream,
7587 sk_file_header_t *hdr,
7588 ipset_walk_t *proc_stream_state)
7589 {
7590 #if SK_ENABLE_IPV6
7591 int is_ipv6;
7592 #endif
7593 sk_header_entry_t *hentry;
7594 ssize_t bytes;
7595 ssize_t b;
7596 size_t count = 0;
7597 int no_more_ipv4 = 0;
7598 int rv;
7599
7600 /* sanity check input */
7601 assert(stream);
7602 assert(proc_stream_state);
7603 if (skStreamCheckSilkHeader(stream, FT_IPSET, IPSET_REC_VERSION_RADIX,
7604 IPSET_REC_VERSION_RADIX, NULL))
7605 {
7606 skAbort();
7607 }
7608 if (skHeaderGetRecordLength(hdr) != 1) {
7609 skAbort();
7610 }
7611 hentry = skHeaderGetFirstMatch(hdr, SK_HENTRY_IPSET_ID);
7612 if (NULL == hentry) {
7613 skAbort();
7614 }
7615
7616 /* Verify that children/node is what we expect */
7617 if (IPSET_NUM_CHILDREN != ipsetHentryGetChildPerNode(hentry)) {
7618 skAbort();
7619 }
7620
7621 /* See if leaf and node sizes are for IPv4 or IPv6. We must check
7622 * IPv4 first, since the size of the IPv4 and IPv6 structs are
7623 * identical when SiLK is built without IPv6 support */
7624 if (sizeof(ipset_leaf_v4_t) == ipsetHentryGetLeafSize(hentry)
7625 && sizeof(ipset_node_v4_t) == ipsetHentryGetNodeSize(hentry))
7626 {
7627 #if SK_ENABLE_IPV6
7628 is_ipv6 = 0;
7629 }
7630 else if (sizeof(ipset_leaf_v6_t) == ipsetHentryGetLeafSize(hentry)
7631 && sizeof(ipset_node_v6_t) == ipsetHentryGetNodeSize(hentry))
7632 {
7633 is_ipv6 = 1;
7634 #endif /* SK_ENABLE_IPV6 */
7635 } else {
7636 /* Unrecognized record sizes */
7637 return SKIPSET_ERR_FILEHEADER;
7638 }
7639
7640 /* skip over the nodes since we only need the IPs in the leaves */
7641 bytes = (ipsetHentryGetNodeCount(hentry)
7642 * ipsetHentryGetNodeSize(hentry));
7643 b = skStreamRead(stream, NULL, bytes);
7644 if (b != bytes) {
7645 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIdZ
7646 " bytes returned %" SK_PRIdZ), bytes, b);
7647 rv = SKIPSET_ERR_FILEIO;
7648 goto END;
7649 }
7650
7651 /* skip the first leaf, which contains no data */
7652 bytes = ipsetHentryGetLeafSize(hentry);
7653 b = skStreamRead(stream, NULL, bytes);
7654 if (b != bytes) {
7655 if (b == 0 && ipsetHentryGetLeafCount(hentry) == 0) {
7656 rv = SKIPSET_OK;
7657 } else {
7658 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIdZ
7659 " bytes returned %" SK_PRIdZ),
7660 bytes, b);
7661 rv = SKIPSET_ERR_FILEIO;
7662 }
7663 goto END;
7664 }
7665 ++count;
7666
7667 #if SK_ENABLE_IPV6
7668 if (is_ipv6) {
7669 ipset_leaf_v6_t leaf;
7670 uint32_t ipv4;
7671
7672 if (proc_stream_state->v6policy >= SK_IPV6POLICY_MIX) {
7673 /* process as IPv6 addresses */
7674 while ((b = skStreamRead(stream, &leaf, bytes)) == bytes) {
7675 ++count;
7676 if (!skHeaderIsNativeByteOrder(hdr)) {
7677 leaf.ip.ip[0] = BSWAP64(leaf.ip.ip[0]);
7678 leaf.ip.ip[1] = BSWAP64(leaf.ip.ip[1]);
7679 }
7680 rv = (ipsetProcessStreamCallback(
7681 &leaf.ip, NULL, leaf.prefix, proc_stream_state));
7682 if (rv) { goto END; }
7683 }
7684 } else {
7685 /* process the IPv4 part of the radix tree; that is,
7686 * process the ::ffff:0:0/96 netblock */
7687 while ((b = skStreamRead(stream, &leaf, bytes)) == bytes) {
7688 ++count;
7689 if (!skHeaderIsNativeByteOrder(hdr)) {
7690 leaf.ip.ip[1] = BSWAP64(leaf.ip.ip[1]);
7691 }
7692 if (leaf.ip.ip[1] < UINT64_C(0x0000ffff00000000)) {
7693 continue;
7694 }
7695 if (leaf.ip.ip[0] > 0
7696 || leaf.ip.ip[1] > UINT64_C(0x0000ffffffffffff))
7697 {
7698 no_more_ipv4 = 1;
7699 break;
7700 }
7701 ipv4 = (uint32_t)(leaf.ip.ip[1] & UINT64_C(0x00000000ffffffff));
7702 rv = (ipsetProcessStreamCallback(
7703 NULL, &ipv4, leaf.prefix - 96, proc_stream_state));
7704 if (rv) { goto END; }
7705 }
7706 #ifndef NDEBUG
7707 /* read any remaining leaves so the assert() passes */
7708 if (b == bytes) {
7709 while ((b = skStreamRead(stream, &leaf, bytes)) == bytes) {
7710 ++count;
7711 }
7712 }
7713 #endif /* NDEBUG */
7714 }
7715 } else
7716 #endif /* SK_ENABLE_IPV6 */
7717 {
7718 ipset_leaf_v4_t leaf;
7719 while ((b = skStreamRead(stream, &leaf, bytes)) == bytes) {
7720 ++count;
7721 if (!skHeaderIsNativeByteOrder(hdr)) {
7722 leaf.ip = BSWAP32(leaf.ip);
7723 }
7724 rv = (ipsetProcessStreamCallback(
7725 NULL, &leaf.ip, leaf.prefix, proc_stream_state));
7726 if (rv) { goto END; }
7727 }
7728 }
7729 if (b != 0) {
7730 if (no_more_ipv4 && b == bytes) {
7731 /* not an error; we exited the loop via a break; */
7732 } else {
7733 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIdZ
7734 " bytes returned %" SK_PRIdZ),
7735 bytes, b);
7736 rv = SKIPSET_ERR_FILEIO;
7737 goto END;
7738 }
7739 }
7740 assert(ipsetHentryGetLeafCount(hentry) == count);
7741
7742 rv = SKIPSET_OK;
7743
7744 END:
7745 return rv;
7746 }
7747
7748
7749 #if SK_ENABLE_IPV6
7750 /*
7751 * status = ipsetProcessStreamSlash64(stream, hdr, proc_stream_state);
7752 *
7753 * Helper function for skIPSetProcessStream() and
7754 * ipsetReadSlash64().
7755 *
7756 * Treat 'stream' as an IPset in the IPSET_REC_VERSION_SLASH64
7757 * format and process all the IPs and CIDR blocks it contains
7758 * without reading the entire IPset into memory. The header of the
7759 * stream is in 'hdr'. The callback to invoke is available in
7760 * 'proc_stream_state'.
7761 *
7762 * See '#define IPSET_REC_VERSION_SLASH64' for description of the
7763 * file format.
7764 */
7765 static int
ipsetProcessStreamSlash64(skstream_t * stream,sk_file_header_t * hdr,ipset_walk_t * proc_stream_state)7766 ipsetProcessStreamSlash64(
7767 skstream_t *stream,
7768 sk_file_header_t *hdr,
7769 ipset_walk_t *proc_stream_state)
7770 {
7771 sk_header_entry_t *hentry;
7772 uint8_t read_buf[sizeof(uint64_t) + sizeof(uint8_t)];
7773 uint32_t bmap[IPTREE_WORDS_PER_SLASH24];
7774 /* ensure the file is valid */
7775 enum state_st {
7776 ANY_ALLOWED, UPPER_REQUIRED, LOWER_REQUIRED
7777 } state;
7778 int swap_flag;
7779 ipset_ipv6_t slash120;
7780 int no_more_ipv4;
7781 ssize_t b;
7782 int rv;
7783
7784 /* UINT64_FROM_READ_BUF(value): Set 'value' to the uint64_t value
7785 * in 'read_buf', byte swapping if necessary. */
7786 #ifdef SK_HAVE_ALIGNED_ACCESS_REQUIRED
7787 #define UINT64_FROM_READ_BUF(value) \
7788 memcpy(&(value), read_buf, sizeof(uint64_t)); \
7789 if (swap_flag) { \
7790 (value) = BSWAP64(value); \
7791 }
7792 #else
7793 #define UINT64_FROM_READ_BUF(value) \
7794 if (swap_flag) { \
7795 (value) = BSWAP64(*(uint64_t *)read_buf); \
7796 } else { \
7797 (value) = *(uint64_t *)read_buf; \
7798 }
7799 #endif /* SK_HAVE_ALIGNED_ACCESS_REQUIRED */
7800
7801 /* sanity check input */
7802 assert(stream);
7803 assert(hdr);
7804 assert(proc_stream_state);
7805 if (skStreamCheckSilkHeader(stream, FT_IPSET, IPSET_REC_VERSION_SLASH64,
7806 IPSET_REC_VERSION_SLASH64, NULL))
7807 {
7808 skAbort();
7809 }
7810 if (skHeaderGetRecordLength(hdr) != 1) {
7811 skAbort();
7812 }
7813 hentry = skHeaderGetFirstMatch(hdr, SK_HENTRY_IPSET_ID);
7814 if (NULL == hentry) {
7815 skAbort();
7816 }
7817 if (IPSET_LEN_V6 != ipsetHentryGetLeafSize(hentry)) {
7818 skAbort();
7819 }
7820
7821 swap_flag = !skHeaderIsNativeByteOrder(hdr);
7822
7823 state = UPPER_REQUIRED;
7824
7825 no_more_ipv4 = 0;
7826 while ((b = skStreamRead(stream, read_buf, sizeof(read_buf)))
7827 == sizeof(read_buf))
7828 {
7829 if (read_buf[sizeof(uint64_t)] <= 64) {
7830 /* Upper 64 bits of IPv6 and one byte CIDR prefix */
7831 if (LOWER_REQUIRED == state || 0 == read_buf[sizeof(uint64_t)]) {
7832 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7833 read_buf[sizeof(uint64_t)]);
7834 rv = SKIPSET_ERR_FILEIO;
7835 goto END;
7836 }
7837 state = UPPER_REQUIRED;
7838 if (SK_IPV6POLICY_ASV4 == proc_stream_state->v6policy) {
7839 /* there cannot be any more IPv4 addresses */
7840 no_more_ipv4 = 1;
7841 break;
7842 }
7843 UINT64_FROM_READ_BUF(slash120.ip[0]);
7844 slash120.ip[1] = 0;
7845 rv = ipsetProcessStreamCallback(&slash120, NULL,
7846 read_buf[sizeof(uint64_t)],
7847 proc_stream_state);
7848 if (rv) { goto END; }
7849 } else if (read_buf[sizeof(uint64_t)] <= 128) {
7850 /* Lower 64 bits of IPv6 and one byte CIDR prefix */
7851 if (UPPER_REQUIRED == state) {
7852 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7853 read_buf[sizeof(uint64_t)]);
7854 rv = SKIPSET_ERR_FILEIO;
7855 goto END;
7856 }
7857 state = ANY_ALLOWED;
7858 UINT64_FROM_READ_BUF(slash120.ip[1]);
7859 if (SK_IPV6POLICY_ASV4 == proc_stream_state->v6policy) {
7860 if (slash120.ip[1] < UINT64_C(0x0000ffff00000000)) {
7861 continue;
7862 }
7863 if (slash120.ip[1] > UINT64_C(0x0000ffffffffffff)) {
7864 no_more_ipv4 = 1;
7865 break;
7866 }
7867 }
7868 rv = ipsetProcessStreamCallback(&slash120, NULL,
7869 read_buf[sizeof(uint64_t)],
7870 proc_stream_state);
7871 if (rv) { goto END; }
7872 } else if (read_buf[sizeof(uint64_t)] == SET_SLASH64_IS_SLASH64) {
7873 /* Upper 64 bits of IPv6 */
7874 if (LOWER_REQUIRED == state) {
7875 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7876 read_buf[sizeof(uint64_t)]);
7877 rv = SKIPSET_ERR_FILEIO;
7878 goto END;
7879 }
7880 state = LOWER_REQUIRED;
7881 UINT64_FROM_READ_BUF(slash120.ip[0]);
7882 if (SK_IPV6POLICY_ASV4 == proc_stream_state->v6policy
7883 && slash120.ip[0] != 0)
7884 {
7885 no_more_ipv4 = 1;
7886 break;
7887 }
7888 } else if (read_buf[sizeof(uint64_t)] != SET_CIDRBMAP_MAP256) {
7889 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7890 read_buf[sizeof(uint64_t)]);
7891 rv = SKIPSET_ERR_FILEIO;
7892 goto END;
7893 } else {
7894 /* Lower 64 bits of IPv6 and 256-bit bitmap */
7895 if (UPPER_REQUIRED == state) {
7896 ipsetReadStrerrror(stream, "Unexpected value for prefix %u",
7897 read_buf[sizeof(uint64_t)]);
7898 rv = SKIPSET_ERR_FILEIO;
7899 goto END;
7900 }
7901 state = ANY_ALLOWED;
7902 UINT64_FROM_READ_BUF(slash120.ip[1]);
7903 if ((b = skStreamRead(stream, bmap, sizeof(bmap)))
7904 != sizeof(bmap))
7905 {
7906 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
7907 " bytes returned %" SK_PRIdZ),
7908 sizeof(bmap), b);
7909 rv = SKIPSET_ERR_FILEIO;
7910 goto END;
7911 }
7912 if (SK_IPV6POLICY_ASV4 == proc_stream_state->v6policy) {
7913 if (slash120.ip[1] < UINT64_C(0x0000ffff00000000)) {
7914 continue;
7915 }
7916 if (slash120.ip[1] > UINT64_C(0x0000ffffffffffff)) {
7917 no_more_ipv4 = 1;
7918 break;
7919 }
7920 }
7921 /* handle the block */
7922 rv = ipsetProcessStreamBmapSlash120(&slash120, bmap, swap_flag,
7923 proc_stream_state);
7924 if (rv) { goto END; }
7925 }
7926 }
7927 if (b != 0) {
7928 if (no_more_ipv4 && b == sizeof(read_buf)) {
7929 /* not an error; we exited the loop via a break; */
7930 } else {
7931 /* read error */
7932 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
7933 " bytes returned %" SK_PRIdZ),
7934 sizeof(read_buf), b);
7935 rv = SKIPSET_ERR_FILEIO;
7936 goto END;
7937 }
7938 }
7939
7940 /* Success */
7941 rv = SKIPSET_OK;
7942
7943 END:
7944 return rv;
7945 }
7946 #endif /* SK_ENABLE_IPV6 */
7947
7948
7949 /*
7950 * status = ipsetReadCidrbmapIntoIPTree(&ipset, stream, hdr);
7951 *
7952 * Helper function for skIPSetRead().
7953 *
7954 * Read an IPset containing only IPv4 addresses in the
7955 * IPSET_REC_VERSION_CIDRBMAP format from 'stream' and create a
7956 * SiLK-2 IPTree data structure.
7957 *
7958 * See '#define IPSET_REC_VERSION_CIDRBMAP' for description of the
7959 * file format.
7960 */
7961 static int
ipsetReadCidrbmapIntoIPTree(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr)7962 ipsetReadCidrbmapIntoIPTree(
7963 skipset_t **ipset_out,
7964 skstream_t *stream,
7965 sk_file_header_t *hdr)
7966 {
7967 skipset_t *ipset = NULL;
7968 ipset_walk_t proc_stream_state;
7969 int rv;
7970
7971 /* sanity check input */
7972 assert(ipset_out);
7973 assert(stream);
7974 assert(hdr);
7975
7976 rv = ipsetCreate(&ipset, 0, 0);
7977 if (rv != SKIPSET_OK) {
7978 return rv;
7979 }
7980
7981 memset(&proc_stream_state, 0, sizeof(proc_stream_state));
7982 proc_stream_state.callback = ipsetInsertIPAddrIPTree;
7983 proc_stream_state.cb_data = ipset;
7984 proc_stream_state.v6policy = SK_IPV6POLICY_ASV4;
7985 proc_stream_state.cidr_blocks = 1;
7986
7987 rv = ipsetProcessStreamCidrbmapV4(stream, hdr, &proc_stream_state);
7988 if (SKIPSET_OK == rv) {
7989 skIPSetClean(ipset);
7990 *ipset_out = ipset;
7991 } else {
7992 skIPSetDestroy(&ipset);
7993 }
7994 return rv;
7995 }
7996
7997
7998 /*
7999 * status = ipsetReadCidrbmapIntoRadixV4(&ipset, stream, hdr, is_ipv6);
8000 * status = ipsetReadCidrbmapIntoRadixV6(&ipset, stream, hdr, is_ipv6);
8001 *
8002 * Helper function for skIPSetRead().
8003 *
8004 * Read an IPset in the IPSET_REC_VERSION_CIDRBMAP format from
8005 * 'stream' and create a radix-tree IPset data structure.
8006 *
8007 * See '#define IPSET_REC_VERSION_CIDRBMAP' for description of the
8008 * file format.
8009 */
8010 static int
ipsetReadCidrbmapIntoRadixV4(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr)8011 ipsetReadCidrbmapIntoRadixV4(
8012 skipset_t **ipset_out,
8013 skstream_t *stream,
8014 sk_file_header_t *hdr)
8015 {
8016 skipset_t *ipset = NULL;
8017 ipset_walk_t proc_stream_state;
8018 int rv;
8019
8020 /* sanity check input */
8021 assert(ipset_out);
8022 assert(stream);
8023 assert(hdr);
8024
8025 rv = ipsetCreate(&ipset, 0, 1);
8026 if (rv != SKIPSET_OK) {
8027 return rv;
8028 }
8029
8030 memset(&proc_stream_state, 0, sizeof(proc_stream_state));
8031 proc_stream_state.callback = ipsetInsertIPAddrV4;
8032 proc_stream_state.cb_data = ipset;
8033 proc_stream_state.v6policy = SK_IPV6POLICY_MIX;
8034 proc_stream_state.cidr_blocks = 1;
8035
8036 rv = ipsetProcessStreamCidrbmapV4(stream, hdr, &proc_stream_state);
8037 if (SKIPSET_OK == rv) {
8038 skIPSetClean(ipset);
8039 *ipset_out = ipset;
8040 } else {
8041 skIPSetDestroy(&ipset);
8042 }
8043 return rv;
8044 }
8045
8046 #if SK_ENABLE_IPV6
8047 static int
ipsetReadCidrbmapIntoRadixV6(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr)8048 ipsetReadCidrbmapIntoRadixV6(
8049 skipset_t **ipset_out,
8050 skstream_t *stream,
8051 sk_file_header_t *hdr)
8052 {
8053 skipset_t *ipset = NULL;
8054 ipset_walk_t proc_stream_state;
8055 int rv;
8056
8057 /* sanity check input */
8058 assert(ipset_out);
8059 assert(stream);
8060 assert(hdr);
8061
8062 rv = ipsetCreate(&ipset, 1, 1);
8063 if (rv != SKIPSET_OK) {
8064 return rv;
8065 }
8066
8067 memset(&proc_stream_state, 0, sizeof(proc_stream_state));
8068 proc_stream_state.callback = ipsetInsertIPAddrV6;
8069 proc_stream_state.cb_data = ipset;
8070 proc_stream_state.v6policy = SK_IPV6POLICY_FORCE;
8071 proc_stream_state.cidr_blocks = 1;
8072
8073 rv = ipsetProcessStreamCidrbmapV6(stream, hdr, &proc_stream_state);
8074 if (SKIPSET_OK == rv) {
8075 skIPSetClean(ipset);
8076 *ipset_out = ipset;
8077 } else {
8078 skIPSetDestroy(&ipset);
8079 }
8080 return rv;
8081 }
8082 #endif /* SK_ENABLE_IPV6 */
8083
8084
8085 /*
8086 * status = ipsetReadClasscIntoIPTree(&ipset, stream, hdr);
8087 *
8088 * Helper function for skIPSetRead().
8089 *
8090 * Also a helper function for the legacy skIPTreeRead() function.
8091 *
8092 * Read an IPset in the IPSET_REC_VERSION_CLASSC format from
8093 * 'stream' and create a SiLK-2 IPTree data structure.
8094 *
8095 * See '#define IPSET_REC_VERSION_CLASSC' for description of the
8096 * file format.
8097 */
8098 static int
ipsetReadClasscIntoIPTree(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr)8099 ipsetReadClasscIntoIPTree(
8100 skipset_t **ipset_out,
8101 skstream_t *stream,
8102 sk_file_header_t *hdr)
8103 {
8104 skipset_t *ipset = NULL;
8105 int swap_flag;
8106 uint32_t block24[1 + IPTREE_WORDS_PER_SLASH24];
8107 uint32_t slash24;
8108 uint32_t slash16;
8109 ssize_t b;
8110 unsigned int i;
8111 int rv;
8112
8113 /* sanity check input */
8114 assert(ipset_out);
8115 assert(stream);
8116 assert(hdr);
8117 if (skStreamCheckSilkHeader(stream, FT_IPSET, 0,
8118 IPSET_REC_VERSION_CLASSC, NULL))
8119 {
8120 skAbort();
8121 }
8122 if (skHeaderGetRecordLength(hdr) != 1) {
8123 skAbort();
8124 }
8125
8126 swap_flag = !skHeaderIsNativeByteOrder(hdr);
8127
8128 rv = ipsetCreate(&ipset, 0, 0);
8129 if (rv != SKIPSET_OK) {
8130 goto END;
8131 }
8132
8133 while ((b = skStreamRead(stream, block24, sizeof(block24)))
8134 == sizeof(block24))
8135 {
8136 if (swap_flag) {
8137 for (i = 0; i < 1+IPTREE_WORDS_PER_SLASH24; ++i) {
8138 block24[i] = BSWAP32(block24[i]);
8139 }
8140 }
8141
8142 /* Put the first two octets of the base IP into slash16, and
8143 * allocate the space for the /16 if we need to */
8144 slash16 = (block24[0] >> 16);
8145 if (NULL == ipset->s.v2->nodes[slash16]) {
8146 ipset->s.v2->nodes[slash16]
8147 = (skIPNode_t*)calloc(1, sizeof(skIPNode_t));
8148 if (NULL == ipset->s.v2->nodes[slash16]) {
8149 rv = SKIPSET_ERR_ALLOC;
8150 goto END;
8151 }
8152 }
8153
8154 /* Locate where this /24 occurs inside the larger /16, then
8155 * copy it into place. Following is equivalent to
8156 * (((block24[0] >> 8) & 0xFF) * 8); */
8157 slash24 = ((block24[0] & 0x0000FF00) >> 5);
8158 memcpy((ipset->s.v2->nodes[slash16]->addressBlock + slash24),
8159 block24 + 1, IPTREE_WORDS_PER_SLASH24 * sizeof(uint32_t));
8160 }
8161 if (b != 0) {
8162 /* read error */
8163 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIuZ
8164 " bytes returned %" SK_PRIdZ),
8165 sizeof(block24), b);
8166 rv = SKIPSET_ERR_FILEIO;
8167 goto END;
8168 }
8169
8170 *ipset_out = ipset;
8171 rv = SKIPSET_OK;
8172
8173 END:
8174 if (rv != SKIPSET_OK) {
8175 skIPSetDestroy(&ipset);
8176 }
8177 return rv;
8178 }
8179
8180
8181 /*
8182 * status = ipsetReadClasscIntoRadix(&ipset, stream, hdr);
8183 *
8184 * Helper function for skIPSetRead().
8185 *
8186 * Read an IPset in the IPSET_REC_VERSION_CLASSC format from
8187 * 'stream' and create a radix-tree IPset data structure.
8188 *
8189 * See '#define IPSET_REC_VERSION_CLASSC' for description of the
8190 * file format.
8191 */
8192 static int
ipsetReadClasscIntoRadix(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr)8193 ipsetReadClasscIntoRadix(
8194 skipset_t **ipset_out,
8195 skstream_t *stream,
8196 sk_file_header_t *hdr)
8197 {
8198 skipset_t *ipset = NULL;
8199 ipset_walk_t proc_stream_state;
8200 int rv;
8201
8202 assert(ipset_out);
8203 assert(stream);
8204 assert(hdr);
8205
8206 rv = ipsetCreate(&ipset, 0, 1);
8207 if (rv != SKIPSET_OK) {
8208 return rv;
8209 }
8210
8211 memset(&proc_stream_state, 0, sizeof(proc_stream_state));
8212 proc_stream_state.callback = ipsetInsertIPAddrV4;
8213 proc_stream_state.cb_data = ipset;
8214 proc_stream_state.v6policy = SK_IPV6POLICY_MIX;
8215 proc_stream_state.cidr_blocks = 1;
8216
8217 rv = ipsetProcessStreamClassc(stream, hdr, &proc_stream_state);
8218
8219 if (SKIPSET_OK == rv) {
8220 skIPSetClean(ipset);
8221 *ipset_out = ipset;
8222 } else {
8223 skIPSetDestroy(&ipset);
8224 }
8225 return rv;
8226 }
8227
8228
8229 /*
8230 * status = ipsetReadRadixIntoIPTree(&ipset, stream, hdr);
8231 *
8232 * Helper function for skIPSetRead().
8233 *
8234 * Read an IPset in the IPSET_REC_VERSION_RADIX format containing
8235 * only IPv4 addresses from 'stream' and create a SiLK-2 IPTree
8236 * data structure.
8237 *
8238 * See '#define IPSET_REC_VERSION_RADIX' for description of the
8239 * file format.
8240 */
8241 static int
ipsetReadRadixIntoIPTree(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr)8242 ipsetReadRadixIntoIPTree(
8243 skipset_t **ipset_out,
8244 skstream_t *stream,
8245 sk_file_header_t *hdr)
8246 {
8247 skipset_t *ipset = NULL;
8248 ipset_walk_t proc_stream_state;
8249 int rv;
8250
8251 /* sanity check input */
8252 assert(ipset_out);
8253 assert(stream);
8254 assert(hdr);
8255
8256 rv = ipsetCreate(&ipset, 0, 0);
8257 if (rv != SKIPSET_OK) {
8258 return rv;
8259 }
8260
8261 memset(&proc_stream_state, 0, sizeof(proc_stream_state));
8262 proc_stream_state.callback = ipsetInsertIPAddrIPTree;
8263 proc_stream_state.cb_data = ipset;
8264 proc_stream_state.v6policy = SK_IPV6POLICY_ASV4;
8265 proc_stream_state.cidr_blocks = 1;
8266
8267 rv = ipsetProcessStreamRadix(stream, hdr, &proc_stream_state);
8268 if (SKIPSET_OK == rv) {
8269 skIPSetClean(ipset);
8270 *ipset_out = ipset;
8271 } else {
8272 skIPSetDestroy(&ipset);
8273 }
8274 return rv;
8275 }
8276
8277
8278 /*
8279 * status = ipsetReadRadixIntoRadix(&ipset, stream, hdr, is_ipv6);
8280 *
8281 * Helper function for skIPSetRead().
8282 *
8283 * Read an IPset in the IPSET_REC_VERSION_RADIX format from
8284 * 'stream' and create a radix-tree IPset data structure.
8285 *
8286 * See '#define IPSET_REC_VERSION_RADIX' for description of the
8287 * file format.
8288 */
8289 static int
ipsetReadRadixIntoRadix(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr,int is_ipv6)8290 ipsetReadRadixIntoRadix(
8291 skipset_t **ipset_out,
8292 skstream_t *stream,
8293 sk_file_header_t *hdr,
8294 int is_ipv6)
8295 {
8296 skipset_t *ipset = NULL;
8297 sk_header_entry_t *hentry;
8298 ssize_t bytes;
8299 ssize_t b;
8300 size_t i;
8301 int rv;
8302
8303 /* sanity check input */
8304 assert(ipset_out);
8305 assert(stream);
8306 if (skStreamCheckSilkHeader(stream, FT_IPSET, IPSET_REC_VERSION_RADIX,
8307 IPSET_REC_VERSION_RADIX, NULL))
8308 {
8309 skAbort();
8310 }
8311 if (skHeaderGetRecordLength(hdr) != 1) {
8312 skAbort();
8313 }
8314 hentry = skHeaderGetFirstMatch(hdr, SK_HENTRY_IPSET_ID);
8315 if (NULL == hentry) {
8316 skAbort();
8317 }
8318
8319 /* create the set */
8320 rv = ipsetCreate(&ipset, is_ipv6, 1);
8321 if (rv != SKIPSET_OK) {
8322 goto END;
8323 }
8324
8325 /* if no nodes or only node#0, root is a leaf */
8326 IPSET_ROOT_INDEX_SET(ipset, ipsetHentryGetRootIndex(hentry),
8327 (ipsetHentryGetNodeCount(hentry) <= 1));
8328
8329 if (skStreamIsSeekable(stream)
8330 && skHeaderIsNativeByteOrder(hdr)
8331 && (SK_COMPMETHOD_NONE == skHeaderGetCompressionMethod(hdr)))
8332 {
8333 /* attempt to mmap() the file */
8334
8335 /* get file size and offset where the data begins */
8336 off_t file_size = skFileSize(skStreamGetPathname(stream));
8337 off_t data_start = skStreamTell(stream);
8338 uint8_t *buf;
8339
8340 if ((0 < data_start) && (data_start < file_size)
8341 && (UINT32_MAX > file_size))
8342 {
8343 ipset->s.v3->mapped_size = (size_t)file_size;
8344 ipset->s.v3->mapped_file = mmap(0, ipset->s.v3->mapped_size,
8345 PROT_READ, MAP_SHARED,
8346 skStreamGetDescriptor(stream), 0);
8347 if (MAP_FAILED == ipset->s.v3->mapped_file) {
8348 ipset->s.v3->mapped_file = NULL;
8349 ipset->s.v3->mapped_size = 0;
8350 } else {
8351 /* this is the start of the file */
8352 buf = (uint8_t*)ipset->s.v3->mapped_file;
8353
8354 /* move to start of data section (the nodes) */
8355 buf += data_start;
8356 ipset->s.v3->nodes.buf = buf;
8357 ipset->s.v3->nodes.entry_count
8358 = ipsetHentryGetNodeCount(hentry);
8359
8360 /* move over the nodes (to the leaves) */
8361 buf += (ipsetHentryGetNodeCount(hentry)
8362 * ipset->s.v3->nodes.entry_size);
8363 ipset->s.v3->leaves.buf = buf;
8364 ipset->s.v3->nodes.entry_count
8365 = ipsetHentryGetLeafCount(hentry);
8366
8367 /* move over the leaves to the end of the file */
8368 buf += (ipsetHentryGetLeafCount(hentry)
8369 * ipset->s.v3->leaves.entry_size);
8370 if (buf >= ((uint8_t*)ipset->s.v3->mapped_file
8371 + ipset->s.v3->mapped_size))
8372 {
8373 /* error */
8374 munmap(ipset->s.v3->mapped_file, ipset->s.v3->mapped_size);
8375 ipset->s.v3->mapped_file = NULL;
8376 ipset->s.v3->mapped_size = 0;
8377
8378 ipset->s.v3->nodes.buf = NULL;
8379 ipset->s.v3->nodes.entry_count = 0;
8380
8381 ipset->s.v3->leaves.buf = NULL;
8382 ipset->s.v3->nodes.entry_count = 0;
8383 }
8384 }
8385 }
8386 }
8387
8388 if (NULL == ipset->s.v3->mapped_file) {
8389 /* Allocate and read the nodes */
8390 rv = ipsetAllocEntries(&ipset->s.v3->nodes,
8391 ipsetHentryGetNodeCount(hentry));
8392 if (rv) {
8393 goto END;
8394 }
8395
8396 bytes = (ipsetHentryGetNodeCount(hentry)
8397 * ipset->s.v3->nodes.entry_size);
8398 b = skStreamRead(stream, ipset->s.v3->nodes.buf, bytes);
8399 if (b != bytes && b != 0) {
8400 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIdZ
8401 " bytes returned %" SK_PRIdZ),
8402 bytes, b);
8403 rv = SKIPSET_ERR_FILEIO;
8404 goto END;
8405 }
8406 ipset->s.v3->nodes.entry_count = ipsetHentryGetNodeCount(hentry);
8407
8408 /* now, if the data is not in native byte order, we need to
8409 * byte-swap the values */
8410 if (!skHeaderIsNativeByteOrder(hdr)) {
8411 #if SK_ENABLE_IPV6
8412 if (ipset->is_ipv6) {
8413 ipset_node_v6_t *node;
8414 for (i = 0, node = (ipset_node_v6_t*)ipset->s.v3->nodes.buf;
8415 i < ipset->s.v3->nodes.entry_count;
8416 ++i, ++node)
8417 {
8418 node->child[0] = BSWAP32(node->child[0]);
8419 node->child[1] = BSWAP32(node->child[1]);
8420 node->ip.ip[0] = BSWAP64(node->ip.ip[0]);
8421 node->ip.ip[1] = BSWAP64(node->ip.ip[1]);
8422 }
8423 } else
8424 #endif /* SK_ENABLE_IPV6 */
8425 {
8426 ipset_node_v4_t *node;
8427 for (i = 0, node = (ipset_node_v4_t*)ipset->s.v3->nodes.buf;
8428 i < ipset->s.v3->nodes.entry_count;
8429 ++i, ++node)
8430 {
8431 node->child[0] = BSWAP32(node->child[0]);
8432 node->child[1] = BSWAP32(node->child[1]);
8433 node->ip = BSWAP32(node->ip);
8434 }
8435 }
8436 }
8437
8438 /* Allocate and read the leaves */
8439 rv = ipsetAllocEntries(&ipset->s.v3->leaves,
8440 ipsetHentryGetLeafCount(hentry));
8441 if (rv) {
8442 goto END;
8443 }
8444
8445 bytes = (ipsetHentryGetLeafCount(hentry)
8446 * ipset->s.v3->leaves.entry_size);
8447 b = skStreamRead(stream, ipset->s.v3->leaves.buf, bytes);
8448 if (b != bytes && b != 0) {
8449 ipsetReadStrerrror(stream, ("Attempting to read %" SK_PRIdZ
8450 " bytes returned %" SK_PRIdZ),
8451 bytes, b);
8452 rv = SKIPSET_ERR_FILEIO;
8453 goto END;
8454 }
8455 ipset->s.v3->leaves.entry_count = ipsetHentryGetLeafCount(hentry);
8456
8457 /* now, if the data is not in native byte order, we need to
8458 * byte-swap the values */
8459 if (!skHeaderIsNativeByteOrder(hdr)) {
8460 #if SK_ENABLE_IPV6
8461 if (ipset->is_ipv6) {
8462 ipset_leaf_v6_t *leaf;
8463 for (i = 0, leaf = (ipset_leaf_v6_t*)ipset->s.v3->leaves.buf;
8464 i < ipset->s.v3->leaves.entry_count;
8465 ++i, ++leaf)
8466 {
8467 leaf->ip.ip[0] = BSWAP64(leaf->ip.ip[0]);
8468 leaf->ip.ip[1] = BSWAP64(leaf->ip.ip[1]);
8469 }
8470 } else
8471 #endif /* SK_ENABLE_IPV6 */
8472 {
8473 ipset_leaf_v4_t *leaf;
8474 for (i = 0, leaf = (ipset_leaf_v4_t*)ipset->s.v3->leaves.buf;
8475 i < ipset->s.v3->leaves.entry_count;
8476 ++i, ++leaf)
8477 {
8478 leaf->ip = BSWAP32(leaf->ip);
8479 }
8480 }
8481 }
8482 }
8483
8484 /* check that the file is valid */
8485 rv = ipsetVerify(ipset);
8486 if (rv) {
8487 goto END;
8488 }
8489
8490 *ipset_out = ipset;
8491 rv = SKIPSET_OK;
8492
8493 END:
8494 if (rv != SKIPSET_OK) {
8495 skIPSetDestroy(&ipset);
8496 }
8497 return rv;
8498 }
8499
8500
8501 #if SK_ENABLE_IPV6
8502 /*
8503 * status = ipsetReadSlash64(&ipset, stream, hdr);
8504 *
8505 * Helper function for skIPSetRead().
8506 *
8507 * Read an IPset in the IPSET_REC_VERSION_SLASH64 format from
8508 * 'stream' and create an IPv6 Radix data structure.
8509 *
8510 * See '#define IPSET_REC_VERSION_SLASH64' for description of the
8511 * file format.
8512 *
8513 * This function uses ipsetProcessStreamSlash64() to read the
8514 * IPset.
8515 */
8516 static int
ipsetReadSlash64(skipset_t ** ipset_out,skstream_t * stream,sk_file_header_t * hdr)8517 ipsetReadSlash64(
8518 skipset_t **ipset_out,
8519 skstream_t *stream,
8520 sk_file_header_t *hdr)
8521 {
8522 skipset_t *ipset = NULL;
8523 ipset_walk_t proc_stream_state;
8524 int rv;
8525
8526 /* sanity check input */
8527 assert(ipset_out);
8528 assert(stream);
8529 assert(hdr);
8530
8531 rv = ipsetCreate(&ipset, 1, 1);
8532 if (rv != SKIPSET_OK) {
8533 return rv;
8534 }
8535
8536 memset(&proc_stream_state, 0, sizeof(proc_stream_state));
8537 proc_stream_state.callback = ipsetInsertIPAddrV6;
8538 proc_stream_state.cb_data = ipset;
8539 proc_stream_state.v6policy = SK_IPV6POLICY_FORCE;
8540 proc_stream_state.cidr_blocks = 1;
8541
8542 rv = ipsetProcessStreamSlash64(stream, hdr, &proc_stream_state);
8543 if (SKIPSET_OK == rv) {
8544 skIPSetClean(ipset);
8545 *ipset_out = ipset;
8546 } else {
8547 skIPSetDestroy(&ipset);
8548 }
8549 return rv;
8550 }
8551 #endif /* SK_ENABLE_IPV6 */
8552
8553
8554 /*
8555 * status = ipsetReadStreamHeader(stream, &hdr, &is_ipv6);
8556 *
8557 * Read the header of 'stream' and verify that it contains an
8558 * IPset. Store the file's header in the memory referenced by
8559 * 'hdr'. Set the value referenced by 'is_ipv6' to 1 if the stream
8560 * is capable of holding IPv6 addresses, and to 0 otherwise.
8561 *
8562 * Return SKIPSET_OK if the stream is valid, on an error code if
8563 * not.
8564 */
8565 static int
ipsetReadStreamHeader(skstream_t * stream,sk_file_header_t ** hdr,int * is_ipv6)8566 ipsetReadStreamHeader(
8567 skstream_t *stream,
8568 sk_file_header_t **hdr,
8569 int *is_ipv6)
8570 {
8571 sk_header_entry_t *hentry;
8572 sk_file_version_t record_version;
8573 int rv;
8574
8575 assert(stream);
8576 assert(hdr);
8577 assert(is_ipv6);
8578
8579 rv = skStreamReadSilkHeader(stream, hdr);
8580 if (rv) {
8581 if (SKSTREAM_ERR_COMPRESS_UNAVAILABLE == rv) {
8582 return SKIPSET_ERR_FILEHEADER;
8583 }
8584 return SKIPSET_ERR_FILEIO;
8585 }
8586
8587 /* Ensure we are reading a file we understand */
8588 rv = skStreamCheckSilkHeader(stream, FT_IPSET,
8589 0, IPSET_REC_VERSION_MAX, NULL);
8590 switch (rv) {
8591 case SKSTREAM_OK:
8592 break;
8593 case SKSTREAM_ERR_UNSUPPORT_FORMAT:
8594 /* not an IPset file */
8595 return SKIPSET_ERR_FILETYPE;
8596 case SKSTREAM_ERR_UNSUPPORT_VERSION:
8597 /* newer than we understand */
8598 return SKIPSET_ERR_FILEVERSION;
8599 default:
8600 return SKIPSET_ERR_FILEHEADER;
8601 }
8602 if (skHeaderGetRecordLength(*hdr) != 1) {
8603 return SKIPSET_ERR_FILEHEADER;
8604 }
8605 record_version = skHeaderGetRecordVersion(*hdr);
8606
8607 if (record_version < IPSET_REC_VERSION_RADIX) {
8608 /* the format we call IPSET_REC_VERSION_CLASSC */
8609 *is_ipv6 = 0;
8610 } else if (record_version == IPSET_REC_VERSION_RADIX) {
8611 hentry = skHeaderGetFirstMatch(*hdr, SK_HENTRY_IPSET_ID);
8612 if (NULL == hentry) {
8613 return SKIPSET_ERR_FILEHEADER;
8614 }
8615 /* Verify that children/node is what we expect */
8616 if (IPSET_NUM_CHILDREN != ipsetHentryGetChildPerNode(hentry)) {
8617 return SKIPSET_ERR_FILEHEADER;
8618 }
8619
8620 /* See if leaf and node sizes are for IPv4 or IPv6. We must
8621 * check IPv4 first, since the size of the IPv4 and IPv6
8622 * structs are identical when SiLK is built without IPv6
8623 * support */
8624 if (sizeof(ipset_leaf_v4_t) == ipsetHentryGetLeafSize(hentry)
8625 && sizeof(ipset_node_v4_t) == ipsetHentryGetNodeSize(hentry))
8626 {
8627 *is_ipv6 = 0;
8628 }
8629 else if (sizeof(ipset_leaf_v6_t) == ipsetHentryGetLeafSize(hentry)
8630 && sizeof(ipset_node_v6_t) == ipsetHentryGetNodeSize(hentry))
8631 {
8632 *is_ipv6 = 1;
8633 } else {
8634 /* Unrecognized record sizes */
8635 return SKIPSET_ERR_FILEHEADER;
8636 }
8637 } else if (record_version == IPSET_REC_VERSION_CIDRBMAP) {
8638 /* read and verify the header */
8639 hentry = skHeaderGetFirstMatch(*hdr, SK_HENTRY_IPSET_ID);
8640 if (NULL == hentry) {
8641 return SKIPSET_ERR_FILEHEADER;
8642 }
8643 /* most sizes are zero */
8644 if (0 != ipsetHentryGetChildPerNode(hentry)
8645 || 0 != ipsetHentryGetRootIndex(hentry)
8646 || 0 != ipsetHentryGetNodeCount(hentry)
8647 || 0 != ipsetHentryGetNodeSize(hentry)
8648 || 0 != ipsetHentryGetLeafCount(hentry))
8649 {
8650 return SKIPSET_ERR_FILEHEADER;
8651 }
8652 if (sizeof(uint32_t) == ipsetHentryGetLeafSize(hentry)) {
8653 *is_ipv6 = 0;
8654 } else if (IPSET_LEN_V6 == ipsetHentryGetLeafSize(hentry)) {
8655 *is_ipv6 = 1;
8656 } else {
8657 /* Unrecognized record size */
8658 return SKIPSET_ERR_FILEHEADER;
8659 }
8660 } else if (record_version == IPSET_REC_VERSION_SLASH64){
8661 /* read and verify the header */
8662 hentry = skHeaderGetFirstMatch(*hdr, SK_HENTRY_IPSET_ID);
8663 if (NULL == hentry) {
8664 return SKIPSET_ERR_FILEHEADER;
8665 }
8666 /* most sizes are zero */
8667 if (0 != ipsetHentryGetChildPerNode(hentry)
8668 || 0 != ipsetHentryGetRootIndex(hentry)
8669 || 0 != ipsetHentryGetNodeCount(hentry)
8670 || 0 != ipsetHentryGetNodeSize(hentry)
8671 || 0 != ipsetHentryGetLeafCount(hentry))
8672 {
8673 return SKIPSET_ERR_FILEHEADER;
8674 }
8675 /* format only supports IPv6 */
8676 if (IPSET_LEN_V6 == ipsetHentryGetLeafSize(hentry)) {
8677 *is_ipv6 = 1;
8678 } else {
8679 /* Unrecognized record size */
8680 return SKIPSET_ERR_FILEHEADER;
8681 }
8682 } else {
8683 skAppPrintErr("Unknown header version %d", record_version);
8684 skAbort();
8685 }
8686 #if !SK_ENABLE_IPV6
8687 if (*is_ipv6) {
8688 /* IPv6 IPSet not supported by this build of SiLK */
8689 return SKIPSET_ERR_IPV6;
8690 }
8691 #endif /* SK_ENABLE_IPV6 */
8692
8693 return SKIPSET_OK;
8694 }
8695
8696
8697 /*
8698 * Print the reason an IPset could not be read when the
8699 * SILK_IPSET_PRINT_READ_ERROR environment variable is set.
8700 */
8701 static void
ipsetReadStrerrror(skstream_t * stream,const char * format,...)8702 ipsetReadStrerrror(
8703 skstream_t *stream,
8704 const char *format,
8705 ...)
8706 {
8707 char buf[3 * PATH_MAX];
8708 const char *env;
8709 va_list args;
8710
8711 va_start(args, format);
8712 env = getenv("SILK_IPSET_PRINT_READ_ERROR");
8713 if (!env || !env[0] || 0 == strcmp(env, "0")) {
8714 va_end(args);
8715 return;
8716 }
8717 vsnprintf(buf, sizeof(buf), format, args);
8718 va_end(args);
8719
8720 skAppPrintErr("Error reading IPset from '%s': %s",
8721 skStreamGetPathname(stream), buf);
8722 }
8723
8724
8725 /*
8726 * rv = ipsetRemoveAddressIPTree(ipset, ipv4, prefix);
8727 *
8728 * Helper function for skIPSetRemoveAddress(); may also be called
8729 * by other internal functions.
8730 */
8731 static int
ipsetRemoveAddressIPTree(skipset_t * ipset,uint32_t ipv4,uint32_t prefix)8732 ipsetRemoveAddressIPTree(
8733 skipset_t *ipset,
8734 uint32_t ipv4,
8735 uint32_t prefix)
8736 {
8737 /* for a description of 'prefix_as_bits', see
8738 * ipsetInsertAddressIPTree() */
8739 const uint32_t prefix_as_bits[] = {
8740 0xFFFFFFFF, 0xFFFF, 0xFF, 0xF, 0x3, 0x1
8741 };
8742 uint32_t ipv4_end;
8743 skIPNode_t empty_node;
8744 skIPTree_t *iptree;
8745
8746 assert(ipset);
8747 assert(1 == ipset->is_iptree);
8748 assert(0 == ipset->is_ipv6);
8749 assert(prefix > 0 || ipv4 == 0);
8750 assert(prefix <= 32);
8751
8752 iptree = ipset->s.v2;
8753
8754 if (prefix <= 16) {
8755 ipv4_end = ((UINT32_MAX >> prefix) | ipv4) >> 16;
8756 ipv4 >>= 16;
8757 do {
8758 if (NULL != iptree->nodes[ipv4]) {
8759 free(iptree->nodes[ipv4]);
8760 iptree->nodes[ipv4] = NULL;
8761 }
8762 } while (ipv4++ < ipv4_end);
8763
8764 } else if (NULL != iptree->nodes[ipv4 >> 16]) {
8765 if (prefix >= 27) {
8766 iptree->nodes[ipv4 >> 16]->addressBlock[(ipv4 & 0xFFFF) >> 5]
8767 &= ~(prefix_as_bits[prefix - 27] << ((ipv4) & 0x1F));
8768
8769 } else {
8770 /* 16 < prefix < 27 */
8771 memset(&iptree->nodes[ipv4>>16]->addressBlock[(ipv4 & 0xFFFF)>>5],
8772 0, (sizeof(skIPNode_t) >> (prefix - 16)));
8773 }
8774
8775 /* free node if block is empty */
8776 memset(&empty_node, 0, sizeof(empty_node));
8777 if (0 == memcmp(&empty_node, iptree->nodes[ipv4 >> 16],
8778 sizeof(skIPNode_t)))
8779 {
8780 free(iptree->nodes[ipv4 >> 16]);
8781 iptree->nodes[ipv4 >> 16] = NULL;
8782 }
8783 }
8784
8785 return SKIPSET_OK;
8786 }
8787
8788
8789 /*
8790 * rv = ipsetRemoveAddressV4(ipset, ipv4, prefix, find_state);
8791 * rv = ipsetRemoveAddressV6(ipset, ipv6, prefix, find_state);
8792 *
8793 * Helper function for skIPSetRemoveAddress(); may also be called
8794 * by other internal functions.
8795 *
8796 * Remove the CIDR block ipv4/prefix or ipv6/prefix from the IPset.
8797 *
8798 * 'find_state' should be NULL or the result of calling
8799 * ipsetFindV4() or ipsetFindV6() on the ip/prefix pair. When
8800 * 'find_state' is NULL, this function does the address search
8801 * itself.
8802 *
8803 * Return SKIPSET_OK if the address block was successfully removed
8804 * or if the address block does not appear in the IPset. Return
8805 * SKIPSET_ERR_ALLOC if there is a memory allocation error.
8806 */
8807 static int
ipsetRemoveAddressV4(skipset_t * ipset,const uint32_t ipv4,const uint32_t prefix,const ipset_find_t * find_state)8808 ipsetRemoveAddressV4(
8809 skipset_t *ipset,
8810 const uint32_t ipv4,
8811 const uint32_t prefix,
8812 const ipset_find_t *find_state)
8813 {
8814 ipset_find_t find_state_local;
8815 ipset_node_v4_t *parent = NULL;
8816 ipset_leaf_v4_t *leaf;
8817 uint32_t which_child;
8818 uint32_t i;
8819 uint32_t j;
8820 int rv;
8821
8822 assert(ipset);
8823 assert(sizeof(ipset_node_v4_t) == ipset->s.v3->nodes.entry_size);
8824 assert(prefix > 0 || ipv4 == 0);
8825 assert(prefix <= 32);
8826 assert(0 == ipset->is_iptree);
8827 assert(0 == ipset->is_ipv6);
8828
8829 /* use the passed in 'find_state' if given */
8830 if (find_state) {
8831 rv = find_state->result;
8832 } else {
8833 rv = ipsetFindV4(ipset, ipv4, prefix, &find_state_local);
8834 /* if IP was not found, we can return */
8835 if (SKIPSET_ERR_NOTFOUND == rv
8836 || SKIPSET_ERR_EMPTY == rv
8837 || SKIPSET_ERR_MULTILEAF == rv)
8838 {
8839 return SKIPSET_OK;
8840 }
8841 find_state = &find_state_local;
8842 }
8843 ipset->is_dirty = 1;
8844
8845 /* if we matched a CIDR block in the IPset that is larger than the
8846 * block/address we want to remove, we must break the CIDR
8847 * block. */
8848 if ((SKIPSET_OK == rv) && (find_state->bitpos < prefix)) {
8849 uint32_t old_ipv4, mid_ipv4, old_prefix;
8850
8851 assert(1 == find_state->node_is_leaf);
8852
8853 leaf = LEAF_PTR_V4(ipset, find_state->node_idx);
8854 old_ipv4 = leaf->ip;
8855 old_prefix = leaf->prefix;
8856
8857 /* remove the current IP */
8858 if (IPSET_NO_PARENT == find_state->parent_idx) {
8859 skIPSetRemoveAll(ipset);
8860 } else {
8861 parent = NODE_PTR_V4(ipset, find_state->parent_idx);
8862 which_child = WHICH_CHILD_V4(leaf->ip, parent->prefix);
8863 if (NUM_BITS <= leaf->prefix - parent->prefix) {
8864 /* leaf occupies a single child[] entry */
8865 parent->child[which_child] = 0;
8866 NODEPTR_CHILD_CLEAR_LEAF(parent, which_child);
8867 } else {
8868 for (i = which_child, j = 0;
8869 j < (1u << (NUM_BITS - (leaf->prefix - parent->prefix)));
8870 ++i, ++j)
8871 {
8872 parent->child[i] = 0;
8873 }
8874 NODEPTR_CHILD_CLEAR_LEAF2(parent, which_child, i - 1);
8875 NODEPTR_CHILD_CLEAR_REPEAT2(parent, which_child, i - 1);
8876 }
8877 LEAFIDX_FREE(ipset, find_state->node_idx);
8878 }
8879
8880 /* insert all IPs not part of the removed block */
8881 do {
8882 ++old_prefix;
8883 /* find midpoint of this block */
8884 mid_ipv4 = old_ipv4 | (1u << (32 - old_prefix));
8885 if (ipv4 < mid_ipv4) {
8886 /* insert upper half of old CIDR block */
8887 rv = ipsetInsertAddressV4(ipset, mid_ipv4, old_prefix, NULL);
8888 /* no change to old_ipv4 */
8889 } else {
8890 /* insert lower half of old CIDR block */
8891 rv = ipsetInsertAddressV4(ipset, old_ipv4, old_prefix, NULL);
8892 /* adjust old_ipv4 to the base of the upper half */
8893 old_ipv4 = mid_ipv4;
8894 }
8895 } while (0 == rv && old_prefix < prefix);
8896
8897 /* all done */
8898 return rv;
8899 }
8900
8901 /* otherwise, we exactly matched the node we want to remove, or we
8902 * are removing a CIDR block that is only partially populated.
8903 * These cases are handled the same way: modify the parent of the
8904 * node to remove the node we found. */
8905
8906 /* handle the simple case */
8907 if (IPSET_NO_PARENT == find_state->parent_idx) {
8908 return skIPSetRemoveAll(ipset);
8909 }
8910 parent = NODE_PTR_V4(ipset, find_state->parent_idx);
8911
8912 if (SKIPSET_ERR_SUBSET == rv
8913 && (NUM_BITS > prefix - parent->prefix))
8914 {
8915 /* need to clear multiple child[] entries */
8916 which_child = WHICH_CHILD_V4(ipv4, parent->prefix);
8917 for (i = which_child, j = 0;
8918 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
8919 ++i, ++j)
8920 {
8921 if (parent->child[i]) {
8922 if (!NODEPTR_CHILD_IS_LEAF(parent, i)) {
8923 ipsetDestroySubtree(ipset, parent->child[i], 1);
8924 parent->child[i] = 0;
8925 } else if (NODEPTR_CHILD_IS_REPEAT(parent, i)) {
8926 parent->child[i] = 0;
8927 } else {
8928 LEAFIDX_FREE(ipset, parent->child[i]);
8929 parent->child[i] = 0;
8930 }
8931 }
8932 }
8933 NODEPTR_CHILD_CLEAR_LEAF2(parent, which_child, i - 1);
8934 NODEPTR_CHILD_CLEAR_REPEAT2(parent, which_child, i - 1);
8935
8936 /* handle case where node has a single child */
8937 ipsetFixNodeSingleChild(ipset, find_state->parent_idx, 0);
8938 return SKIPSET_OK;
8939 }
8940
8941 if (!find_state->node_is_leaf) {
8942 /* remove this node from the parent, and delete the node and
8943 * everything below it */
8944 parent->child[find_state->parents_child] = 0;
8945 ipsetDestroySubtree(ipset, find_state->node_idx, 1);
8946 } else {
8947 /* remove this leaf from the parent */
8948 leaf = LEAF_PTR_V4(ipset, find_state->node_idx);
8949 if (NUM_BITS <= leaf->prefix - parent->prefix) {
8950 /* leaf occupies a single child[] entry */
8951 parent->child[find_state->parents_child] = 0;
8952 NODEPTR_CHILD_CLEAR_LEAF(parent, find_state->parents_child);
8953 } else {
8954 /* leaf occupies multiple child[] entries */
8955 which_child = WHICH_CHILD_V4(leaf->ip, parent->prefix);
8956 for (i = which_child, j = 0;
8957 j < (1u << (NUM_BITS - (leaf->prefix - parent->prefix)));
8958 ++i, ++j)
8959 {
8960 parent->child[i] = 0;
8961 }
8962 NODEPTR_CHILD_CLEAR_LEAF2(parent, which_child, i - 1);
8963 NODEPTR_CHILD_CLEAR_REPEAT2(parent, which_child, i - 1);
8964 }
8965 LEAFIDX_FREE(ipset, find_state->node_idx);
8966 }
8967
8968 /* handle case where node has a single child */
8969 ipsetFixNodeSingleChild(ipset, find_state->parent_idx, 0);
8970 return SKIPSET_OK;
8971 }
8972
8973 #if SK_ENABLE_IPV6
8974 static int
ipsetRemoveAddressV6(skipset_t * ipset,const ipset_ipv6_t * ipv6,const uint32_t prefix,const ipset_find_t * find_state)8975 ipsetRemoveAddressV6(
8976 skipset_t *ipset,
8977 const ipset_ipv6_t *ipv6,
8978 const uint32_t prefix,
8979 const ipset_find_t *find_state)
8980 {
8981 ipset_find_t find_state_local;
8982 ipset_node_v6_t *parent = NULL;
8983 ipset_leaf_v6_t *leaf;
8984 uint32_t which_child;
8985 uint32_t i;
8986 uint32_t j;
8987 int rv;
8988
8989 assert(ipset);
8990 assert(sizeof(ipset_node_v6_t) == ipset->s.v3->nodes.entry_size);
8991 assert(0 < prefix && prefix <= 128);
8992 assert(0 == ipset->is_iptree);
8993 assert(1 == ipset->is_ipv6);
8994
8995 /* use the passed in 'find_state' if given */
8996 if (find_state) {
8997 rv = find_state->result;
8998 } else {
8999 rv = ipsetFindV6(ipset, ipv6, prefix, &find_state_local);
9000 /* if IP was not found, we can return */
9001 if (SKIPSET_ERR_NOTFOUND == rv
9002 || SKIPSET_ERR_EMPTY == rv
9003 || SKIPSET_ERR_MULTILEAF == rv)
9004 {
9005 return SKIPSET_OK;
9006 }
9007 find_state = &find_state_local;
9008 }
9009 ipset->is_dirty = 1;
9010
9011 /* if we matched a CIDR block in the IPset that is larger than the
9012 * block/address we want to remove, we must break the CIDR
9013 * block. */
9014 if ((SKIPSET_OK == rv) && (find_state->bitpos < prefix)) {
9015 ipset_ipv6_t old_ipv6, mid_ipv6;
9016 uint32_t old_prefix;
9017
9018 assert(1 == find_state->node_is_leaf);
9019
9020 leaf = LEAF_PTR_V6(ipset, find_state->node_idx);
9021 IPSET_IPV6_COPY(&old_ipv6, &leaf->ip);
9022 old_prefix = leaf->prefix;
9023
9024 /* remove the current IP */
9025 if (IPSET_NO_PARENT == find_state->parent_idx) {
9026 skIPSetRemoveAll(ipset);
9027 } else {
9028 parent = NODE_PTR_V6(ipset, find_state->parent_idx);
9029 which_child = WHICH_CHILD_V6(&leaf->ip, parent->prefix);
9030 if (NUM_BITS <= leaf->prefix - parent->prefix) {
9031 /* leaf occupies a single child[] entry */
9032 parent->child[which_child] = 0;
9033 NODEPTR_CHILD_CLEAR_LEAF(parent, which_child);
9034 } else {
9035 for (i = which_child, j = 0;
9036 j < (1u << (NUM_BITS - (leaf->prefix - parent->prefix)));
9037 ++i, ++j)
9038 {
9039 parent->child[i] = 0;
9040 }
9041 NODEPTR_CHILD_CLEAR_LEAF2(parent, which_child, i - 1);
9042 NODEPTR_CHILD_CLEAR_REPEAT2(parent, which_child, i - 1);
9043 }
9044 LEAFIDX_FREE(ipset, find_state->node_idx);
9045 }
9046
9047 /* insert all IPs not part of the removed block */
9048 IPSET_IPV6_COPY(&mid_ipv6, &old_ipv6);
9049 do {
9050 ++old_prefix;
9051 if (old_prefix <= 64) {
9052 /* find midpoint of this block */
9053 mid_ipv6.ip[0]
9054 = old_ipv6.ip[0] | (UINT64_C(1) << (64 - old_prefix));
9055 if (ipv6->ip[0] < mid_ipv6.ip[0]) {
9056 /* insert upper half of old CIDR block */
9057 rv = ipsetInsertAddressV6(ipset, &mid_ipv6, old_prefix,
9058 NULL);
9059 /* no change to old_ipv6 */
9060 if (64 == old_prefix) {
9061 /* reset mid_ipv6 so it is correct for lower
9062 * half of the IP */
9063 mid_ipv6.ip[0] = old_ipv6.ip[0];
9064 }
9065 } else {
9066 /* insert lower hald of old CIDR block */
9067 rv = ipsetInsertAddressV6(ipset, &old_ipv6, old_prefix,
9068 NULL);
9069 /* adjust old_ipv6 to the base of the upper half */
9070 old_ipv6.ip[0] = mid_ipv6.ip[0];
9071 }
9072 } else {
9073 mid_ipv6.ip[1]
9074 = old_ipv6.ip[1] | (UINT64_C(1) << (128 - old_prefix));
9075 if (ipv6->ip[1] < mid_ipv6.ip[1]) {
9076 rv = ipsetInsertAddressV6(ipset, &mid_ipv6, old_prefix,
9077 NULL);
9078 } else {
9079 rv = ipsetInsertAddressV6(ipset, &old_ipv6, old_prefix,
9080 NULL);
9081 old_ipv6.ip[1] = mid_ipv6.ip[1];
9082 }
9083 }
9084 } while (0 == rv && old_prefix < prefix);
9085
9086 /* done */
9087 return rv;
9088 }
9089
9090 /* otherwise, we exactly matched the node we want to remove, or we
9091 * are removing a CIDR block that is only partially populated.
9092 * These cases are handled the same way: modify the parent of the
9093 * node to remove the node we found. */
9094
9095 /* handle the simple case */
9096 if (IPSET_NO_PARENT == find_state->parent_idx) {
9097 return skIPSetRemoveAll(ipset);
9098 }
9099
9100 parent = NODE_PTR_V6(ipset, find_state->parent_idx);
9101
9102 if (SKIPSET_ERR_SUBSET == rv
9103 && (NUM_BITS > prefix - parent->prefix))
9104 {
9105 /* need to clear multiple child[] entries */
9106 which_child = WHICH_CHILD_V6(ipv6, parent->prefix);
9107 for (i = which_child, j = 0;
9108 j < (1u << (NUM_BITS - (prefix - parent->prefix)));
9109 ++i, ++j)
9110 {
9111 if (parent->child[i]) {
9112 if (!NODEPTR_CHILD_IS_LEAF(parent, i)) {
9113 ipsetDestroySubtree(ipset, parent->child[i], 1);
9114 parent->child[i] = 0;
9115 } else if (NODEPTR_CHILD_IS_REPEAT(parent, i)) {
9116 parent->child[i] = 0;
9117 } else {
9118 LEAFIDX_FREE(ipset, parent->child[i]);
9119 parent->child[i] = 0;
9120 }
9121 }
9122 }
9123 NODEPTR_CHILD_CLEAR_LEAF2(parent, which_child, i - 1);
9124 NODEPTR_CHILD_CLEAR_REPEAT2(parent, which_child, i - 1);
9125
9126 /* handle case where node has a single child */
9127 ipsetFixNodeSingleChild(ipset, find_state->parent_idx, 0);
9128 return SKIPSET_OK;
9129 }
9130
9131 if (!find_state->node_is_leaf) {
9132 /* remove this node from the parent, and delete the node and
9133 * everything below it */
9134 parent->child[find_state->parents_child] = 0;
9135 ipsetDestroySubtree(ipset, find_state->node_idx, 1);
9136 } else {
9137 /* remove this leaf from the parent */
9138 leaf = LEAF_PTR_V6(ipset, find_state->node_idx);
9139 if (NUM_BITS <= leaf->prefix - parent->prefix) {
9140 /* leaf occupies a single child[] entry */
9141 parent->child[find_state->parents_child] = 0;
9142 NODEPTR_CHILD_CLEAR_LEAF(parent, find_state->parents_child);
9143 } else {
9144 /* leaf occupies multiple child[] entries */
9145 which_child = WHICH_CHILD_V6(&leaf->ip, parent->prefix);
9146 for (i = which_child, j = 0;
9147 j < (1u << (NUM_BITS - (leaf->prefix - parent->prefix)));
9148 ++i, ++j)
9149 {
9150 parent->child[i] = 0;
9151 }
9152 NODEPTR_CHILD_CLEAR_LEAF2(parent, which_child, i - 1);
9153 NODEPTR_CHILD_CLEAR_REPEAT2(parent, which_child, i - 1);
9154 }
9155 LEAFIDX_FREE(ipset, find_state->node_idx);
9156 }
9157
9158 /* handle case where node has a single child */
9159 ipsetFixNodeSingleChild(ipset, find_state->parent_idx, 0);
9160 return SKIPSET_OK;
9161 }
9162 #endif /* SK_ENABLE_IPV6 */
9163
9164
9165 /*
9166 * Helper function for skIPSetRemoveAll() when the IPset is a
9167 * SiLK-2 IPTree.
9168 *
9169 * Also a helper function for legacy skIPTreeRemoveAll().
9170 */
9171 static void
ipsetRemoveAllIPTree(skIPTree_t * ipset)9172 ipsetRemoveAllIPTree(
9173 skIPTree_t *ipset)
9174 {
9175 unsigned int i;
9176
9177 /* delete all the nodes */
9178 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
9179 if (ipset->nodes[i] != NULL) {
9180 free(ipset->nodes[i]);
9181 }
9182 }
9183 memset(ipset, 0, sizeof(skIPTree_t));
9184 }
9185
9186
9187 /*
9188 * new_leaf_id = ipsetReplaceNodeWithLeaf(ipset, parent, which_child);
9189 *
9190 * Replace the node at position child['which_child'] on the node
9191 * 'parent' with a leaf. Return the index of the new leaf.
9192 *
9193 * If 'parent' is NULL, the node at the root of the 'ipset' is
9194 * replaced with a leaf.
9195 *
9196 * This function always succeeds, since destroying the node and its
9197 * subtree provides leaf entries on the free_list.
9198 */
9199 static uint32_t
ipsetReplaceNodeWithLeaf(skipset_t * ipset,ipset_node_t * parent,uint32_t which_child)9200 ipsetReplaceNodeWithLeaf(
9201 skipset_t *ipset,
9202 ipset_node_t *parent,
9203 uint32_t which_child)
9204 {
9205 uint32_t new_leaf_idx;
9206
9207 assert(ipset);
9208 assert(which_child < IPSET_NUM_CHILDREN);
9209
9210 if (NULL == parent) {
9211 assert(0 == IPSET_ROOT_IS_LEAF(ipset));
9212 ipsetDestroySubtree(ipset, IPSET_ROOT_INDEX(ipset), 1);
9213 ASSERT_OK(ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx));
9214 IPSET_ROOT_INDEX_SET(ipset, new_leaf_idx, 1);
9215 } else {
9216 assert(0 == NODEPTR_CHILD_IS_LEAF(&parent->v4, which_child));
9217 ipsetDestroySubtree(ipset, parent->v4.child[which_child], 1);
9218 ASSERT_OK(ipsetNewEntries(ipset, 0, 1, NULL, &new_leaf_idx));
9219 parent->v4.child[which_child] = new_leaf_idx;
9220 NODEPTR_CHILD_SET_LEAF(&parent->v4, which_child);
9221 }
9222
9223 return new_leaf_idx;
9224 }
9225
9226
9227
9228 /*
9229 * ipsetSortLeaves(ipset);
9230 *
9231 * Sort the leaves so they occur in ascending order in memory.
9232 */
9233 static void
ipsetSortLeaves(skipset_t * ipset)9234 ipsetSortLeaves(
9235 skipset_t *ipset)
9236 {
9237 uint32_t to_visit[IPSET_MAX_DEPTH];
9238 #if IPSET_NUM_CHILDREN < 256
9239 uint8_t children[IPSET_MAX_DEPTH];
9240 #else
9241 uint16_t children[IPSET_MAX_DEPTH];
9242 #endif
9243 uint32_t child_idx;
9244 uint32_t depth;
9245 uint32_t cur;
9246 ipset_node_t *node;
9247
9248 /* first, ensure the tree is compact */
9249 ipsetCompact(ipset);
9250
9251 /* nothing to do if the root is a leaf */
9252 if (IPSET_ROOT_IS_LEAF(ipset)) {
9253 return;
9254 }
9255
9256 /* the new index to assign to each leaf */
9257 child_idx = 0;
9258
9259 /* visit the leaves in the tree to update the indexes */
9260 depth = 0;
9261 to_visit[depth] = IPSET_ROOT_INDEX(ipset);
9262 children[depth++] = 0;
9263
9264 cur = 0;
9265 while (depth) {
9266 VISIT_NODE:
9267 node = NODE_PTR(ipset, to_visit[cur]);
9268 for ( ; children[cur] < IPSET_NUM_CHILDREN; ++children[cur]) {
9269 if (0 == node->v4.child[children[cur]]) {
9270 /* no-op */
9271 } else if (!NODEPTR_CHILD_IS_LEAF(&node->v4, children[cur])) {
9272 /* this is a node; push this node onto the visit list
9273 * and break out of the for() loop to visit the node
9274 * immediately */
9275 to_visit[depth] = node->v4.child[children[cur]];
9276 children[depth++] = 0;
9277 /* we're done with this entry on the node */
9278 ++children[cur];
9279 ++cur;
9280 goto VISIT_NODE;
9281 } else if (NODEPTR_CHILD_IS_REPEAT(&node->v4, children[cur])) {
9282 /* leaf is a repeat, use current child_idx */
9283 node->v4.child[children[cur]] = child_idx;
9284 } else {
9285 /* this is a new leaf */
9286 ++child_idx;
9287 node->v4.child[children[cur]] = child_idx;
9288 }
9289 }
9290 assert(IPSET_NUM_CHILDREN == children[cur]);
9291 --cur;
9292 --depth;
9293 }
9294
9295 /* child_idx is number of leaves if we ignore the entry at 0 */
9296 if (child_idx+1 != ipset->s.v3->leaves.entry_count) {
9297 skAbort();
9298 }
9299
9300 /* sort the leaves, ignoring the entry at position 0 */
9301 #if SK_ENABLE_IPV6
9302 if (ipset->is_ipv6) {
9303 skQSort(ipset->s.v3->leaves.buf + ipset->s.v3->leaves.entry_size,
9304 child_idx, ipset->s.v3->leaves.entry_size, ipsetLeafCompareV6);
9305 } else
9306 #endif
9307 {
9308 skQSort(ipset->s.v3->leaves.buf + ipset->s.v3->leaves.entry_size,
9309 child_idx, ipset->s.v3->leaves.entry_size, ipsetLeafCompareV4);
9310 }
9311 }
9312
9313
9314 /*
9315 * status = ipsetSubtractCallbackV4(ipv4, prefix, ipset);
9316 * status = ipsetSubtractCallbackV6(ipv6, prefix, ipset);
9317 * status = ipsetSubtractCallback(ipaddr, prefix, ipset);
9318 *
9319 * Helper callback function for skIPSetSubtract().
9320 *
9321 * Removes the CIDR block specified by 'ipaddr'/'prefix' from
9322 * 'ipset'.
9323 */
9324 static int
ipsetSubtractCallbackV4(uint32_t ipv4,uint32_t prefix,void * v_ipset)9325 ipsetSubtractCallbackV4(
9326 uint32_t ipv4,
9327 uint32_t prefix,
9328 void *v_ipset)
9329 {
9330 return ipsetRemoveAddressV4((skipset_t*)v_ipset, ipv4, prefix, NULL);
9331 }
9332
9333 #if SK_ENABLE_IPV6
9334 static int
ipsetSubtractCallbackV6(const ipset_ipv6_t * ipv6,uint32_t prefix,void * v_ipset)9335 ipsetSubtractCallbackV6(
9336 const ipset_ipv6_t *ipv6,
9337 uint32_t prefix,
9338 void *v_ipset)
9339 {
9340 return ipsetRemoveAddressV6((skipset_t*)v_ipset, ipv6, prefix, NULL);
9341 }
9342 #endif /* SK_ENABLE_IPV6 */
9343
9344 static int
ipsetSubtractCallback(skipaddr_t * ipaddr,uint32_t prefix,void * v_ipset)9345 ipsetSubtractCallback(
9346 skipaddr_t *ipaddr,
9347 uint32_t prefix,
9348 void *v_ipset)
9349 {
9350 return skIPSetRemoveAddress((skipset_t*)v_ipset, ipaddr, prefix);
9351 }
9352
9353 /*
9354 * Helper function for skIPSetSubtract() when both IPsets are
9355 * implmented by SiLK-2 IPTrees.
9356 *
9357 * Also a helper function for legacy skIPTreeSubtract().
9358 */
9359 static int
ipsetSubtractIPTree(skIPTree_t * result_ipset,const skIPTree_t * ipset)9360 ipsetSubtractIPTree(
9361 skIPTree_t *result_ipset,
9362 const skIPTree_t *ipset)
9363 {
9364 unsigned int i, j;
9365
9366 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
9367 if (NULL == ipset->nodes[i] || NULL == result_ipset->nodes[i]) {
9368 /* no change required */
9369
9370 } else {
9371 /* Need to intersect with the complement in the /16 */
9372 uint32_t keep_node = 0;
9373
9374 for (j = 0; keep_node == 0 && j < SKIP_BBLOCK_SIZE; ++j) {
9375 result_ipset->nodes[i]->addressBlock[j]
9376 &= ~(ipset->nodes[i]->addressBlock[j]);
9377 keep_node = result_ipset->nodes[i]->addressBlock[j];
9378 }
9379 if (keep_node) {
9380 for ( ; j < SKIP_BBLOCK_SIZE; ++j) {
9381 result_ipset->nodes[i]->addressBlock[j]
9382 &= ~(ipset->nodes[i]->addressBlock[j]);
9383 }
9384 } else {
9385 free(result_ipset->nodes[i]);
9386 result_ipset->nodes[i] = NULL;
9387 }
9388 }
9389 /* ELSE This /16 is off in at least one ipset. Leave it alone. */
9390 }
9391
9392 return SKIPSET_OK;
9393 }
9394
9395
9396 /*
9397 * status = ipsetUnionCallbackIPTree(ipv4, prefix, ipset);
9398 * status = ipsetUnionCallbackV4(ipv4, prefix, ipset);
9399 * status = ipsetUnionCallbackV6(ipv6, prefix, ipset);
9400 * status = ipsetUnionCallback(ipaddr, prefix, ipset);
9401 *
9402 * Helper callback function for skIPSetUnion().
9403 *
9404 * Adds the CIDR block specified by 'ipaddr'/'prefix' to 'ipset'.
9405 */
9406 static int
ipsetUnionCallbackIPTree(uint32_t ipv4,uint32_t prefix,void * v_ipset)9407 ipsetUnionCallbackIPTree(
9408 uint32_t ipv4,
9409 uint32_t prefix,
9410 void *v_ipset)
9411 {
9412 return ipsetInsertAddressIPTree(((skipset_t*)v_ipset)->s.v2, ipv4, prefix);
9413 }
9414
9415 static int
ipsetUnionCallbackV4(uint32_t ipv4,uint32_t prefix,void * v_ipset)9416 ipsetUnionCallbackV4(
9417 uint32_t ipv4,
9418 uint32_t prefix,
9419 void *v_ipset)
9420 {
9421 return ipsetInsertAddressV4((skipset_t*)v_ipset, ipv4, prefix, NULL);
9422 }
9423
9424 #if SK_ENABLE_IPV6
9425 static int
ipsetUnionCallbackV6(const ipset_ipv6_t * ipv6,uint32_t prefix,void * v_ipset)9426 ipsetUnionCallbackV6(
9427 const ipset_ipv6_t *ipv6,
9428 uint32_t prefix,
9429 void *v_ipset)
9430 {
9431 return ipsetInsertAddressV6((skipset_t*)v_ipset, ipv6, prefix, NULL);
9432 }
9433 #endif /* SK_ENABLE_IPV6 */
9434
9435 static int
ipsetUnionCallback(skipaddr_t * ipaddr,uint32_t prefix,void * v_ipset)9436 ipsetUnionCallback(
9437 skipaddr_t *ipaddr,
9438 uint32_t prefix,
9439 void *v_ipset)
9440 {
9441 return skIPSetInsertAddress((skipset_t*)v_ipset, ipaddr, prefix);
9442 }
9443
9444 /*
9445 * Helper function for skIPSetUnion() when combining two IPsets
9446 * that are implmented as SiLK-2 IPTrees.
9447 *
9448 * Also a helper function for legacy skIPTreeUnion().
9449 */
9450 static int
ipsetUnionIPTree(skIPTree_t * result_ipset,const skIPTree_t * ipset)9451 ipsetUnionIPTree(
9452 skIPTree_t *result_ipset,
9453 const skIPTree_t *ipset)
9454 {
9455 unsigned int i, j;
9456
9457 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
9458 if (NULL == ipset->nodes[i]) {
9459 /* no change required in 'result_ipset' */
9460
9461 } else if (NULL == result_ipset->nodes[i]) {
9462 /* create a new block on 'result_ipset' and make it
9463 * identical to that from 'ipset' */
9464 IPTREE_NODE_ALLOC(result_ipset, i);
9465 memcpy(result_ipset->nodes[i], ipset->nodes[i],
9466 sizeof(skIPNode_t));
9467
9468 } else {
9469 /* merge the values */
9470 for (j = 0; j < SKIP_BBLOCK_SIZE; ++j) {
9471 result_ipset->nodes[i]->addressBlock[j]
9472 |= ipset->nodes[i]->addressBlock[j];
9473 }
9474 }
9475 }
9476 return SKIPSET_OK;
9477 }
9478
9479
9480 /*
9481 * When the following macro is defined, ipsetVerify() prints a
9482 * message to stderr saying why verification of the IPset failed.
9483 * If it is not defined, no reason is given.
9484 *
9485 * The arguments to the macro should appear in double parentheses,
9486 * and the first argument should be VF3. Example:
9487 *
9488 * VERIFAIL((VF3, "root index is invalid"));
9489 */
9490 /* #define VERIFAIL(args) ipsetVerifail args */
9491
9492 #ifndef VERIFAIL
9493 #define VERIFAIL(args)
9494 #else
9495 #define VF3 ipset, __FILE__, __LINE__
9496
9497 /*
9498 * Print a message saying why verification failed.
9499 */
9500 static void
9501 ipsetVerifail(
9502 const skipset_t *ipset,
9503 const char *file,
9504 int line,
9505 const char *format,
9506 ...)
9507 SK_CHECK_PRINTF(4, 5);
9508
9509 static void
ipsetVerifail(const skipset_t * ipset,const char * file,int line,const char * format,...)9510 ipsetVerifail(
9511 const skipset_t *ipset,
9512 const char *file,
9513 int line,
9514 const char *format,
9515 ...)
9516 {
9517 va_list args;
9518
9519 va_start(args, format);
9520 fprintf(stderr, "%s:%d: IPset %p is not valid: ",
9521 file, line, (void*)ipset);
9522 vfprintf(stderr, format, args);
9523 fprintf(stderr, "\n");
9524 va_end(args);
9525 }
9526 #endif /* #else of #ifndef VERIFAIL */
9527
9528
9529 /*
9530 * status = ipsetVerify(ipset);
9531 *
9532 * Verify that all the indexes in a Radix-Tree based IPset are
9533 * valid---that is, less than number of allocated nodes and leaves.
9534 * Return SKIPSET_OK on success, or SKIPSET_ERR_CORRUPT on failure.
9535 * Verify that every prefix is less than the maximum.
9536 */
9537 static int
ipsetVerify(const skipset_t * ipset)9538 ipsetVerify(
9539 const skipset_t *ipset)
9540 {
9541 uint32_t to_visit[IPSET_MAX_DEPTH];
9542 uint32_t bitmap_size;
9543 sk_bitmap_t *bitmap = NULL;
9544 const ipset_node_t *node;
9545 const ipset_leaf_t *leaf;
9546 const ipset_node_t *n2;
9547 uint32_t node_idx;
9548 uint32_t depth;
9549 uint32_t i;
9550
9551 int rv = SKIPSET_ERR_CORRUPT;
9552
9553 if (NULL == ipset || 1 == ipset->is_iptree) {
9554 return SKIPSET_OK;
9555 }
9556 if (ipset->s.v3->nodes.entry_count > ipset->s.v3->nodes.entry_capacity) {
9557 VERIFAIL((VF3, "nodes_count(%u) > nodes_capacity(%u)",
9558 ipset->s.v3->nodes.entry_count,
9559 ipset->s.v3->nodes.entry_capacity));
9560 return rv;
9561 }
9562 if (ipset->s.v3->leaves.entry_count > ipset->s.v3->leaves.entry_capacity) {
9563 VERIFAIL((VF3, "leaves_count(%u) > leaves_capacity(%u)",
9564 ipset->s.v3->leaves.entry_count,
9565 ipset->s.v3->leaves.entry_capacity));
9566 return rv;
9567 }
9568
9569 if (IPSET_ISEMPTY(ipset)) {
9570 return SKIPSET_OK;
9571 }
9572
9573 if (ipset->s.v3->root_is_leaf) {
9574 if (IPSET_ROOT_INDEX(ipset) >= ipset->s.v3->leaves.entry_count) {
9575 VERIFAIL((VF3, "leaf_index(%u) >= leaves_count(%u) [root]",
9576 IPSET_ROOT_INDEX(ipset),
9577 ipset->s.v3->leaves.entry_count));
9578 return rv;
9579 }
9580 leaf = LEAF_PTR(ipset, IPSET_ROOT_INDEX(ipset));
9581 if (((leaf->v4.prefix > 32) && !ipset->is_ipv6)
9582 || (leaf->v4.prefix > 128))
9583 {
9584 VERIFAIL((VF3, "leaf(%u) prefix is invalid %u [root]",
9585 IPSET_ROOT_INDEX(ipset), leaf->v4.prefix));
9586 return rv;
9587 }
9588 return SKIPSET_OK;
9589 }
9590
9591 if (IPSET_ROOT_INDEX(ipset) >= ipset->s.v3->nodes.entry_count) {
9592 VERIFAIL((VF3, "node_index(%u) >= nodes_count(%u) [root]",
9593 IPSET_ROOT_INDEX(ipset), ipset->s.v3->nodes.entry_count));
9594 return rv;
9595 }
9596 n2 = NODE_PTR(ipset, IPSET_ROOT_INDEX(ipset));
9597 if (((n2->v4.prefix > 32) && !ipset->is_ipv6)
9598 || (n2->v4.prefix > 128))
9599 {
9600 VERIFAIL((VF3, "node(%u) prefix is invalid %u [root]",
9601 IPSET_ROOT_INDEX(ipset), n2->v4.prefix));
9602 return rv;
9603 }
9604
9605 /* create a bitmap to note which nodes and leaves are on the free
9606 * list and to check for diamonds in the structure. assume the
9607 * IPset is okay if we cannot allocate the bitmap */
9608 if (ipset->s.v3->nodes.entry_count > ipset->s.v3->leaves.entry_count) {
9609 bitmap_size = ipset->s.v3->nodes.entry_count;
9610 } else {
9611 bitmap_size = ipset->s.v3->leaves.entry_count;
9612 }
9613 if (skBitmapCreate(&bitmap, bitmap_size)) {
9614 VERIFAIL((VF3, "cannot create bitmap"));
9615 return SKIPSET_OK;
9616 }
9617
9618 /* check the tree for a node linked to by multiple nodes, for
9619 * invalid node indexes, and for invalid prefixes */
9620 depth = 0;
9621 skBitmapSetBit(bitmap, IPSET_ROOT_INDEX(ipset));
9622 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
9623 while (depth) {
9624 node_idx = to_visit[--depth];
9625 node = NODE_PTR(ipset, node_idx);
9626 for (i = 0; i < IPSET_NUM_CHILDREN; ++i) {
9627 if (node->v4.child[i] && !NODEPTR_CHILD_IS_LEAF(&node->v4, i)) {
9628 if (node->v4.child[i] >= ipset->s.v3->nodes.entry_count) {
9629 VERIFAIL((VF3, ("node_index(%u) >= nodes_count(%u)"
9630 " [child %u of %u]"),
9631 node->v4.child[i],
9632 ipset->s.v3->nodes.entry_count, i, node_idx));
9633 goto END;
9634 }
9635 if (skBitmapGetBit(bitmap, node->v4.child[i])) {
9636 VERIFAIL((VF3, "duplicate node(%u) [child %u of %u]",
9637 node->v4.child[i], i, node_idx));
9638 goto END;
9639 }
9640 n2 = NODE_PTR(ipset, node->v4.child[i]);
9641 if (((n2->v4.prefix > 32) && !ipset->is_ipv6)
9642 || (n2->v4.prefix > 128) || (0 == n2->v4.prefix))
9643 {
9644 VERIFAIL((VF3, ("node(%u) prefix is invalid %u"
9645 " [child %u of %u]"),
9646 node->v4.child[i], n2->v4.prefix, i, node_idx));
9647 goto END;
9648 }
9649 skBitmapSetBit(bitmap, node->v4.child[i]);
9650 to_visit[depth++] = node->v4.child[i];
9651 }
9652 }
9653 }
9654
9655 /* check for duplicates on the node free list and for elements on
9656 * free list that are also in the tree; use depth to keep track of
9657 * how far into the list we go */
9658 depth = 0;
9659 for (node_idx = ipset->s.v3->nodes.free_list;
9660 0 != node_idx;
9661 node_idx = NODEIDX_FREE_LIST(ipset, node_idx))
9662 {
9663 ++depth;
9664 if (node_idx >= ipset->s.v3->nodes.entry_count) {
9665 VERIFAIL((VF3, ("node_index(%u) >= nodes_count(%u)"
9666 " [free list item %u]"),
9667 node_idx, ipset->s.v3->nodes.entry_count, depth));
9668 goto END;
9669 }
9670 if (!skBitmapGetBit(bitmap, node_idx)) {
9671 skBitmapSetBit(bitmap, node_idx);
9672 } else {
9673 /* is this a duplicate of a node in the tree or on the
9674 * free list? */
9675 skBitmapClearAllBits(bitmap);
9676 for (node_idx = ipset->s.v3->nodes.free_list;
9677 0 != node_idx && depth > 0;
9678 node_idx = NODEIDX_FREE_LIST(ipset, node_idx))
9679 {
9680 --depth;
9681 if (skBitmapGetBit(bitmap, node_idx)) {
9682 VERIFAIL((VF3, "duplicate free node_index(%u)", node_idx));
9683 goto END;
9684 }
9685 skBitmapSetBit(bitmap, node_idx);
9686 }
9687 VERIFAIL((VF3, "node_index(%u) also on free list", node_idx));
9688 goto END;
9689 }
9690 }
9691
9692 /* check the tree for a leaf linked to by multiple nodes, for
9693 * invalid leaf indexes, and for invalid prefixes */
9694 skBitmapClearAllBits(bitmap);
9695 depth = 0;
9696 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
9697 while (depth) {
9698 node_idx = to_visit[--depth];
9699 node = NODE_PTR(ipset, node_idx);
9700 for (i = 0; i < IPSET_NUM_CHILDREN; ++i) {
9701 if (0 == node->v4.child[i]) {
9702 /* no-op */
9703 } else if (!NODEPTR_CHILD_IS_LEAF(&node->v4, i)) {
9704 to_visit[depth++] = node->v4.child[i];
9705 } else if (NODEPTR_CHILD_IS_REPEAT(&node->v4, i)) {
9706 if (0 == i) {
9707 skAbort();
9708 }
9709 if (node->v4.child[i] != node->v4.child[i - 1]) {
9710 VERIFAIL((VF3, ("on node %u, bad id on child %u (%u)"
9711 " marked as repeat of previous (%u)"),
9712 node_idx, i, node->v4.child[i],
9713 node->v4.child[i-1]));
9714 goto END;
9715 }
9716 } else {
9717 if (node->v4.child[i] >= ipset->s.v3->leaves.entry_count) {
9718 VERIFAIL((VF3, ("leaf_index(%u) >= leaves_count(%u)"
9719 " [child %u of %u]"),
9720 node->v4.child[i],
9721 ipset->s.v3->leaves.entry_count, i, node_idx));
9722 goto END;
9723 }
9724 if (skBitmapGetBit(bitmap, node->v4.child[i])) {
9725 VERIFAIL((VF3, "duplicate leaf(%u) [child %u of %u]",
9726 node->v4.child[i], i, node_idx));
9727 goto END;
9728 }
9729 leaf = LEAF_PTR(ipset, node->v4.child[i]);
9730 if (((leaf->v4.prefix > 32) && !ipset->is_ipv6)
9731 || (leaf->v4.prefix > 128) || (0 == leaf->v4.prefix))
9732 {
9733 VERIFAIL((VF3, ("leaf(%u) prefix is invalid %u"
9734 " [child %u of %u]"),
9735 node->v4.child[i], leaf->v4.prefix, i,node_idx));
9736 goto END;
9737 }
9738 skBitmapSetBit(bitmap, node->v4.child[i]);
9739 }
9740 }
9741 }
9742
9743 /* check for duplicates on the leaf free list and for elements on
9744 * free list that are also in the tree; use depth to keep track of
9745 * how far into the list we go */
9746 depth = 0;
9747 for (node_idx = ipset->s.v3->leaves.free_list;
9748 0 != node_idx;
9749 node_idx = LEAFIDX_FREE_LIST(ipset, node_idx))
9750 {
9751 ++depth;
9752 if (node_idx >= ipset->s.v3->leaves.entry_count) {
9753 VERIFAIL((VF3, ("leaf_index(%u) >= leaves_count(%u)"
9754 " [free list item %u]"),
9755 node_idx, ipset->s.v3->leaves.entry_count, depth));
9756 goto END;
9757 }
9758 if (!skBitmapGetBit(bitmap, node_idx)) {
9759 skBitmapSetBit(bitmap, node_idx);
9760 } else {
9761 /* is this a duplicate of a leaf in the tree or on the
9762 * free list? */
9763 skBitmapClearAllBits(bitmap);
9764 for (node_idx = ipset->s.v3->leaves.free_list;
9765 0 != node_idx;
9766 node_idx = LEAFIDX_FREE_LIST(ipset, node_idx))
9767 {
9768 --depth;
9769 if (skBitmapGetBit(bitmap, node_idx)) {
9770 VERIFAIL((VF3, "duplicate free leaf_index(%u)", node_idx));
9771 goto END;
9772 }
9773 skBitmapSetBit(bitmap, node_idx);
9774 }
9775 VERIFAIL((VF3, "leaf_index(%u) also on free list", node_idx));
9776 goto END;
9777 }
9778 }
9779
9780 rv = SKIPSET_OK;
9781
9782 END:
9783 if (bitmap) {
9784 skBitmapDestroy(&bitmap);
9785 }
9786 return rv;
9787 }
9788
9789
9790 /*
9791 * status = ipsetWalkInternalV4(ipset, callback, cb_data);
9792 * status = ipsetWalkInternalV6(ipset, callback, cb_data);
9793 *
9794 * These are internal functions for walking over the contents a
9795 * Radix-Tree based IPset. They are NOT helper functions for
9796 * skIPSetWalk(). The helper functions for skIPSetWalk() are named
9797 * ipsetWalkV4() and ipsetWalkV6().
9798 *
9799 * These function visit the leaves in an IPset in order from lowest
9800 * to highest. They will use the iterator if the IPset is clean,
9801 * or recursively walk the nodes if the IPset is dirty.
9802 *
9803 * These functions always invoke the 'callback' with the IP/prefix
9804 * pair---that is they do not visit individual IP addresses.
9805 *
9806 * The callback will be invoked with the IP in the form stored
9807 * internally by the IPset, eliminating the conversion to/from an
9808 * skipaddr_t that skIPSetWalk() performs.
9809 *
9810 * The function stops visiting the leaves when the callback returns
9811 * a value other than SKIPSET_OK.
9812 *
9813 * Return SKIPSET_OK if the IPset is empty; otherwise, return the
9814 * value returned by the final call to the callback.
9815 */
9816 static int
ipsetWalkInternalV4(const skipset_t * ipset,ipset_walk_v4_fn_t callback,void * cb_data)9817 ipsetWalkInternalV4(
9818 const skipset_t *ipset,
9819 ipset_walk_v4_fn_t callback,
9820 void *cb_data)
9821 {
9822 uint8_t is_leaf[IPSET_MAX_DEPTH_V4];
9823 uint32_t to_visit[IPSET_MAX_DEPTH_V4];
9824 const ipset_node_v4_t *node;
9825 const ipset_leaf_v4_t *leaf;
9826 uint32_t depth;
9827 uint32_t i;
9828 int rv = SKIPSET_OK;
9829
9830 assert(ipset);
9831 assert(0 == ipset->is_iptree);
9832 assert(0 == ipset->is_ipv6);
9833 assert(callback);
9834
9835 if (IPSET_ISEMPTY(ipset)) {
9836 return SKIPSET_OK;
9837 }
9838
9839 /* use the iterator if we can */
9840 if (!ipset->is_dirty) {
9841 uint32_t cur = IPSET_ITER_FIRST_LEAF;
9842 while (0 == rv && cur < ipset->s.v3->leaves.entry_count) {
9843 leaf = LEAF_PTR_V4(ipset, cur);
9844 rv = callback(leaf->ip, leaf->prefix, cb_data);
9845 ++cur;
9846 }
9847 return rv;
9848 }
9849
9850 depth = 0;
9851 is_leaf[depth] = IPSET_ROOT_IS_LEAF(ipset);
9852 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
9853
9854 while (depth) {
9855 if (is_leaf[--depth]) {
9856 /* handle a leaf node */
9857 leaf = LEAF_PTR_V4(ipset, to_visit[depth]);
9858 rv = callback(leaf->ip, leaf->prefix, cb_data);
9859 if (0 != rv) {
9860 break;
9861 }
9862 } else {
9863 /* push children onto the stack in reverse order */
9864 node = NODE_PTR_V4(ipset, to_visit[depth]);
9865 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
9866 --i;
9867 if (node->child[i]
9868 && !NODEPTR_CHILD_IS_REPEAT(node, i))
9869 {
9870 is_leaf[depth] = NODEPTR_CHILD_IS_LEAF(node, i);
9871 to_visit[depth++] = node->child[i];
9872 }
9873 }
9874 }
9875 }
9876 return rv;
9877 }
9878
9879 #if SK_ENABLE_IPV6
9880 static int
ipsetWalkInternalV6(const skipset_t * ipset,ipset_walk_v6_fn_t callback,void * cb_data)9881 ipsetWalkInternalV6(
9882 const skipset_t *ipset,
9883 ipset_walk_v6_fn_t callback,
9884 void *cb_data)
9885 {
9886 uint8_t is_leaf[IPSET_MAX_DEPTH_V6];
9887 uint32_t to_visit[IPSET_MAX_DEPTH_V6];
9888 const ipset_node_v6_t *node;
9889 const ipset_leaf_v6_t *leaf;
9890 uint32_t depth;
9891 uint32_t i;
9892 int rv = SKIPSET_OK;
9893
9894 assert(ipset);
9895 assert(0 == ipset->is_iptree);
9896 assert(1 == ipset->is_ipv6);
9897 assert(callback);
9898
9899 if (IPSET_ISEMPTY(ipset)) {
9900 return SKIPSET_OK;
9901 }
9902
9903 /* use the iterator if we can */
9904 if (!ipset->is_dirty) {
9905 uint32_t cur = IPSET_ITER_FIRST_LEAF;
9906 while (0 == rv && cur < ipset->s.v3->leaves.entry_count) {
9907 leaf = LEAF_PTR_V6(ipset, cur);
9908 rv = callback(&leaf->ip, leaf->prefix, cb_data);
9909 ++cur;
9910 }
9911 return rv;
9912 }
9913
9914 depth = 0;
9915 is_leaf[depth] = IPSET_ROOT_IS_LEAF(ipset);
9916 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
9917
9918 while (depth) {
9919 if (is_leaf[--depth]) {
9920 /* handle a leaf node */
9921 leaf = LEAF_PTR_V6(ipset, to_visit[depth]);
9922 rv = callback(&leaf->ip, leaf->prefix, cb_data);
9923 if (0 != rv) {
9924 break;
9925 }
9926 } else {
9927 /* push children onto the stack in reverse order */
9928 node = NODE_PTR_V6(ipset, to_visit[depth]);
9929 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
9930 --i;
9931 if (node->child[i]
9932 && !NODEPTR_CHILD_IS_REPEAT(node, i))
9933 {
9934 is_leaf[depth] = NODEPTR_CHILD_IS_LEAF(node, i);
9935 to_visit[depth++] = node->child[i];
9936 }
9937 }
9938 }
9939 }
9940 return rv;
9941 }
9942 #endif /* SK_ENABLE_IPV6 */
9943
9944
9945 /*
9946 * status = ipsetWalkV4(ipset, walk_state);
9947 * status = ipsetWalkV6(ipset, walk_state);
9948 *
9949 * Helper function for skIPSetWalk().
9950 *
9951 * These function visit the leaves in an IPset in order from lowest
9952 * to highest. They will use the iterator if the IPset is clean,
9953 * or walk the nodes if the IPset is dirty.
9954 *
9955 * Depending on 'walk_state', the callback is invoked on the CIDR
9956 * blocks as stored in the tree or on individual IP addresses.
9957 *
9958 * The callback will be invoked with the IP converted to an
9959 * skipaddr_t. The 'walk_state' determines whether the skipaddr_t
9960 * contains an IPv4 or IPv6 representation of the IP address.
9961 *
9962 * The function stops visiting the leaves when the callback returns
9963 * a value other than SKIPSET_OK.
9964 *
9965 * Return SKIPSET_OK if the IPset is empty; otherwise, return the
9966 * value returned by the final call to the callback.
9967 *
9968 * Do not confuse these helper functions for skIPSetWalk() with the
9969 * internal functions for walking over an IPset, which are
9970 * ipsetWalkInternalV4() and ipsetWalkInternalV6().
9971 */
9972 static int
ipsetWalkV4(const skipset_t * ipset,const ipset_walk_t * walk_state)9973 ipsetWalkV4(
9974 const skipset_t *ipset,
9975 const ipset_walk_t *walk_state)
9976 {
9977 uint8_t is_leaf[IPSET_MAX_DEPTH_V4];
9978 uint32_t to_visit[IPSET_MAX_DEPTH_V4];
9979 const ipset_node_v4_t *node;
9980 const ipset_leaf_v4_t *leaf;
9981 skipaddr_t ipaddr;
9982 uint32_t depth;
9983 uint32_t ipv4;
9984 uint32_t fin4;
9985 uint32_t i;
9986 int rv = 0;
9987
9988 assert(ipset);
9989 assert(walk_state);
9990 assert(walk_state->callback);
9991 assert(walk_state->v6policy != SK_IPV6POLICY_ONLY);
9992
9993 depth = 0;
9994 is_leaf[depth] = IPSET_ROOT_IS_LEAF(ipset);
9995 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
9996
9997 if (walk_state->cidr_blocks) {
9998 while (depth) {
9999 if (!is_leaf[--depth]) {
10000 node = NODE_PTR_V4(ipset, to_visit[depth]);
10001 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
10002 --i;
10003 if (node->child[i]
10004 && !NODEPTR_CHILD_IS_REPEAT(node, i))
10005 {
10006 is_leaf[depth] = NODEPTR_CHILD_IS_LEAF(node, i);
10007 to_visit[depth++] = node->child[i];
10008 }
10009 }
10010 } else {
10011 /* handle a leaf node */
10012 leaf = LEAF_PTR_V4(ipset, to_visit[depth]);
10013 #if SK_ENABLE_IPV6
10014 if (SK_IPV6POLICY_FORCE == walk_state->v6policy) {
10015 skipaddrSetV6FromUint32(&ipaddr, &leaf->ip);
10016 rv = walk_state->callback(&ipaddr, 96 + leaf->prefix,
10017 walk_state->cb_data);
10018 } else
10019 #endif /* SK_ENABLE_IPV6 */
10020 {
10021 skipaddrSetV4(&ipaddr, &leaf->ip);
10022 rv = walk_state->callback(&ipaddr, leaf->prefix,
10023 walk_state->cb_data);
10024 }
10025 if (0 != rv) {
10026 break;
10027 }
10028 }
10029 }
10030 return rv;
10031 }
10032
10033 /* Walk over IPset, running the callback function with each
10034 * individual IP address */
10035 while (depth) {
10036 if (!is_leaf[--depth]) {
10037 node = NODE_PTR_V4(ipset, to_visit[depth]);
10038 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
10039 --i;
10040 if (node->child[i]
10041 && !NODEPTR_CHILD_IS_REPEAT(node, i))
10042 {
10043 is_leaf[depth] = NODEPTR_CHILD_IS_LEAF(node, i);
10044 to_visit[depth++] = node->child[i];
10045 }
10046 }
10047
10048 #if SK_ENABLE_IPV6
10049 } else if (SK_IPV6POLICY_FORCE == walk_state->v6policy) {
10050 /* handle a leaf node where IPv6 addresses are to be
10051 * returned */
10052 leaf = LEAF_PTR_V4(ipset, to_visit[depth]);
10053 if (32 == leaf->prefix) {
10054 skipaddrSetV6FromUint32(&ipaddr, &leaf->ip);
10055 rv = walk_state->callback(&ipaddr, 128, walk_state->cb_data);
10056 } else {
10057 /* else visit each IP in the block */
10058 ipv4 = leaf->ip;
10059 fin4 = leaf->ip | (UINT32_MAX >> leaf->prefix);
10060
10061 do {
10062 skipaddrSetV6FromUint32(&ipaddr, &ipv4);
10063 rv = walk_state->callback(&ipaddr, 128,
10064 walk_state->cb_data);
10065 } while ((0 == rv) && (ipv4++ < fin4));
10066 }
10067 if (0 != rv) {
10068 break;
10069 }
10070 #endif /* SK_ENABLE_IPV6 */
10071
10072 } else {
10073 /* handle a leaf node */
10074 leaf = LEAF_PTR_V4(ipset, to_visit[depth]);
10075 if (32 == leaf->prefix) {
10076 skipaddrSetV4(&ipaddr, &leaf->ip);
10077 rv = walk_state->callback(&ipaddr, leaf->prefix,
10078 walk_state->cb_data);
10079 } else {
10080 /* else visit each IP in the block */
10081 ipv4 = leaf->ip;
10082 fin4 = leaf->ip | (UINT32_MAX >> leaf->prefix);
10083 do {
10084 skipaddrSetV4(&ipaddr, &ipv4);
10085 rv = walk_state->callback(&ipaddr, 32, walk_state->cb_data);
10086 } while ((0 == rv) && (ipv4++ < fin4));
10087 }
10088 if (0 != rv) {
10089 break;
10090 }
10091 }
10092 }
10093 return rv;
10094 }
10095
10096 #if SK_ENABLE_IPV6
10097 static int
ipsetWalkV6(const skipset_t * ipset,const ipset_walk_t * walk_state)10098 ipsetWalkV6(
10099 const skipset_t *ipset,
10100 const ipset_walk_t *walk_state)
10101 {
10102 uint8_t is_leaf[IPSET_MAX_DEPTH_V6];
10103 uint32_t to_visit[IPSET_MAX_DEPTH_V6];
10104 const ipset_node_v6_t *node;
10105 const ipset_leaf_v6_t *leaf;
10106 skipaddr_t ipaddr;
10107 uint32_t depth;
10108 ipset_ipv6_t ipv6;
10109 ipset_ipv6_t fin6;
10110 int i;
10111 int rv = 0;
10112
10113 assert(ipset);
10114 assert(walk_state);
10115 assert(walk_state->callback);
10116 assert(walk_state->v6policy != SK_IPV6POLICY_IGNORE);
10117
10118 if (SK_IPV6POLICY_ASV4 != walk_state->v6policy) {
10119 /* visit all the nodes in the tree */
10120 depth = 0;
10121 is_leaf[depth] = IPSET_ROOT_IS_LEAF(ipset);
10122 to_visit[depth++] = IPSET_ROOT_INDEX(ipset);
10123 } else {
10124 /* limit to the nodes under ::ffff:0:0/96 */
10125 ipset_find_t find_state;
10126
10127 ipv6.ip[0] = 0;
10128 ipv6.ip[1] = UINT64_C(0xffff00000000);
10129
10130 rv = ipsetFindV6(ipset, &ipv6, 96, &find_state);
10131 if (SKIPSET_OK != rv && SKIPSET_ERR_SUBSET != rv) {
10132 /* no IPv4 addresses in the IPset */
10133 return SKIPSET_OK;
10134 }
10135 depth = 0;
10136 is_leaf[depth] = find_state.node_is_leaf;
10137 to_visit[depth++] = find_state.node_idx;
10138 rv = 0;
10139 }
10140
10141 if (walk_state->cidr_blocks) {
10142 while (depth) {
10143 if (!is_leaf[--depth]) {
10144 node = NODE_PTR_V6(ipset, to_visit[depth]);
10145 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
10146 --i;
10147 if (node->child[i]
10148 && !NODEPTR_CHILD_IS_REPEAT(node, i))
10149 {
10150 is_leaf[depth] = NODEPTR_CHILD_IS_LEAF(node, i);
10151 to_visit[depth++] = node->child[i];
10152 }
10153 }
10154 } else {
10155 /* handle a leaf node */
10156 leaf = LEAF_PTR_V6(ipset, to_visit[depth]);
10157 if (SK_IPV6POLICY_ASV4 == walk_state->v6policy) {
10158 IPSET_IPV6_TO_ADDR_V4(&leaf->ip, &ipaddr);
10159 rv = walk_state->callback(&ipaddr, leaf->prefix - 96,
10160 walk_state->cb_data);
10161 } else {
10162 IPSET_IPV6_TO_ADDR(&leaf->ip, &ipaddr);
10163 rv = walk_state->callback(&ipaddr, leaf->prefix,
10164 walk_state->cb_data);
10165 }
10166 if (0 != rv) {
10167 break;
10168 }
10169 }
10170 }
10171 return rv;
10172 }
10173
10174 /* Walk over IPset, running the callback function with each
10175 * individual IP address */
10176 while (depth) {
10177 if (!is_leaf[--depth]) {
10178 node = NODE_PTR_V6(ipset, to_visit[depth]);
10179 for (i = IPSET_NUM_CHILDREN; i > 0; ) {
10180 --i;
10181 if (node->child[i]
10182 && !NODEPTR_CHILD_IS_REPEAT(node, i))
10183 {
10184 is_leaf[depth] = NODEPTR_CHILD_IS_LEAF(node, i);
10185 to_visit[depth++] = node->child[i];
10186 }
10187 }
10188
10189 } else if (SK_IPV6POLICY_ASV4 == walk_state->v6policy) {
10190 /* handle a leaf node where IPv4 addresses are to be
10191 * returned */
10192 leaf = LEAF_PTR_V6(ipset, to_visit[depth]);
10193 if (128 == leaf->prefix) {
10194 IPSET_IPV6_TO_ADDR_V4(&leaf->ip, &ipaddr);
10195 rv = walk_state->callback(&ipaddr, 32, walk_state->cb_data);
10196 } else {
10197 /* else visit each IP in the block; convert CIDR block
10198 * to current IP (ipv4) and final IP (fin4) */
10199 uint32_t ipv4;
10200 uint32_t fin4;
10201
10202 assert(96 <= leaf->prefix);
10203 assert(0 == leaf->ip.ip[0]);
10204 assert(UINT64_C(0x0000ffff00000000)
10205 == (UINT64_C(0xffffffff00000000) & leaf->ip.ip[1]));
10206 ipv4 = (uint32_t)(UINT64_C(0x00000000ffffffff)
10207 & leaf->ip.ip[1]);
10208 fin4 = ipv4 | (UINT32_MAX >> (leaf->prefix - 96));
10209
10210 do {
10211 skipaddrSetV4(&ipaddr, &ipv4);
10212 rv = walk_state->callback(&ipaddr, 32,
10213 walk_state->cb_data);
10214 } while ((0 == rv) && (ipv4++ < fin4));
10215 }
10216 if (0 != rv) {
10217 break;
10218 }
10219
10220 } else {
10221 /* handle a leaf node */
10222 leaf = LEAF_PTR_V6(ipset, to_visit[depth]);
10223 if (128 == leaf->prefix) {
10224 IPSET_IPV6_TO_ADDR(&leaf->ip, &ipaddr);
10225 rv = walk_state->callback(&ipaddr, leaf->prefix,
10226 walk_state->cb_data);
10227 } else {
10228 /* else visit each IP in the block; convert CIDR block
10229 * to current IP (ipv6) and final IP (fin6) */
10230 if (leaf->prefix > 64) {
10231 ipv6.ip[0] = fin6.ip[0] = leaf->ip.ip[0];
10232 ipv6.ip[1] = leaf->ip.ip[1];
10233 fin6.ip[1] = (leaf->ip.ip[1]
10234 | (UINT64_MAX >> (leaf->prefix - 64)));
10235 } else if (leaf->prefix == 64) {
10236 ipv6.ip[0] = fin6.ip[0] = leaf->ip.ip[0];
10237 ipv6.ip[1] = 0;
10238 fin6.ip[1] = UINT64_MAX;
10239 } else {
10240 ipv6.ip[0] = leaf->ip.ip[0];
10241 fin6.ip[0] = (leaf->ip.ip[0]
10242 | (UINT64_MAX >> leaf->prefix));
10243 ipv6.ip[1] = 0;
10244 fin6.ip[1] = UINT64_MAX;
10245 }
10246
10247 for (;;) {
10248 IPSET_IPV6_TO_ADDR(&ipv6, &ipaddr);
10249 rv = walk_state->callback(&ipaddr,128,walk_state->cb_data);
10250 if (rv) {
10251 return rv;
10252 }
10253 if (ipv6.ip[1] < fin6.ip[1]) {
10254 ++ipv6.ip[1];
10255 } else if (ipv6.ip[0] < fin6.ip[0]) {
10256 if (ipv6.ip[1] == UINT64_MAX) {
10257 ++ipv6.ip[0];
10258 ipv6.ip[1] = 0;
10259 } else {
10260 ++ipv6.ip[1];
10261 }
10262 } else {
10263 break;
10264 }
10265 }
10266 }
10267 }
10268 }
10269
10270 return rv;
10271 }
10272 #endif /* SK_ENABLE_IPV6 */
10273
10274
10275 /*
10276 * status = ipsetWriteCidrbmapFromIPTree(ipset, stream);
10277 *
10278 * Helper function for skIPSetWrite() via ipsetWriteCidrbmap().
10279 *
10280 * Write an IPset from the SiLK-2 IPTree data structure to 'stream'
10281 * in the IPSET_REC_VERSION_CIDRBMAP format.
10282 *
10283 * See '#define IPSET_REC_VERSION_CIDRBMAP' for description of the
10284 * file format.
10285 */
10286 static int
ipsetWriteCidrbmapFromIPTree(const skipset_t * ipset,skstream_t * stream)10287 ipsetWriteCidrbmapFromIPTree(
10288 const skipset_t *ipset,
10289 skstream_t *stream)
10290 {
10291 sk_file_header_t *hdr;
10292 uint8_t write_buf[sizeof(uint32_t) + sizeof(uint8_t)];
10293 skIPNode_t *slash16;
10294 uint32_t i;
10295 uint32_t j;
10296 ssize_t rv;
10297 struct build_cidr_st {
10298 /* starting ip for this netblock */
10299 uint32_t start;
10300 /* number of trailing 0s; used to set CIDR mask */
10301 uint32_t trail_zero;
10302 /* maximum number of /24s this block can hold */
10303 uint32_t max_block;
10304 /* number of the max_block we have seen so far */
10305 uint32_t count;
10306 } build_cidr;
10307
10308 #define WRITE_BUILD_CIDR \
10309 while (build_cidr.count) { \
10310 --build_cidr.trail_zero; \
10311 if (build_cidr.count >= (1u << (build_cidr.trail_zero - 8))) { \
10312 *(uint32_t*)write_buf = build_cidr.start; \
10313 write_buf[sizeof(uint32_t)] \
10314 = (uint8_t)(32 - build_cidr.trail_zero); \
10315 rv = skStreamWrite(stream, write_buf, sizeof(write_buf)); \
10316 if (rv != sizeof(write_buf)) { \
10317 return SKIPSET_ERR_FILEIO; \
10318 } \
10319 build_cidr.count -= (1 << (build_cidr.trail_zero - 8)); \
10320 build_cidr.start |= (0x100 << (build_cidr.trail_zero - 8)); \
10321 } \
10322 }
10323
10324 /* sanity check input */
10325 assert(ipset);
10326 assert(stream);
10327 if (ipset->is_dirty || !ipset->is_iptree || ipset->is_ipv6) {
10328 skAbort();
10329 }
10330 hdr = skStreamGetSilkHeader(stream);
10331 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_CIDRBMAP) {
10332 skAbort();
10333 }
10334
10335 memset(&build_cidr, 0, sizeof(build_cidr));
10336
10337 for (i = 0; i < SKIP_BBLOCK_COUNT; ++i) {
10338 /* slash16 represents a /16 */
10339 slash16 = ipset->s.v2->nodes[i];
10340 if (NULL == slash16) {
10341 /* no data in this /16; write any CIDR range that was
10342 * being built */
10343 WRITE_BUILD_CIDR;
10344 continue;
10345 }
10346
10347 /* There is data in this /16, walk over the addressBlocks by
10348 * 8s, which is equivalent to visiting each /24. */
10349 for (j = 0; j < SKIP_BBLOCK_SIZE; j += IPTREE_WORDS_PER_SLASH24) {
10350
10351 if (0 == memcmp(slash16->addressBlock + j,
10352 bmap256_zero, sizeof(bmap256_zero)))
10353 {
10354 /* no data in this /24; write existing CIDR block */
10355 WRITE_BUILD_CIDR;
10356 continue;
10357 }
10358 if (0 == memcmp(slash16->addressBlock + j,
10359 bmap256_full, sizeof(bmap256_full)))
10360 {
10361 /* this /24 is full; if CIDR block is being built,
10362 * this block must be contiguous with it */
10363 if (build_cidr.count) {
10364 ++build_cidr.count;
10365 if (build_cidr.count == build_cidr.max_block) {
10366 /* cidr block is at its maximum size */
10367 *(uint32_t*)write_buf = build_cidr.start;
10368 write_buf[sizeof(uint32_t)]
10369 = (uint8_t)(32 - build_cidr.trail_zero);
10370 rv = skStreamWrite(stream,write_buf,sizeof(write_buf));
10371 if (rv != sizeof(write_buf)) {
10372 return SKIPSET_ERR_FILEIO;
10373 }
10374 build_cidr.count = 0;
10375 }
10376 continue;
10377 }
10378
10379 /* no existing CIDR block to join; start a new one */
10380 build_cidr.start = ((i << 16) | (j << 5)) & 0xFFFFFF00;
10381 if (build_cidr.start & 0x100) {
10382 /* the third octet is odd, so this block cannot be
10383 * combined with another */
10384 *(uint32_t*)write_buf = build_cidr.start;
10385 write_buf[sizeof(uint32_t)] = 24;
10386 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10387 if (rv != sizeof(write_buf)) {
10388 return SKIPSET_ERR_FILEIO;
10389 }
10390 continue;
10391 }
10392
10393 /* compute the maximum number of blocks that can be
10394 * joined with this one by computing the number of
10395 * trailing 0s on the IP. */
10396 if (0 == build_cidr.start) {
10397 build_cidr.trail_zero = 32;
10398 } else {
10399 build_cidr.trail_zero
10400 = ipsetCountTrailingZeros(build_cidr.start);
10401 }
10402 build_cidr.max_block = (1 << (build_cidr.trail_zero - 8));
10403 build_cidr.count = 1;
10404 continue;
10405 }
10406
10407 /* there is some data in this /24. First, handle any CIDR
10408 * range that was being build. Then, write this block as
10409 * a base address and bitmap. */
10410 WRITE_BUILD_CIDR;
10411
10412 /* write the IP and the 'bitmap-follows' value */
10413 *(uint32_t*)write_buf = (((i << 16) | (j << 5)) & 0xFFFFFF00);
10414 write_buf[sizeof(uint32_t)] = SET_CIDRBMAP_MAP256;
10415 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10416 if (rv != sizeof(write_buf)) {
10417 return SKIPSET_ERR_FILEIO;
10418 }
10419 /* write the complete /24: 8 uint32_t's */
10420 rv = skStreamWrite(stream, slash16->addressBlock + j,
10421 sizeof(bmap256_zero));
10422 if (rv != sizeof(bmap256_zero)) {
10423 return SKIPSET_ERR_FILEIO;
10424 }
10425 }
10426 }
10427
10428 rv = skStreamFlush(stream);
10429 if (rv) {
10430 return SKIPSET_ERR_FILEIO;
10431 }
10432
10433 return SKIPSET_OK;
10434 }
10435
10436
10437 /*
10438 * status = ipsetWriteCidrbmapFromRadixV4(&ipset, stream, hdr);
10439 * status = ipsetWriteCidrbmapFromRadixV6(&ipset, stream, hdr);
10440 *
10441 * Helper function for skIPSetWrite() via ipsetWriteCidrbmap().
10442 *
10443 * Write an IPset from the radix-tree IPset data structure to
10444 * 'stream' in the IPSET_REC_VERSION_CIDRBMAP format.
10445 *
10446 * See '#define IPSET_REC_VERSION_CIDRBMAP' for description of the
10447 * file format.
10448 */
10449 static int
ipsetWriteCidrbmapFromRadixV4(const skipset_t * ipset,skstream_t * stream)10450 ipsetWriteCidrbmapFromRadixV4(
10451 const skipset_t *ipset,
10452 skstream_t *stream)
10453 {
10454 sk_file_header_t *hdr;
10455 skipset_iterator_t iter;
10456 enum status_en {
10457 Empty, First_IP, Bitmap
10458 };
10459 struct state_st {
10460 /* starting ip for this netblock, or an unmasked IP if
10461 * 'status' is First_IP. */
10462 uint32_t base_ip;
10463 /* the 256-bit bitmap */
10464 uint32_t bmap[IPTREE_WORDS_PER_SLASH24];
10465 /* the prefix for 'base_ip' if 'status' is First_IP */
10466 uint8_t prefix;
10467 /* what this structure currently holds */
10468 enum status_en status;
10469 } state;
10470 /* the bitmap holds 256 bits or a /24 */
10471 const uint32_t bmap_prefix = 24;
10472 /* each uint32_t in the bitmap holds a /27 */
10473 const uint32_t word_prefix = 27;
10474 uint8_t write_buf[sizeof(uint32_t) + 1];
10475 uint32_t ipv4;
10476 skipaddr_t ipaddr;
10477 uint32_t prefix;
10478 uint32_t buf_idx;
10479 ssize_t rv;
10480
10481 /* sanity check input */
10482 assert(ipset);
10483 assert(stream);
10484 if (ipset->is_dirty || ipset->is_iptree || ipset->is_ipv6) {
10485 skAbort();
10486 }
10487 hdr = skStreamGetSilkHeader(stream);
10488 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_CIDRBMAP) {
10489 skAbort();
10490 }
10491
10492 memset(&state, 0, sizeof(state));
10493 state.status = Empty;
10494
10495 ASSERT_OK(skIPSetIteratorBind(&iter, ipset, 1, SK_IPV6POLICY_ASV4));
10496 while (skIPSetIteratorNext(&iter, &ipaddr, &prefix) == SK_ITERATOR_OK){
10497 ipv4 = skipaddrGetV4(&ipaddr);
10498 if (state.status != Empty && (prefix <= bmap_prefix
10499 || (state.base_ip ^ ipv4) > 0xFF))
10500 {
10501 /* 'ipv4' is not in the same /24 as 'state'; write the IP
10502 * or bitmap currently in 'state' */
10503 if (First_IP == state.status) {
10504 /* write the single ip and prefix */
10505 *(uint32_t*)write_buf = state.base_ip;
10506 write_buf[sizeof(uint32_t)] = (uint8_t)state.prefix;
10507 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10508 if (rv != sizeof(write_buf)) {
10509 return SKIPSET_ERR_FILEIO;
10510 }
10511 } else {
10512 /* write base ip, 'bitmap-follows' value for the
10513 * prefix, and the bitmap */
10514 *(uint32_t*)write_buf = state.base_ip;
10515 write_buf[sizeof(uint32_t)] = SET_CIDRBMAP_MAP256;
10516 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10517 if (rv != sizeof(write_buf)) {
10518 return SKIPSET_ERR_FILEIO;
10519 }
10520 rv = skStreamWrite(stream, state.bmap, sizeof(state.bmap));
10521 if (rv != sizeof(state.bmap)) {
10522 return SKIPSET_ERR_FILEIO;
10523 }
10524 }
10525 state.status = Empty;
10526 }
10527
10528 if (Empty == state.status) {
10529 if (prefix <= bmap_prefix) {
10530 /* netblock is larger than fits into a bitmap; write
10531 * the block as an IP and prefix */
10532 *(uint32_t*)write_buf = ipv4;
10533 write_buf[sizeof(uint32_t)] = (uint8_t)prefix;
10534 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10535 if (rv != sizeof(write_buf)) {
10536 return SKIPSET_ERR_FILEIO;
10537 }
10538 } else {
10539 /* initialize 'state' with this IP and look for more
10540 * IPs in this /24. */
10541 state.status = First_IP;
10542 state.base_ip = ipv4;
10543 state.prefix = (uint8_t)prefix;
10544 }
10545 continue;
10546 }
10547
10548 assert(prefix > bmap_prefix);
10549 if (First_IP == state.status) {
10550 /* found a second IP in this /24; convert 'state' to hold
10551 * a bitmap */
10552 state.status = Bitmap;
10553 memset(state.bmap, 0, sizeof(state.bmap));
10554
10555 buf_idx = ((state.base_ip & 0xFF) >> 5);
10556 if (state.prefix <= word_prefix) {
10557 /* prefix spans one or more uint32_t's */
10558 memset(&(state.bmap[buf_idx]), 0xff,
10559 (sizeof(uint32_t) << (word_prefix - state.prefix)));
10560 } else {
10561 state.bmap[buf_idx]
10562 |= (((1 << (1 << (32 - state.prefix))) - 1)
10563 << (state.base_ip & 0x1f));
10564 }
10565 /* mask base_ip as a /24 */
10566 state.base_ip = state.base_ip & 0xFFFFFF00;
10567 }
10568 assert(Bitmap == state.status);
10569 assert((ipv4 & 0xFFFFFF00) == state.base_ip);
10570
10571 /* add the current IP/prefix to the bitmap */
10572 buf_idx = ((ipv4 & 0xFF) >> 5);
10573 if (prefix <= word_prefix) {
10574 /* set several uint32_t's */
10575 memset(&(state.bmap[buf_idx]), 0xff,
10576 (sizeof(uint32_t) << (word_prefix - prefix)));
10577 } else {
10578 state.bmap[buf_idx] |= (((1 << (1 << (32 - prefix))) - 1)
10579 << (ipv4 & 0x1f));
10580 }
10581 }
10582
10583 /* write any IP or bitmap still in 'state' */
10584 switch (state.status) {
10585 case Empty:
10586 break;
10587 case First_IP:
10588 *(uint32_t*)write_buf = state.base_ip;
10589 write_buf[sizeof(uint32_t)] = (uint8_t)state.prefix;
10590 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10591 if (rv != sizeof(write_buf)) {
10592 return SKIPSET_ERR_FILEIO;
10593 }
10594 break;
10595 case Bitmap:
10596 *(uint32_t*)write_buf = state.base_ip;
10597 write_buf[sizeof(uint32_t)] = SET_CIDRBMAP_MAP256;
10598 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10599 if (rv != sizeof(write_buf)) {
10600 return SKIPSET_ERR_FILEIO;
10601 }
10602 rv = skStreamWrite(stream, state.bmap, sizeof(state.bmap));
10603 if (rv != sizeof(state.bmap)) {
10604 return SKIPSET_ERR_FILEIO;
10605 }
10606 break;
10607 }
10608
10609 return SKIPSET_OK;
10610 }
10611
10612 #if SK_ENABLE_IPV6
10613 static int
ipsetWriteCidrbmapFromRadixV6(const skipset_t * ipset,skstream_t * stream)10614 ipsetWriteCidrbmapFromRadixV6(
10615 const skipset_t *ipset,
10616 skstream_t *stream)
10617 {
10618 sk_file_header_t *hdr;
10619 skipset_iterator_t iter;
10620 enum status_en {
10621 Empty, First_IP, Bitmap
10622 };
10623 struct state_st {
10624 /* starting ip for this netblock, or an unmasked IP if
10625 * 'status' is 'First_IP'. */
10626 ipset_ipv6_t base_ip;
10627 /* the 256-bit bitmap */
10628 uint32_t bmap[IPTREE_WORDS_PER_SLASH24];
10629 /* the prefix for 'base_ip' if 'status' is First_IP */
10630 uint8_t prefix;
10631 /* what this structure currently holds */
10632 enum status_en status;
10633 } state;
10634 /* the bitmap holds 256 bits or a /120 */
10635 const uint32_t bmap_prefix = 120;
10636 /* each uint32_t in the bitmap holds a /123 */
10637 const uint32_t word_prefix = 123;
10638 uint8_t write_buf[IPSET_LEN_V6 + sizeof(uint8_t)];
10639 ipset_ipv6_t ipv6;
10640 skipaddr_t ipaddr;
10641 uint32_t prefix;
10642 uint32_t buf_idx;
10643 ssize_t rv;
10644
10645 /* sanity check input */
10646 assert(ipset);
10647 assert(stream);
10648 if (ipset->is_dirty || ipset->is_iptree || !ipset->is_ipv6) {
10649 skAbort();
10650 }
10651 hdr = skStreamGetSilkHeader(stream);
10652 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_CIDRBMAP) {
10653 skAbort();
10654 }
10655
10656 memset(&state, 0, sizeof(state));
10657 state.status = Empty;
10658
10659 ASSERT_OK(skIPSetIteratorBind(&iter, ipset, 1, SK_IPV6POLICY_FORCE));
10660 while (skIPSetIteratorNext(&iter, &ipaddr, &prefix) == SK_ITERATOR_OK) {
10661 IPSET_IPV6_FROM_ADDRV6(&ipv6, &ipaddr);
10662 if (state.status != Empty
10663 && (prefix <= bmap_prefix
10664 || (state.base_ip.ip[0] != ipv6.ip[0])
10665 || ((state.base_ip.ip[1] ^ ipv6.ip[1]) > 0xFF)))
10666 {
10667 /* 'ipv6' is not in the same /120 as 'state'; write the IP
10668 * or bitmap currently in 'state' */
10669 if (First_IP == state.status) {
10670 /* write the single ip and prefix */
10671 IPSET_IPV6_TO_ARRAY(&state.base_ip, write_buf);
10672 write_buf[IPSET_LEN_V6] = (uint8_t)state.prefix;
10673 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10674 if (rv != sizeof(write_buf)) {
10675 return SKIPSET_ERR_FILEIO;
10676 }
10677 } else {
10678 /* write base ip, 'bitmap-follows' value for the
10679 * prefix, and the bitmap */
10680 assert(Bitmap == state.status);
10681 IPSET_IPV6_TO_ARRAY(&state.base_ip, write_buf);
10682 write_buf[IPSET_LEN_V6] = SET_CIDRBMAP_MAP256;
10683 rv = skStreamWrite(stream, &write_buf, sizeof(write_buf));
10684 if (rv != sizeof(write_buf)) {
10685 return SKIPSET_ERR_FILEIO;
10686 }
10687 rv = skStreamWrite(stream, state.bmap, sizeof(state.bmap));
10688 if (rv != sizeof(state.bmap)) {
10689 return SKIPSET_ERR_FILEIO;
10690 }
10691 }
10692 state.status = Empty;
10693 }
10694
10695 if (Empty == state.status) {
10696 if (prefix <= bmap_prefix) {
10697 /* netblock is larger than fits into a bitmap; write
10698 * the block as an IP and prefix */
10699 IPSET_IPV6_TO_ARRAY(&ipv6, write_buf);
10700 write_buf[IPSET_LEN_V6] = (uint8_t)prefix;
10701 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10702 if (rv != sizeof(write_buf)) {
10703 return SKIPSET_ERR_FILEIO;
10704 }
10705 } else {
10706 /* initialize 'state' with this IP and look for more
10707 * IPs in this /120. */
10708 state.status = First_IP;
10709 IPSET_IPV6_COPY(&state.base_ip, &ipv6);
10710 state.prefix = (uint8_t)prefix;
10711 }
10712 continue;
10713 }
10714 assert(prefix > bmap_prefix);
10715 if (First_IP == state.status) {
10716 /* found a second IP in this /120; convert 'state' to hold
10717 * a bitmap */
10718 state.status = Bitmap;
10719 memset(state.bmap, 0, sizeof(state.bmap));
10720
10721 buf_idx = ((state.base_ip.ip[1] & 0xFF) >> 5);
10722 if (state.prefix <= word_prefix) {
10723 /* prefix spans one or more uint32_t's */
10724 memset(&(state.bmap[buf_idx]), 0xff,
10725 (sizeof(uint32_t) << (word_prefix-state.prefix)));
10726 } else {
10727 state.bmap[buf_idx]
10728 |= (((1 << (1 << (128 - state.prefix))) - 1)
10729 << (state.base_ip.ip[1] & 0x1f));
10730 }
10731 /* mask base_ip as a /120 */
10732 state.base_ip.ip[1] = (state.base_ip.ip[1] & ~UINT64_C(0xFF));
10733 }
10734 assert(Bitmap == state.status);
10735 assert(ipv6.ip[0] == state.base_ip.ip[0]);
10736 assert((ipv6.ip[1] & ~UINT64_C(0xFF)) == state.base_ip.ip[1]);
10737
10738 /* add the current IP/prefix to the bitmap */
10739 buf_idx = ((ipv6.ip[1] & 0xFF) >> 5);
10740 if (prefix <= word_prefix) {
10741 /* set several uint32_t's */
10742 memset(&(state.bmap[buf_idx]), 0xff,
10743 (sizeof(uint32_t) << (word_prefix - prefix)));
10744 } else {
10745 state.bmap[buf_idx] |= (((1 << (1 << (128 - prefix))) - 1)
10746 << (ipv6.ip[1] & 0x1f));
10747 }
10748 }
10749
10750 /* write any IP or bitmap still in 'state' */
10751 switch (state.status) {
10752 case Empty:
10753 break;
10754 case First_IP:
10755 IPSET_IPV6_TO_ARRAY(&state.base_ip, write_buf);
10756 write_buf[IPSET_LEN_V6] = (uint8_t)state.prefix;
10757 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
10758 if (rv != sizeof(write_buf)) {
10759 return SKIPSET_ERR_FILEIO;
10760 }
10761 break;
10762 case Bitmap:
10763 IPSET_IPV6_TO_ARRAY(&state.base_ip, write_buf);
10764 write_buf[IPSET_LEN_V6] = SET_CIDRBMAP_MAP256;
10765 rv = skStreamWrite(stream, &write_buf, sizeof(write_buf));
10766 if (rv != sizeof(write_buf)) {
10767 return SKIPSET_ERR_FILEIO;
10768 }
10769 rv = skStreamWrite(stream, state.bmap, sizeof(state.bmap));
10770 if (rv != sizeof(state.bmap)) {
10771 return SKIPSET_ERR_FILEIO;
10772 }
10773 break;
10774 }
10775
10776 return SKIPSET_OK;
10777 }
10778 #endif /* SK_ENABLE_IPV6 */
10779
10780
10781 /*
10782 * status = ipsetWriteCidrbmap(&ipset, stream, hdr);
10783 *
10784 * Helper function for skIPSetWrite().
10785 *
10786 * Write an IPset to 'stream' in the IPSET_REC_VERSION_CIDRBMAP
10787 * format.
10788 *
10789 * This function writes the header then calls another helper
10790 * function depending on the data structure being used.
10791 */
10792 static int
ipsetWriteCidrbmap(const skipset_t * ipset,skstream_t * stream)10793 ipsetWriteCidrbmap(
10794 const skipset_t *ipset,
10795 skstream_t *stream)
10796 {
10797 sk_file_header_t *hdr;
10798 int rv;
10799
10800 /* sanity check input */
10801 assert(ipset);
10802 assert(stream);
10803 if (ipset->is_dirty) {
10804 skAbort();
10805 }
10806 hdr = skStreamGetSilkHeader(stream);
10807 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_CIDRBMAP) {
10808 skAbort();
10809 }
10810
10811 /* Add the appropriate header */
10812 rv = ipsetHentryAddToFile(hdr, 0, 0,
10813 ipset->is_ipv6 ? IPSET_LEN_V6 : sizeof(uint32_t),
10814 0, 0, 0);
10815 if (rv) {
10816 skAppPrintErr("%s", skHeaderStrerror(rv));
10817 return SKIPSET_ERR_FILEIO;
10818 }
10819 rv = skStreamWriteSilkHeader(stream);
10820 if (rv) {
10821 return SKIPSET_ERR_FILEIO;
10822 }
10823
10824 if (ipset->is_iptree) {
10825 return ipsetWriteCidrbmapFromIPTree(ipset, stream);
10826 }
10827 #if SK_ENABLE_IPV6
10828 if (ipset->is_ipv6) {
10829 return ipsetWriteCidrbmapFromRadixV6(ipset, stream);
10830 }
10831 #endif
10832 return ipsetWriteCidrbmapFromRadixV4(ipset, stream);
10833 }
10834
10835
10836 /*
10837 * status = ipsetWriteClasscFromIPTree(ipset, stream);
10838 *
10839 * Helper function for skIPSetWrite() via ipsetWriteClassc().
10840 *
10841 * Write an IPset from the SiLK-2 IPTree data structure to 'stream'
10842 * in the IPSET_REC_VERSION_CLASSC format.
10843 *
10844 * See '#define IPSET_REC_VERSION_CLASSC' for description of the
10845 * file format.
10846 */
10847 static int
ipsetWriteClasscFromIPTree(const skipset_t * ipset,skstream_t * stream)10848 ipsetWriteClasscFromIPTree(
10849 const skipset_t *ipset,
10850 skstream_t *stream)
10851 {
10852 sk_file_header_t *hdr;
10853 skIPNode_t *slash16;
10854 uint32_t slash24;
10855 uint32_t i;
10856 uint32_t j;
10857 ssize_t rv;
10858
10859 /* sanity check input */
10860 assert(ipset);
10861 assert(stream);
10862 if (ipset->is_dirty || !ipset->is_iptree || ipset->is_ipv6) {
10863 skAbort();
10864 }
10865 hdr = skStreamGetSilkHeader(stream);
10866 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_CLASSC) {
10867 skAbort();
10868 }
10869
10870 for (i = 0; i < SKIP_BBLOCK_COUNT; i++) {
10871 /* slash16 represents a /16 */
10872 slash16 = ipset->s.v2->nodes[i];
10873 if (NULL == slash16) {
10874 continue;
10875 }
10876
10877 /* There is data in this /16, walk over the addressBlocks by
10878 * 8s, which is equivalent to visiting each /24. */
10879 for (j = 0; j < SKIP_BBLOCK_SIZE; j += IPTREE_WORDS_PER_SLASH24) {
10880 if (memcmp(slash16->addressBlock + j,
10881 bmap256_zero, sizeof(bmap256_zero)))
10882 {
10883 /* there is data in this /24; write the base address. */
10884 slash24 = ((i << 16) | (j << 5)) & 0xFFFFFF00;
10885 rv = skStreamWrite(stream, &slash24, sizeof(uint32_t));
10886 if (rv != sizeof(uint32_t)) {
10887 return SKIPSET_ERR_FILEIO;
10888 }
10889 /* write the complete /24: 8 uint32_t's */
10890 rv = skStreamWrite(stream, slash16->addressBlock + j,
10891 sizeof(bmap256_zero));
10892 if (rv != sizeof(bmap256_zero)) {
10893 return SKIPSET_ERR_FILEIO;
10894 }
10895 }
10896 }
10897 }
10898
10899 rv = skStreamFlush(stream);
10900 if (rv) {
10901 return SKIPSET_ERR_FILEIO;
10902 }
10903
10904 return SKIPSET_OK;
10905 }
10906
10907
10908 /*
10909 * status = ipsetWriteClasscFromRadixCallbackV4(ipv4, prefix, &state);
10910 * status = ipsetWriteClasscFromRadixCallback(ipaddr, prefix, &state);
10911 *
10912 * Callback function used by ipsetWriteClasscFromRadix().
10913 *
10914 * This function is the callback invoked by skIPSetWalk(). When
10915 * the current 'ipaddr' and 'prefix' are part of the same /24
10916 * contained in 'state'->buffer, the IPs are added to that buffer.
10917 * Otherwise, the buffer is printed if it contains data, and then
10918 * the buffer is initialized with new data.
10919 */
10920 static int
ipsetWriteClasscFromRadixCallbackV4(uint32_t ipv4,uint32_t prefix,void * v_state)10921 ipsetWriteClasscFromRadixCallbackV4(
10922 uint32_t ipv4,
10923 uint32_t prefix,
10924 void *v_state)
10925 {
10926 ipset_write_silk2_t *state = (ipset_write_silk2_t*)v_state;
10927 uint32_t slash24;
10928 uint32_t buf_idx;
10929 int i;
10930 ssize_t rv;
10931
10932 /* get the /24 that holds this IP */
10933 slash24 = ipv4 & 0xFFFFFF00;
10934
10935 if (prefix <= 24) {
10936 /* write the buffer if it contains data */
10937 if (state->buffer_is_dirty) {
10938 rv = skStreamWrite(state->stream, state->buffer,
10939 sizeof(state->buffer));
10940 if (rv != sizeof(state->buffer)) {
10941 return SKIPSET_ERR_FILEIO;
10942 }
10943 state->buffer_is_dirty = 0;
10944 }
10945
10946 /* initialize the buffer to all-1s */
10947 memset(state->buffer, 0xff, sizeof(state->buffer));
10948
10949 /* loop over all /24s in this block and print each one */
10950 for (i = 0; i < (1 << (24 - prefix)); ++i, slash24 += 256) {
10951 state->buffer[0] = slash24;
10952
10953 rv = skStreamWrite(state->stream, state->buffer,
10954 sizeof(state->buffer));
10955 if (rv != sizeof(state->buffer)) {
10956 return SKIPSET_ERR_FILEIO;
10957 }
10958 }
10959
10960 return SKIPSET_OK;
10961 }
10962
10963 if (!state->buffer_is_dirty) {
10964 /* initialize the block to hold this /24 */
10965 memset(state->buffer, 0, sizeof(state->buffer));
10966 state->buffer[0] = slash24;
10967 state->buffer_is_dirty = 1;
10968 } else if (state->buffer[0] != slash24) {
10969 /* the /24s are different---print the block and reset it */
10970 rv = skStreamWrite(state->stream, state->buffer,sizeof(state->buffer));
10971 if (rv != sizeof(state->buffer)) {
10972 return SKIPSET_ERR_FILEIO;
10973 }
10974 memset(state->buffer, 0, sizeof(state->buffer));
10975 state->buffer[0] = slash24;
10976 }
10977 /* else data is in the same /24 */
10978
10979 /* add our IPs to the bitmap */
10980 buf_idx = 1 + ((ipv4 & 0xFF) >> 5);
10981
10982 if (prefix <= 27) {
10983 /* set several uint32_t's */
10984 memset(&(state->buffer[buf_idx]), 0xff,
10985 ((1 << (27 - prefix)) * sizeof(uint32_t)));
10986 } else {
10987 state->buffer[buf_idx] |= ((UINT32_MAX >> (32 - (1 << (32 - prefix))))
10988 << (ipv4 & 0x1f & (0x1f << (32 - prefix))));
10989 }
10990
10991 return SKIPSET_OK;
10992 }
10993
10994 #if SK_ENABLE_IPV6
10995 static int
ipsetWriteClasscFromRadixCallback(skipaddr_t * ipaddr,uint32_t prefix,void * v_state)10996 ipsetWriteClasscFromRadixCallback(
10997 skipaddr_t *ipaddr,
10998 uint32_t prefix,
10999 void *v_state)
11000 {
11001 uint32_t ipv4;
11002
11003 /* get the IPv4 address */
11004 if (skipaddrGetAsV4(ipaddr, &ipv4)) {
11005 return SKIPSET_ERR_IPV6;
11006 }
11007 return ipsetWriteClasscFromRadixCallbackV4(ipv4, prefix, v_state);
11008 }
11009 #endif /* SK_ENABLE_IPV6 */
11010
11011
11012 /*
11013 * status = ipsetWriteClasscFromRadix(ipset, stream);
11014 *
11015 * Helper function for skIPSetWrite() via ipsetWriteClassc().
11016 *
11017 * Write an IPset from the radix-tree IPset data structure to
11018 * 'stream' in the IPSET_REC_VERSION_CLASSC format.
11019 *
11020 * See '#define IPSET_REC_VERSION_CLASSC' for description of the
11021 * file format.
11022 */
11023 static int
ipsetWriteClasscFromRadix(const skipset_t * ipset,skstream_t * stream)11024 ipsetWriteClasscFromRadix(
11025 const skipset_t *ipset,
11026 skstream_t *stream)
11027 {
11028 sk_file_header_t *hdr;
11029 ipset_write_silk2_t write_state;
11030 ssize_t rv;
11031
11032 /* sanity check input */
11033 assert(ipset);
11034 assert(stream);
11035 if (ipset->is_dirty || ipset->is_iptree || skIPSetContainsV6(ipset)) {
11036 skAbort();
11037 }
11038 hdr = skStreamGetSilkHeader(stream);
11039 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_CLASSC) {
11040 skAbort();
11041 }
11042
11043 memset(&write_state, 0, sizeof(write_state));
11044 write_state.stream = stream;
11045
11046 #if SK_ENABLE_IPV6
11047 if (ipset->is_ipv6) {
11048 rv = skIPSetWalk(ipset, 1, SK_IPV6POLICY_ASV4,
11049 &ipsetWriteClasscFromRadixCallback,
11050 (void*)&write_state);
11051 } else
11052 #endif
11053 {
11054 rv = ipsetWalkInternalV4(ipset, ipsetWriteClasscFromRadixCallbackV4,
11055 (void*)&write_state);
11056 }
11057 if (rv != 0) {
11058 return rv;
11059 }
11060
11061 if (write_state.buffer_is_dirty) {
11062 rv = skStreamWrite(stream, write_state.buffer,
11063 sizeof(write_state.buffer));
11064 if (rv != sizeof(write_state.buffer)) {
11065 return SKIPSET_ERR_FILEIO;
11066 }
11067 }
11068
11069 rv = skStreamFlush(stream);
11070 if (rv) {
11071 return SKIPSET_ERR_FILEIO;
11072 }
11073
11074 return SKIPSET_OK;
11075 }
11076
11077
11078 /*
11079 * status = ipsetWriteClassc(&ipset, stream);
11080 *
11081 * Helper function for skIPSetWrite().
11082 *
11083 * Write an IPset to 'stream' in the IPSET_REC_VERSION_CLASSC
11084 * format.
11085 *
11086 * This function writes the header then calls another helper
11087 * function depending on the data structure being used.
11088 */
11089 static int
ipsetWriteClassc(const skipset_t * ipset,skstream_t * stream)11090 ipsetWriteClassc(
11091 const skipset_t *ipset,
11092 skstream_t *stream)
11093 {
11094 sk_file_header_t *hdr;
11095 int rv;
11096
11097 /* sanity check input */
11098 assert(ipset);
11099 assert(stream);
11100 if (ipset->is_dirty || skIPSetContainsV6(ipset)) {
11101 skAbort();
11102 }
11103 hdr = skStreamGetSilkHeader(stream);
11104 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_CLASSC) {
11105 skAbort();
11106 }
11107
11108 rv = skStreamWriteSilkHeader(stream);
11109 if (rv) {
11110 return SKIPSET_ERR_FILEIO;
11111 }
11112
11113 if (ipset->is_iptree) {
11114 return ipsetWriteClasscFromIPTree(ipset, stream);
11115 }
11116 return ipsetWriteClasscFromRadix(ipset, stream);
11117 }
11118
11119
11120 /*
11121 * status = ipsetWriteRadix(ipset, stream);
11122 *
11123 * Helper function for skIPSetWrite().
11124 *
11125 * Write an IPset to 'stream' in the IPSET_REC_VERSION_RADIX
11126 * format.
11127 *
11128 * See '#define IPSET_REC_VERSION_RADIX' for description of the
11129 * file format.
11130 */
11131 static int
ipsetWriteRadix(const skipset_t * ipset,skstream_t * stream)11132 ipsetWriteRadix(
11133 const skipset_t *ipset,
11134 skstream_t *stream)
11135 {
11136 sk_file_header_t *hdr;
11137 skipset_t *set3 = NULL;
11138 ssize_t rv;
11139
11140 /* sanity check input */
11141 assert(ipset);
11142 assert(stream);
11143 if (ipset->is_dirty) {
11144 skAbort();
11145 }
11146 hdr = skStreamGetSilkHeader(stream);
11147 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_RADIX) {
11148 skAbort();
11149 }
11150
11151 /* we must convert the IPTree to a Radix-Tree when writing an
11152 * IPTree-based IPset to the IPSET_REC_VERSION_RADIX format */
11153 if (ipset->is_iptree) {
11154 skipset_iterator_t iter;
11155 skipaddr_t ipaddr;
11156 uint32_t prefix;
11157
11158 /* create a Radix-based IPv4 IPset */
11159 rv = ipsetCreate(&set3, 0, 1);
11160 if (rv) {
11161 goto END;
11162 }
11163
11164 /* add the elements from 'ipset' to 'set3' */
11165 ASSERT_OK(skIPSetIteratorBind(&iter, ipset, 1, SK_IPV6POLICY_ASV4));
11166 while (skIPSetIteratorNext(&iter, &ipaddr, &prefix) == SK_ITERATOR_OK){
11167 rv = ipsetInsertAddressV4(
11168 set3, skipaddrGetV4(&ipaddr), prefix, NULL);
11169 if (rv) {
11170 goto END;
11171 }
11172 }
11173 rv = skIPSetClean(set3);
11174 if (rv) {
11175 goto END;
11176 }
11177
11178 ipset = set3;
11179 }
11180
11181 if (ipset->is_iptree) {
11182 skAbort();
11183 }
11184
11185 /* Add the appropriate header */
11186 rv = ipsetHentryAddToFile(hdr, IPSET_NUM_CHILDREN,
11187 ipset->s.v3->leaves.entry_count,
11188 ipset->s.v3->leaves.entry_size,
11189 ipset->s.v3->nodes.entry_count,
11190 ipset->s.v3->nodes.entry_size,
11191 IPSET_ROOT_INDEX(ipset));
11192 if (rv) {
11193 skAppPrintErr("%s", skHeaderStrerror(rv));
11194 rv = SKIPSET_ERR_FILEIO;
11195 goto END;
11196 }
11197 rv = skStreamWriteSilkHeader(stream);
11198 if (rv) {
11199 rv = SKIPSET_ERR_FILEIO;
11200 goto END;
11201 }
11202
11203 /* write the arrays */
11204 if (ipset->s.v3->nodes.entry_count) {
11205 rv = skStreamWrite(stream, ipset->s.v3->nodes.buf,
11206 (ipset->s.v3->nodes.entry_size
11207 * ipset->s.v3->nodes.entry_count));
11208 if ((size_t)rv != (ipset->s.v3->nodes.entry_size
11209 * ipset->s.v3->nodes.entry_count))
11210 {
11211 rv = SKIPSET_ERR_FILEIO;
11212 goto END;
11213 }
11214 }
11215 if (ipset->s.v3->leaves.entry_count) {
11216 rv = skStreamWrite(stream, ipset->s.v3->leaves.buf,
11217 (ipset->s.v3->leaves.entry_size
11218 * ipset->s.v3->leaves.entry_count));
11219 if ((size_t)rv != (ipset->s.v3->leaves.entry_size
11220 * ipset->s.v3->leaves.entry_count))
11221 {
11222 rv = SKIPSET_ERR_FILEIO;
11223 goto END;
11224 }
11225 }
11226
11227 rv = skStreamFlush(stream);
11228 if (rv) {
11229 rv = SKIPSET_ERR_FILEIO;
11230 goto END;
11231 }
11232
11233 /* success */
11234 rv = SKIPSET_OK;
11235
11236 END:
11237 skIPSetDestroy(&set3);
11238 return rv;
11239 }
11240
11241
11242 #if SK_ENABLE_IPV6
11243 /*
11244 * status = ipsetWriteSlash64(&ipset, stream, hdr);
11245 *
11246 * Helper function for skIPSetWrite().
11247 *
11248 * Write an IPset to 'stream' in the IPSET_REC_VERSION_SLASH64
11249 * format.
11250 *
11251 * See '#define IPSET_REC_VERSION_SLASH64' for description of the
11252 * file format.
11253 */
11254 static int
ipsetWriteSlash64(const skipset_t * ipset,skstream_t * stream)11255 ipsetWriteSlash64(
11256 const skipset_t *ipset,
11257 skstream_t *stream)
11258 {
11259 sk_file_header_t *hdr;
11260 skipset_iterator_t iter;
11261 enum status_en {
11262 Empty, First_IP, Bitmap
11263 };
11264 struct state_st {
11265 /* starting ip for this netblock bitmap when 'status' is
11266 * Bitmap, an unmasked IP when 'status' is First_IP, or the
11267 * start of the outer block when 'outer_written' is set. */
11268 ipset_ipv6_t base_ip;
11269 /* the 256-bit bitmap */
11270 uint32_t bmap[IPTREE_WORDS_PER_SLASH24];
11271 /* the prefix for 'base_ip' when 'status' is First_IP */
11272 uint8_t prefix;
11273 /* what this structure currently holds */
11274 enum status_en status;
11275 /* true when the iterator is exhausted */
11276 uint8_t is_last;
11277 } state;
11278 /* the bitmap holds 256 bits or a /120 */
11279 const uint32_t bmap_prefix = 120;
11280 /* each uint32_t in the bitmap holds a /123 */
11281 const uint32_t word_prefix = 123;
11282 uint8_t write_buf[sizeof(uint64_t) + sizeof(uint8_t)];
11283 ipset_ipv6_t ipv6;
11284 skipaddr_t ipaddr;
11285 uint32_t prefix;
11286 uint32_t buf_idx;
11287 ssize_t rv;
11288
11289 /* sanity check input */
11290 assert(ipset);
11291 assert(stream);
11292 if (ipset->is_dirty) {
11293 skAbort();
11294 }
11295 if (ipset->is_iptree) {
11296 skAbort();
11297 }
11298 if (!ipset->is_ipv6) {
11299 skAbort();
11300 }
11301 hdr = skStreamGetSilkHeader(stream);
11302 if (skHeaderGetRecordVersion(hdr) != IPSET_REC_VERSION_SLASH64) {
11303 skAbort();
11304 }
11305
11306 /* Add the appropriate header */
11307 rv = ipsetHentryAddToFile(hdr, 0, 0, IPSET_LEN_V6, 0, 0, 0);
11308 if (rv) {
11309 skAppPrintErr("%s", skHeaderStrerror(rv));
11310 return SKIPSET_ERR_FILEIO;
11311 }
11312 rv = skStreamWriteSilkHeader(stream);
11313 if (rv) {
11314 return SKIPSET_ERR_FILEIO;
11315 }
11316
11317 /* get the first IP */
11318 ASSERT_OK(skIPSetIteratorBind(&iter, ipset, 1, SK_IPV6POLICY_FORCE));
11319 if (skIPSetIteratorNext(&iter, &ipaddr, &prefix) != SK_ITERATOR_OK) {
11320 return SKIPSET_OK;
11321 }
11322 IPSET_IPV6_FROM_ADDRV6(&ipv6, &ipaddr);
11323
11324 /* initialize state and ensure base_ip does not match ipv6 */
11325 memset(&state, 0, sizeof(state));
11326 state.base_ip.ip[0] = ~ipv6.ip[0];
11327 state.base_ip.ip[1] = ~ipv6.ip[1];
11328 state.status = Empty;
11329
11330 for (;;) {
11331 if (state.status != Empty
11332 && (prefix <= bmap_prefix
11333 || (state.base_ip.ip[0] != ipv6.ip[0])
11334 || ((state.base_ip.ip[1] ^ ipv6.ip[1]) > 0xFF)))
11335 {
11336 /* 'ipv6' is not in the same /120 as 'state'; write the IP
11337 * or bitmap currently in 'state' */
11338 #ifdef SK_HAVE_ALIGNED_ACCESS_REQUIRED
11339 memcpy(write_buf, &state.base_ip.ip[1], sizeof(uint64_t));
11340 #else
11341 *(uint64_t *)write_buf = state.base_ip.ip[1];
11342 #endif /* SK_HAVE_ALIGNED_ACCESS_REQUIRED */
11343 write_buf[sizeof(uint64_t)] = ((First_IP == state.status)
11344 ? state.prefix
11345 : SET_CIDRBMAP_MAP256);
11346 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
11347 if (rv != (ssize_t)sizeof(write_buf)) {
11348 return SKIPSET_ERR_FILEIO;
11349 }
11350 if (Bitmap == state.status) {
11351 /* write the bitmap */
11352 rv = skStreamWrite(stream, state.bmap, sizeof(state.bmap));
11353 if (rv != sizeof(state.bmap)) {
11354 return SKIPSET_ERR_FILEIO;
11355 }
11356 }
11357 state.status = Empty;
11358 }
11359
11360 if (Empty == state.status) {
11361 if (prefix <= 64) {
11362 if (state.is_last) {
11363 break;
11364 }
11365 /* write the upper 64 bits of the IP and prefix */
11366 #ifdef SK_HAVE_ALIGNED_ACCESS_REQUIRED
11367 memcpy(write_buf, &ipv6.ip[0], sizeof(uint64_t));
11368 #else
11369 *(uint64_t *)write_buf = ipv6.ip[0];
11370 #endif /* SK_HAVE_ALIGNED_ACCESS_REQUIRED */
11371 write_buf[sizeof(uint64_t)] = (uint8_t)prefix;
11372 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
11373 if (rv != (ssize_t)sizeof(write_buf)) {
11374 return SKIPSET_ERR_FILEIO;
11375 }
11376 state.base_ip.ip[0] = ipv6.ip[0];
11377 } else {
11378 if (state.base_ip.ip[0] == ipv6.ip[0]) {
11379 /* only need to copy lower uint64 */
11380 state.base_ip.ip[1] = ipv6.ip[1];
11381 } else {
11382 IPSET_IPV6_COPY(&state.base_ip, &ipv6);
11383 /* write the upper 64 bits of the IP */
11384 #ifdef SK_HAVE_ALIGNED_ACCESS_REQUIRED
11385 memcpy(write_buf, &state.base_ip.ip[0], sizeof(uint64_t));
11386 #else
11387 *(uint64_t *)write_buf = state.base_ip.ip[0];
11388 #endif /* SK_HAVE_ALIGNED_ACCESS_REQUIRED */
11389 write_buf[sizeof(uint64_t)] = SET_SLASH64_IS_SLASH64;
11390 rv = skStreamWrite(stream, write_buf, sizeof(write_buf));
11391 if (rv != (ssize_t)sizeof(write_buf)) {
11392 return SKIPSET_ERR_FILEIO;
11393 }
11394 }
11395 state.prefix = (uint8_t)prefix;
11396 state.status = First_IP;
11397 }
11398 } else {
11399 if (First_IP == state.status) {
11400 /* convert 'state' to hold a bitmap */
11401 state.status = Bitmap;
11402 memset(state.bmap, 0, sizeof(state.bmap));
11403
11404 buf_idx = ((state.base_ip.ip[1] & 0xFF) >> 5);
11405 if (state.prefix <= word_prefix) {
11406 /* prefix spans one or more uint32_t's */
11407 memset(&(state.bmap[buf_idx]), 0xff,
11408 sizeof(uint32_t) << (word_prefix - state.prefix));
11409 } else {
11410 state.bmap[buf_idx]
11411 |= (((1 << (1 << (128 - state.prefix))) - 1)
11412 << (state.base_ip.ip[1] & 0x1f));
11413 }
11414 /* mask base_ip as a /120 */
11415 state.base_ip.ip[1]
11416 = (state.base_ip.ip[1] & ~UINT64_C(0xFF));
11417 }
11418 assert(Bitmap == state.status);
11419 assert(ipv6.ip[0] == state.base_ip.ip[0]);
11420 assert((ipv6.ip[1] & ~UINT64_C(0xFF)) == state.base_ip.ip[1]);
11421
11422 /* add the current IP/prefix to the bitmap */
11423 buf_idx = ((ipv6.ip[1] & 0xFF) >> 5);
11424 if (prefix <= word_prefix) {
11425 /* set several uint32_t's */
11426 memset(&(state.bmap[buf_idx]), 0xff,
11427 (sizeof(uint32_t) << (word_prefix - prefix)));
11428 } else {
11429 state.bmap[buf_idx] |= (((1 << (1 << (128 - prefix))) - 1)
11430 << (ipv6.ip[1] & 0x1f));
11431 }
11432 }
11433
11434 /* get the next IP */
11435 if (skIPSetIteratorNext(&iter, &ipaddr, &prefix) != SK_ITERATOR_OK) {
11436 prefix = 0;
11437 state.is_last = 1;
11438 }
11439 IPSET_IPV6_FROM_ADDRV6(&ipv6, &ipaddr);
11440 }
11441
11442 return SKIPSET_OK;
11443 }
11444 #endif /* SK_ENABLE_IPV6 */
11445
11446
11447 /* **** PUBLIC FUNCTION DEFINITIONS BEGIN HERE **** */
11448
11449 void
skIPSetAutoConvertDisable(skipset_t * ipset)11450 skIPSetAutoConvertDisable(
11451 skipset_t *ipset)
11452 {
11453 ipset->no_autoconvert = 1;
11454 }
11455
11456 void
skIPSetAutoConvertEnable(skipset_t * ipset)11457 skIPSetAutoConvertEnable(
11458 skipset_t *ipset)
11459 {
11460 ipset->no_autoconvert = 0;
11461 }
11462
11463 int
skIPSetAutoConvertIsEnabled(const skipset_t * ipset)11464 skIPSetAutoConvertIsEnabled(
11465 const skipset_t *ipset)
11466 {
11467 return !ipset->no_autoconvert;
11468 }
11469
11470
11471 /* Return true if 'ipset' contains 'ipaddr' */
11472 int
skIPSetCheckAddress(const skipset_t * ipset,const skipaddr_t * ipaddr)11473 skIPSetCheckAddress(
11474 const skipset_t *ipset,
11475 const skipaddr_t *ipaddr)
11476 {
11477 uint32_t ipv4;
11478
11479 if (ipset->is_iptree) {
11480 #if SK_ENABLE_IPV6
11481 if (skipaddrIsV6(ipaddr)) {
11482 /* attempt to convert to IPv4 */
11483 if (skipaddrGetAsV4(ipaddr, &ipv4)) {
11484 /* conversion failed; this IP is not in the IPSet */
11485 return 0;
11486 }
11487 } else
11488 #endif
11489 {
11490 ipv4 = skipaddrGetV4(ipaddr);
11491 }
11492 return IPTREE_CHECK_ADDRESS(ipset->s.v2, ipv4);
11493 }
11494
11495 #if SK_ENABLE_IPV6
11496 if (ipset->is_ipv6) {
11497 ipset_ipv6_t ipv6;
11498
11499 IPSET_IPV6_FROM_ADDRV4(&ipv6, ipaddr);
11500 return (ipsetFindV6(ipset, &ipv6, 128, NULL) == SKIPSET_OK);
11501 }
11502 /* else IPset is IPv4 */
11503
11504 if (skipaddrIsV6(ipaddr)) {
11505 if (skipaddrGetAsV4(ipaddr, &ipv4)) {
11506 /* conversion failed; this IP is not in the IPSet */
11507 return 0;
11508 }
11509 } else
11510 #endif /* SK_ENABLE_IPV6 */
11511 {
11512 ipv4 = skipaddrGetV4(ipaddr);
11513 }
11514
11515 return (ipsetFindV4(ipset, ipv4, 32, NULL) == SKIPSET_OK);
11516 }
11517
11518
11519 /* Return true if 'ipset1' and 'ipset2' have any IPs in common. */
11520 int
skIPSetCheckIPSet(const skipset_t * ipset1,const skipset_t * ipset2)11521 skIPSetCheckIPSet(
11522 const skipset_t *ipset1,
11523 const skipset_t *ipset2)
11524 {
11525 const skipset_t *walk_set = NULL;
11526 const skipset_t *search_set = NULL;
11527 uint32_t leaf_count1;
11528 uint32_t leaf_count2;
11529 int rv = SKIPSET_OK;
11530
11531 /* check input */
11532 if (!ipset1 || !ipset2) {
11533 return 0;
11534 }
11535
11536 if (ipset1->is_iptree) {
11537 if (ipset2->is_iptree) {
11538 /* both are SiLK-2 IPTrees */
11539 return ipsetCheckIPSetIPTree(ipset1->s.v2, ipset2->s.v2);
11540 }
11541
11542 walk_set = ipset1;
11543 search_set = ipset2;
11544
11545 } else if (ipset2->is_iptree) {
11546 walk_set = ipset2;
11547 search_set = ipset1;
11548
11549 } else {
11550 /* handle trivial case */
11551 if (IPSET_ISEMPTY(ipset1) || IPSET_ISEMPTY(ipset2)) {
11552 return 0;
11553 }
11554
11555 /*
11556 * The current implementation walks over the IPset that has the
11557 * fewest leaves asking whether those IPs are in the other IPset.
11558 * If we could guarantee that at least one IPset was clean, we
11559 * could implement the check similar to how skIPSetIntersect()
11560 * works with an iterator and a walker. This would allow the
11561 * code to stop walking one IPset once it knew the other IPset
11562 * was out of IPs.
11563 */
11564
11565 /* check which set as the fewest number of leaves */
11566 leaf_count1 = ipsetCountOccupiedLeaves(ipset1);
11567 leaf_count2 = ipsetCountOccupiedLeaves(ipset2);
11568 if (leaf_count1 < leaf_count2) {
11569 walk_set = ipset1;
11570 search_set = ipset2;
11571 } else {
11572 walk_set = ipset2;
11573 search_set = ipset1;
11574 }
11575 }
11576
11577 /* visit the IPs on the walk_set */
11578 #if SK_ENABLE_IPV6
11579 if (search_set->is_ipv6) {
11580 rv = skIPSetWalk(walk_set, 1, SK_IPV6POLICY_FORCE,
11581 &ipsetCheckIPSetCallbackV6, (void*)search_set);
11582 } else
11583 #endif /* SK_ENABLE_IPV6 */
11584 {
11585 rv = skIPSetWalk(walk_set, 1, SK_IPV6POLICY_ASV4,
11586 &ipsetCheckIPSetCallbackV4, (void*)search_set);
11587 }
11588 switch (rv) {
11589 case SKIPSET_OK:
11590 /* reached end of walk_set with no matches */
11591 break;
11592
11593 case SKIPSET_ERR_SUBSET:
11594 /* found IPs in common */
11595 return 1;
11596
11597 default:
11598 skAbortBadCase(rv);
11599 }
11600
11601 return 0;
11602 }
11603
11604
11605 /* Return true if 'ipset' contains any IPs represened by 'ipwild' */
11606 int
skIPSetCheckIPWildcard(const skipset_t * ipset,const skIPWildcard_t * ipwild)11607 skIPSetCheckIPWildcard(
11608 const skipset_t *ipset,
11609 const skIPWildcard_t *ipwild)
11610 {
11611 skIPWildcardIterator_t iter;
11612 skipaddr_t ipaddr;
11613 uint32_t prefix;
11614
11615 if (ipset->is_iptree) {
11616 return ipsetCheckWildcardIPTree(ipset->s.v2, ipwild);
11617 }
11618
11619 /* Iterate over the IPs from the wildcard */
11620 #if SK_ENABLE_IPV6
11621 if (ipset->is_ipv6) {
11622 ipset_ipv6_t ipv6;
11623
11624 skIPWildcardIteratorBindV6(&iter, ipwild);
11625 if (skIPWildcardIteratorNextCidr(&iter, &ipaddr, &prefix)
11626 != SK_ITERATOR_OK)
11627 {
11628 return 0;
11629 }
11630 if (0 == prefix) {
11631 /* wildcard was x:x:x:x:x:x:x:x */
11632 if (!skipaddrIsZero(&ipaddr)) {
11633 skAppPrintErr("Wildcard iterator bug: prefix == 0 but IP != 0");
11634 skAbort();
11635 }
11636 return !IPSET_ISEMPTY(ipset);
11637 }
11638
11639 do {
11640 assert(0 < prefix && prefix <= 128);
11641 IPSET_IPV6_FROM_ADDRV6(&ipv6, &ipaddr);
11642 switch (ipsetFindV6(ipset, &ipv6, prefix, NULL)) {
11643 case SKIPSET_OK:
11644 case SKIPSET_ERR_SUBSET:
11645 return 1;
11646 default:
11647 break;
11648 }
11649 } while (skIPWildcardIteratorNextCidr(&iter, &ipaddr, &prefix)
11650 == SK_ITERATOR_OK);
11651 /* no intersesction */
11652 return 0;
11653 }
11654 /* else IPset is IPv4 */
11655
11656 if (skIPWildcardIsV6(ipwild)) {
11657 /* only visit the ::ffff:0:0/96 netblock and return as IPv4 */
11658 skIPWildcardIteratorBindV4(&iter, ipwild);
11659 } else
11660 #endif /* SK_ENABLE_IPV6 */
11661 {
11662 /* both wildcard and IPset are IPv4 */
11663 skIPWildcardIteratorBind(&iter, ipwild);
11664 }
11665
11666 if (skIPWildcardIteratorNextCidr(&iter, &ipaddr, &prefix)
11667 != SK_ITERATOR_OK)
11668 {
11669 return 0;
11670 }
11671 assert(!skipaddrIsV6(&ipaddr));
11672 if (0 == prefix) {
11673 /* wildcard was x.x.x.x */
11674 if (!skipaddrIsZero(&ipaddr)) {
11675 skAppPrintErr("Wildcard iterator bug: prefix == 0 but IP != 0");
11676 skAbort();
11677 }
11678 return !IPSET_ISEMPTY(ipset);
11679 }
11680
11681 do {
11682 assert(prefix <= 32);
11683 assert(!skipaddrIsV6(&ipaddr));
11684 switch (ipsetFindV4(ipset, skipaddrGetV4(&ipaddr), prefix, NULL)) {
11685 case SKIPSET_OK:
11686 case SKIPSET_ERR_SUBSET:
11687 return 1;
11688 default:
11689 break;
11690 }
11691 } while (skIPWildcardIteratorNextCidr(&iter, &ipaddr, &prefix)
11692 == SK_ITERATOR_OK);
11693 /* no intersesction */
11694 return 0;
11695 }
11696
11697
11698 /* Return true if the specified address on 'rwrec' is in the 'ipset' */
11699 int
skIPSetCheckRecord(const skipset_t * ipset,const rwRec * rwrec,int src_dst_nh)11700 skIPSetCheckRecord(
11701 const skipset_t *ipset,
11702 const rwRec *rwrec,
11703 int src_dst_nh)
11704 {
11705 uint32_t ipv4;
11706
11707 #if SK_ENABLE_IPV6
11708 if (ipset->is_ipv6) {
11709 ipset_ipv6_t ipv6;
11710
11711 switch (src_dst_nh) {
11712 case 1:
11713 rwRecMemGetSIPv6(rwrec, &ipv6);
11714 break;
11715 case 2:
11716 rwRecMemGetDIPv6(rwrec, &ipv6);
11717 break;
11718 case 4:
11719 rwRecMemGetNhIPv6(rwrec, &ipv6);
11720 break;
11721 default:
11722 skAbortBadCase(src_dst_nh);
11723 }
11724 ipv6.ip[0] = ntoh64(ipv6.ip[0]);
11725 ipv6.ip[1] = ntoh64(ipv6.ip[1]);
11726
11727 return (ipsetFindV6(ipset, &ipv6, 128, NULL) == SKIPSET_OK);
11728 }
11729 /* else IPset is IPv4 */
11730
11731 if (rwRecIsIPv6(rwrec)) {
11732 /* try to handle addresses as IPv4 */
11733 skipaddr_t ipaddr;
11734
11735 switch (src_dst_nh) {
11736 case 1:
11737 rwRecMemGetSIP(rwrec, &ipaddr);
11738 break;
11739 case 2:
11740 rwRecMemGetDIP(rwrec, &ipaddr);
11741 break;
11742 case 4:
11743 rwRecMemGetNhIP(rwrec, &ipaddr);
11744 break;
11745 default:
11746 skAbortBadCase(src_dst_nh);
11747 }
11748 if (skipaddrGetAsV4(&ipaddr, &ipv4)) {
11749 /* conversion failed; this IP is not in the IPSet */
11750 return 0;
11751 }
11752 } else
11753 #endif /* SK_ENABLE_IPV6 */
11754 {
11755 /* neither IPSet nor rwRec are V6 */
11756 switch (src_dst_nh) {
11757 case 1:
11758 ipv4 = rwRecGetSIPv4(rwrec);
11759 break;
11760 case 2:
11761 ipv4 = rwRecGetDIPv4(rwrec);
11762 break;
11763 case 4:
11764 ipv4 = rwRecGetNhIPv4(rwrec);
11765 break;
11766 default:
11767 skAbortBadCase(src_dst_nh);
11768 }
11769 }
11770
11771 if (ipset->is_iptree) {
11772 return IPTREE_CHECK_ADDRESS(ipset->s.v2, ipv4);
11773 }
11774 return (ipsetFindV4(ipset, ipv4, 32, NULL) == SKIPSET_OK);
11775 }
11776
11777
11778 /* Make the ipset use as few nodes as possible and make sure the ipset
11779 * uses a contiguous region of memory. */
11780 int
skIPSetClean(skipset_t * ipset)11781 skIPSetClean(
11782 skipset_t *ipset)
11783 {
11784 if (!ipset) {
11785 return SKIPSET_ERR_BADINPUT;
11786 }
11787 if (ipset->is_iptree) {
11788 ipset->is_dirty = 0;
11789 return SKIPSET_OK;
11790 }
11791 if (!ipset->is_dirty) {
11792 return SKIPSET_OK;
11793 }
11794 if (0 == ipset->s.v3->nodes.entry_count) {
11795 skIPSetRemoveAll(ipset);
11796 ipset->is_dirty = 0;
11797 return SKIPSET_OK;
11798 }
11799
11800 IPSET_COPY_ON_WRITE(ipset);
11801
11802 if (ipsetVerify(ipset)) {
11803 return SKIPSET_ERR_CORRUPT;
11804 }
11805 ipsetCombineAdjacentCIDR(ipset);
11806 /* ipsetCompact(ipset); -- ipsetSortLeaves() calles this */
11807 ipsetSortLeaves(ipset);
11808 assert(0 == ipsetVerify(ipset));
11809
11810 ipset->is_dirty = 0;
11811
11812 return SKIPSET_OK;
11813 }
11814
11815
11816 /* Return true if 'ipset' contains any IPs that cannot be represented
11817 * as an IPv4 address. */
11818 int
skIPSetContainsV6(const skipset_t * ipset)11819 skIPSetContainsV6(
11820 const skipset_t *ipset)
11821 {
11822 #if !SK_ENABLE_IPV6
11823 if (ipset->is_ipv6) {
11824 skAbort();
11825 }
11826 return 0;
11827 #else /* SK_ENABLE_IPV6 */
11828
11829 if (!ipset->is_ipv6) {
11830 return 0;
11831 }
11832 assert(0 == ipset->is_iptree);
11833 if (IPSET_ISEMPTY(ipset)) {
11834 return 0;
11835 }
11836
11837 /* For the IPset to containly only IPv4 addresses, the root node
11838 * must be something like "::ffff:0.0.0.0/96" or more specific,
11839 * such as "::ffff.10.11.12.0/120" */
11840
11841 if (IPSET_ROOT_IS_LEAF(ipset)) {
11842 const ipset_leaf_v6_t *leaf;
11843
11844 leaf = LEAF_PTR_V6(ipset, IPSET_ROOT_INDEX(ipset));
11845 if (leaf->prefix < 96) {
11846 return 1;
11847 }
11848 return (leaf->ip.ip[0] != 0
11849 || ((leaf->ip.ip[1] >> 32) != 0x0000ffff));
11850
11851 } else {
11852 const ipset_node_v6_t *node;
11853
11854 node = NODE_PTR_V6(ipset, IPSET_ROOT_INDEX(ipset));
11855 if (node->prefix < 96) {
11856 return 1;
11857 }
11858 return (node->ip.ip[0] != 0
11859 || ((node->ip.ip[1] >> 32) != 0x0000ffff));
11860 }
11861 #endif /* SK_ENABLE_IPV6 */
11862 }
11863
11864
11865 /* Convert 'ipset' to hold IPs of the specific version. */
11866 int
skIPSetConvert(skipset_t * ipset,int target_ip_version)11867 skIPSetConvert(
11868 skipset_t *ipset,
11869 int target_ip_version)
11870 {
11871 if (!ipset) {
11872 return SKIPSET_ERR_BADINPUT;
11873 }
11874
11875 #if !SK_ENABLE_IPV6
11876 if (4 != target_ip_version) {
11877 return SKIPSET_ERR_IPV6;
11878 }
11879 if (1 == ipset->is_ipv6) {
11880 skAbort();
11881 }
11882 return SKIPSET_OK;
11883
11884 #else /* SK_ENABLE_IPV6 */
11885
11886 switch (target_ip_version) {
11887 case 4:
11888 if (!ipset->is_ipv6) {
11889 /* IPset is already IPv4 */
11890 return SKIPSET_OK;
11891 }
11892 if (skIPSetContainsV6(ipset)) {
11893 /* can't convert when IPv6 addresses are present */
11894 return SKIPSET_ERR_IPV6;
11895 }
11896 break;
11897
11898 case 6:
11899 if (ipset->is_ipv6) {
11900 /* IPset is already IPv6 */
11901 return SKIPSET_OK;
11902 }
11903 break;
11904
11905 default:
11906 return SKIPSET_ERR_BADINPUT;
11907 }
11908
11909 if (ipset->is_iptree) {
11910 return ipsetConvertIPTreetoV6(ipset);
11911 }
11912
11913 IPSET_COPY_ON_WRITE(ipset);
11914
11915 /* ensure the tree is compact */
11916 skIPSetClean(ipset);
11917
11918 if (ipset->is_ipv6) {
11919 return ipsetConvertV6toV4(ipset);
11920 }
11921 return ipsetConvertV4toV6(ipset);
11922 #endif /* SK_ENABLE_IPV6 */
11923 }
11924
11925
11926 /* Return number of IPs in the IPset */
11927 uint64_t
skIPSetCountIPs(const skipset_t * ipset,double * count)11928 skIPSetCountIPs(
11929 const skipset_t *ipset,
11930 double *count)
11931 {
11932 ipset_count_t count_state;
11933
11934 if (!ipset) {
11935 return 0;
11936 }
11937 if (ipset->is_iptree) {
11938 uint64_t c;
11939
11940 c = ipsetCountIPTree(ipset->s.v2);
11941 if (count) {
11942 *count = (double)c;
11943 }
11944 return c;
11945 }
11946
11947 memset(&count_state, 0, sizeof(ipset_count_t));
11948
11949 #if SK_ENABLE_IPV6
11950 if (ipset->is_ipv6) {
11951 ipsetWalkInternalV6(ipset, ipsetCountCallbackV6, (void*)&count_state);
11952 } else
11953 #endif /* SK_ENABLE_IPV6 */
11954 {
11955 ipsetWalkInternalV4(ipset, ipsetCountCallbackV4, (void*)&count_state);
11956 }
11957
11958 if (count_state.upper) {
11959 if (count) {
11960 *count = ((double)count_state.upper * ((double)UINT64_MAX + 1.0)
11961 + (double)count_state.lower);
11962 }
11963 return UINT64_MAX;
11964 }
11965
11966 if (count) {
11967 *count = (double)count_state.lower;
11968 }
11969 return count_state.lower;
11970 }
11971
11972
11973 /* Fill 'buf' with number of IPs in the set */
11974 char *
skIPSetCountIPsString(const skipset_t * ipset,char * buf,size_t buflen)11975 skIPSetCountIPsString(
11976 const skipset_t *ipset,
11977 char *buf,
11978 size_t buflen)
11979 {
11980 uint64_t i_count;
11981 double d_count;
11982 ssize_t sz;
11983
11984 #if SK_ENABLE_IPV6
11985 if (ipset && ipset->is_ipv6) {
11986 ipset_count_t count_state;
11987
11988 memset(&count_state, 0, sizeof(count_state));
11989 ipsetWalkInternalV6(ipset, ipsetCountCallbackV6, (void*)&count_state);
11990 return ipsetCountToString(&count_state, buf, buflen);
11991 }
11992 #endif /* SK_ENABLE_IPV6 */
11993
11994 i_count = skIPSetCountIPs(ipset, &d_count);
11995 if (i_count == UINT64_MAX) {
11996 sz = snprintf(buf, buflen, ("%.0f"), d_count);
11997 } else {
11998 sz = snprintf(buf, buflen, ("%" PRIu64), i_count);
11999 }
12000 if ((size_t)sz >= buflen) {
12001 return NULL;
12002 }
12003 return buf;
12004 }
12005
12006
12007 /* Create a new IPset */
12008 int
skIPSetCreate(skipset_t ** ipset,int support_ipv6)12009 skIPSetCreate(
12010 skipset_t **ipset,
12011 int support_ipv6)
12012 {
12013 if (!ipset) {
12014 return SKIPSET_ERR_BADINPUT;
12015 }
12016
12017 #if !SK_ENABLE_IPV6
12018 if (support_ipv6) {
12019 return SKIPSET_ERR_IPV6;
12020 }
12021 #endif /* SK_ENABLE_IPV6 */
12022
12023 if (IPSET_USE_IPTREE) {
12024 return ipsetCreate(ipset, support_ipv6, 0);
12025 }
12026 return ipsetCreate(ipset, support_ipv6, 1);
12027 }
12028
12029
12030 /* Destroy an IPset. */
12031 void
skIPSetDestroy(skipset_t ** ipset)12032 skIPSetDestroy(
12033 skipset_t **ipset)
12034 {
12035 if (!ipset || !*ipset) {
12036 return;
12037 }
12038
12039 if ((*ipset)->is_iptree) {
12040 ipsetDestroyIPTree((*ipset)->s.v2);
12041 free(*ipset);
12042 *ipset = NULL;
12043 return;
12044 }
12045
12046 if (getenv(IPSET_ENVAR_DESTROY_PRINT)) {
12047 skIPSetDebugPrint(*ipset);
12048 }
12049
12050 if ((*ipset)->s.v3->mapped_file) {
12051 munmap((*ipset)->s.v3->mapped_file, (*ipset)->s.v3->mapped_size);
12052 (*ipset)->s.v3->mapped_file = NULL;
12053 (*ipset)->s.v3->mapped_size = 0;
12054 } else {
12055 skIPSetRemoveAll(*ipset);
12056 if ((*ipset)->s.v3->nodes.buf) {
12057 free((*ipset)->s.v3->nodes.buf);
12058 (*ipset)->s.v3->nodes.buf = NULL;
12059 (*ipset)->s.v3->nodes.entry_count = 0;
12060 }
12061 if ((*ipset)->s.v3->leaves.buf) {
12062 free((*ipset)->s.v3->leaves.buf);
12063 (*ipset)->s.v3->leaves.buf = NULL;
12064 (*ipset)->s.v3->leaves.entry_count = 0;
12065 }
12066 }
12067
12068 free((*ipset)->s.v3);
12069 free(*ipset);
12070 *ipset = NULL;
12071 }
12072
12073
12074 /* Insert the IP address into the IPset. */
12075 int
skIPSetInsertAddress(skipset_t * ipset,const skipaddr_t * ipaddr,uint32_t prefix)12076 skIPSetInsertAddress(
12077 skipset_t *ipset,
12078 const skipaddr_t *ipaddr,
12079 uint32_t prefix)
12080 {
12081 ipset_find_t find_state;
12082 uint32_t ipv4;
12083 int rv;
12084
12085 #if SK_ENABLE_IPV6
12086 /* handle auto-conversion */
12087 if (skipaddrIsV6(ipaddr) && !ipset->is_ipv6) {
12088 if (skipaddrGetAsV4(ipaddr, &ipv4)
12089 || (prefix <= 96 && 0 != prefix))
12090 {
12091 /* cannot convert IPv6 address to IPv4 */
12092 if (ipset->no_autoconvert) {
12093 return SKIPSET_ERR_IPV6;
12094 }
12095 rv = skIPSetConvert(ipset, 6);
12096 if (rv) {
12097 return rv;
12098 }
12099 }
12100 }
12101
12102 if (ipset->is_ipv6) {
12103 ipset_ipv6_t ipv6;
12104
12105 if (skipaddrIsV6(ipaddr)) {
12106 /* both set and address are V6 */
12107 IPSET_IPV6_FROM_ADDRV6(&ipv6, ipaddr);
12108 if (128 == prefix) {
12109 /* no-op */
12110 } else if (0 == prefix) {
12111 prefix = 128;
12112 } else if (prefix > 128) {
12113 return SKIPSET_ERR_PREFIX;
12114 } else {
12115 IPSET_IPV6_APPLY_CIDR(&ipv6, prefix);
12116 }
12117 } else {
12118 /* set is V6 and address is V4 */
12119 IPSET_IPV6_FROM_ADDRV4(&ipv6, ipaddr);
12120 if (0 == prefix || 32 == prefix) {
12121 prefix = 128;
12122 } else if (prefix > 32) {
12123 return SKIPSET_ERR_PREFIX;
12124 } else {
12125 prefix += 96;
12126 /* apply mask */
12127 IPSET_IPV6_APPLY_CIDR(&ipv6, prefix);
12128 }
12129 }
12130 rv = ipsetFindV6(ipset, &ipv6, prefix, &find_state);
12131 if (SKIPSET_OK == rv) {
12132 return rv;
12133 }
12134 IPSET_COPY_ON_WRITE(ipset);
12135 rv = ipsetInsertAddressV6(ipset, &ipv6, prefix, &find_state);
12136 if (rv) {
12137 return rv;
12138 }
12139 IPSET_MAYBE_COMBINE(ipset);
12140 return rv;
12141 }
12142
12143 /* To get here, IPset must be IPv4 */
12144 if (skipaddrIsV6(ipaddr)) {
12145 /* set is V4 and address is V6 */
12146 /* attempt to convert V6 ipaddr to V4 */
12147 if (skipaddrGetAsV4(ipaddr, &ipv4)) {
12148 /* cannot store V6 ipaddr in a V4 IPSet */
12149 return SKIPSET_ERR_IPV6;
12150 }
12151 if (0 == prefix || 128 == prefix) {
12152 prefix = 32;
12153 } else if (prefix > 128) {
12154 return SKIPSET_ERR_PREFIX;
12155 } else if (prefix <= 96) {
12156 return SKIPSET_ERR_IPV6;
12157 } else {
12158 prefix -= 96;
12159 /* apply mask */
12160 ipv4 &= ~(UINT32_MAX >> prefix);
12161 }
12162 } else
12163 #endif /* SK_ENABLE_IPV6 */
12164 {
12165 /* both set and address are V4 */
12166 ipv4 = skipaddrGetV4(ipaddr);
12167 if (prefix == 32) {
12168 /* no-op */
12169 } else if (0 == prefix) {
12170 prefix = 32;
12171 } else if (prefix > 32) {
12172 return SKIPSET_ERR_PREFIX;
12173 } else {
12174 /* apply mask */
12175 ipv4 &= ~(UINT32_MAX >> prefix);
12176 }
12177 }
12178
12179 if (ipset->is_iptree) {
12180 ipset->is_dirty = 1;
12181 return ipsetInsertAddressIPTree(ipset->s.v2, ipv4, prefix);
12182 }
12183
12184 rv = ipsetFindV4(ipset, ipv4, prefix, &find_state);
12185 if (SKIPSET_OK == rv) {
12186 return rv;
12187 }
12188 IPSET_COPY_ON_WRITE(ipset);
12189 rv = ipsetInsertAddressV4(ipset, ipv4, prefix, &find_state);
12190 if (rv) {
12191 return rv;
12192 }
12193 IPSET_MAYBE_COMBINE(ipset);
12194 return rv;
12195 }
12196
12197
12198 /* Add each IP in the IPWildcard to the IPset. */
12199 int
skIPSetInsertIPWildcard(skipset_t * ipset,const skIPWildcard_t * ipwild)12200 skIPSetInsertIPWildcard(
12201 skipset_t *ipset,
12202 const skIPWildcard_t *ipwild)
12203 {
12204 skIPWildcardIterator_t iter;
12205 skipaddr_t ip;
12206 uint32_t prefix;
12207 int rv = SKIPSET_OK;
12208
12209 #if SK_ENABLE_IPV6
12210 /* handle auto-conversion */
12211 if (skIPWildcardIsV6(ipwild) && !ipset->is_ipv6) {
12212 if (ipset->no_autoconvert) {
12213 return SKIPSET_ERR_IPV6;
12214 }
12215 rv = skIPSetConvert(ipset, 6);
12216 if (rv) {
12217 return rv;
12218 }
12219 }
12220 #endif /* SK_ENABLE_IPV6 */
12221
12222 if (ipset->is_iptree) {
12223 ipset->is_dirty = 1;
12224
12225 return ipsetInsertWildcardIPTree(ipset->s.v2, ipwild);
12226 }
12227
12228 /* Insert the netblocks contained in the wildcard */
12229 #if SK_ENABLE_IPV6
12230 if (ipset->is_ipv6 && !skIPWildcardIsV6(ipwild)) {
12231 skIPWildcardIteratorBindV6(&iter, ipwild);
12232 } else
12233 #endif /* SK_ENABLE_IPV6 */
12234 {
12235 skIPWildcardIteratorBind(&iter, ipwild);
12236 }
12237
12238 if (skIPWildcardIteratorNextCidr(&iter, &ip, &prefix)
12239 != SK_ITERATOR_OK)
12240 {
12241 return rv;
12242 }
12243 if (0 == prefix) {
12244 /* wildcard was x.x.x.x or x:x:x:x:x:x:x:x */
12245 if (!skipaddrIsZero(&ip)) {
12246 skAppPrintErr("Wildcard iterator bug: prefix == 0 but IP != 0");
12247 skAbort();
12248 }
12249 /* code thinks prefix of 0 means "default", so must insert two
12250 * CIDR blocks of prefix 1 */
12251 prefix = 1;
12252 rv = skIPSetInsertAddress(ipset, &ip, prefix);
12253 if (rv) { return rv; }
12254 skCIDRComputeEnd(&ip, prefix, &ip);
12255 skipaddrIncrement(&ip);
12256 return skIPSetInsertAddress(ipset, &ip, prefix);
12257 }
12258
12259 /* it would be more efficient to inline skIPSetInsertAddress()
12260 * here; but often there is only one CIDR block in a wildcard */
12261 do {
12262 rv = skIPSetInsertAddress(ipset, &ip, prefix);
12263 } while (skIPWildcardIteratorNextCidr(&iter, &ip, &prefix)==SK_ITERATOR_OK
12264 && SKIPSET_OK == rv);
12265
12266 return rv;
12267 }
12268
12269
12270 int
skIPSetInsertRange(skipset_t * ipset,const skipaddr_t * ipaddr_start,const skipaddr_t * ipaddr_end)12271 skIPSetInsertRange(
12272 skipset_t *ipset,
12273 const skipaddr_t *ipaddr_start,
12274 const skipaddr_t *ipaddr_end)
12275 {
12276 skipaddr_t this_start;
12277 skipaddr_t next_start;
12278 uint32_t prefix;
12279 int rv;
12280
12281 rv = skipaddrCompare(ipaddr_start, ipaddr_end);
12282 if (rv > 0) {
12283 return SKIPSET_ERR_BADINPUT;
12284 }
12285 if (0 == rv) {
12286 /* single ip */
12287 return skIPSetInsertAddress(ipset, ipaddr_start, 0);
12288 }
12289
12290 if (ipset->is_iptree) {
12291 #if !SK_ENABLE_IPV6
12292 return ipsetInsertRangeIPTree(ipset, ipaddr_start, ipaddr_end);
12293 #else
12294 if (!skipaddrIsV6(ipaddr_start) && !skipaddrIsV6(ipaddr_end)) {
12295 return ipsetInsertRangeIPTree(ipset, ipaddr_start, ipaddr_end);
12296 }
12297 if (ipset->no_autoconvert) {
12298 return SKIPSET_ERR_IPV6;
12299 }
12300 rv = ipsetConvertIPTreetoV6(ipset);
12301 if (rv) {
12302 return rv;
12303 }
12304 #endif /* #else of #if !SK_ENABLE_IPV6 */
12305 }
12306
12307 /* get a modifiable version of the beginning IP */
12308 skipaddrCopy(&this_start, ipaddr_start);
12309
12310 do {
12311 prefix = skCIDRComputePrefix(&this_start, ipaddr_end, &next_start);
12312 rv = skIPSetInsertAddress(ipset, &this_start, prefix);
12313 if (rv) {
12314 return rv;
12315 }
12316 skipaddrCopy(&this_start, &next_start);
12317 } while (!skipaddrIsZero(&this_start));
12318
12319 return SKIPSET_OK;
12320 }
12321
12322
12323 /* Make 'result_ipset' hold the intersection of itself with 'ipset' */
12324 int
skIPSetIntersect(skipset_t * result_ipset,const skipset_t * ipset)12325 skIPSetIntersect(
12326 skipset_t *result_ipset,
12327 const skipset_t *ipset)
12328 {
12329 ipset_intersect_t state;
12330 uint32_t prefix;
12331 skipaddr_t tmp_ip;
12332 int rv = SKIPSET_OK;
12333 int i;
12334
12335 /* check input */
12336 if (!result_ipset || !ipset) {
12337 return SKIPSET_ERR_BADINPUT;
12338 }
12339
12340 if (result_ipset->is_iptree && ipset->is_iptree) {
12341 /* both are in the SiLK-2 format (IPTree) */
12342 result_ipset->is_dirty = 1;
12343 ipsetIntersectIPTree(result_ipset->s.v2, ipset->s.v2);
12344 return SKIPSET_OK;
12345 }
12346
12347 /* handle trivial cases */
12348 if (!result_ipset->is_iptree && IPSET_ISEMPTY(result_ipset)) {
12349 return SKIPSET_OK;
12350 }
12351 if (!ipset->is_iptree && IPSET_ISEMPTY(ipset)) {
12352 skIPSetRemoveAll(result_ipset);
12353 return SKIPSET_OK;
12354 }
12355
12356 /* ensure we can use the iterator for the result_ipset */
12357 if (result_ipset->is_dirty) {
12358 skIPSetClean(result_ipset);
12359 }
12360
12361 /* clear memory */
12362 memset(&state, 0, sizeof(ipset_intersect_t));
12363
12364 /* create a vector to hold the blocks that the two IPsets have in
12365 * common; after visiting the IPsets, the result_ipset will be
12366 * updated with the IPs in this vector */
12367 state.vec_add = skVectorNew(sizeof(state.addr));
12368 if (NULL == state.vec_add) {
12369 return SKIPSET_ERR_ALLOC;
12370 }
12371
12372 /* bind the iterator for the result_ipset, get its first CIDR
12373 * block, and convert the block to start and end IPs */
12374 ASSERT_OK(skIPSetIteratorBind(
12375 &state.iter, result_ipset, 1, SK_IPV6POLICY_MIX));
12376 if (skIPSetIteratorNext(&state.iter, &state.addr[0], &prefix)
12377 != SK_ITERATOR_OK)
12378 {
12379 skIPSetRemoveAll(result_ipset);
12380 goto END;
12381 }
12382 skCIDR2IPRange(&state.addr[0], prefix, &state.addr[0], &state.addr[1]);
12383
12384 /* visit the IPs on the ipset */
12385 rv = skIPSetWalk(ipset, 1, (result_ipset->is_ipv6
12386 ? SK_IPV6POLICY_FORCE : SK_IPV6POLICY_MIX),
12387 ipsetIntersectCallback, (void*)&state);
12388 if (SKIPSET_ERR_ALLOC == rv) {
12389 goto END;
12390 }
12391 rv = SKIPSET_OK;
12392
12393 /* remove all IPs from the result IPset */
12394 skIPSetRemoveAll(result_ipset);
12395
12396 /* loop over the start_addr/final_addr IP pairs in the vec_add
12397 * vector, convert them to CIDR blocks, and add them to the result
12398 * IPset. */
12399 for (i = 0; (0 == skVectorGetValue(state.addr, state.vec_add, i)); ++i) {
12400 do {
12401 prefix = skCIDRComputePrefix(&state.addr[0], &state.addr[1],
12402 &tmp_ip);
12403 rv = skIPSetInsertAddress(result_ipset, &state.addr[0], prefix);
12404 if (rv != SKIPSET_OK) {
12405 goto END;
12406 }
12407 skipaddrCopy(&state.addr[0], &tmp_ip);
12408 } while (!skipaddrIsZero(&tmp_ip));
12409 }
12410
12411 END:
12412 if (state.vec_add) {
12413 skVectorDestroy(state.vec_add);
12414 }
12415 return rv;
12416 }
12417
12418
12419 /* Return true if 'ipset' can hold IPv6 addresses */
12420 int
skIPSetIsV6(const skipset_t * ipset)12421 skIPSetIsV6(
12422 const skipset_t *ipset)
12423 {
12424 return ipset->is_ipv6;
12425 }
12426
12427
12428 /* Bind the iterator to an IPset */
12429 int
skIPSetIteratorBind(skipset_iterator_t * iter,const skipset_t * ipset,uint32_t cidr_blocks,sk_ipv6policy_t v6_policy)12430 skIPSetIteratorBind(
12431 skipset_iterator_t *iter,
12432 const skipset_t *ipset,
12433 uint32_t cidr_blocks,
12434 sk_ipv6policy_t v6_policy)
12435 {
12436 if (!ipset || !iter) {
12437 return SKIPSET_ERR_BADINPUT;
12438 }
12439 if (ipset->is_dirty && !ipset->is_iptree) {
12440 return SKIPSET_ERR_REQUIRE_CLEAN;
12441 }
12442
12443 memset(iter, 0, sizeof(skipset_iterator_t));
12444 iter->ipset = ipset;
12445 iter->v6policy = v6_policy;
12446 iter->cidr_blocks = (cidr_blocks ? 1 : 0);
12447 iter->is_iptree = ipset->is_iptree;
12448
12449 if (iter->is_iptree) {
12450 iter->it.v2.tree = ipset->s.v2;
12451 }
12452 skIPSetIteratorReset(iter);
12453
12454 return 0;
12455 }
12456
12457
12458 /* Return the next CIDR block associated with the IPset */
12459 int
skIPSetIteratorNext(skipset_iterator_t * iter,skipaddr_t * ipaddr,uint32_t * prefix)12460 skIPSetIteratorNext(
12461 skipset_iterator_t *iter,
12462 skipaddr_t *ipaddr,
12463 uint32_t *prefix)
12464 {
12465 ipset_leaf_v4_t *leaf4;
12466 uint32_t ipv4;
12467
12468 if (iter->is_iptree) {
12469 return ipsetIteratorNextIPTree(iter, ipaddr, prefix);
12470 }
12471
12472 if (iter->it.v3.cur >= iter->ipset->s.v3->leaves.entry_count) {
12473 return SK_ITERATOR_NO_MORE_ENTRIES;
12474 }
12475 assert(0 == iter->ipset->is_dirty);
12476
12477 #if SK_ENABLE_IPV6
12478 if (iter->ipset->is_ipv6) {
12479 ipset_leaf_v6_t *leaf6;
12480 ipset_ipv6_t *ipv6;
12481 ipset_ipv6_t *fin6;
12482
12483 if (iter->cidr_blocks) {
12484 leaf6 = LEAF_PTR_V6(iter->ipset, iter->it.v3.cur);
12485 if (SK_IPV6POLICY_ASV4 == iter->v6policy) {
12486 /* check stopping condition */
12487 if (leaf6->ip.ip[0] != 0
12488 || ((UINT64_C(0xffffffff00000000) & leaf6->ip.ip[1])
12489 != UINT64_C(0x0000ffff00000000)))
12490 {
12491 iter->it.v3.cur = iter->ipset->s.v3->leaves.entry_count;
12492 return SK_ITERATOR_NO_MORE_ENTRIES;
12493 }
12494 IPSET_IPV6_TO_ADDR_V4(&leaf6->ip, ipaddr);
12495 *prefix = leaf6->prefix - 96;
12496 } else {
12497 IPSET_IPV6_TO_ADDR(&leaf6->ip, ipaddr);
12498 *prefix = leaf6->prefix;
12499 }
12500 ++iter->it.v3.cur;
12501
12502 } else {
12503 /* return value is value on the iterator */
12504 ipv6 = (ipset_ipv6_t*)&iter->it.v3.data[0];
12505 fin6 = (ipset_ipv6_t*)&iter->it.v3.data[2];
12506 if (SK_IPV6POLICY_ASV4 == iter->v6policy) {
12507 IPSET_IPV6_TO_ADDR_V4(ipv6, ipaddr);
12508 *prefix = 32;
12509 } else {
12510 IPSET_IPV6_TO_ADDR(ipv6, ipaddr);
12511 *prefix = 128;
12512 }
12513
12514 /* point iterator at next value */
12515 if (ipv6->ip[1] < fin6->ip[1]) {
12516 ++ipv6->ip[1];
12517 } else if (ipv6->ip[0] < fin6->ip[0]) {
12518 if (ipv6->ip[1] == UINT64_MAX) {
12519 ++ipv6->ip[0];
12520 ipv6->ip[1] = 0;
12521 } else {
12522 ++ipv6->ip[1];
12523 }
12524 } else {
12525 ++iter->it.v3.cur;
12526 if (iter->it.v3.cur < iter->ipset->s.v3->leaves.entry_count) {
12527 ipsetIteratorNextRangeV6(iter);
12528 }
12529 }
12530 }
12531 return SK_ITERATOR_OK;
12532 }
12533
12534 if (SK_IPV6POLICY_FORCE == iter->v6policy) {
12535 if (iter->cidr_blocks) {
12536 leaf4 = LEAF_PTR_V4(iter->ipset, iter->it.v3.cur);
12537 skipaddrSetV6FromUint32(ipaddr, &leaf4->ip);
12538 *prefix = 96 + leaf4->prefix;
12539 ++iter->it.v3.cur;
12540
12541 } else {
12542 /* return value is value on the iterator */
12543 ipv4 = (uint32_t)iter->it.v3.data[0];
12544 skipaddrSetV6FromUint32(ipaddr, &ipv4);
12545 *prefix = 128;
12546
12547 /* point iterator at next value */
12548 if (iter->it.v3.data[0] < iter->it.v3.data[2]) {
12549 ++iter->it.v3.data[0];
12550 } else {
12551 ++iter->it.v3.cur;
12552 if (iter->it.v3.cur < iter->ipset->s.v3->leaves.entry_count) {
12553 ipsetIteratorNextRangeV4(iter);
12554 }
12555 }
12556 }
12557 return SK_ITERATOR_OK;
12558 }
12559 #endif /* SK_ENABLE_IPV6 */
12560
12561 if (iter->cidr_blocks) {
12562 leaf4 = LEAF_PTR_V4(iter->ipset, iter->it.v3.cur);
12563 skipaddrSetV4(ipaddr, &leaf4->ip);
12564 *prefix = leaf4->prefix;
12565 ++iter->it.v3.cur;
12566
12567 } else {
12568 /* return value is value on the iterator */
12569 ipv4 = (uint32_t)iter->it.v3.data[0];
12570 skipaddrSetV4(ipaddr, &ipv4);
12571 *prefix = 32;
12572
12573 /* point iterator at next value */
12574 if (iter->it.v3.data[0] < iter->it.v3.data[2]) {
12575 ++iter->it.v3.data[0];
12576 } else {
12577 ++iter->it.v3.cur;
12578 if (iter->it.v3.cur < iter->ipset->s.v3->leaves.entry_count) {
12579 ipsetIteratorNextRangeV4(iter);
12580 }
12581 }
12582 }
12583
12584 return SK_ITERATOR_OK;
12585 }
12586
12587
12588 /* Reset iterator so we can visit the IPs again */
12589 void
skIPSetIteratorReset(skipset_iterator_t * iter)12590 skIPSetIteratorReset(
12591 skipset_iterator_t *iter)
12592 {
12593 assert(iter);
12594
12595 if (iter->is_iptree) {
12596 if (SK_IPV6POLICY_ONLY == iter->v6policy) {
12597 iter->it.v2.top_16 = SKIP_BBLOCK_COUNT;
12598 return;
12599 }
12600
12601 iter->it.v2.count = 0;
12602 iter->it.v2.trail_zero = 0;
12603 iter->it.v2.base_ip = 0;
12604 iter->it.v2.top_16 = 0;
12605 iter->it.v2.mid_11 = 0;
12606 iter->it.v2.bot_5 = 0;
12607 ipsetIteratorIPTreeNextSlash27(iter);
12608 return;
12609 }
12610
12611 iter->it.v3.cur = IPSET_ITER_FIRST_LEAF;
12612 if (IPSET_ISEMPTY(iter->ipset)) {
12613 return;
12614 }
12615
12616 #if SK_ENABLE_IPV6
12617 if (iter->ipset->is_ipv6) {
12618 if (iter->v6policy == SK_IPV6POLICY_IGNORE) {
12619 /* caller wants only IPv4 addresses, and there are none in
12620 * an IPv6 IPset. */
12621 iter->it.v3.cur = iter->ipset->s.v3->leaves.entry_count;
12622 return;
12623 }
12624 if (iter->v6policy == SK_IPV6POLICY_ASV4) {
12625 /* find the left-most leaf under ::ffff:0:0/96 */
12626 ipset_find_t find_state;
12627 ipset_ipv6_t ipv6;
12628 const ipset_node_v6_t *node;
12629 uint32_t i;
12630 int rv;
12631
12632 ipv6.ip[0] = 0;
12633 ipv6.ip[1] = UINT64_C(0xffff00000000);
12634
12635 rv = ipsetFindV6(iter->ipset, &ipv6, 96, &find_state);
12636 if (SKIPSET_OK != rv && SKIPSET_ERR_SUBSET != rv) {
12637 /* no IPv4 addresses in the IPset */
12638 iter->it.v3.cur = iter->ipset->s.v3->leaves.entry_count;
12639 return;
12640 }
12641
12642 if (find_state.node_is_leaf) {
12643 iter->it.v3.cur = find_state.node_idx;
12644 } else {
12645 node = NODE_PTR_V6(iter->ipset, find_state.node_idx);
12646 for (;;) {
12647 for (i=0; i < IPSET_NUM_CHILDREN && !node->child[i]; ++i)
12648 ; /* empty */
12649 if (NODEPTR_CHILD_IS_LEAF(node, i)) {
12650 iter->it.v3.cur = node->child[i];
12651 break;
12652 }
12653 node = NODE_PTR_V6(iter->ipset, node->child[i]);
12654 }
12655 }
12656 }
12657 assert(iter->it.v3.cur < iter->ipset->s.v3->leaves.entry_count);
12658 if (!iter->cidr_blocks) {
12659 ipsetIteratorNextRangeV6(iter);
12660 }
12661 return;
12662 }
12663 /* else, IPset contains IPv4 addresses */
12664
12665 if (iter->v6policy == SK_IPV6POLICY_ONLY) {
12666 /* caller wants only IPv6 addresses, and there are none in an
12667 * IPv4 IPset. */
12668 iter->it.v3.cur = iter->ipset->s.v3->leaves.entry_count;
12669 return;
12670 }
12671
12672 #else /* #if SK_ENABLE_IPV6 */
12673
12674 if (iter->v6policy > SK_IPV6POLICY_MIX) {
12675 /* caller wants IPv6 addresses, which are not supported in
12676 * IPv4-only SiLK. */
12677 iter->it.v3.cur = iter->ipset->s.v3->leaves.entry_count;
12678 return;
12679 }
12680
12681 #endif /* #else of #if SK_ENABLE_IPV6 */
12682
12683 assert(iter->it.v3.cur < iter->ipset->s.v3->leaves.entry_count);
12684 if (!iter->cidr_blocks) {
12685 ipsetIteratorNextRangeV4(iter);
12686 }
12687 }
12688
12689
12690 /* Read IPSet from filename---a wrapper around skIPSetRead(). */
12691 int
skIPSetLoad(skipset_t ** ipset,const char * filename)12692 skIPSetLoad(
12693 skipset_t **ipset,
12694 const char *filename)
12695 {
12696 skstream_t *stream = NULL;
12697 int rv;
12698
12699 if (filename == NULL || ipset == NULL) {
12700 return -1;
12701 }
12702
12703 if ((rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK))
12704 || (rv = skStreamBind(stream, filename))
12705 || (rv = skStreamOpen(stream)))
12706 {
12707 /* skStreamPrintLastErr(stream, rv, &skAppPrintErr); */
12708 rv = SKIPSET_ERR_OPEN;
12709 goto END;
12710 }
12711
12712 rv = skIPSetRead(ipset, stream);
12713 if (rv) {
12714 goto END;
12715 }
12716
12717 END:
12718 skStreamDestroy(&stream);
12719 return rv;
12720 }
12721
12722
12723 /* For each occupied block of size 'mask_prefix', set a single IP. */
12724 int
skIPSetMask(skipset_t * ipset,uint32_t mask_prefix)12725 skIPSetMask(
12726 skipset_t *ipset,
12727 uint32_t mask_prefix)
12728 {
12729 if (!ipset) {
12730 return SKIPSET_ERR_BADINPUT;
12731 }
12732
12733 #if SK_ENABLE_IPV6
12734 if (ipset->is_ipv6) {
12735 /* verify mask_prefix value is valid */
12736 if (mask_prefix >= 128 || mask_prefix == 0) {
12737 return SKIPSET_ERR_PREFIX;
12738 }
12739
12740 if (IPSET_ISEMPTY(ipset)) {
12741 return SKIPSET_OK;
12742 }
12743 IPSET_COPY_ON_WRITE(ipset);
12744
12745 return ipsetMaskV6(ipset, mask_prefix);
12746 }
12747 #endif /* SK_ENABLE_IPV6 */
12748
12749 /* verify mask_prefix value is valid */
12750 if (mask_prefix >= 32 || mask_prefix == 0) {
12751 return SKIPSET_ERR_PREFIX;
12752 }
12753
12754 if (ipset->is_iptree) {
12755 ipset->is_dirty = 1;
12756 return ipsetMaskIPTree(ipset->s.v2, mask_prefix);
12757 }
12758
12759 if (IPSET_ISEMPTY(ipset)) {
12760 return SKIPSET_OK;
12761 }
12762 IPSET_COPY_ON_WRITE(ipset);
12763
12764 return ipsetMaskV4(ipset, mask_prefix);
12765 }
12766
12767
12768 /* For each occupied block of size 'mask_prefix', set all IPs. */
12769 int
skIPSetMaskAndFill(skipset_t * ipset,uint32_t mask_prefix)12770 skIPSetMaskAndFill(
12771 skipset_t *ipset,
12772 uint32_t mask_prefix)
12773 {
12774 if (!ipset) {
12775 return SKIPSET_ERR_BADINPUT;
12776 }
12777
12778 #if SK_ENABLE_IPV6
12779 if (ipset->is_ipv6) {
12780 /* verify mask_prefix value is valid */
12781 if (mask_prefix >= 128 || mask_prefix == 0) {
12782 return SKIPSET_ERR_PREFIX;
12783 }
12784
12785 if (IPSET_ISEMPTY(ipset)) {
12786 return SKIPSET_OK;
12787 }
12788 IPSET_COPY_ON_WRITE(ipset);
12789
12790 return ipsetMaskAndFillV6(ipset, mask_prefix);
12791 }
12792 #endif /* SK_ENABLE_IPV6 */
12793
12794 /* verify mask_prefix value is valid */
12795 if (mask_prefix >= 32 || mask_prefix == 0) {
12796 return SKIPSET_ERR_PREFIX;
12797 }
12798
12799 if (ipset->is_iptree) {
12800 return ipsetMaskAndFillIPTree(ipset, mask_prefix);
12801 }
12802
12803 if (IPSET_ISEMPTY(ipset)) {
12804 return SKIPSET_OK;
12805 }
12806 IPSET_COPY_ON_WRITE(ipset);
12807
12808 return ipsetMaskAndFillV4(ipset, mask_prefix);
12809 }
12810
12811
12812 /* Set the parameters to use when writing an IPset */
12813 void
skIPSetOptionsBind(skipset_t * ipset,const skipset_options_t * set_options)12814 skIPSetOptionsBind(
12815 skipset_t *ipset,
12816 const skipset_options_t *set_options)
12817 {
12818 assert(ipset);
12819
12820 ipset->options = set_options;
12821 }
12822
12823
12824 /* Initialize 'ipset_opts' and register options */
12825 int
skIPSetOptionsRegister(skipset_options_t * ipset_opts)12826 skIPSetOptionsRegister(
12827 skipset_options_t *ipset_opts)
12828 {
12829 assert(ipset_opts);
12830 assert(sizeof(ipset_options)/sizeof(struct option)
12831 == sizeof(ipset_options_help)/sizeof(char*));
12832
12833 if (skIPSetOptionsRegisterRecordVersion(ipset_opts, NULL)) {
12834 return -1;
12835 }
12836
12837 if (skOptionsRegister(ipset_options, ipsetOptionsHandler,
12838 (clientData)ipset_opts)
12839 || skOptionsNotesRegister(ipset_opts->existing_silk_files
12840 ? &ipset_opts->note_strip
12841 : NULL)
12842 || skCompMethodOptionsRegister(&ipset_opts->comp_method))
12843 {
12844 return -1;
12845 }
12846 return 0;
12847 }
12848
12849
12850 int
skIPSetOptionsRegisterRecordVersion(skipset_options_t * ipset_opts,const char * option_name)12851 skIPSetOptionsRegisterRecordVersion(
12852 skipset_options_t *ipset_opts,
12853 const char *option_name)
12854 {
12855 const char *envar;
12856 uint32_t tmp32 = 0;
12857
12858 assert(ipset_opts);
12859
12860 if (ipset_options_record_version[0].name) {
12861 skAppPrintErr("skIPSetOptionsRegister called multiple times");
12862 return -1;
12863 }
12864
12865 /* set default record version */
12866 ipset_opts->record_version = IPSET_REC_VERSION_DEFAULT;
12867 ipset_opts->invocation_strip = 0;
12868 ipset_opts->comp_method = 0;
12869 ipset_opts->note_strip = 0;
12870
12871 /* use the environment to override the default version */
12872 envar = getenv(IPSET_REC_VERSION_ENVAR);
12873 if (envar
12874 && 0 == skStringParseUint32(&tmp32, envar, IPSET_REC_VERSION_MIN,
12875 IPSET_REC_VERSION_MAX)
12876 && 1 != tmp32)
12877 {
12878 ipset_opts->record_version = (uint16_t)tmp32;
12879 }
12880
12881 /* set name of record-version option */
12882 if (NULL == option_name) {
12883 ipset_options_record_version[0].name
12884 = strdup(ipset_options_record_version_default_name);
12885 } else {
12886 ipset_options_record_version[0].name = strdup(option_name);
12887 }
12888 if (NULL == ipset_options_record_version[0].name) {
12889 skAppPrintOutOfMemory("strdup");
12890 return -1;
12891 }
12892
12893 if (skOptionsRegister(ipset_options_record_version, ipsetOptionsHandler,
12894 (clientData)ipset_opts))
12895 {
12896 free((void*)ipset_options_record_version[0].name);
12897 ipset_options_record_version[0].name = NULL;
12898 return -1;
12899 }
12900 return 0;
12901 }
12902
12903
12904 /* Clean up memory used by the IPset options */
12905 void
skIPSetOptionsTeardown(void)12906 skIPSetOptionsTeardown(
12907 void)
12908 {
12909 free((void*)ipset_options_record_version[0].name);
12910 ipset_options_record_version[0].name = NULL;
12911 skOptionsNotesTeardown();
12912 }
12913
12914
12915 /* Print the usage strings for the options that the library registers */
12916 void
skIPSetOptionsUsage(FILE * fh)12917 skIPSetOptionsUsage(
12918 FILE *fh)
12919 {
12920 unsigned int i;
12921
12922 skIPSetOptionsUsageRecordVersion(fh);
12923
12924 for (i = 0; ipset_options[i].name; ++i) {
12925 fprintf(fh, "--%s %s. %s\n",
12926 ipset_options[i].name, SK_OPTION_HAS_ARG(ipset_options[i]),
12927 ipset_options_help[i]);
12928 }
12929 skOptionsNotesUsage(fh);
12930 skCompMethodOptionsUsage(fh);
12931 }
12932
12933 void
skIPSetOptionsUsageRecordVersion(FILE * fh)12934 skIPSetOptionsUsageRecordVersion(
12935 FILE *fh)
12936 {
12937 if (NULL == ipset_options_record_version[0].name) {
12938 return;
12939 }
12940 fprintf(fh, ("--%s %s. Specify version when writing IPset records.\n"),
12941 ipset_options_record_version[0].name,
12942 SK_OPTION_HAS_ARG(ipset_options_record_version[0]));
12943 fprintf(fh, ("\t0 - Default."
12944 " Uses %d for IPv4 IPsets and %d for IPv6 IPsets.\n"),
12945 IPSET_REC_VERSION_DEFAULT_IPV4, IPSET_REC_VERSION_DEFAULT_IPV6);
12946 fprintf(fh, ("\t2 - Stores IPv4 only (error if IPv6)."
12947 " Available in all releases.\n"));
12948 fprintf(fh, ("\t3 - Stores IPv4 or IPv6. Available since SiLK 3.0.\n"));
12949 fprintf(fh, ("\t4 - Stores IPv4 or IPv6. Available since SiLK 3.7.\n"));
12950 fprintf(fh, ("\t5 - Stores IPv6 only (uses 4 for IPv4)."
12951 " Available since SiLK 3.14.\n"));
12952 }
12953
12954
12955 /* Print the IPs in ipset to 'stream'. */
12956 void
skIPSetPrint(const skipset_t * ipset,skstream_t * stream,skipaddr_flags_t ip_format,int as_cidr)12957 skIPSetPrint(
12958 const skipset_t *ipset,
12959 skstream_t *stream,
12960 skipaddr_flags_t ip_format,
12961 int as_cidr)
12962 {
12963 ipset_print_t print_state;
12964
12965 print_state.ipset = ipset;
12966 print_state.stream = stream;
12967 print_state.ip_format = ip_format;
12968
12969 skIPSetWalk(ipset, (as_cidr ? 1 : 0), SK_IPV6POLICY_MIX,
12970 &ipsetPrintCallback, (void*)&print_state);
12971 }
12972
12973
12974 /*
12975 * ipsetDebugPrintAddrV4(ip, prefix);
12976 * ipsetDebugPrintAddrV6(ip, prefix);
12977 *
12978 * Helper functions for the various skIPSetDebugPrint*() functions
12979 * to print an IP address and its prefix.
12980 */
12981 static void
ipsetDebugPrintAddrV4(uint32_t ipv4,uint32_t prefix)12982 ipsetDebugPrintAddrV4(
12983 uint32_t ipv4,
12984 uint32_t prefix)
12985 {
12986 int i;
12987
12988 /* print IP (2 ways) */
12989 for (i = 24; i >= 0; i -= 8) {
12990 fprintf(stderr, "%02x%c",
12991 0xFF & (ipv4 >> i), (i ? '.' : '/'));
12992 }
12993 fprintf(stderr, "%2u [", prefix);
12994 for (i = 24; i >= 0; i -= 8) {
12995 fprintf(stderr, "%3d%c",
12996 0xFF & (ipv4 >> i), (i ? '.' : '/'));
12997 }
12998 fprintf(stderr, "%2u]", prefix);
12999 }
13000
13001 #if SK_ENABLE_IPV6
13002 static void
ipsetDebugPrintAddrV6(const ipset_ipv6_t * ipv6,uint32_t prefix)13003 ipsetDebugPrintAddrV6(
13004 const ipset_ipv6_t *ipv6,
13005 uint32_t prefix)
13006 {
13007 uint32_t i;
13008 uint32_t j;
13009
13010 /* print IP */
13011 fprintf(stderr, "[");
13012 for (j = 0; j < 2; ++j) {
13013 for (i = 48; i > 0; i -= 16) {
13014 fprintf(stderr, ("%4" PRIx64 ":"),
13015 0xFFFF & (ipv6->ip[j] >> i));
13016 }
13017 fprintf(stderr, ("%4" PRIx64 "%c"),
13018 (0xFFFF & ipv6->ip[j]), (j ? '/' : ':'));
13019 }
13020 fprintf(stderr, "%3u]", prefix);
13021 }
13022 #endif /* SK_ENABLE_IPV6 */
13023
13024
13025 /*
13026 * ipsetDebugPrintChildren(node, width);
13027 *
13028 * A helper function for the various skIPSetDebugPrint*()
13029 * functions. This function takes a node and prints the indexes of
13030 * the children that the node points to.
13031 */
13032 static void
ipsetDebugPrintChildren(const ipset_node_t * node,int width)13033 ipsetDebugPrintChildren(
13034 const ipset_node_t *node,
13035 int width)
13036 {
13037 uint32_t i;
13038
13039 /* print children's IDs, followed by N for node, L for
13040 * leaf, or R for repeated leaf */
13041 for (i = 0; i < IPSET_NUM_CHILDREN; ++i) {
13042 if (0 == node->v4.child[i]) {
13043 fprintf(stderr, " %*c ", width, '-');
13044 } else {
13045 fprintf(stderr, " %*u%c",
13046 width, node->v4.child[i],
13047 (!NODEPTR_CHILD_IS_LEAF(&node->v4, i)
13048 ? 'N'
13049 : (NODEPTR_CHILD_IS_REPEAT(&node->v4, i)
13050 ? 'R' : 'L')));
13051 }
13052 }
13053 }
13054
13055
13056 /*
13057 * ipsetDebugPrintLeaf(ipset, leaf);
13058 *
13059 * Print the IP address on a leaf.
13060 */
13061 static void
ipsetDebugPrintLeaf(const skipset_t * ipset,const ipset_leaf_t * leaf)13062 ipsetDebugPrintLeaf(
13063 const skipset_t *ipset,
13064 const ipset_leaf_t *leaf)
13065 {
13066 if (ipset->is_ipv6) {
13067 #if SK_ENABLE_IPV6
13068 ipsetDebugPrintAddrV6(&leaf->v6.ip, leaf->v6.prefix);
13069 #endif /* SK_ENABLE_IPV6 */
13070 fprintf(stderr, "\n");
13071 } else {
13072 ipsetDebugPrintAddrV4(leaf->v4.ip, leaf->v4.prefix);
13073 fprintf(stderr, "\n");
13074 }
13075 }
13076
13077
13078 /*
13079 * ipsetDebugPrintNode(ipset, node);
13080 *
13081 * Print the IP address and child values from a node.
13082 */
13083 static void
ipsetDebugPrintNode(const skipset_t * ipset,const ipset_node_t * node)13084 ipsetDebugPrintNode(
13085 const skipset_t *ipset,
13086 const ipset_node_t *node)
13087 {
13088 int width = 0;
13089
13090 if (ipset->s.v3->leaves.entry_count) {
13091 width = 2 + (int)log10(ipset->s.v3->leaves.entry_count);
13092 }
13093
13094 #if SK_ENABLE_IPV6
13095 if (ipset->is_ipv6) {
13096 ipsetDebugPrintAddrV6(&node->v6.ip, node->v6.prefix);
13097 fprintf(stderr, " ");
13098 } else
13099 #endif /* SK_ENABLE_IPV6 */
13100 {
13101 ipsetDebugPrintAddrV4(node->v4.ip, node->v4.prefix);
13102 fprintf(stderr, " ");
13103 }
13104
13105 ipsetDebugPrintChildren(node, width);
13106
13107 fprintf(stderr, "\n");
13108 }
13109
13110
13111 /*
13112 * ipsetDebugPrintByIndex(ipset, node_idx, is_leaf);
13113 *
13114 * Print information about a node or a leaf whose index is
13115 * 'node_idx'.
13116 */
13117 static void
ipsetDebugPrintByIndex(const skipset_t * ipset,uint32_t node_idx,int is_leaf)13118 ipsetDebugPrintByIndex(
13119 const skipset_t *ipset,
13120 uint32_t node_idx,
13121 int is_leaf)
13122 {
13123 if (is_leaf) {
13124 if (node_idx < ipset->s.v3->leaves.entry_count) {
13125 ipsetDebugPrintLeaf(ipset, LEAF_PTR(ipset, node_idx));
13126 } else {
13127 fprintf(stderr, "%" PRIu32 "L is too large\n", node_idx);
13128 }
13129 } else {
13130 if (node_idx < ipset->s.v3->nodes.entry_count) {
13131 ipsetDebugPrintNode(ipset, NODE_PTR(ipset, node_idx));
13132 } else {
13133 fprintf(stderr, "%" PRIu32 "N is too large\n", node_idx);
13134 }
13135 }
13136 }
13137
13138
13139 /* Debugging print function. */
13140 void
skIPSetDebugPrint(const skipset_t * ipset)13141 skIPSetDebugPrint(
13142 const skipset_t *ipset)
13143 {
13144 const ipset_node_t *node;
13145 const ipset_leaf_t *leaf;
13146 uint32_t node_idx;
13147 uint32_t bitmap_size;
13148 sk_bitmap_t *isfree;
13149 int width = 0;
13150
13151 if (ipset->is_iptree) {
13152 return;
13153 }
13154
13155 if (ipset->s.v3->leaves.entry_count) {
13156 width = 2 + (int)log10(ipset->s.v3->leaves.entry_count);
13157 }
13158
13159 /* print root ID */
13160 fprintf(stderr,
13161 ">> %*sROOT %u%c NODE_FREE %uN LEAF_FREE %uL\n",
13162 width, "", (unsigned)IPSET_ROOT_INDEX(ipset),
13163 (IPSET_ROOT_IS_LEAF(ipset) ? 'L' : 'N'),
13164 (unsigned)ipset->s.v3->nodes.free_list,
13165 (unsigned)ipset->s.v3->leaves.free_list);
13166
13167 if (IPSET_ISEMPTY(ipset)) {
13168 return;
13169 }
13170
13171 /* this function creates a bitmap to note which nodes and leaves
13172 * are on the free list. this is the size of the bitmap */
13173 if (ipset->s.v3->nodes.entry_count > ipset->s.v3->leaves.entry_count) {
13174 bitmap_size = ipset->s.v3->nodes.entry_count;
13175 } else {
13176 bitmap_size = ipset->s.v3->leaves.entry_count;
13177 }
13178
13179 /* create the bitmap */
13180 if (skBitmapCreate(&isfree, bitmap_size)) {
13181 /* unable to create bitmap; use simple printing (this also
13182 * allows us to use the functions and avoid warnings from
13183 * gcc) */
13184
13185 /* print nodes */
13186 for (node_idx = 0;
13187 node_idx < ipset->s.v3->nodes.entry_count;
13188 ++node_idx)
13189 {
13190 fprintf(stderr, "** %*uN ", width, node_idx);
13191 ipsetDebugPrintByIndex(ipset, node_idx, 0);
13192 }
13193
13194 /* print leaves */
13195 fprintf(stderr, "\n");
13196 for (node_idx = 0;
13197 node_idx < ipset->s.v3->leaves.entry_count;
13198 ++node_idx)
13199 {
13200 fprintf(stderr, "** %*uL ", width, node_idx);
13201 ipsetDebugPrintByIndex(ipset, node_idx, 1);
13202 }
13203
13204 return;
13205 }
13206
13207 /* fill the bitmap for nodes on the free list */
13208 for (node_idx = ipset->s.v3->nodes.free_list;
13209 0 != node_idx;
13210 node_idx = NODEIDX_FREE_LIST(ipset, node_idx))
13211 {
13212 assert(node_idx < ipset->s.v3->nodes.entry_count);
13213 skBitmapSetBit(isfree, node_idx);
13214 }
13215
13216 /* print the nodes */
13217 for (node_idx = 0; node_idx < ipset->s.v3->nodes.entry_count; ++node_idx) {
13218 node = NODE_PTR(ipset, node_idx);
13219 fprintf(stderr, "** %*uN ", width, node_idx);
13220 #if SK_ENABLE_IPV6
13221 if (ipset->is_ipv6) {
13222 ipsetDebugPrintAddrV6(&node->v6.ip, node->v6.prefix);
13223 } else
13224 #endif
13225 {
13226 ipsetDebugPrintAddrV4(node->v4.ip, node->v4.prefix);
13227 }
13228
13229 /* note whether this entry is on free-list */
13230 fprintf(stderr, " %c",
13231 (skBitmapGetBit(isfree, node_idx) ? 'F' : ' '));
13232
13233 ipsetDebugPrintChildren(node, width);
13234 fprintf(stderr, "\n");
13235 }
13236
13237 skBitmapClearAllBits(isfree);
13238
13239 /* mark leaves that are on the free list */
13240 for (node_idx = ipset->s.v3->leaves.free_list;
13241 0 != node_idx;
13242 node_idx = LEAFIDX_FREE_LIST(ipset, node_idx))
13243 {
13244 assert(node_idx < ipset->s.v3->leaves.entry_count);
13245 skBitmapSetBit(isfree, node_idx);
13246 }
13247
13248 /* print the leaves */
13249 fprintf(stderr, "\n");
13250 for (node_idx = 0; node_idx < ipset->s.v3->leaves.entry_count; ++node_idx) {
13251 leaf = LEAF_PTR(ipset, node_idx);
13252 fprintf(stderr, "** %*uL ", width, node_idx);
13253 #if SK_ENABLE_IPV6
13254 if (ipset->is_ipv6) {
13255 ipsetDebugPrintAddrV6(&leaf->v6.ip, leaf->v6.prefix);
13256 } else
13257 #endif
13258 {
13259 ipsetDebugPrintAddrV4(leaf->v4.ip, leaf->v4.prefix);
13260 }
13261 /* note whether this entry is on free-list */
13262 fprintf(stderr, "%s",
13263 (skBitmapGetBit(isfree, node_idx) ? " F\n" : "\n"));
13264 }
13265
13266 skBitmapDestroy(&isfree);
13267 }
13268
13269
13270 int
skIPSetProcessStream(skstream_t * stream,skipset_procstream_init_t cb_init_func,void * cb_init_func_ctx,skipset_procstream_parm_t * proc_stream_settings)13271 skIPSetProcessStream(
13272 skstream_t *stream,
13273 skipset_procstream_init_t cb_init_func,
13274 void *cb_init_func_ctx,
13275 skipset_procstream_parm_t *proc_stream_settings)
13276 {
13277 sk_file_header_t *hdr;
13278 ipset_walk_t proc_stream_state;
13279 int is_ipv6 = 0;
13280 int rv;
13281
13282 if (NULL == stream || NULL == proc_stream_settings) {
13283 return SKIPSET_ERR_BADINPUT;
13284 }
13285 if (NULL == proc_stream_settings->cb_entry_func && NULL == cb_init_func) {
13286 return SKIPSET_ERR_BADINPUT;
13287 }
13288
13289 rv = ipsetReadStreamHeader(stream, &hdr, &is_ipv6);
13290 if (rv) {
13291 return rv;
13292 }
13293
13294 if (cb_init_func) {
13295 skipset_t *fake_set = NULL;
13296 rv = skIPSetCreate(&fake_set, is_ipv6);
13297 if (SKIPSET_OK == rv) {
13298 rv = cb_init_func(fake_set, hdr, cb_init_func_ctx,
13299 proc_stream_settings);
13300 skIPSetDestroy(&fake_set);
13301 }
13302 if (rv) {
13303 return rv;
13304 }
13305 }
13306 if (NULL == proc_stream_settings->cb_entry_func) {
13307 return SKIPSET_OK;
13308 }
13309
13310 switch (proc_stream_settings->v6_policy) {
13311 case SK_IPV6POLICY_ONLY:
13312 if (!is_ipv6) {
13313 /* caller wants only IPv6 addresses; there are none */
13314 return SKIPSET_OK;
13315 }
13316 break;
13317 case SK_IPV6POLICY_IGNORE:
13318 if (is_ipv6) {
13319 /* caller wants only IPv4 addresses; there are none */
13320 return SKIPSET_OK;
13321 }
13322 break;
13323 case SK_IPV6POLICY_FORCE:
13324 case SK_IPV6POLICY_ASV4:
13325 case SK_IPV6POLICY_MIX:
13326 break;
13327 #ifdef NDEBUG
13328 default:
13329 skAbortBadCase(proc_stream_settings->v6_policy);
13330 #endif
13331 }
13332
13333 memset(&proc_stream_state, 0, sizeof(proc_stream_state));
13334 proc_stream_state.callback = proc_stream_settings->cb_entry_func;
13335 proc_stream_state.cb_data = proc_stream_settings->cb_entry_func_ctx;
13336 proc_stream_state.v6policy = proc_stream_settings->v6_policy;
13337 proc_stream_state.cidr_blocks = proc_stream_settings->visit_cidr;
13338
13339 if (skHeaderGetRecordVersion(hdr) < IPSET_REC_VERSION_RADIX) {
13340 /* Handle files in IPSET_REC_VERSION_CLASSC format */
13341 return ipsetProcessStreamClassc(stream, hdr, &proc_stream_state);
13342 }
13343 if (skHeaderGetRecordVersion(hdr) == IPSET_REC_VERSION_RADIX) {
13344 return ipsetProcessStreamRadix(stream, hdr, &proc_stream_state);
13345 }
13346 if (skHeaderGetRecordVersion(hdr) == IPSET_REC_VERSION_CIDRBMAP) {
13347 return ipsetProcessStreamCidrbmap(stream, hdr, &proc_stream_state);
13348 }
13349 if (skHeaderGetRecordVersion(hdr) == IPSET_REC_VERSION_SLASH64) {
13350 #if !SK_ENABLE_IPV6
13351 skAbort();
13352 #else
13353 return ipsetProcessStreamSlash64(stream, hdr, &proc_stream_state);
13354 #endif /* SK_ENABLE_IPV6 */
13355 }
13356
13357 skAbort();
13358 }
13359
13360
13361 static int
ipsetProcessStreamCountInit(const skipset_t * ipset,const sk_file_header_t UNUSED (* hdr),void UNUSED (* init_func_ctx),skipset_procstream_parm_t * param)13362 ipsetProcessStreamCountInit(
13363 const skipset_t *ipset,
13364 const sk_file_header_t UNUSED(*hdr),
13365 void UNUSED(*init_func_ctx),
13366 skipset_procstream_parm_t *param)
13367 {
13368 #if !SK_ENABLE_IPV6
13369 /* unused param */
13370 (void)ipset;
13371 #else
13372 if (ipset->is_ipv6) {
13373 param->v6_policy = SK_IPV6POLICY_FORCE;
13374 param->cb_entry_func = ipsetCountStreamCallbackV6;
13375 return 0;
13376 }
13377 #endif /* SK_ENABLE_IPV6 */
13378 param->v6_policy = SK_IPV6POLICY_ASV4;
13379 param->cb_entry_func = ipsetCountStreamCallbackV4;
13380 return 0;
13381 }
13382
13383
13384 int
skIPSetProcessStreamCountIPs(skstream_t * stream,char * count_buf,size_t count_buf_size)13385 skIPSetProcessStreamCountIPs(
13386 skstream_t *stream,
13387 char *count_buf,
13388 size_t count_buf_size)
13389 {
13390 skipset_procstream_parm_t param;
13391 ipset_count_t count;
13392 int rv;
13393
13394 memset(&count, 0, sizeof(count));
13395
13396 memset(¶m, 0, sizeof(param));
13397 param.visit_cidr = 1;
13398 param.cb_entry_func_ctx = &count;
13399
13400 rv = skIPSetProcessStream(stream, ipsetProcessStreamCountInit,
13401 NULL, ¶m);
13402 if (rv) {
13403 return rv;
13404 }
13405
13406 if (NULL == ipsetCountToString(&count, count_buf, count_buf_size)) {
13407 return SKIPSET_ERR_BADINPUT;
13408 }
13409
13410 return SKIPSET_OK;
13411 }
13412
13413
13414 int
skIPSetRead(skipset_t ** ipset_out,skstream_t * stream)13415 skIPSetRead(
13416 skipset_t **ipset_out,
13417 skstream_t *stream)
13418 {
13419 sk_file_header_t *hdr;
13420 sk_header_entry_t *hentry;
13421 int is_ipv6;
13422 int rv;
13423
13424 if (!stream || !ipset_out) {
13425 return SKIPSET_ERR_BADINPUT;
13426 }
13427 *ipset_out = NULL;
13428
13429 rv = ipsetReadStreamHeader(stream, &hdr, &is_ipv6);
13430 if (rv) {
13431 return rv;
13432 }
13433
13434 /* Go to helper function depending on record version */
13435
13436 if (skHeaderGetRecordVersion(hdr) < IPSET_REC_VERSION_RADIX) {
13437 /* Handle files in IPSET_REC_VERSION_CLASSC format */
13438 if (IPSET_USE_IPTREE) {
13439 return ipsetReadClasscIntoIPTree(ipset_out, stream, hdr);
13440 }
13441 return ipsetReadClasscIntoRadix(ipset_out, stream, hdr);
13442 }
13443 if (skHeaderGetRecordVersion(hdr) == IPSET_REC_VERSION_RADIX) {
13444 hentry = skHeaderGetFirstMatch(hdr, SK_HENTRY_IPSET_ID);
13445 if (NULL == hentry) {
13446 skAbort();
13447 }
13448 /* check for an empty IPset */
13449 if (0 == ipsetHentryGetNodeCount(hentry)
13450 && 0 == ipsetHentryGetLeafCount(hentry))
13451 {
13452 if (!is_ipv6 && IPSET_USE_IPTREE) {
13453 return ipsetCreate(ipset_out, 0, 0);
13454 }
13455 return ipsetCreate(ipset_out, is_ipv6, 1);
13456 }
13457 if (!is_ipv6 && IPSET_USE_IPTREE) {
13458 /* Read IPv4-only file into the IPTree format */
13459 return ipsetReadRadixIntoIPTree(ipset_out, stream, hdr);
13460 }
13461 return ipsetReadRadixIntoRadix(ipset_out, stream, hdr, is_ipv6);
13462 }
13463 if (skHeaderGetRecordVersion(hdr) == IPSET_REC_VERSION_CIDRBMAP) {
13464 #if SK_ENABLE_IPV6
13465 if (is_ipv6) {
13466 return ipsetReadCidrbmapIntoRadixV6(ipset_out, stream, hdr);
13467 }
13468 #endif
13469 if (IPSET_USE_IPTREE) {
13470 /* Read IPv4-only file into the IPTree format */
13471 return ipsetReadCidrbmapIntoIPTree(ipset_out, stream, hdr);
13472 }
13473 return ipsetReadCidrbmapIntoRadixV4(ipset_out, stream, hdr);
13474 }
13475 if (skHeaderGetRecordVersion(hdr) == IPSET_REC_VERSION_SLASH64) {
13476 #if SK_ENABLE_IPV6
13477 if (!is_ipv6) {
13478 skAbort();
13479 }
13480 return ipsetReadSlash64(ipset_out, stream, hdr);
13481 #endif /* SK_ENABLE_IPV6 */
13482 }
13483
13484 skAbort();
13485 }
13486
13487
13488 /* the prototype for this function is in skheader_priv.h */
13489 int
skIPSetRegisterHeaderEntry(sk_hentry_type_id_t entry_id)13490 skIPSetRegisterHeaderEntry(
13491 sk_hentry_type_id_t entry_id)
13492 {
13493 assert(SK_HENTRY_IPSET_ID == entry_id);
13494 return (skHentryTypeRegister(
13495 entry_id, &ipsetHentryPacker, &ipsetHentryUnpacker,
13496 &ipsetHentryCopy, &ipsetHentryFree, &ipsetHentryPrint));
13497 }
13498
13499
13500 int
skIPSetRemoveAddress(skipset_t * ipset,const skipaddr_t * ipaddr,uint32_t prefix)13501 skIPSetRemoveAddress(
13502 skipset_t *ipset,
13503 const skipaddr_t *ipaddr,
13504 uint32_t prefix)
13505 {
13506 ipset_find_t find_state;
13507 uint32_t ipv4;
13508 int rv;
13509
13510 #if SK_ENABLE_IPV6
13511 if (ipset->is_ipv6) {
13512 ipset_ipv6_t ipv6;
13513
13514 if (skipaddrIsV6(ipaddr)) {
13515 /* both set and address are V6 */
13516 IPSET_IPV6_FROM_ADDRV6(&ipv6, ipaddr);
13517 if (128 == prefix) {
13518 /* no-op */
13519 } else if (0 == prefix) {
13520 prefix = 128;
13521 } else if (prefix > 128) {
13522 return SKIPSET_ERR_PREFIX;
13523 } else {
13524 IPSET_IPV6_APPLY_CIDR(&ipv6, prefix);
13525 }
13526 } else {
13527 /* set is V6 and address is V4 */
13528 IPSET_IPV6_FROM_ADDRV4(&ipv6, ipaddr);
13529 if (0 == prefix || 32 == prefix) {
13530 prefix = 128;
13531 } else if (prefix > 32) {
13532 return SKIPSET_ERR_PREFIX;
13533 } else {
13534 prefix += 96;
13535 /* apply mask */
13536 IPSET_IPV6_APPLY_CIDR(&ipv6, prefix);
13537 }
13538 }
13539 rv = ipsetFindV6(ipset, &ipv6, prefix, &find_state);
13540 /* if IP was not found, we can return */
13541 if (SKIPSET_ERR_NOTFOUND == rv
13542 || SKIPSET_ERR_EMPTY == rv
13543 || SKIPSET_ERR_MULTILEAF == rv)
13544 {
13545 return SKIPSET_OK;
13546 }
13547 IPSET_COPY_ON_WRITE(ipset);
13548 rv = ipsetRemoveAddressV6(ipset, &ipv6, prefix, &find_state);
13549 if (rv) {
13550 return rv;
13551 }
13552 IPSET_MAYBE_COMBINE(ipset);
13553 return rv;
13554 }
13555
13556 /* To get here, IPset must be IPv4 */
13557 if (skipaddrIsV6(ipaddr)) {
13558 /* set is V4 and address is V6 */
13559 /* attempt to convert V6 ipaddr to V4 */
13560 if (skipaddrGetAsV4(ipaddr, &ipv4)) {
13561 /* an V6 ipaddr is not going to be in a V4 IPSet */
13562 return SKIPSET_OK;
13563 }
13564 if (0 == prefix || 128 == prefix) {
13565 prefix = 32;
13566 } else if (prefix > 128) {
13567 return SKIPSET_ERR_PREFIX;
13568 } else if (prefix <= 96) {
13569 return SKIPSET_OK;
13570 } else {
13571 prefix -= 96;
13572 /* apply mask */
13573 ipv4 &= ~(UINT32_MAX >> prefix);
13574 }
13575 } else
13576 #endif /* SK_ENABLE_IPV6 */
13577 {
13578 /* both set and address are V4 */
13579 ipv4 = skipaddrGetV4(ipaddr);
13580 if (prefix == 32) {
13581 /* no-op */
13582 } else if (0 == prefix) {
13583 prefix = 32;
13584 } else if (prefix > 32) {
13585 return SKIPSET_ERR_PREFIX;
13586 } else {
13587 /* apply mask */
13588 ipv4 &= ~(UINT32_MAX >> prefix);
13589 }
13590 }
13591
13592 if (ipset->is_iptree) {
13593 return ipsetRemoveAddressIPTree(ipset, ipv4, prefix);
13594 }
13595
13596 rv = ipsetFindV4(ipset, ipv4, prefix, &find_state);
13597 /* if IP was not found, we can return */
13598 if (SKIPSET_ERR_NOTFOUND == rv
13599 || SKIPSET_ERR_EMPTY == rv
13600 || SKIPSET_ERR_MULTILEAF == rv)
13601 {
13602 return SKIPSET_OK;
13603 }
13604 IPSET_COPY_ON_WRITE(ipset);
13605 rv = ipsetRemoveAddressV4(ipset, ipv4, prefix, &find_state);
13606 if (rv) {
13607 return rv;
13608 }
13609 IPSET_MAYBE_COMBINE(ipset);
13610 return rv;
13611 }
13612
13613
13614 int
skIPSetRemoveAll(skipset_t * ipset)13615 skIPSetRemoveAll(
13616 skipset_t *ipset)
13617 {
13618 if (!ipset) {
13619 return SKIPSET_ERR_BADINPUT;
13620 }
13621
13622 if (ipset->is_iptree) {
13623 ipset->is_dirty = 1;
13624 ipsetRemoveAllIPTree(ipset->s.v2);
13625 return SKIPSET_OK;
13626 }
13627
13628 IPSET_COPY_ON_WRITE(ipset);
13629
13630 IPSET_ROOT_INDEX_SET(ipset, 0, 0);
13631
13632 if (ipset->s.v3->nodes.buf) {
13633 memset(ipset->s.v3->nodes.buf, 0, (ipset->s.v3->nodes.entry_capacity
13634 * ipset->s.v3->nodes.entry_size));
13635 ipset->s.v3->nodes.entry_count = 0;
13636 ipset->is_dirty = 0;
13637 }
13638 if (ipset->s.v3->leaves.buf) {
13639 memset(ipset->s.v3->leaves.buf, 0, (ipset->s.v3->leaves.entry_capacity
13640 * ipset->s.v3->leaves.entry_size));
13641 ipset->s.v3->leaves.entry_count = 0;
13642 ipset->is_dirty = 0;
13643 ipset->s.v3->realloc_leaves = 0;
13644 }
13645 return SKIPSET_OK;
13646 }
13647
13648
13649 /* Remove each IP in the IPWildcard from the IPset */
13650 int
skIPSetRemoveIPWildcard(skipset_t * ipset,const skIPWildcard_t * ipwild)13651 skIPSetRemoveIPWildcard(
13652 skipset_t *ipset,
13653 const skIPWildcard_t *ipwild)
13654 {
13655 skIPWildcardIterator_t iter;
13656 skipaddr_t ip;
13657 uint32_t prefix;
13658 int rv = SKIPSET_OK;
13659
13660 /* Remove the netblocks contained in the wildcard */
13661 #if SK_ENABLE_IPV6
13662 if (ipset->is_ipv6 && !skIPWildcardIsV6(ipwild)) {
13663 skIPWildcardIteratorBindV6(&iter, ipwild);
13664 } else
13665 #endif /* SK_ENABLE_IPV6 */
13666 {
13667 skIPWildcardIteratorBind(&iter, ipwild);
13668 }
13669
13670 if (skIPWildcardIteratorNextCidr(&iter, &ip, &prefix)
13671 != SK_ITERATOR_OK)
13672 {
13673 return rv;
13674 }
13675 if (0 == prefix) {
13676 /* wildcard was x.x.x.x or x:x:x:x:x:x:x:x */
13677 if (!skipaddrIsZero(&ip)) {
13678 skAppPrintErr("Wildcard iterator bug: prefix == 0 but IP != 0");
13679 skAbort();
13680 }
13681 return skIPSetRemoveAll(ipset);
13682 }
13683
13684 /* it would be more efficient to inline skIPSetRemoveAddress()
13685 * here; but often there is only one CIDR block in a wildcard */
13686 do {
13687 rv = skIPSetRemoveAddress(ipset, &ip, prefix);
13688 } while (skIPWildcardIteratorNextCidr(&iter, &ip, &prefix)==SK_ITERATOR_OK
13689 && SKIPSET_OK == rv);
13690
13691 return rv;
13692 }
13693
13694
13695 /* Write 'ipset' to 'filename'--a wrapper around skIPSetWrite(). */
13696 int
skIPSetSave(const skipset_t * ipset,const char * filename)13697 skIPSetSave(
13698 const skipset_t *ipset,
13699 const char *filename)
13700 {
13701 skstream_t *stream = NULL;
13702 int rv;
13703
13704 if (filename == NULL || ipset == NULL) {
13705 return SKIPSET_ERR_BADINPUT;
13706 }
13707 if (ipset->is_dirty) {
13708 return SKIPSET_ERR_REQUIRE_CLEAN;
13709 }
13710
13711 if ((rv = skStreamCreate(&stream, SK_IO_WRITE, SK_CONTENT_SILK))
13712 || (rv = skStreamBind(stream, filename))
13713 || (rv = skStreamOpen(stream)))
13714 {
13715 /* skStreamPrintLastErr(stream, rv, &skAppPrintErr); */
13716 rv = SKIPSET_ERR_FILEIO;
13717 goto END;
13718 }
13719
13720 rv = skIPSetWrite(ipset, stream);
13721
13722 END:
13723 skStreamDestroy(&stream);
13724 return rv;
13725 }
13726
13727
13728 /* Convert 'error_code' to a string. */
13729 const char *
skIPSetStrerror(int error_code)13730 skIPSetStrerror(
13731 int error_code)
13732 {
13733 static char errbuf[128];
13734
13735 switch ((skipset_return_t)error_code) {
13736 case SKIPSET_OK:
13737 return "Success";
13738 case SKIPSET_ERR_EMPTY:
13739 return "IPset is empty";
13740 case SKIPSET_ERR_PREFIX:
13741 return "Invalid prefix";
13742 case SKIPSET_ERR_NOTFOUND:
13743 return "Value not found in IPset";
13744 case SKIPSET_ERR_ALLOC:
13745 return "Unable to allocate memory";
13746 case SKIPSET_ERR_BADINPUT:
13747 return "Empty input value";
13748 case SKIPSET_ERR_FILEIO:
13749 return "Error in read/write";
13750 case SKIPSET_ERR_FILETYPE:
13751 return "Input is not an IPset";
13752 case SKIPSET_ERR_FILEHEADER:
13753 return "File header values incompatible with this compile of SiLK";
13754 case SKIPSET_ERR_FILEVERSION:
13755 return "IPset version unsupported by this SiLK release";
13756 case SKIPSET_ERR_OPEN:
13757 return "Error opening file";
13758 case SKIPSET_ERR_IPV6:
13759 return "IPset does not allow IPv6 addresses";
13760 case SKIPSET_ERR_REQUIRE_CLEAN:
13761 return "Function requires a clean IPset";
13762 case SKIPSET_ERR_CORRUPT:
13763 return "IPset state is inconsistent (corrupt file?)";
13764 case SKIPSET_ERR_SUBSET:
13765 return "Part of netblock exists in IPset";
13766 case SKIPSET_ERR_MULTILEAF:
13767 return "Search ended at missing branch";
13768 }
13769
13770 snprintf(errbuf, sizeof(errbuf),
13771 "Unrecognized IPset error code %d", error_code);
13772 return errbuf;
13773 }
13774
13775
13776 /* Turn off IPs of 'result_ipset' that are on in 'ipset'. */
13777 int
skIPSetSubtract(skipset_t * result_ipset,const skipset_t * ipset)13778 skIPSetSubtract(
13779 skipset_t *result_ipset,
13780 const skipset_t *ipset)
13781 {
13782 int rv;
13783
13784 if (!result_ipset) {
13785 return SKIPSET_ERR_BADINPUT;
13786 }
13787 if (!ipset) {
13788 return SKIPSET_OK;
13789 }
13790
13791 if (ipset->is_iptree) {
13792 if (result_ipset->is_iptree) {
13793 /* both are in the SiLK-2 format (IPTree) */
13794 result_ipset->is_dirty = 1;
13795 return ipsetSubtractIPTree(result_ipset->s.v2, ipset->s.v2);
13796 }
13797 /* result_ipset is SiLK-3 and other is SiLK-2. Walk over the
13798 * entries of the SiLK-2 IPset and remove from the SiLK-3
13799 * IPset. */
13800 IPSET_COPY_ON_WRITE(result_ipset);
13801 return skIPSetWalk(ipset, 1, SK_IPV6POLICY_MIX,
13802 &ipsetSubtractCallback, (void*)result_ipset);
13803 }
13804 if (result_ipset->is_iptree) {
13805 /* only the result_ipset is in SiLK-2 format */
13806 return skIPSetWalk(ipset, 1, SK_IPV6POLICY_ASV4,
13807 &ipsetSubtractCallback, (void*)result_ipset);
13808 }
13809
13810 IPSET_COPY_ON_WRITE(result_ipset);
13811
13812 #if SK_ENABLE_IPV6
13813 if (result_ipset->is_ipv6) {
13814 if (ipset->is_ipv6) {
13815 /* both are IPv6 */
13816 rv = ipsetWalkInternalV6(ipset, ipsetSubtractCallbackV6,
13817 (void*)result_ipset);
13818 } else {
13819 rv = skIPSetWalk(ipset, 1, SK_IPV6POLICY_FORCE,
13820 &ipsetSubtractCallback, (void*)result_ipset);
13821 }
13822 } else if (ipset->is_ipv6) {
13823 rv = skIPSetWalk(ipset, 1, SK_IPV6POLICY_ASV4,
13824 &ipsetSubtractCallback, (void*)result_ipset);
13825 } else
13826 #endif
13827 {
13828 /* both are IPv4 */
13829 rv = ipsetWalkInternalV4(ipset, ipsetSubtractCallbackV4,
13830 (void*)result_ipset);
13831 }
13832 if (rv) {
13833 return rv;
13834 }
13835 IPSET_MAYBE_COMBINE(result_ipset);
13836 return rv;
13837 }
13838
13839
13840 /* Turn on IPs of 'result_ipset' that are on in 'ipset'. */
13841 int
skIPSetUnion(skipset_t * result_ipset,const skipset_t * ipset)13842 skIPSetUnion(
13843 skipset_t *result_ipset,
13844 const skipset_t *ipset)
13845 {
13846 int rv;
13847
13848 if (!result_ipset) {
13849 return SKIPSET_ERR_BADINPUT;
13850 }
13851 if (!ipset) {
13852 return SKIPSET_OK;
13853 }
13854
13855 if (ipset->is_iptree) {
13856 if (result_ipset->is_iptree) {
13857 /* both are in the SiLK-2 format (IPTree) */
13858 result_ipset->is_dirty = 1;
13859 return ipsetUnionIPTree(result_ipset->s.v2, ipset->s.v2);
13860 }
13861 /* result_ipset is SiLK-3 and other is SiLK-2. Walk over the
13862 * entries of the SiLK-2 IPset and add to the SiLK-3 IPset. */
13863 IPSET_COPY_ON_WRITE(result_ipset);
13864 return skIPSetWalk(ipset, 1, SK_IPV6POLICY_MIX,
13865 &ipsetUnionCallback, (void*)result_ipset);
13866 }
13867 if (result_ipset->is_iptree) {
13868 /* only the result_ipset is in SiLK-2 format */
13869 #if !SK_ENABLE_IPV6
13870 return ipsetWalkInternalV4(ipset, ipsetUnionCallbackIPTree,
13871 (void*)result_ipset);
13872 #else
13873 if (!skIPSetContainsV6(ipset)) {
13874 if (ipset->is_ipv6) {
13875 return skIPSetWalk(ipset, 1, SK_IPV6POLICY_ASV4,
13876 &ipsetUnionCallback, (void*)result_ipset);
13877 }
13878 return ipsetWalkInternalV4(ipset, ipsetUnionCallbackIPTree,
13879 (void*)result_ipset);
13880 }
13881 if (result_ipset->no_autoconvert) {
13882 return SKIPSET_ERR_IPV6;
13883 }
13884 rv = ipsetConvertIPTreetoV6(result_ipset);
13885 if (rv) {
13886 return rv;
13887 }
13888 #endif /* #else of #if !SK_ENABLE_IPV6 */
13889 }
13890
13891 if (result_ipset->no_autoconvert && !result_ipset->is_ipv6
13892 && skIPSetContainsV6(ipset))
13893 {
13894 return SKIPSET_ERR_IPV6;
13895 }
13896 IPSET_COPY_ON_WRITE(result_ipset);
13897
13898 #if SK_ENABLE_IPV6
13899 if (result_ipset->is_ipv6 || ipset->is_ipv6) {
13900 if (result_ipset->is_ipv6 == ipset->is_ipv6) {
13901 /* both are IPv6 */
13902 rv = ipsetWalkInternalV6(ipset, ipsetUnionCallbackV6,
13903 (void*)result_ipset);
13904 } else {
13905 rv = skIPSetWalk(ipset, 1, SK_IPV6POLICY_FORCE,
13906 &ipsetUnionCallback, (void*)result_ipset);
13907 }
13908 } else
13909 #endif
13910 {
13911 /* both are IPv4 */
13912 rv = ipsetWalkInternalV4(ipset, ipsetUnionCallbackV4,
13913 (void*)result_ipset);
13914 }
13915 if (rv) {
13916 return rv;
13917 }
13918 IPSET_MAYBE_COMBINE(result_ipset);
13919 return rv;
13920 }
13921
13922
13923 /* Invoke the 'callback' function on all IPs in the 'ipset' */
13924 int
skIPSetWalk(const skipset_t * ipset,uint32_t cidr_blocks,sk_ipv6policy_t v6_policy,skipset_walk_fn_t callback,void * cb_data)13925 skIPSetWalk(
13926 const skipset_t *ipset,
13927 uint32_t cidr_blocks,
13928 sk_ipv6policy_t v6_policy,
13929 skipset_walk_fn_t callback,
13930 void *cb_data)
13931 {
13932 ipset_walk_t walk_state;
13933 skipaddr_t ipaddr;
13934 uint32_t prefix;
13935 int rv;
13936
13937 if (!ipset || !callback) {
13938 return SKIPSET_ERR_BADINPUT;
13939 }
13940
13941 if (!ipset->is_iptree && IPSET_ISEMPTY(ipset)) {
13942 return SKIPSET_OK;
13943 }
13944
13945 /* use the iterator if we can */
13946 if (ipset->is_iptree || !ipset->is_dirty) {
13947 skipset_iterator_t iter;
13948
13949 rv = skIPSetIteratorBind(&iter, ipset, cidr_blocks, v6_policy);
13950 while (rv == 0
13951 && (skIPSetIteratorNext(&iter, &ipaddr, &prefix)
13952 == SK_ITERATOR_OK))
13953 {
13954 rv = callback(&ipaddr, prefix, cb_data);
13955 }
13956 return rv;
13957 }
13958
13959 memset(&walk_state, 0, sizeof(ipset_walk_t));
13960 walk_state.cidr_blocks = (uint8_t)(cidr_blocks ? 1 : 0);
13961 walk_state.v6policy = v6_policy;
13962 walk_state.callback = callback;
13963 walk_state.cb_data = cb_data;
13964
13965 #if SK_ENABLE_IPV6
13966 if (ipset->is_ipv6) {
13967 if (v6_policy == SK_IPV6POLICY_IGNORE) {
13968 /* caller wants only IPv4 addresses, and there are none in
13969 * an IPv6 IPset. */
13970 return SKIPSET_OK;
13971 }
13972 return ipsetWalkV6(ipset, &walk_state);
13973 }
13974 if (v6_policy == SK_IPV6POLICY_ONLY) {
13975 /* caller wants only IPv6 addresses, and there are none in an
13976 * IPv4 IPset. */
13977 return SKIPSET_OK;
13978 }
13979 return ipsetWalkV4(ipset, &walk_state);
13980
13981 #else /* #if SK_ENABLE_IPV6 */
13982
13983 if (ipset->is_ipv6) {
13984 /* impossible to have an IPv6 set */
13985 skAbort();
13986 }
13987 if (v6_policy > SK_IPV6POLICY_MIX) {
13988 /* caller wants IPv6 addresses, which are not supported in
13989 * IPv4-only SiLK */
13990 return SKIPSET_OK;
13991 }
13992 return ipsetWalkV4(ipset, &walk_state);
13993
13994 #endif /* #else of #if SK_ENABLE_IPV6 */
13995 }
13996
13997
13998 int
skIPSetWrite(const skipset_t * ipset,skstream_t * stream)13999 skIPSetWrite(
14000 const skipset_t *ipset,
14001 skstream_t *stream)
14002 {
14003 const skipset_options_t *opts;
14004 sk_file_version_t record_version = 0;
14005 sk_file_header_t *hdr;
14006 ssize_t rv;
14007
14008 if (!ipset || !stream) {
14009 return SKIPSET_ERR_BADINPUT;
14010 }
14011
14012 /* do not write an unclean ipset */
14013 if (ipset->is_dirty) {
14014 return SKIPSET_ERR_REQUIRE_CLEAN;
14015 }
14016
14017 opts = ipset->options;
14018
14019 /* Use the version that is explicitly requested. If none
14020 * requested, use DEFAULT_IPV4 for IPv4 IPsets and DEFAULT_IPV6
14021 * for IPv6 IPsets. */
14022 if (NULL == opts
14023 || IPSET_REC_VERSION_DEFAULT == opts->record_version)
14024 {
14025 if (skIPSetContainsV6(ipset)) {
14026 record_version = IPSET_REC_VERSION_DEFAULT_IPV6;
14027 } else {
14028 record_version = IPSET_REC_VERSION_DEFAULT_IPV4;
14029 }
14030 } else if (skIPSetContainsV6(ipset)) {
14031 switch (opts->record_version) {
14032 case IPSET_REC_VERSION_CLASSC:
14033 /* Cannot write an IPv6 IPset into a this format */
14034 return SKIPSET_ERR_IPV6;
14035 case IPSET_REC_VERSION_RADIX:
14036 case IPSET_REC_VERSION_CIDRBMAP:
14037 case IPSET_REC_VERSION_SLASH64:
14038 record_version = opts->record_version;
14039 break;
14040 default:
14041 break;
14042 }
14043 } else {
14044 switch (opts->record_version) {
14045 case IPSET_REC_VERSION_CLASSC:
14046 case IPSET_REC_VERSION_RADIX:
14047 case IPSET_REC_VERSION_CIDRBMAP:
14048 record_version = opts->record_version;
14049 break;
14050 case IPSET_REC_VERSION_SLASH64:
14051 /* this is an IPv6 only format; use the Cidrbmap format
14052 * for IPv4 IPsets */
14053 record_version = IPSET_REC_VERSION_CIDRBMAP;
14054 break;
14055 default:
14056 break;
14057 }
14058 }
14059 if (0 == record_version) {
14060 return SKIPSET_ERR_BADINPUT;
14061 }
14062
14063 /* prep the header */
14064 hdr = skStreamGetSilkHeader(stream);
14065 skHeaderSetByteOrder(hdr, SILK_ENDIAN_NATIVE);
14066 skHeaderSetFileFormat(hdr, FT_IPSET);
14067 skHeaderSetRecordVersion(hdr, record_version);
14068 skHeaderSetRecordLength(hdr, 1);
14069
14070 if (opts) {
14071 if (opts->note_strip) {
14072 skHeaderRemoveAllMatching(hdr, SK_HENTRY_ANNOTATION_ID);
14073 }
14074 if (opts->invocation_strip) {
14075 skHeaderRemoveAllMatching(hdr, SK_HENTRY_INVOCATION_ID);
14076 } else if (opts->argc && opts->argv) {
14077 rv = skHeaderAddInvocation(hdr, 1, opts->argc, opts->argv);
14078 if (rv) {
14079 return SKIPSET_ERR_FILEIO;
14080 }
14081 }
14082 if ((rv = skHeaderSetCompressionMethod(hdr, opts->comp_method))
14083 || (rv = skOptionsNotesAddToStream(stream)))
14084 {
14085 return SKIPSET_ERR_FILEIO;
14086 }
14087 }
14088
14089 if (IPSET_REC_VERSION_CLASSC == record_version) {
14090 return ipsetWriteClassc(ipset, stream);
14091 }
14092 if (IPSET_REC_VERSION_RADIX == record_version) {
14093 return ipsetWriteRadix(ipset, stream);
14094 }
14095 if (IPSET_REC_VERSION_CIDRBMAP == record_version) {
14096 return ipsetWriteCidrbmap(ipset, stream);
14097 }
14098 if (IPSET_REC_VERSION_SLASH64 == record_version) {
14099 #if !SK_ENABLE_IPV6
14100 skAbort();
14101 #else
14102 return ipsetWriteSlash64(ipset, stream);
14103 #endif /* SK_ENABLE_IPV6 */
14104 }
14105
14106 skAbort();
14107 }
14108
14109
14110 /* **** SUPPORT FOR LEGACY IPTREE API BEGINS HERE **** */
14111
14112
14113 #include <silk/iptree.h>
14114
14115
14116 /* FUNCTION DEFINITIONS */
14117
14118 /*
14119 * Helper function for skIPTreeSave() and skIPSetWrite().
14120 *
14121 * Initialize a temporary skipset_t, set its IPTree pointer to the
14122 * 'iptree' parameter, set its skipset_options_t to write a
14123 * IPSET_REC_VERSION_CLASSC IPset, and call skIPSetWrite() to write
14124 * the skIPTree_t.
14125 */
14126 static int
iptreeSaveOrWrite(const skIPTree_t * iptree,const char * filename,skstream_t * stream)14127 iptreeSaveOrWrite(
14128 const skIPTree_t *iptree,
14129 const char *filename,
14130 skstream_t *stream)
14131 {
14132 skipset_t ipset;
14133 skipset_options_t opts;
14134 int rv;
14135
14136 assert(iptree);
14137 assert((filename && !stream) || (stream && !filename));
14138
14139 memset(&ipset, 0, sizeof(ipset));
14140 ipset.s.v2 = (skIPTree_t*)iptree;
14141 ipset.is_iptree = 1;
14142 ipset.no_autoconvert = 1;
14143 ipset.options = &opts;
14144
14145 memset(&opts, 0, sizeof(opts));
14146 opts.record_version = IPSET_REC_VERSION_CLASSC;
14147
14148 if (filename) {
14149 rv = skIPSetSave(&ipset, filename);
14150 } else {
14151 sk_file_header_t *hdr;
14152
14153 hdr = skStreamGetSilkHeader(stream);
14154 if (hdr) {
14155 opts.comp_method = skHeaderGetCompressionMethod(hdr);
14156 }
14157 rv = skIPSetWrite(&ipset, stream);
14158 }
14159
14160 switch (rv) {
14161 case SKIPSET_OK:
14162 break;
14163 case SKIPSET_ERR_FILEIO:
14164 return SKIP_ERR_OPEN;
14165 default:
14166 skAbortBadCase(rv);
14167 }
14168
14169 return SKIP_OK;
14170 }
14171
14172
14173 /* Add addr to ipset */
14174 int
skIPTreeAddAddress(skIPTree_t * ipset,uint32_t addr)14175 skIPTreeAddAddress(
14176 skIPTree_t *ipset,
14177 uint32_t addr)
14178 {
14179 assert(ipset);
14180 if (!ipset) {
14181 return SKIP_ERR_BADINPUT;
14182 }
14183 return (ipsetInsertAddressIPTree(ipset, addr, 32)
14184 ? SKIP_ERR_ALLOC
14185 : SKIP_OK);
14186 }
14187
14188
14189 /* Add the addresses in an IPWildcard to ipset */
14190 int
skIPTreeAddIPWildcard(skIPTree_t * ipset,const skIPWildcard_t * ipwild)14191 skIPTreeAddIPWildcard(
14192 skIPTree_t *ipset,
14193 const skIPWildcard_t *ipwild)
14194 {
14195 assert(ipset);
14196 if (!ipset) {
14197 return SKIP_ERR_BADINPUT;
14198 }
14199 return (ipsetInsertWildcardIPTree(ipset, ipwild)
14200 ? SKIP_ERR_ALLOC
14201 : SKIP_OK);
14202 }
14203
14204
14205 /* Return 1 if the address is present in the ipset */
14206 int
skIPTreeCheckAddress(const skIPTree_t * ipset,uint32_t ipv4)14207 skIPTreeCheckAddress(
14208 const skIPTree_t *ipset,
14209 uint32_t ipv4)
14210 {
14211 assert(ipset);
14212 return IPTREE_CHECK_ADDRESS(ipset, ipv4);
14213 }
14214
14215
14216 /* Return 1 if the two IPsets have any IPs in common */
14217 int
skIPTreeCheckIntersectIPTree(const skIPTree_t * ipset1,const skIPTree_t * ipset2)14218 skIPTreeCheckIntersectIPTree(
14219 const skIPTree_t *ipset1,
14220 const skIPTree_t *ipset2)
14221 {
14222 return ipsetCheckIPSetIPTree(ipset1, ipset2);
14223 }
14224
14225
14226 /* Return 1 if the IPset and IPWildcard have any IPs in common */
14227 int
skIPTreeCheckIntersectIPWildcard(const skIPTree_t * ipset,const skIPWildcard_t * ipwild)14228 skIPTreeCheckIntersectIPWildcard(
14229 const skIPTree_t *ipset,
14230 const skIPWildcard_t *ipwild)
14231 {
14232 return ipsetCheckWildcardIPTree(ipset, ipwild);
14233 }
14234
14235
14236 /* Return 1 if the IPset in 'ipset_path' intersects with 'ipset'.
14237 * Return 0 for no intersect or on error. */
14238 int
skIPTreeCheckIntersectIPTreeFile(const skIPTree_t * ipset,const char * ipset_path,skIPTreeErrors_t * err_code)14239 skIPTreeCheckIntersectIPTreeFile(
14240 const skIPTree_t *ipset,
14241 const char *ipset_path,
14242 skIPTreeErrors_t *err_code)
14243 {
14244 skstream_t *stream = NULL;
14245 sk_file_header_t *hdr;
14246 int swap_flag;
14247 uint32_t tBuffer[1 + IPTREE_WORDS_PER_SLASH24];
14248 ssize_t b;
14249 int i;
14250 int rv;
14251 int intersect = 0;
14252 skIPTreeErrors_t err = SKIP_OK;
14253 skIPNode_t *n;
14254
14255 if (ipset_path == NULL || ipset == NULL) {
14256 err = SKIP_ERR_BADINPUT;
14257 goto END;
14258 }
14259
14260 if ((rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK))
14261 || (rv = skStreamBind(stream, ipset_path))
14262 || (rv = skStreamOpen(stream)))
14263 {
14264 err = SKIP_ERR_OPEN;
14265 goto END;
14266 }
14267
14268 rv = skStreamReadSilkHeader(stream, &hdr);
14269 if (rv) {
14270 err = SKIP_ERR_FILEIO;
14271 goto END;
14272 }
14273
14274 /* Only accept SiLK-2 files */
14275 rv = skStreamCheckSilkHeader(
14276 stream, FT_IPSET, 0, IPSET_REC_VERSION_CLASSC, NULL);
14277 if (rv) {
14278 if (SKSTREAM_ERR_UNSUPPORT_VERSION == rv) {
14279 err = SKIP_ERR_FILEVERSION;
14280 } else {
14281 err = SKIP_ERR_FILETYPE;
14282 }
14283 goto END;
14284 }
14285
14286 swap_flag = !skHeaderIsNativeByteOrder(hdr);
14287
14288 /*
14289 * IPs are stored on disk in blocks of nine 32-bit words which
14290 * represent a /24. The first uint32_t is the base IP of the /24
14291 * (a.b.c.0); the remaining eight uint32_t's have a bit for each
14292 * address in the /24.
14293 */
14294 while ((b = skStreamRead(stream, tBuffer, sizeof(tBuffer)))
14295 == sizeof(tBuffer))
14296 {
14297 if (swap_flag) {
14298 for (i = 0; i < 9; ++i) {
14299 tBuffer[i] = BSWAP32(tBuffer[i]);
14300 }
14301 }
14302
14303 n = ipset->nodes[tBuffer[0] >> 16];
14304 if (NULL == n) {
14305 /* ignore this block */
14306 continue;
14307 }
14308
14309 for (i = 0; i < 8; ++i) {
14310 if (n->addressBlock[i] & tBuffer[i+1]) {
14311 intersect = 1;
14312 goto END;
14313 }
14314 }
14315 }
14316 if (b == -1) {
14317 /* read error */
14318 err = SKIP_ERR_FILEIO;
14319 goto END;
14320 }
14321
14322 END:
14323 skStreamDestroy(&stream);
14324 if (err_code) {
14325 *err_code = err;
14326 }
14327 return intersect;
14328 }
14329
14330
14331 /* Return a count of the number of IPs in tree. */
14332 uint64_t
skIPTreeCountIPs(const skIPTree_t * ipset)14333 skIPTreeCountIPs(
14334 const skIPTree_t *ipset)
14335 {
14336 return ipsetCountIPTree(ipset);
14337 }
14338
14339
14340 /* Allocate an IPset and set contents to empty */
14341 int
skIPTreeCreate(skIPTree_t ** iptree)14342 skIPTreeCreate(
14343 skIPTree_t **iptree)
14344 {
14345 skipset_t *ipset;
14346
14347 if (NULL == iptree) {
14348 return SKIP_ERR_BADINPUT;
14349 }
14350 if (ipsetCreate(&ipset, 0, 0)) {
14351 return SKIP_ERR_ALLOC;
14352 }
14353
14354 /* Steal the IPTree from the IPset and destroy the IPset */
14355 *iptree = ipset->s.v2;
14356 ipset->s.v2 = NULL;
14357 skIPSetDestroy(&ipset);
14358 return SKIP_OK;
14359 }
14360
14361
14362 /* Frees space associated with *ipset. */
14363 void
skIPTreeDelete(skIPTree_t ** ipset)14364 skIPTreeDelete(
14365 skIPTree_t **ipset)
14366 {
14367 if (NULL == ipset || NULL == *ipset) {
14368 return;
14369 }
14370 ipsetDestroyIPTree(*ipset);
14371 *ipset = NULL;
14372 }
14373
14374
14375 /* Turn off bits of 'result_ipset' that are off in 'ipset'. */
14376 void
skIPTreeIntersect(skIPTree_t * result_ipset,const skIPTree_t * ipset)14377 skIPTreeIntersect(
14378 skIPTree_t *result_ipset,
14379 const skIPTree_t *ipset)
14380 {
14381 (void)ipsetIntersectIPTree(result_ipset, ipset);
14382 }
14383
14384
14385 /* Mask the IPs in ipset so only one is set per every (32-mask) bits */
14386 void
skIPTreeMask(skIPTree_t * ipset,uint32_t mask)14387 skIPTreeMask(
14388 skIPTree_t *ipset,
14389 uint32_t mask)
14390 {
14391 (void)ipsetMaskIPTree(ipset, mask);
14392 }
14393
14394
14395 /* Read IPset from filename---a wrapper around skIPTreeRead(). */
14396 int
skIPTreeLoad(skIPTree_t ** iptree,const char * filename)14397 skIPTreeLoad(
14398 skIPTree_t **iptree,
14399 const char *filename)
14400 {
14401 skstream_t *stream = NULL;
14402 int rv;
14403
14404 if (filename == NULL || iptree == NULL) {
14405 return SKIP_ERR_BADINPUT;
14406 }
14407
14408 if ((rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK))
14409 || (rv = skStreamBind(stream, filename))
14410 || (rv = skStreamOpen(stream)))
14411 {
14412 rv = SKIP_ERR_OPEN;
14413 goto END;
14414 }
14415
14416 rv = skIPTreeRead(iptree, stream);
14417
14418 END:
14419 skStreamDestroy(&stream);
14420 return rv;
14421 }
14422
14423
14424 /* Print a textual prepresentation of the IP Tree. */
14425 void
skIPTreePrint(const skIPTree_t * iptree,skstream_t * stream,skipaddr_flags_t ip_format,int as_cidr)14426 skIPTreePrint(
14427 const skIPTree_t *iptree,
14428 skstream_t *stream,
14429 skipaddr_flags_t ip_format,
14430 int as_cidr)
14431 {
14432 skipset_t ipset;
14433
14434 if (NULL == iptree || NULL == stream) {
14435 return;
14436 }
14437 memset(&ipset, 0, sizeof(ipset));
14438 ipset.s.v2 = (skIPTree_t*)iptree;
14439 ipset.is_iptree = 1;
14440 ipset.no_autoconvert = 1;
14441
14442 skIPSetPrint(&ipset, stream, ip_format, as_cidr);
14443 }
14444
14445
14446 /* Allocate 'ipset' and read it from the data stream 'stream'. */
14447 int
skIPTreeRead(skIPTree_t ** iptree,skstream_t * stream)14448 skIPTreeRead(
14449 skIPTree_t **iptree,
14450 skstream_t *stream)
14451 {
14452 skipset_t *ipset;
14453 sk_file_header_t *hdr;
14454 ssize_t rv;
14455
14456 if (stream == NULL || iptree == NULL) {
14457 return SKIP_ERR_BADINPUT;
14458 }
14459 *iptree = NULL;
14460
14461 rv = skStreamReadSilkHeader(stream, &hdr);
14462 if (rv) {
14463 return SKIP_ERR_FILEIO;
14464 }
14465
14466 /* only accept SiLK-2 files */
14467 rv = skStreamCheckSilkHeader(
14468 stream, FT_IPSET, 0, IPSET_REC_VERSION_CLASSC, NULL);
14469 if (rv) {
14470 if (SKSTREAM_ERR_UNSUPPORT_VERSION == rv) {
14471 return SKIP_ERR_FILEVERSION;
14472 }
14473 return SKIP_ERR_FILETYPE;
14474 }
14475 if (skHeaderGetRecordLength(hdr) != 1) {
14476 return SKIPSET_ERR_FILEVERSION;
14477 }
14478
14479 /* Read the stream as a SiLK-3 IPset */
14480 ipset = NULL;
14481 rv = ipsetReadClasscIntoIPTree(&ipset, stream, hdr);
14482 switch (rv) {
14483 case SKIPSET_OK:
14484 break;
14485 case SKIPSET_ERR_ALLOC:
14486 return SKIP_ERR_ALLOC;
14487 case SKIPSET_ERR_FILEIO:
14488 return SKIP_ERR_FILEIO;
14489 default:
14490 skAbortBadCase(rv);
14491 }
14492
14493 /* Steal the IPTree from the IPset and destroy the IPset */
14494 *iptree = ipset->s.v2;
14495 ipset->s.v2 = NULL;
14496 skIPSetDestroy(&ipset);
14497
14498 return SKIP_OK;
14499 }
14500
14501
14502 /* Remove all addresses from an IPset */
14503 int
skIPTreeRemoveAll(skIPTree_t * ipset)14504 skIPTreeRemoveAll(
14505 skIPTree_t *ipset)
14506 {
14507 if (ipset == NULL) {
14508 return SKIP_ERR_BADINPUT;
14509 }
14510 ipsetRemoveAllIPTree(ipset);
14511 return SKIP_OK;
14512 }
14513
14514
14515 /* Write 'ipset' to 'filename'--a wrapper around skIPTreeWrite(). */
14516 int
skIPTreeSave(const skIPTree_t * iptree,const char * filename)14517 skIPTreeSave(
14518 const skIPTree_t *iptree,
14519 const char *filename)
14520 {
14521 if (NULL == iptree || NULL == filename) {
14522 return SKIP_ERR_BADINPUT;
14523 }
14524 return iptreeSaveOrWrite(iptree, filename, NULL);
14525 }
14526
14527
14528 /* Convert 'error_code' to a string. */
14529 const char *
skIPTreeStrError(int error_code)14530 skIPTreeStrError(
14531 int error_code)
14532 {
14533 static char buf[128];
14534
14535 switch ((skIPTreeErrors_t)error_code) {
14536 case SKIP_OK:
14537 return "Success";
14538 case SKIP_ERR_ALLOC:
14539 return "Unable to allocate memory";
14540 case SKIP_ERR_BADINPUT:
14541 return "Empty input value";
14542 case SKIP_ERR_FILEIO:
14543 return "Error in read/write";
14544 case SKIP_ERR_FILETYPE:
14545 return "Input is not an IPset";
14546 case SKIP_ERR_NONEMPTY:
14547 return "Input IPset is not empty";
14548 case SKIP_ERR_OPEN:
14549 return "Error opening file";
14550 case SKIP_ERR_IPV6:
14551 return "IPsets do not support IPv6 addresses";
14552 case SKIP_ERR_FILEVERSION:
14553 return "This application does not support the new IPset file format";
14554 }
14555
14556 snprintf(buf, sizeof(buf), "Unrecognized IPTree error code %d",error_code);
14557 buf[sizeof(buf)-1] = '\0';
14558 return buf;
14559 }
14560
14561
14562 /* Subtract 'ipset' from 'result_ipset' */
14563 void
skIPTreeSubtract(skIPTree_t * result_ipset,const skIPTree_t * ipset)14564 skIPTreeSubtract(
14565 skIPTree_t *result_ipset,
14566 const skIPTree_t *ipset)
14567 {
14568 (void)ipsetSubtractIPTree(result_ipset, ipset);
14569 }
14570
14571
14572 /* Merge 'ipset' into 'result_ipset' */
14573 int
skIPTreeUnion(skIPTree_t * result_ipset,const skIPTree_t * ipset)14574 skIPTreeUnion(
14575 skIPTree_t *result_ipset,
14576 const skIPTree_t *ipset)
14577 {
14578 return (ipsetUnionIPTree(result_ipset, ipset) ? SKIP_ERR_ALLOC : SKIP_OK);
14579 }
14580
14581
14582 /* Write 'ipset' to 'stream'. */
14583 int
skIPTreeWrite(const skIPTree_t * iptree,skstream_t * stream)14584 skIPTreeWrite(
14585 const skIPTree_t *iptree,
14586 skstream_t *stream)
14587 {
14588 if (NULL == iptree || NULL == stream) {
14589 return SKIP_ERR_BADINPUT;
14590 }
14591 return iptreeSaveOrWrite(iptree, NULL, stream);
14592 }
14593
14594
14595 /* Bind iterator to ipset */
14596 static int
iptreeIteratorBind(skipset_iterator_t * iter,const skIPTree_t * iptree,int cidr)14597 iptreeIteratorBind(
14598 skipset_iterator_t *iter,
14599 const skIPTree_t *iptree,
14600 int cidr)
14601 {
14602 skipset_t ipset;
14603
14604 if (iter == NULL || iptree == NULL) {
14605 return SKIP_ERR_BADINPUT;
14606 }
14607
14608 memset(&ipset, 0, sizeof(ipset));
14609 ipset.s.v2 = (skIPTree_t*)iptree;
14610 ipset.is_iptree = 1;
14611 ipset.no_autoconvert = 1;
14612
14613 ASSERT_OK(skIPSetIteratorBind(iter, &ipset, cidr, SK_IPV6POLICY_IGNORE));
14614 return SKIP_OK;
14615 }
14616
14617 int
skIPTreeIteratorBind(skIPTreeIterator_t * iter,const skIPTree_t * iptree)14618 skIPTreeIteratorBind(
14619 skIPTreeIterator_t *iter,
14620 const skIPTree_t *iptree)
14621 {
14622 return iptreeIteratorBind(iter, iptree, 0);
14623 }
14624
14625 int
skIPTreeCIDRBlockIteratorBind(skIPTreeCIDRBlockIterator_t * block_iter,const skIPTree_t * iptree)14626 skIPTreeCIDRBlockIteratorBind(
14627 skIPTreeCIDRBlockIterator_t *block_iter,
14628 const skIPTree_t *iptree)
14629 {
14630 return iptreeIteratorBind(block_iter, iptree, 0);
14631 }
14632
14633
14634 /* Create iterator */
14635 static int
iptreeIteratorCreate(skipset_iterator_t ** out_iter,const skIPTree_t * iptree,int cidr)14636 iptreeIteratorCreate(
14637 skipset_iterator_t **out_iter,
14638 const skIPTree_t *iptree,
14639 int cidr)
14640 {
14641 assert(out_iter);
14642
14643 *out_iter = (skipset_iterator_t*)malloc(sizeof(skipset_iterator_t));
14644 if (*out_iter == NULL) {
14645 return SKIP_ERR_ALLOC;
14646 }
14647 if (iptreeIteratorBind(*out_iter, iptree, cidr)) {
14648 skIPTreeIteratorDestroy(out_iter);
14649 return SKIP_ERR_BADINPUT;
14650 }
14651
14652 return SKIP_OK;
14653 }
14654
14655 int
skIPTreeIteratorCreate(skIPTreeIterator_t ** out_iter,const skIPTree_t * iptree)14656 skIPTreeIteratorCreate(
14657 skIPTreeIterator_t **out_iter,
14658 const skIPTree_t *iptree)
14659 {
14660 return iptreeIteratorCreate(out_iter, iptree, 0);
14661 }
14662
14663 int
skIPTreeCIDRBlockIteratorCreate(skIPTreeCIDRBlockIterator_t ** out_block_iter,const skIPTree_t * iptree)14664 skIPTreeCIDRBlockIteratorCreate(
14665 skIPTreeCIDRBlockIterator_t **out_block_iter,
14666 const skIPTree_t *iptree)
14667 {
14668 return iptreeIteratorCreate(out_block_iter, iptree, 1);
14669 }
14670
14671
14672 /* Destroy iterator */
14673 void
skIPTreeIteratorDestroy(skIPTreeIterator_t ** out_iter)14674 skIPTreeIteratorDestroy(
14675 skIPTreeIterator_t **out_iter)
14676 {
14677 if (*out_iter) {
14678 free(*out_iter);
14679 *out_iter = NULL;
14680 }
14681 }
14682
14683
14684 /* Get next entry in tree */
14685 skIteratorStatus_t
skIPTreeIteratorNext(uint32_t * out_addr,skIPTreeIterator_t * iter)14686 skIPTreeIteratorNext(
14687 uint32_t *out_addr,
14688 skIPTreeIterator_t *iter)
14689 {
14690 skipaddr_t ipaddr;
14691 uint32_t prefix;
14692 skIteratorStatus_t rv;
14693
14694 assert(iter);
14695 assert(iter->is_iptree);
14696 assert(0 == iter->cidr_blocks);
14697
14698 rv = (skIteratorStatus_t)skIPSetIteratorNext(iter, &ipaddr, &prefix);
14699 if (SK_ITERATOR_OK == rv) {
14700 assert(32 == prefix);
14701 *out_addr = skipaddrGetV4(&ipaddr);
14702 }
14703 return rv;
14704 }
14705
14706 skIteratorStatus_t
skIPTreeCIDRBlockIteratorNext(skIPTreeCIDRBlock_t * out_cidr,skIPTreeCIDRBlockIterator_t * iter)14707 skIPTreeCIDRBlockIteratorNext(
14708 skIPTreeCIDRBlock_t *out_cidr,
14709 skIPTreeCIDRBlockIterator_t *iter)
14710 {
14711 skipaddr_t ipaddr;
14712 uint32_t prefix;
14713 skIteratorStatus_t rv;
14714
14715 assert(iter);
14716 assert(iter->is_iptree);
14717 assert(1 == iter->cidr_blocks);
14718
14719 rv = (skIteratorStatus_t)skIPSetIteratorNext(iter, &ipaddr, &prefix);
14720 if (SK_ITERATOR_OK == rv) {
14721 out_cidr->addr = skipaddrGetV4(&ipaddr);
14722 out_cidr->mask = prefix;
14723 }
14724 return rv;
14725 }
14726
14727
14728 /* Reset iterator */
14729 void
skIPTreeIteratorReset(skIPTreeIterator_t * iter)14730 skIPTreeIteratorReset(
14731 skIPTreeIterator_t *iter)
14732 {
14733 skIPSetIteratorReset(iter);
14734 }
14735
14736
14737 /*
14738 ** Local Variables:
14739 ** mode:c
14740 ** indent-tabs-mode:nil
14741 ** c-basic-offset:4
14742 ** End:
14743 */
14744