You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
3.4 KiB
130 lines
3.4 KiB
/* -*- coding: utf-8 -*-
|
|
* ----------------------------------------------------------------------
|
|
* Copyright © 2012, RedJack, LLC.
|
|
* All rights reserved.
|
|
*
|
|
* Please see the LICENSE.txt file in this distribution for license
|
|
* details.
|
|
* ----------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <libcork/core.h>
|
|
|
|
#include "ipset/bdd/nodes.h"
|
|
#include "ipset/bits.h"
|
|
#include "ipset/errors.h"
|
|
#include "ipset/ipset.h"
|
|
|
|
|
|
/**
|
|
* Given a BDD variable number, return the index of the corresponding
|
|
* bit in an IP address. IPv4 addresses use variables 1-32; IPv6
|
|
* addresses use 1-128. (Variable 0 is used to identify the kind of
|
|
* address — TRUE for IPv4, FALSE for IPv6.)
|
|
*/
|
|
|
|
static unsigned int
|
|
IPSET_NAME(bit_for_var)(ipset_variable var)
|
|
{
|
|
return (var - 1);
|
|
}
|
|
|
|
|
|
/**
|
|
* An assignment function that can be used to evaluate an IP set BDD.
|
|
*/
|
|
|
|
static bool
|
|
IPSET_NAME(assignment)(const void *addr, ipset_variable var)
|
|
{
|
|
if (var == 0) {
|
|
return IP_DISCRIMINATOR_VALUE;
|
|
} else {
|
|
unsigned int bit = IPSET_NAME(bit_for_var)(var);
|
|
return IPSET_BIT_GET(addr, bit);
|
|
}
|
|
}
|
|
|
|
|
|
bool
|
|
IPSET_PRENAME(contains)(const struct ip_set *set, CORK_IP *elem)
|
|
{
|
|
return ipset_node_evaluate
|
|
(set->cache, set->set_bdd, IPSET_NAME(assignment), elem);
|
|
}
|
|
|
|
|
|
bool
|
|
IPSET_NAME(add_network)(struct ip_set *set, CORK_IP *elem,
|
|
unsigned int cidr_prefix)
|
|
{
|
|
/* Special case — the BDD for a netmask that's out of range never
|
|
* evaluates to true. */
|
|
if (cidr_prefix > IP_BIT_SIZE) {
|
|
cork_error_set
|
|
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
|
"CIDR block %u out of range [0..%u]", cidr_prefix, IP_BIT_SIZE);
|
|
return false;
|
|
}
|
|
|
|
ipset_node_id new_bdd =
|
|
ipset_node_insert
|
|
(set->cache, set->set_bdd,
|
|
IPSET_NAME(assignment), elem, cidr_prefix + 1, 1);
|
|
bool result = (new_bdd == set->set_bdd);
|
|
ipset_node_decref(set->cache, set->set_bdd);
|
|
set->set_bdd = new_bdd;
|
|
return result;
|
|
}
|
|
|
|
|
|
bool
|
|
IPSET_NAME(add)(struct ip_set *set, CORK_IP *elem)
|
|
{
|
|
ipset_node_id new_bdd =
|
|
ipset_node_insert
|
|
(set->cache, set->set_bdd,
|
|
IPSET_NAME(assignment), elem, IP_BIT_SIZE + 1, 1);
|
|
bool result = (new_bdd == set->set_bdd);
|
|
ipset_node_decref(set->cache, set->set_bdd);
|
|
set->set_bdd = new_bdd;
|
|
return result;
|
|
}
|
|
|
|
|
|
bool
|
|
IPSET_NAME(remove)(struct ip_set *set, CORK_IP *elem)
|
|
{
|
|
ipset_node_id new_bdd =
|
|
ipset_node_insert
|
|
(set->cache, set->set_bdd,
|
|
IPSET_NAME(assignment), elem, IP_BIT_SIZE + 1, 0);
|
|
bool result = (new_bdd == set->set_bdd);
|
|
ipset_node_decref(set->cache, set->set_bdd);
|
|
set->set_bdd = new_bdd;
|
|
return result;
|
|
}
|
|
|
|
|
|
bool
|
|
IPSET_NAME(remove_network)(struct ip_set *set, CORK_IP *elem,
|
|
unsigned int cidr_prefix)
|
|
{
|
|
/* Special case — the BDD for a netmask that's out of range never
|
|
* evaluates to true. */
|
|
if (cidr_prefix > IP_BIT_SIZE) {
|
|
cork_error_set
|
|
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
|
"CIDR block %u out of range [0..%u]", cidr_prefix, IP_BIT_SIZE);
|
|
return false;
|
|
}
|
|
|
|
ipset_node_id new_bdd =
|
|
ipset_node_insert
|
|
(set->cache, set->set_bdd,
|
|
IPSET_NAME(assignment), elem, cidr_prefix + 1, 0);
|
|
bool result = (new_bdd == set->set_bdd);
|
|
ipset_node_decref(set->cache, set->set_bdd);
|
|
set->set_bdd = new_bdd;
|
|
return result;
|
|
}
|