]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
acl list setup. 8 to tab in net_help.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 16 Nov 2007 16:25:37 +0000 (16:25 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 16 Nov 2007 16:25:37 +0000 (16:25 +0000)
git-svn-id: file:///svn/unbound/trunk@753 be551aaa-1e26-0410-a405-d3ace91eadb9

12 files changed:
Makefile.in
checkconf/worker_cb.c
daemon/acl_list.c [new file with mode: 0644]
daemon/acl_list.h [new file with mode: 0644]
doc/Changelog
iterator/iter_donotq.c
iterator/iter_donotq.h
util/config_file.c
util/config_file.h
util/fptr_wlist.c
util/net_help.c
util/net_help.h

index c44640c5c0751a7ad473afcd89e6ae64ce6a1622..42c87f4e84e0d4aebcee426053fcacae2ef48f30 100644 (file)
@@ -71,8 +71,8 @@ DAEMON_OBJ=$(addprefix $(BUILD),$(DAEMON_SRC:.c=.o)) $(COMPAT_OBJ)
 CHECKCONF_SRC=checkconf/unbound-checkconf.c checkconf/worker_cb.c $(COMMON_SRC)
 CHECKCONF_OBJ=$(addprefix $(BUILD),$(CHECKCONF_SRC:.c=.o)) $(COMPAT_OBJ)
 TESTBOUND_SRC=testcode/testbound.c testcode/ldns-testpkts.c \
-       daemon/worker.c daemon/daemon.c daemon/stats.c testcode/replay.c \
-       testcode/fake_event.c $(filter-out util/netevent.c \
+       daemon/worker.c daemon/acl_list.c daemon/daemon.c daemon/stats.c \
+       testcode/replay.c testcode/fake_event.c $(filter-out util/netevent.c \
        services/listen_dnsport.c services/outside_network.c, $(COMMON_SRC))
 TESTBOUND_OBJ=$(addprefix $(BUILD),$(TESTBOUND_SRC:.c=.o)) $(COMPAT_OBJ)
 LOCKVERIFY_SRC=testcode/lock_verify.c checkconf/worker_cb.c $(COMMON_SRC)
index 7f14450172179a09fa41f3e38e8d6d06a1fa1e18..fb7dbd091becebfb1ee32818b5d3dbdb4707bb4a 100644 (file)
@@ -107,3 +107,10 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
 {
        log_assert(0);
 }
+
+int
+acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
+{
+       log_assert(0);
+       return 0;
+}
diff --git a/daemon/acl_list.c b/daemon/acl_list.c
new file mode 100644 (file)
index 0000000..82b5795
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * daemon/acl_list.h - client access control storage for the server.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file helps the server keep out queries from outside sources, that
+ * should not be answered.
+ */
+#include "config.h"
+#include "daemon/acl_list.h"
+#include "util/regional.h"
+#include "util/log.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+
+int
+acl_list_cmp(const void* k1, const void* k2)
+{
+       struct acl_addr* n1 = (struct acl_addr*)k1;
+       struct acl_addr* n2 = (struct acl_addr*)k2;
+       int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr, 
+               n2->addrlen);
+       if(r != 0) return r;
+       if(n1->net < n2->net)
+               return -1;
+       if(n1->net > n2->net)
+               return 1;
+       return 0;
+}
+
+struct acl_list* 
+acl_list_create()
+{
+       struct acl_list* acl = (struct acl_list*)calloc(1,
+               sizeof(struct acl_list));
+       if(!acl)
+               return NULL;
+       acl->region = regional_create();
+       if(!acl->region) {
+               acl_list_delete(acl);
+               return NULL;
+       }
+       return acl;
+}
+
+void 
+acl_list_delete(struct acl_list* acl)
+{
+       if(!acl) 
+               return;
+       regional_destroy(acl->region);
+       free(acl->tree);
+       free(acl);
+}
+
+/** insert new address into acl_list structure */
+static int
+acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr, 
+       socklen_t addrlen, int net, enum acl_access control, 
+       int complain_duplicates)
+{
+       struct acl_addr* node = regional_alloc(acl->region,
+               sizeof(struct acl_addr));
+       if(!node)
+               return 0;
+       node->node.key = node;
+       memcpy(&node->addr, addr, addrlen);
+       node->addrlen = addrlen;
+       node->net = net;
+       node->parent = NULL;
+       node->control = control;
+       if(!rbtree_insert(acl->tree, &node->node)) {
+               if(complain_duplicates)
+                       verbose(VERB_DETAIL, "duplicate acl address ignored.");
+       }
+       return 1;
+}
+
+/** apply acl_list string */
+static int
+acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
+       int complain_duplicates)
+{
+       struct sockaddr_storage addr;
+       int net;
+       char* s = NULL;
+       socklen_t addrlen;
+       enum acl_access control;
+       if(strcmp(s2, "allow") == 0)
+               control = acl_allow;
+       else if(strcmp(s2, "deny") == 0)
+               control = acl_deny;
+       else if(strcmp(s2, "refuse") == 0)
+               control = acl_refuse;
+       else {
+               log_err("access control type %s unknown", str);
+               return 0;
+       }
+       net = (str_is_ip6(str)?128:32);
+       if((s=strchr(str, '/'))) {
+               if(atoi(s+1) > net) {
+                       log_err("acl netblock too large: %s", str);
+                       return 0;
+               }
+               net = atoi(s+1);
+               if(net == 0 && strcmp(s+1, "0") != 0) {
+                       log_err("cannot parse acl netblock:"
+                               " '%s'", str);
+                       return 0;
+               }
+               if(!(s = strdup(str))) {
+                       log_err("out of memory");
+                       return 0;
+               }
+               *strchr(s, '/') = '\0';
+       }
+       if(!ipstrtoaddr(s?s:str, UNBOUND_DNS_PORT, &addr, &addrlen)) {
+               free(s);
+               log_err("cannot parse acl ip address: '%s'", str);
+               return 0;
+       }
+       if(s) {
+               free(s);
+               addr_mask(&addr, addrlen, net);
+       }
+       if(!acl_list_insert(acl, &addr, addrlen, net, control, 
+               complain_duplicates)) {
+               log_err("out of memory");
+               return 0;
+       }
+       return 1;
+}
+
+/** read acl_list config */
+static int 
+read_acl_list(struct acl_list* acl, struct config_file* cfg)
+{
+       struct config_acl* p;
+       for(p = cfg->acls; p; p = p->next) {
+               log_assert(p->address && p->control);
+               if(!acl_list_str_cfg(acl, p->address, p->control, 1))
+                       return 0;
+       }
+       return 1;
+}
+
+/** initialise parent pointers in the tree */
+static void
+acl_list_init_parents(struct acl_list* acl)
+{
+       struct acl_addr* node, *prev = NULL, *p;
+       int m;
+       RBTREE_FOR(node, struct acl_addr*, acl->tree) {
+               node->parent = NULL;
+               if(!prev || prev->addrlen != node->addrlen) {
+                       prev = node;
+                       continue;
+               }
+               m = addr_in_common(&prev->addr, prev->net, &node->addr, 
+                       node->net, node->addrlen);
+               /* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */
+               /* find the previous, or parent-parent-parent */
+               for(p = prev; p; p = p->parent)
+                       if(p->net <= m) {
+                               /* ==: since prev matched m, this is closest*/
+                               /* <: prev matches more, but is not a parent,
+                               * this one is a (grand)parent */
+                               node->parent = p;
+                               break;
+                       }
+               prev = node;
+       }
+}
+
+int 
+acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg)
+{
+       regional_free_all(acl->region);
+       free(acl->tree);
+       acl->tree = rbtree_create(acl_list_cmp);
+       if(!acl->tree)
+               return 0;
+       if(!read_acl_list(acl, cfg))
+               return 0;
+       /* insert defaults, with '0' to ignore them if they are duplicates */
+       if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0))
+               return 0;
+       if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0))
+               return 0;
+       if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
+               return 0;
+       if(!acl_list_str_cfg(acl, "::1", "allow", 0))
+               return 0;
+       acl_list_init_parents(acl);
+       return 1;
+}
+
+enum acl_access 
+acl_list_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
+        socklen_t addrlen)
+{
+       /* lookup in the tree */
+       rbnode_t* res = NULL;
+       struct acl_addr* result;
+       struct acl_addr key;
+       key.node.key = &key;
+       memcpy(&key.addr, addr, addrlen);
+       key.addrlen = addrlen;
+       key.net = (addr_is_ip6(addr, addrlen)?128:32);
+       if(rbtree_find_less_equal(acl->tree, &key, &res)) {
+               /* exact */
+               result = (struct acl_addr*)res;
+               return result->control;
+       } else {
+               /* smaller element (or no element) */
+               int m;
+               result = (struct acl_addr*)res;
+               if(!result || result->addrlen != addrlen)
+                       return acl_deny;
+               /* count number of bits matched */
+               m = addr_in_common(&result->addr, result->net, addr, 
+                       key.net, addrlen);
+               while(result) { /* go up until addr is inside netblock */
+                       if(result->net <= m)
+                               return result->control;
+                       result = result->parent;
+               }
+       }
+       return acl_deny;
+}
+
+size_t 
+acl_list_get_mem(struct acl_list* acl)
+{
+       if(!acl) return 0;
+       return sizeof(*acl) + regional_get_mem(acl->region);
+}
diff --git a/daemon/acl_list.h b/daemon/acl_list.h
new file mode 100644 (file)
index 0000000..1edf899
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * daemon/acl_list.h - client access control storage for the server.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file keeps track of the list of clients that are allowed to 
+ * access the server.
+ */
+
+#ifndef DAEMON_ACL_LIST_H
+#define DAEMON_ACL_LIST_H
+#include "util/rbtree.h"
+struct config_file;
+struct regional;
+
+/**
+ * Enumeration of access control options for an address range.
+ * Allow or deny access.
+ */
+enum acl_access {
+       /** disallow any access whatsoever, drop it */
+       acl_deny = 0,
+       /** disallow access, send a polite 'REFUSED' reply */
+       acl_refuse,
+       /** allow full access */
+       acl_allow
+};
+
+/**
+ * Access control storage structure
+ */
+struct acl_list {
+       /** regional for allocation */
+       struct regional* region;
+       /** 
+        * Tree of the addresses that are allowed/blocked.
+        * contents of type acl_addr.
+        */
+       rbtree_t* tree;
+};
+
+/**
+ *
+ * An address span with access control information
+ */
+struct acl_addr {
+       /** redblacktree node, key is this structure: addr and addrlen, net */
+       rbnode_t node;
+       /** address */
+       struct sockaddr_storage addr;
+       /** length of addr */
+       socklen_t addrlen;
+       /** netblock size */
+       int net;
+       /** parent node in acl tree that encompasses this entry */
+       struct acl_addr* parent;
+       /** access control on this netblock */
+       enum acl_access control;
+};
+
+/**
+ * Create acl structure 
+ * @return new structure or NULL on error.
+ */
+struct acl_list* acl_list_create();
+
+/**
+ * Delete acl structure.
+ * @param acl: to delete.
+ */
+void acl_list_delete(struct acl_list* acl);
+
+/**
+ * Process access control config.
+ * @param acl: where to store.
+ * @param cfg: config options.
+ * @return 0 on error.
+ */
+int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg);
+
+/**
+ * Lookup address to see its access control status.
+ * @param acl: structure for address storage.
+ * @param addr: address to check
+ * @param addrlen: length of addr.
+ * @return: what to do with message from this address.
+ */
+enum acl_access acl_list_lookup(struct acl_list* acl, 
+       struct sockaddr_storage* addr, socklen_t addrlen);
+
+/**
+ * Get memory used by acl structure.
+ * @param acl: structure for address storage.
+ * @return bytes in use.
+ */
+size_t acl_list_get_mem(struct acl_list* acl);
+
+/** compare two acl list entries */
+int acl_list_cmp(const void* k1, const void* k2);
+
+#endif /* DAEMON_ACL_LIST_H */
index d16dcd1c8c62e8451a7c9d86a187e497136dcc3e..d5beb220c8e7356352926ce89529692929d9e930 100644 (file)
@@ -4,6 +4,7 @@
        - created beta-0.7 branch for support.
        - tagged 0.7 for beta release.
        - moved trunk to 0.8 for 0.8(auth features) development.
