IP maps

The functions in this section allow you to work with IP maps, which map IP addresses to integer values. IP maps work seamlessly with both IPv4 and IPv6 addresses. Every IP address is mapped to some value; each IP map has a default value that will be used for any addresses that aren’t explicitly mapped to something else. (This is the map equivalent of an address not appearing in a set; “removing” an address from a map is the same as setting it to the map’s default value.)

Note

With this definition of a map, an IP set is just an IP map that is restricted to the values 0 and 1. This is actually how sets are implemented internally.

Note

Before using any of the IP map functions, you must initialize this library using ipset_init_library().

Creating and freeing maps

struct ip_map

Maps IP addresses to integer values. The fields of this struct are opaque; you should only use the public library functions to access the contents of the map.

There are two ways that you can work with IP maps. The first is that you can allocate the space for the ip_map instance yourself — for instance, directly on the stack. The second is to let the IP map library allocate the space for you. Your choice determines which of the following functions you will use to create and free your IP maps.

void ipmap_init(struct ip_map \*map, int default_value)
struct ip_map \*ipmap_new(int default_value)

Creates a new IP map. The map will use default_value as the default value for any addresses that aren’t explicitly mapped to something else.

The init variant should be used if you’ve allocated space for the map 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 map starts off empty.

void ipmap_done(struct ip_map \*map)
void ipmap_free(struct ip_map \*map)

Finalizes an IP map. The done variant must be used if you created the map using ipmap_init(); the free variant must be used if you created the map using ipmap_new().

Adding and removing elements

We provide a variety of functions for adding and removing addresses from an IP map.

void ipmap_ipv4_set(struct ip_map \*map, struct cork_ipv4 \*ip, int value)
void ipmap_ipv6_set(struct ip_map \*map, struct cork_ipv6 \*ip, int value)
void ipmap_ip_set(struct ip_map \*map, struct cork_ip \*ip, int value)

Updates map so that ip is mapped to value.

void ipmap_ipv4_set_network(struct ip_map \*map, struct cork_ipv4 \*ip, unsigned int cidr_prefix, int value)
void ipmap_ipv6_set_network(struct ip_map \*map, struct cork_ipv6 \*ip, unsigned int cidr_prefix, int value)
void ipmap_ip_set_network(struct ip_map \*map, struct cork_ip \*ip, unsigned int cidr_prefix, int value)

Updates map so that all of the addresses in a CIDR network are mapped to value. ip is one of the addresses in the CIDR network; 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.

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 map to 0. We do not enforce this, however.

Querying a map

int ipmap_get_ipv4(const struct ip_map \*map, struct cork_ipv4 \*ip)
int ipmap_get_ipv6(const struct ip_map \*map, struct cork_ipv6 \*ip)
int ipmap_get_ip(const struct ip_map \*map, struct cork_ip \*ip)

Returns the value that ip is mapped to in map.

bool ipmap_is_empty(const struct ip_map \*map)

Returns whether map is empty. A map is considered empty is every IP address is mapped to the default value.

bool ipmap_is_equal(const struct ip_map \*map1, const struct ip_map \*map2)

Returns whether every IP address is mapped to the same value in map1 and map2.

size_t ipmap_memory_size(const struct ip_map \*map)

Returns the number of bytes of memory needed to store map. Note that adding together the storage needed for each map you use doesn’t necessarily give you the total memory requirements, since some storage can be shared between maps.

Storing maps in files

The functions in this section allow you to store IP maps 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 maps 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; maps 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 another section.)

int ipmap_save(FILE \*stream, const struct ip_map \*map)

Saves an IP map into stream. You’re responsible for opening stream before calling this function, and for closing stream afterwards. If there are any errors writing the map, we return -1 and fill in a libcork error condition.

int ipmap_save_to_stream(struct cork_stream_consumer \*stream, const struct ip_map \*map)

Saves an IP map into a libcork stream consumer. If there are any errors writing the map, we return -1 and fill in a libcork error condition.

struct ip_map \*ipmap_load(FILE \*stream)

Loads an IP map from stream. You’re responsible for opening stream before calling this function, and for closing stream afterwards. If there are any errors reading the map, we return NULL and fill in a libcork error condition. You must use ipmap_free() to free the map when you’re done with it.