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)
{
log_assert(0);
}
+
+int
+acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
+{
+ log_assert(0);
+ return 0;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 */
- 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.
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)
}
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");
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)
/** 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;
/**
* 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;
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;
}
}
+/** 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)
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);
}
#define UTIL_CONFIG_FILE_H
struct config_stub;
struct config_strlist;
+struct config_acl;
/**
* The configuration options.
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;
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.
#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)
{
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;
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
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);
}
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);
}
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;
+}
*/
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 */