/** * Add CIDR IPv4 network to the database. * * @param db the IP range database * @param net the IPv4 network prefix * @param bits the amount of bits in the network prefix * @param value value associated to this IP network (must be non-zero) * * @return IPR_ERR_OK if successful, an error code otherwise. */ iprange_err_t iprange_add_cidr(struct iprange_db *idb, uint32 net, unsigned bits, uint16 value) { struct iprange_net4 item; uint32 mask; iprange_db_check(idb); g_assert(value != 0); g_return_val_if_fail(bits > 0, IPR_ERR_BAD_PREFIX); g_return_val_if_fail(bits <= 32, IPR_ERR_BAD_PREFIX); item.ip = net; item.value = value; item.bits = bits; mask = cidr_to_netmask(bits); if ((item.ip & mask) != item.ip) { return IPR_ERR_BAD_PREFIX; } else { sorted_array_add(idb->tab4, &item); idb->tab4_unsorted = TRUE; return IPR_ERR_OK; } }
/** * Discard IPv4 set from database. */ void iprange_reset_ipv4(struct iprange_db *idb) { iprange_db_check(idb); sorted_array_free(&idb->tab4); idb->tab4 = sorted_array_new(sizeof(struct iprange_net4), iprange_net4_cmp); idb->tab4_unsorted = FALSE; }
/** * Discard IPv6 set from database. */ void iprange_reset_ipv6(struct iprange_db *idb) { iprange_db_check(idb); sorted_array_free(&idb->tab6); idb->tab6 = sorted_array_new(sizeof(struct iprange_net6), iprange_net6_cmp); idb->tab6_unsorted = FALSE; }
/** * Retrieve value associated with an IPv6 address, i.e. that of the range * containing it. * * @param db the IP range database * @param ip6 the IPv6 address to lookup * * @return The data associated with the IP address or 0 if not found. */ uint16 iprange_get6(const struct iprange_db *idb, const uint8 *ip6) { struct iprange_net6 key, *item; iprange_db_check(idb); memcpy(&key.ip[0], ip6, sizeof key.ip); key.bits = 128; item = sorted_array_lookup(idb->tab6, &key); return item != NULL ? item->value : 0; }
/** * Retrieve value associated with an IPv4 address, i.e. that of the range * containing it. * * @param db the IP range database * @param ip the IPv4 address to lookup * * @return The data associated with the IP address or 0 if not found. */ uint16 iprange_get(const struct iprange_db *idb, uint32 ip) { struct iprange_net4 key, *item; iprange_db_check(idb); key.ip = ip; key.bits = 32; item = sorted_array_lookup(idb->tab4, &key); return item != NULL ? item->value : 0; }
/** * Retrieve value associated with an IPv4 address, i.e. that of the range * containing it. * * @param db the IP range database * @param ip the IPv4 address to lookup * @return The data associated with the IPv address or NULL if not found. */ void * iprange_get(const struct iprange_db *idb, guint32 ip) { struct iprange_net key, *item; iprange_db_check(idb); key.ip = ip; key.mask = cidr_to_netmask(32); item = sorted_array_lookup(idb->tab, &key); return item ? item->value : NULL; }
/** * Destroy the database. * * @param db the database */ void iprange_free(struct iprange_db **idb_ptr) { struct iprange_db *idb; idb = *idb_ptr; if (idb) { iprange_db_check(idb); sorted_array_free(&idb->tab); WFREE(idb); *idb_ptr = NULL; } }
/** * This function must be called after iprange_add_cidr() to make the * changes effective. As this function is costly, it should not be * called each time but rather after the complete list of addresses * has been added to the database. * * @param db the IP range database */ void iprange_sync(struct iprange_db *idb) { iprange_db_check(idb); if (idb->tab4_unsorted) { sorted_array_sync(idb->tab4, iprange_net4_collision); idb->tab4_unsorted = FALSE; } if (idb->tab6_unsorted) { sorted_array_sync(idb->tab6, iprange_net6_collision); idb->tab6_unsorted = FALSE; } }
/** * Add CIDR IPv6 network to the database. * * @param db the IP range database * @param net the IPv6 network prefix * @param bits the amount of bits in the network prefix * @param value value associated to this IP network (must be non-zero) * * @return IPR_ERR_OK if successful, an error code otherwise. */ iprange_err_t iprange_add_cidr6(struct iprange_db *idb, const uint8 *net, unsigned bits, uint16 value) { struct iprange_net6 item; unsigned i, trailing, bytes, n; iprange_db_check(idb); g_assert(value != 0); g_return_val_if_fail(bits > 0, IPR_ERR_BAD_PREFIX); g_return_val_if_fail(bits <= 128, IPR_ERR_BAD_PREFIX); memcpy(&item.ip[0], net, sizeof item.ip); item.value = value; item.bits = bits; /* * Check that the trailing bits are all zero before inserting. */ trailing = 128 - bits; bytes = trailing / 8; n = trailing - 8 * bytes; /* Trailing bits in first zero byte */ if (n != 0) { uint8 mask = ~(~0U << n); if (0 != (net[(bits - 1) / 8] & mask)) return IPR_ERR_BAD_PREFIX; } for (i = 15; bytes > 0; i--, bytes--) { if (net[i] != 0) return IPR_ERR_BAD_PREFIX; } sorted_array_add(idb->tab6, &item); idb->tab6_unsorted = TRUE; return IPR_ERR_OK; }
/** * Add CIDR network to the database. * * @param db the IP range database * @param net the network prefix * @param bits the amount of bits in the network prefix * @param value value associated to this IP network * * @return IPR_ERR_OK if successful, an error code otherwise. */ iprange_err_t iprange_add_cidr(struct iprange_db *idb, guint32 net, guint bits, void *value) { struct iprange_net item; iprange_db_check(idb); g_return_val_if_fail(bits > 0, IPR_ERR_BAD_PREFIX); g_return_val_if_fail(bits <= 32, IPR_ERR_BAD_PREFIX); item.ip = net; item.mask = cidr_to_netmask(bits); item.value = value; if ((item.ip & item.mask) != item.ip) { return IPR_ERR_BAD_PREFIX; } else { sorted_array_add(idb->tab, &item); return IPR_ERR_OK; } }
/** * Get the number of IPv6 ranges in the database. * * @param db the IP range database * * @return The total number of IPv6 items. */ unsigned iprange_get_item_count6(const struct iprange_db *idb) { iprange_db_check(idb); return sorted_array_size(idb->tab6); }
/** * Get the number of ranges in the database. * * @param db the IP range database * @return The number of items. */ guint iprange_get_item_count(const struct iprange_db *idb) { iprange_db_check(idb); return sorted_array_size(idb->tab); }
/** * This function must be called after iprange_add_cidr() to make the * changes effective. As this function is costly, it should not be * called each time but rather after the complete list of addresses * has been added to the database. * * @param db the IP range database */ void iprange_sync(struct iprange_db *idb) { iprange_db_check(idb); sorted_array_sync(idb->tab, iprange_net_collision); }