+       - 0.8: access control list setup.
 
 15 November 2007: Wouter
        - review fixups from Jelte.
index df0908ebdfcd1eefa5c8ec3624cf41150201a201..f415e360c733460edc0b2914b055ca2e4e739e92 100644 (file)
@@ -108,28 +108,6 @@ donotq_insert(struct iter_donotq* dq, struct sockaddr_storage* addr,
        return 1;
 }
 
-/** make sure the netblock ends in zeroes for compare in tree */
-static void
-mask_block(int ip6, struct sockaddr_storage* addr, int net)
-{
-       uint8_t mask[8] = {0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f};
-       int i, max;
-       uint8_t* s;
-       if(ip6) {
-               s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
-               max = 128;
-       } else {
-               s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr;
-               max = 32;
-       }
-       if(net >= max)
-               return;
-       for(i=net/8+1; i<max/8; i++) {
-               s[i] = 0;
-       }
-       s[net/8] &= mask[net&0x7];
-}
-
 /** apply donotq string */
 static int
 donotq_str_cfg(struct iter_donotq* dq, const char* str)
@@ -163,7 +141,7 @@ donotq_str_cfg(struct iter_donotq* dq, const char* str)
        }
        if(s) {
                free(s);
-               mask_block(str_is_ip6(str), &addr, net);
+               addr_mask(&addr, addrlen, net);
        }
        if(!donotq_insert(dq, &addr, addrlen, net)) {
                log_err("out of memory");
@@ -185,42 +163,6 @@ read_donotq(struct iter_donotq* dq, struct config_file* cfg)
        return 1;
 }
 
