mirror of
https://github.com/bolucat/Archive.git
synced 2025-12-24 13:28:37 +08:00
235 lines
10 KiB
ReStructuredText
235 lines
10 KiB
ReStructuredText
.. _sets:
|
|
|
|
IP sets
|
|
=======
|
|
|
|
The functions in this section allow you to work with sets of IP addresses. IP
|
|
sets work seamlessly with both IPv4 and IPv6 addresses.
|
|
|
|
.. note::
|
|
|
|
Before using any of the IP set functions, you must initialize this library
|
|
using the following function.
|
|
|
|
.. function:: int ipset_init_library(void)
|
|
|
|
Initializes the IP set library. This function **must** be called before any
|
|
other function in the library. It is safe to call this function multiple
|
|
times, and from multiple threads.
|
|
|
|
|
|
Creating and freeing sets
|
|
-------------------------
|
|
|
|
.. type:: struct ip_set
|
|
|
|
A set of IP addresses. The fields of this ``struct`` are opaque; you should
|
|
only use the public library functions to access the contents of the set.
|
|
|
|
There are two ways that you can work with IP sets. The first is that you can
|
|
allocate the space for the :c:type:`ip_set` instance yourself --- for instance,
|
|
directly on the stack. The second is to let the IP set library allocate the
|
|
space for you. Your choice determines which of the following functions you will
|
|
use to create and free your IP sets.
|
|
|
|
.. function:: void ipset_init(struct ip_set \*set)
|
|
struct ip_set \*ipset_new(void)
|
|
|
|
Creates a new IP set. The ``init`` variant should be used if you've
|
|
allocated space for the set yourself. The ``new`` variant should be used if
|
|
you want the library to allocate the space for you. (The ``new`` variant
|
|
never returns ``NULL``; it will abort the program if the allocation fails.)
|
|
In both cases, the set starts off empty.
|
|
|
|
.. function:: void ipset_done(struct ip_set \*set)
|
|
void ipset_free(struct ip_set \*set)
|
|
|
|
Finalizes an IP set. The ``done`` variant must be used if you created the
|
|
set using :c:func:`ipset_init`; the ``free`` variant must be used if you
|
|
created the set using :c:func:`ipset_new`.
|
|
|
|
|
|
Adding and removing elements
|
|
----------------------------
|
|
|
|
We provide a variety of functions for adding and removing addresses from an IP
|
|
set.
|
|
|
|
.. function:: bool ipset_ipv4_add(struct ip_set \*set, struct cork_ipv4 \*ip)
|
|
bool ipset_ipv6_add(struct ip_set \*set, struct cork_ipv6 \*ip)
|
|
bool ipset_ip_add(struct ip_set \*set, struct cork_ip \*ip)
|
|
|
|
Adds a single IP address to *set*. If the IP address was not already in the
|
|
set, we return ``true``; otherwise we return ``false``. (In other words, we
|
|
return whether the set changed as a result of this operation.)
|
|
|
|
.. function:: bool ipset_ipv4_remove(struct ip_set \*set, struct cork_ipv4 \*ip)
|
|
bool ipset_ipv6_remove(struct ip_set \*set, struct cork_ipv6 \*ip)
|
|
bool ipset_ip_remove(struct ip_set \*set, struct cork_ip \*ip)
|
|
|
|
Removes a single IP removeress from *set*. If the IP address was previously
|
|
in the set, we return ``true``; otherwise we return ``false``. (In other
|
|
words, we return whether the set changed as a result of this operation.)
|
|
|
|
.. function:: bool ipset_ipv4_add_network(struct ip_set \*set, struct cork_ipv4 \*ip, unsigned int cidr_prefix)
|
|
bool ipset_ipv6_add_network(struct ip_set \*set, struct cork_ipv6 \*ip, unsigned int cidr_prefix)
|
|
bool ipset_ip_add_network(struct ip_set \*set, struct cork_ip \*ip, unsigned int cidr_prefix)
|
|
|
|
Adds an entire CIDR network of IP addresses to *set*. *ip* is one of the
|
|
addresses in the set; *cidr_prefix* is the number of bits in the network
|
|
portion of each IP address in the CIDR network, as defined in `RFC 4632`_.
|
|
*cidr_prefix* must be in the range 0-32 (inclusive) if *ip* is an IPv4
|
|
address, and in the range 0-128 (inclusive) if it's an IPv6 address.
|
|
|
|
We return whether the set changed as a result of this operation; if we return
|
|
``true``, than at least one of the address in the CIDR network was not
|
|
already present in *set*. We cannot currently distinguish whether *all* of
|
|
the addresses were missing (and therefore added).
|
|
|
|
.. function:: bool ipset_ipv4_remove_network(struct ip_set \*set, struct cork_ipv4 \*ip, unsigned int cidr_prefix)
|
|
bool ipset_ipv6_remove_network(struct ip_set \*set, struct cork_ipv6 \*ip, unsigned int cidr_prefix)
|
|
bool ipset_ip_remove_network(struct ip_set \*set, struct cork_ip \*ip, unsigned int cidr_prefix)
|
|
|
|
Removes an entire CIDR network of IP addresses from *set*. *ip* is one of
|
|
the addresses in the set; *cidr_prefix* is the number of bits in the network
|
|
portion of each IP address in the CIDR network, as defined in `RFC 4632`_.
|
|
*cidr_prefix* must be in the range 0-32 (inclusive) if *ip* is an IPv4
|
|
address, and in the range 0-128 (inclusive) if it's an IPv6 address.
|
|
|
|
We return whether the set changed as a result of this operation; if we return
|
|
``true``, than at least one of the address in the CIDR network was present in
|
|
*set*. We cannot currently distinguish whether *all* of the addresses were
|
|
present (and therefore removed).
|
|
|
|
.. _RFC 4632: http://tools.ietf.org/html/rfc4632
|
|
|
|
.. note::
|
|
|
|
In all of the ``_network`` functions, if you want to strictly adhere to RFC
|
|
4632, *ip* can only have non-zero bits in its *cidr_prefix* uppermost bits.
|
|
All of the lower-order bits (i.e., in the host portion of the IP address)
|
|
must be set to 0. We do not enforce this, however.
|
|
|
|
|
|
Querying a set
|
|
--------------
|
|
|
|
.. function:: bool ipset_contains_ipv4(const struct ip_set \*set, struct cork_ipv4 \*ip)
|
|
bool ipset_contains_ipv6(const struct ip_set \*set, struct cork_ipv6 \*ip)
|
|
bool ipset_contains_ip(const struct ip_set \*set, struct cork_ip \*ip)
|
|
|
|
Returns whether *set* contains *ip*.
|
|
|
|
.. function:: bool ipset_is_empty(const struct ip_set \*set)
|
|
|
|
Returns whether *set* is empty.
|
|
|
|
.. function:: bool ipset_is_equal(const struct ip_set \*set1, const struct ip_set \*set2)
|
|
|
|
Returns whether *set1* and *set2* contain exactly the same addresses.
|
|
|
|
.. function:: size_t ipset_memory_size(const struct ip_set \*set)
|
|
|
|
Returns the number of bytes of memory needed to store *set*. Note that
|
|
adding together the storage needed for each set you use doesn't necessarily
|
|
give you the total memory requirements, since some storage can be shared
|
|
between sets.
|
|
|
|
|
|
Iterating through a set
|
|
-----------------------
|
|
|
|
In addition to querying individual addresses, you can iterate through the entire
|
|
contents of an IP set. There are two iterator functions; one that provides
|
|
every individual IP address, and one that collapses addresses into CIDR networks
|
|
as much as possible, and returns those networks.
|
|
|
|
.. note::
|
|
|
|
You should not modify an IP set while you're actively iterating through its
|
|
contents; if you do this, you'll get undefined behavior.
|
|
|
|
|
|
.. type:: struct ipset_iterator
|
|
|
|
An iterator object that lets you query all of the addresses in an IP set.
|
|
|
|
.. member:: struct cork_ip addr
|
|
|
|
If iterating through individual addresses, this contains the address that
|
|
the iterator currently points at. If iterating through CIDR networks,
|
|
this is the representative address of the current network.
|
|
|
|
.. member:: unsigned int cidr_prefix
|
|
|
|
If iterating through CIDR networks, this is the CIDR prefix of the current
|
|
network. If iterating through individual IP addresses, this will always
|
|
be ``32`` or ``128``, depending on whether *addr* contains an IPv4 or IPv6
|
|
address.
|
|
|
|
.. function:: struct ipset_iterator \*ipset_iterate(struct ip_set \*set, bool desired_value)
|
|
struct ipset_iterator \*ipset_iterate_networks(struct ip_set \*set, bool desired_value)
|
|
|
|
If *desired_value* is ``true``, then we return an iterator that will produce
|
|
the IP addresses that are present in *set*. If it's ``false``, then the
|
|
iterator will produce the IP addresses that are *not* in *set*.
|
|
|
|
The ``_networks`` variant will summarize the IP addresses into CIDR networks,
|
|
to reduce the number of items that are reported by the iterator. (This can
|
|
be especially useful (necessary?) if your set contains any /8 or /16 IPv4
|
|
networks, for instance; or even worse, a /64 IPv6 network.)
|
|
|
|
.. function:: void ipset_iterator_advance(struct ipset_iterator \*iterator)
|
|
|
|
Advance *iterator* to the next IP address or network in its underlying set.
|
|
|
|
.. function:: void ipset_iterator_free(struct ipset_iterator \*iterator)
|
|
|
|
Frees an IP set iterator.
|
|
|
|
|
|
Storing sets in files
|
|
---------------------
|
|
|
|
The functions in this section allow you to store IP sets on disk, and reload
|
|
them into another program at a later time. You don't have to know the details
|
|
of the file format to be able to use these functions; we guarantee that sets
|
|
written with previous versions of the library will be readable by later versions
|
|
of the library (but not vice versa). And we guarantee that the file format is
|
|
platform-independent; sets written on any machine will be readable on any other
|
|
machine.
|
|
|
|
(That said, if you do want to know the details of the file format, that's
|
|
documented in :ref:`another section <file-format>`.)
|
|
|
|
.. function:: int ipset_save(FILE \*stream, const struct ip_set \*set)
|
|
|
|
Saves an IP set into *stream*. You're responsible for opening *stream*
|
|
before calling this function, and for closing *stream* afterwards. If there
|
|
are any errors writing the set, we return ``-1`` and fill in a libcork
|
|
:ref:`error condition <libcork:errors>`.
|
|
|
|
.. function:: int ipset_save_to_stream(struct cork_stream_consumer \*stream, const struct ip_set \*set)
|
|
|
|
Saves an IP set into a libcork :ref:`stream consumer <libcork:stream>`. If
|
|
there are any errors writing the set, we return ``-1`` and fill in a libcork
|
|
:ref:`error condition <libcork:errors>`.
|
|
|
|
.. function:: struct ip_set \*ipset_load(FILE \*stream)
|
|
|
|
Loads an IP set from *stream*. You're responsible for opening *stream*
|
|
before calling this function, and for closing *stream* afterwards. If there
|
|
are any errors reading the set, we return ``NULL`` and fill in a libcork
|
|
:ref:`error condition <libcork:errors>`. You must use :c:func:`ipset_free`
|
|
to free the set when you're done with it.
|
|
|
|
.. function:: int ipset_save_dot(FILE \*stream, const struct ip_set \*set)
|
|
|
|
Produces a GraphViz_ ``dot`` representation of the BDD graph used to store
|
|
*set*, and writes this graph representation to *stream*. You're responsible
|
|
for opening *stream* before calling this function, and for closing *stream*
|
|
afterwards. If there are any errors writing the set, we return ``-1`` and
|
|
fill in a libcork :ref:`error condition <libcork:errors>`.
|
|
|
|
.. _GraphViz: http://www.graphviz.org/
|