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(&param, 0, sizeof(param));
13397     param.visit_cidr = 1;
13398     param.cb_entry_func_ctx = &count;
13399 
13400     rv = skIPSetProcessStream(stream, ipsetProcessStreamCountInit,
13401                               NULL, &param);
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