-/** number of bits that two addrs share (are equal) */
-static int
-addr_in_common(struct sockaddr_storage* addr1, int net1, 
-       struct sockaddr_storage* addr2, int net2, socklen_t addrlen)
-{
-       int min = (net1<net2)?net1:net2;
-       int i, to;
-       int match = 0;
-       uint8_t* s1, *s2;
-       if(addr_is_ip6(addr1, addrlen)) {
-               s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr;
-               s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr;
-               to = 16;
-       } else {
-               s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr;
-               s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr;
-               to = 4;
-       }
-       /* match = bits_in_common(s1, s2, to); */
-       for(i=0; i<to; i++) {
-               if(s1[i] == s2[i]) {
-                       match += 8;
-               } else {
-                       uint8_t z = s1[i]^s2[i];
-                       log_assert(z);
-                       while(!(z&0x80)) {
-                               match++;
-                               z<<=1;
-                       }
-                       break;
-               }
-       }
-       if(match > min) match = min;
-       return match;
-}
-
 /** initialise parent pointers in the tree */
 static void
 donotq_init_parents(struct iter_donotq* donotq)
index bb6d659e0b9442bf10da0e272b82adf4535146a8..0274ebf605b631cdfe778dd4ef4541460e59ee4e 100644 (file)
@@ -54,7 +54,7 @@ struct iter_donotq {
        /** regional for allocation */
        struct regional* region;
        /** 
-        * Tree of the single addresses that are blocked.
+        * Tree of the address spans that are blocked.
         * contents of type iter_donotq_addr.
         */
        rbtree_t* tree;
@@ -62,10 +62,10 @@ struct iter_donotq {
 
 /**
  * Iterator donotquery address.
- * A single address that must not be used to send queries to.
+ * An address span that must not be used to send queries to.
  */
 struct iter_donotq_addr {
-       /** redblacktree node, key is this structure: addr and addrlen */
+       /** redblacktree node, key is this structure: addr and addrlen, net */
        rbnode_t node;
        /** address */
        struct sockaddr_storage addr;
index b0e9b275d143fdeac5bbc8d9b9bab0e982120680..16ca3e99ee0e18ed3f0629783afff796bf693be4 100644 (file)
@@ -110,6 +110,7 @@ config_create()
        cfg->out_ifs = NULL;
        cfg->stubs = NULL;
        cfg->forwards = NULL;
+       cfg->acls = NULL;
        cfg->harden_short_bufsize = 0;
        cfg->harden_large_queries = 0;
        cfg->harden_glue = 1;
@@ -184,6 +185,20 @@ config_delstrlist(struct config_strlist* p)
        }
 }
 
+/** delete config acl list */
+static void
+config_delacllist(struct config_acl* p)
+{
+       struct config_acl *np;
+       while(p) {
+               np = p->next;
+               free(p->address);
+               free(p->control);
+               free(p);
+               p = np;
+       }
+}
+
 /** delete config stublist */
 static void
 config_delstubs(struct config_stub* p)
@@ -231,6 +246,7 @@ config_delete(struct config_file* cfg)
        config_delstrlist(cfg->trust_anchor_file_list);
        config_delstrlist(cfg->trusted_keys_file_list);
        config_delstrlist(cfg->trust_anchor_list);
+       config_delacllist(cfg->acls);
        free(cfg->val_nsec3_key_iterations);
        free(cfg);
 }
