1/* -*- coding: utf-8 -*- 2 * ---------------------------------------------------------------------- 3 * Copyright © 2012, RedJack, LLC. 4 * All rights reserved. 5 * 6 * Please see the LICENSE.txt file in this distribution for license 7 * details. 8 * ---------------------------------------------------------------------- 9 */ 10 11#include <libcork/core.h> 12 13#include "ipset/bdd/nodes.h" 14#include "ipset/bits.h" 15#include "ipset/errors.h" 16#include "ipset/ipset.h" 17 18 19/** 20 * Given a BDD variable number, return the index of the corresponding 21 * bit in an IP address. IPv4 addresses use variables 1-32; IPv6 22 * addresses use 1-128. (Variable 0 is used to identify the kind of 23 * address — TRUE for IPv4, FALSE for IPv6.) 24 */ 25 26static unsigned int 27IPSET_NAME(bit_for_var)(ipset_variable var) 28{ 29 return (var - 1); 30} 31 32 33/** 34 * An assignment function that can be used to evaluate an IP set BDD. 35 */ 36 37static bool 38IPSET_NAME(assignment)(const void *addr, ipset_variable var) 39{ 40 if (var == 0) { 41 return IP_DISCRIMINATOR_VALUE; 42 } else { 43 unsigned int bit = IPSET_NAME(bit_for_var)(var); 44 return IPSET_BIT_GET(addr, bit); 45 } 46} 47 48 49bool 50IPSET_PRENAME(contains)(const struct ip_set *set, CORK_IP *elem) 51{ 52 return ipset_node_evaluate 53 (set->cache, set->set_bdd, IPSET_NAME(assignment), elem); 54} 55 56 57bool 58IPSET_NAME(add_network)(struct ip_set *set, CORK_IP *elem, 59 unsigned int cidr_prefix) 60{ 61 /* Special case — the BDD for a netmask that's out of range never 62 * evaluates to true. */ 63 if (cidr_prefix > IP_BIT_SIZE) { 64 cork_error_set 65 (IPSET_ERROR, IPSET_PARSE_ERROR, 66 "CIDR block %u out of range [0..%u]", cidr_prefix, IP_BIT_SIZE); 67 return false; 68 } 69 70 ipset_node_id new_bdd = 71 ipset_node_insert 72 (set->cache, set->set_bdd, 73 IPSET_NAME(assignment), elem, cidr_prefix + 1, 1); 74 bool result = (new_bdd == set->set_bdd); 75 ipset_node_decref(set->cache, set->set_bdd); 76 set->set_bdd = new_bdd; 77 return result; 78} 79 80 81bool 82IPSET_NAME(add)(struct ip_set *set, CORK_IP *elem) 83{ 84 ipset_node_id new_bdd = 85 ipset_node_insert 86 (set->cache, set->set_bdd, 87 IPSET_NAME(assignment), elem, IP_BIT_SIZE + 1, 1); 88 bool result = (new_bdd == set->set_bdd); 89 ipset_node_decref(set->cache, set->set_bdd); 90 set->set_bdd = new_bdd; 91 return result; 92} 93 94 95bool 96IPSET_NAME(remove)(struct ip_set *set, CORK_IP *elem) 97{ 98 ipset_node_id new_bdd = 99 ipset_node_insert 100 (set->cache, set->set_bdd, 101 IPSET_NAME(assignment), elem, IP_BIT_SIZE + 1, 0); 102 bool result = (new_bdd == set->set_bdd); 103 ipset_node_decref(set->cache, set->set_bdd); 104 set->set_bdd = new_bdd; 105 return result; 106} 107 108 109bool 110IPSET_NAME(remove_network)(struct ip_set *set, CORK_IP *elem, 111 unsigned int cidr_prefix) 112{ 113 /* Special case — the BDD for a netmask that's out of range never 114 * evaluates to true. */ 115 if (cidr_prefix > IP_BIT_SIZE) { 116 cork_error_set 117 (IPSET_ERROR, IPSET_PARSE_ERROR, 118 "CIDR block %u out of range [0..%u]", cidr_prefix, IP_BIT_SIZE); 119 return false; 120 } 121 122 ipset_node_id new_bdd = 123 ipset_node_insert 124 (set->cache, set->set_bdd, 125 IPSET_NAME(assignment), elem, cidr_prefix + 1, 0); 126 bool result = (new_bdd == set->set_bdd); 127 ipset_node_decref(set->cache, set->set_bdd); 128 set->set_bdd = new_bdd; 129 return result; 130} 131