index 3eb0faf5d197822d15b6f1cabd4d31957cba8702..b9e90022b997a5d9a3144808d99e7636bbdb0b04 100644 (file)
@@ -43,6 +43,7 @@
 #define UTIL_CONFIG_FILE_H
 struct config_stub;
 struct config_strlist;
+struct config_acl;
 
 /**
  * The configuration options.
@@ -120,6 +121,8 @@ struct config_file {
        struct config_stub* forwards;
        /** list of donotquery addresses, linked list */
        struct config_strlist* donotqueryaddrs;
+       /** list of access control entries, linked list */
+       struct config_acl* acls;
        /** use default localhost donotqueryaddr entries */
        int donotquery_localhost;
 
@@ -211,6 +214,18 @@ struct config_strlist {
        char* str;
 };
 
+/**
+ * List of access control options
+ */
+struct config_acl {
+       /** next item in list */
+       struct config_acl* next;
+       /** ip addr string */
+       char* address;
+       /** control string */
+       char* control;
+};
+
 /**
  * Create config file structure. Filled with default values.
  * @return: the new structure or NULL on memory error.
index ac67b6e532257d403eb64df0b45937290a3efc56..452d6c6aeec1b8aa695e465bee34a82c68dda1f2 100644 (file)
@@ -64,6 +64,7 @@
 #include "util/storage/slabhash.h"
 #include "util/locks.h"
 #include "testcode/checklocks.h"
+#include "daemon/acl_list.h"
 
 int 
 fptr_whitelist_comm_point(comm_point_callback_t *fptr)
@@ -130,6 +131,7 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
 {
        if(fptr == &mesh_state_compare) return 1;
        else if(fptr == &mesh_state_ref_compare) return 1;
+       else if(fptr == &acl_list_cmp) return 1;
        else if(fptr == &donotq_cmp) return 1;
        else if(fptr == &fwd_cmp) return 1;
        else if(fptr == &stub_cmp) return 1;
index d9535c15249a6f43af4b4c25c4544d1e55a96bed..46e0587426813e35b71e88bce32ab19cc1fbee6a 100644 (file)
@@ -58,25 +58,25 @@ str_is_ip6(const char* str)
 int 
 write_socket(int s, const void *buf, size_t size)
 {
-        const char* data = (const char*)buf;
-        size_t total_count = 0;
+       const char* data = (const char*)buf;
+       size_t total_count = 0;
 
        fd_set_block(s);
-        while (total_count < size) {
-                ssize_t count
-                        = write(s, data + total_count, size - total_count);
-                if (count == -1) {
-                        if (errno != EAGAIN && errno != EINTR) {
+       while (total_count < size) {
+               ssize_t count
+                       = write(s, data + total_count, size - total_count);
+               if (count == -1) {
+                       if (errno != EAGAIN && errno != EINTR) {
                                fd_set_nonblock(s);
-                                return 0;
-                        } else {
-                                continue;
-                        }
-                }
-                total_count += count;
-        }
+                               return 0;
+                       } else {
+                               continue;
+                       }
+               }
+               total_count += count;
+       }
        fd_set_nonblock(s);
-        return 1;
+       return 1;
 }
 
 int 
@@ -149,27 +149,27 @@ void
 log_addr(enum verbosity_value v, const char* str, 
        struct sockaddr_storage* addr, socklen_t addrlen)
 {
-        uint16_t port;
-        const char* family = "unknown";
-        char dest[100];
-        int af = (int)((struct sockaddr_in*)addr)->sin_family;
-        void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+       uint16_t port;
+       const char* family = "unknown";
+       char dest[100];
+       int af = (int)((struct sockaddr_in*)addr)->sin_family;
+       void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
        if(verbosity < v)
                return;
-        switch(af) {
-                case AF_INET: family="ip4"; break;
-                case AF_INET6: family="ip6";
-                        sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
-                        break;
-                case AF_UNIX: family="unix"; break;
-                default: break;
-        }
-        if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
-                strncpy(dest, "(inet_ntop error)", sizeof(dest));
-        }
+       switch(af) {
+               case AF_INET: family="ip4"; break;
+               case AF_INET6: family="ip6";
+                       sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
+                       break;
+               case AF_UNIX: family="unix"; break;
+               default: break;
+       }
+       if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
+               strncpy(dest, "(inet_ntop error)", sizeof(dest));
+       }
        dest[sizeof(dest)-1] = 0;
-        port = ntohs(((struct sockaddr_in*)addr)->sin_port);
-        log_info("%s %s %s %d (len %d)", str, family, dest, (int)port, 
+       port = ntohs(((struct sockaddr_in*)addr)->sin_port);
+       log_info("%s %s %s %d (len %d)", str, family, dest, (int)port, 
                (int)addrlen);
 }
 
@@ -264,32 +264,32 @@ log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name,
 void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone, 
        struct sockaddr_storage* addr, socklen_t addrlen)
 {
-        uint16_t port;
-        const char* family = "unknown_family ";
+       uint16_t port;
+       const char* family = "unknown_family ";
        char namebuf[LDNS_MAX_DOMAINLEN+1];
-        char dest[100];
-        int af = (int)((struct sockaddr_in*)addr)->sin_family;
-        void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+       char dest[100];
+       int af = (int)((struct sockaddr_in*)addr)->sin_family;
+       void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
        if(verbosity < v)
                return;
-        switch(af) {
-                case AF_INET: family=""; break;
-                case AF_INET6: family="";
-                        sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
-                        break;
-                case AF_UNIX: family="unix_family "; break;
-                default: break;
-        }
-        if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
-                strncpy(dest, "(inet_ntop error)", sizeof(dest));
-        }
+       switch(af) {
+               case AF_INET: family=""; break;
+               case AF_INET6: family="";
+                       sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
+                       break;
+               case AF_UNIX: family="unix_family "; break;
+               default: break;
+       }
+       if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
+               strncpy(dest, "(inet_ntop error)", sizeof(dest));
+       }
        dest[sizeof(dest)-1] = 0;
-        port = ntohs(((struct sockaddr_in*)addr)->sin_port);
+       port = ntohs(((struct sockaddr_in*)addr)->sin_port);
        dname_str(zone, namebuf);
        if(af != AF_INET && af != AF_INET6)
                verbose(VERB_DETAIL, "%s <%s> %s%s#%d (addrlen %d)",
                        str, namebuf, family, dest, (int)port, (int)addrlen);
-        else   verbose(VERB_DETAIL, "%s <%s> %s%s#%d",
+       else    verbose(VERB_DETAIL, "%s <%s> %s%s#%d",
                        str, namebuf, family, dest, (int)port);
 }
 
@@ -373,3 +373,59 @@ addr_is_ip6(struct sockaddr_storage* addr, socklen_t len)
                return 1;
        else    return 0;
 }
+
+void
+addr_mask(struct sockaddr_storage* addr, socklen_t len, int net)
+{
+       uint8_t mask[8] = {0x0, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f};
+       int i, max;
+       uint8_t* s;
+       if(addr_is_ip6(addr, len)) {
+               s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
+               max = 128;
+       } else {
+               s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr;
+               max = 32;
+       }
+       if(net >= max)
+               return;
+       for(i=net/8+1; i<max/8; i++) {
+               s[i] = 0;
+       }
+       s[net/8] &= mask[net&0x7];
+}
+
+int
+addr_in_common(struct sockaddr_storage* addr1, int net1,
+       struct sockaddr_storage* addr2, int net2, socklen_t addrlen)
+{
+       int min = (net1<net2)?net1:net2;
+       int i, to;
+       int match = 0;
+       uint8_t* s1, *s2;
+       if(addr_is_ip6(addr1, addrlen)) {
+               s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr;
+               s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr;
+               to = 16;
+       } else {
+               s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr;
+               s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr;
+               to = 4;
+       }
+       /* match = bits_in_common(s1, s2, to); */
+       for(i=0; i<to; i++) {
+               if(s1[i] == s2[i]) {
+                       match += 8;
+               } else {
+                       uint8_t z = s1[i]^s2[i];
+                       log_assert(z);
+                       while(!(z&0x80)) {
+                               match++;
+                               z<<=1;
+                       }
+                       break;
+               }
+       }
+       if(match > min) match = min;
+       return match;
+}
index a635a1045c32b117b3aac99434432c92f4840cc9..02f59758c39abcd160645df3eed2001f0c281f14 100644 (file)
@@ -228,4 +228,27 @@ int sockaddr_cmp_addr(struct sockaddr_storage* addr1, socklen_t len1,
  */
 int addr_is_ip6(struct sockaddr_storage* addr, socklen_t len);
 
+/**
+ * Make sure the sockaddr ends in zeroes. For tree insertion and subsequent
+ * comparison.
+ * @param addr: the ip4 or ip6 addr.
+ * @Param len: lentgh of addr.
+ * @param net: number of bits to leave untouched, the rest of the netblock
+ *     address is zeroed.
+ */
+void addr_mask(struct sockaddr_storage* addr, socklen_t len, int net);
+
+/**
+ * See how many bits are shared, equal, between two addrs.
+ * @param addr1: first addr.
+ * @param net1: netblock size of first addr.
+ * @param addr2: second addr.
+ * @param net2: netblock size of second addr.
+ * @param addrlen: length of first addr and of second addr.
+ *     They must be of the same length (i.e. same type IP4, IP6).
+ * @return: number of bits the same.
+ */
+int addr_in_common(struct sockaddr_storage* addr1, int net1,
+       struct sockaddr_storage* addr2, int net2, socklen_t addrlen);
+
 #endif /* NET_HELP_H */