Support bogus subnet search
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
BIN=smartdns
|
BIN=smartdns
|
||||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o
|
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o
|
||||||
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o conf.o dns_cache.o $(OBJS_LIB)
|
OBJS=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o conf.o dns_cache.o $(OBJS_LIB)
|
||||||
CFLAGS +=-O2 -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
|
CFLAGS +=-O2 -Wall -Wstrict-prototypes -fno-omit-frame-pointer -Wstrict-aliasing
|
||||||
CFLAGS +=-Iinclude
|
CFLAGS +=-Iinclude
|
||||||
|
|||||||
99
src/conf.c
99
src/conf.c
@@ -31,7 +31,9 @@ char dns_conf_audit_file[DNS_MAX_PATH];
|
|||||||
int dns_conf_audit_size = 1024 * 1024;
|
int dns_conf_audit_size = 1024 * 1024;
|
||||||
int dns_conf_audit_num = 2;
|
int dns_conf_audit_num = 2;
|
||||||
|
|
||||||
art_tree dns_conf_address;
|
art_tree dns_conf_domain_rule;
|
||||||
|
radix_tree_t *dns_conf_address_rule;
|
||||||
|
|
||||||
int dns_conf_rr_ttl;
|
int dns_conf_rr_ttl;
|
||||||
int dns_conf_rr_ttl_min;
|
int dns_conf_rr_ttl_min;
|
||||||
int dns_conf_rr_ttl_max;
|
int dns_conf_rr_ttl_max;
|
||||||
@@ -90,16 +92,30 @@ int config_server(char *value, dns_server_type_t type, int default_port)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_address_iter_cb(void *data, const unsigned char *key, uint32_t key_len, void *value)
|
int config_domain_iter_cb(void *data, const unsigned char *key, uint32_t key_len, void *value)
|
||||||
{
|
{
|
||||||
free(value);
|
free(value);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_address_destroy(void)
|
void config_domain_destroy(void)
|
||||||
{
|
{
|
||||||
art_iter(&dns_conf_address, config_address_iter_cb, 0);
|
art_iter(&dns_conf_domain_rule, config_domain_iter_cb, 0);
|
||||||
art_tree_destroy(&dns_conf_address);
|
art_tree_destroy(&dns_conf_domain_rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void config_address_destroy(radix_node_t *node, void *cbctx)
|
||||||
|
{
|
||||||
|
if (node == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->data == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(node->data);
|
||||||
|
node->data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_address(char *value)
|
int config_address(char *value)
|
||||||
@@ -184,7 +200,7 @@ int config_address(char *value)
|
|||||||
|
|
||||||
domain_key[0] = type;
|
domain_key[0] = type;
|
||||||
len++;
|
len++;
|
||||||
oldaddress = art_insert(&dns_conf_address, (unsigned char *)domain_key, len, address);
|
oldaddress = art_insert(&dns_conf_domain_rule, (unsigned char *)domain_key, len, address);
|
||||||
if (oldaddress) {
|
if (oldaddress) {
|
||||||
free(oldaddress);
|
free(oldaddress);
|
||||||
}
|
}
|
||||||
@@ -465,8 +481,68 @@ void conf_bogus_nxdomain_destroy(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
radix_node_t *create_addr_node(radix_tree_t *tree, char *addr)
|
||||||
|
{
|
||||||
|
radix_node_t *node;
|
||||||
|
void *p;
|
||||||
|
prefix_t prefix;
|
||||||
|
const char *errmsg = NULL;
|
||||||
|
|
||||||
|
p = prefix_pton(addr, -1, &prefix, &errmsg);
|
||||||
|
if (p == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = radix_lookup(tree, &prefix);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int config_iplist_action(char *subnet, enum address_action act)
|
||||||
|
{
|
||||||
|
radix_node_t *node = NULL;
|
||||||
|
struct dns_ip_address_rule *ip_rule = NULL;
|
||||||
|
|
||||||
|
node = create_addr_node(dns_conf_address_rule, subnet);
|
||||||
|
if (node == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->data == NULL) {
|
||||||
|
ip_rule = malloc(sizeof(*ip_rule));
|
||||||
|
if (ip_rule == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->data = ip_rule;
|
||||||
|
memset(ip_rule, 0, sizeof(*ip_rule));
|
||||||
|
}
|
||||||
|
|
||||||
|
ip_rule = node->data;
|
||||||
|
|
||||||
|
switch (act) {
|
||||||
|
case ACTION_BLACKLIST:
|
||||||
|
ip_rule->blacklist = 1;
|
||||||
|
break;
|
||||||
|
case ACTION_BOGUS:
|
||||||
|
ip_rule->bogus = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_blacklist_ip(char *value)
|
||||||
|
{
|
||||||
|
return config_iplist_action(value, ACTION_BLACKLIST);
|
||||||
|
}
|
||||||
|
|
||||||
int conf_bogus_nxdomain(char *value)
|
int conf_bogus_nxdomain(char *value)
|
||||||
{
|
{
|
||||||
|
//////////////////////////////////////
|
||||||
|
config_iplist_action(value, ACTION_BOGUS);
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
struct dns_bogus_ip_address *ip_addr = NULL;
|
struct dns_bogus_ip_address *ip_addr = NULL;
|
||||||
char ip[MAX_IP_LEN];
|
char ip[MAX_IP_LEN];
|
||||||
int port;
|
int port;
|
||||||
@@ -570,6 +646,7 @@ struct config_item config_item[] = {
|
|||||||
{"rr-ttl-min", config_rr_ttl_min},
|
{"rr-ttl-min", config_rr_ttl_min},
|
||||||
{"rr-ttl-max", config_rr_ttl_max},
|
{"rr-ttl-max", config_rr_ttl_max},
|
||||||
{"force-AAAA-SOA", config_force_AAAA_SOA},
|
{"force-AAAA-SOA", config_force_AAAA_SOA},
|
||||||
|
{"blacklist-ip", config_blacklist_ip},
|
||||||
{"bogus-nxdomain", conf_bogus_nxdomain},
|
{"bogus-nxdomain", conf_bogus_nxdomain},
|
||||||
{"conf-file", config_addtional_file},
|
{"conf-file", config_addtional_file},
|
||||||
};
|
};
|
||||||
@@ -577,7 +654,12 @@ int config_item_num = sizeof(config_item) / sizeof(struct config_item);
|
|||||||
|
|
||||||
int load_conf_init(void)
|
int load_conf_init(void)
|
||||||
{
|
{
|
||||||
art_tree_init(&dns_conf_address);
|
dns_conf_address_rule = New_Radix();
|
||||||
|
art_tree_init(&dns_conf_domain_rule);
|
||||||
|
if (dns_conf_address_rule == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
hash_init(dns_conf_bogus_nxdomain.ip_hash);
|
hash_init(dns_conf_bogus_nxdomain.ip_hash);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -585,7 +667,8 @@ int load_conf_init(void)
|
|||||||
void load_exit(void)
|
void load_exit(void)
|
||||||
{
|
{
|
||||||
conf_bogus_nxdomain_destroy();
|
conf_bogus_nxdomain_destroy();
|
||||||
config_address_destroy();
|
config_domain_destroy();
|
||||||
|
Destroy_Radix(dns_conf_address_rule, config_address_destroy, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_conf_file(const char *file)
|
int load_conf_file(const char *file)
|
||||||
|
|||||||
15
src/conf.h
15
src/conf.h
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "art.h"
|
#include "art.h"
|
||||||
|
#include "radix.h"
|
||||||
#include "dns.h"
|
#include "dns.h"
|
||||||
#include "dns_client.h"
|
#include "dns_client.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
@@ -44,6 +45,17 @@ struct dns_bogus_ip_address {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum address_action {
|
||||||
|
ACTION_BLACKLIST = 1,
|
||||||
|
ACTION_BOGUS = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dns_ip_address_rule
|
||||||
|
{
|
||||||
|
unsigned int blacklist : 1;
|
||||||
|
unsigned int bogus : 1;
|
||||||
|
};
|
||||||
|
|
||||||
struct dns_bogus_nxdomain {
|
struct dns_bogus_nxdomain {
|
||||||
DECLARE_HASHTABLE(ip_hash, 12);
|
DECLARE_HASHTABLE(ip_hash, 12);
|
||||||
};
|
};
|
||||||
@@ -69,7 +81,8 @@ extern int dns_conf_audit_size;
|
|||||||
extern int dns_conf_audit_num;
|
extern int dns_conf_audit_num;
|
||||||
|
|
||||||
extern char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
|
extern char dns_conf_server_name[DNS_MAX_CONF_CNAME_LEN];
|
||||||
extern art_tree dns_conf_address;
|
extern art_tree dns_conf_domain_rule;
|
||||||
|
extern radix_tree_t *dns_conf_address_rule;
|
||||||
|
|
||||||
extern int dns_conf_rr_ttl;
|
extern int dns_conf_rr_ttl;
|
||||||
extern int dns_conf_rr_ttl_min;
|
extern int dns_conf_rr_ttl_min;
|
||||||
|
|||||||
@@ -683,6 +683,30 @@ static int _dns_server_bogus_nxdomain_exists(struct dns_request *request, unsign
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_server_ip_rule_check(struct dns_request *request, unsigned char *addr, int addr_len, dns_type_t addr_type)
|
||||||
|
{
|
||||||
|
prefix_t prefix;
|
||||||
|
radix_node_t *node = NULL;
|
||||||
|
struct dns_ip_address_rule *rule = NULL;
|
||||||
|
|
||||||
|
if (prefix_from_blob(addr, addr_len, addr_len * 8, &prefix) == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = radix_search_best(dns_conf_address_rule, &prefix);
|
||||||
|
if (node == NULL) {
|
||||||
|
return - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->data == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rule = node->data;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet)
|
static int _dns_server_process_answer(struct dns_request *request, char *domain, struct dns_packet *packet)
|
||||||
{
|
{
|
||||||
int ttl;
|
int ttl;
|
||||||
@@ -717,6 +741,11 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
|||||||
|
|
||||||
tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
|
tlog(TLOG_DEBUG, "domain: %s TTL:%d IP: %d.%d.%d.%d", name, ttl, addr[0], addr[1], addr[2], addr[3]);
|
||||||
|
|
||||||
|
if (_dns_server_ip_rule_check(request, addr, 4, DNS_T_A) == 0) {
|
||||||
|
_dns_server_request_release(request);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* bogus ip address, skip */
|
/* bogus ip address, skip */
|
||||||
if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_A) == 0) {
|
if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_A) == 0) {
|
||||||
_dns_server_request_release(request);
|
_dns_server_request_release(request);
|
||||||
@@ -770,6 +799,11 @@ static int _dns_server_process_answer(struct dns_request *request, char *domain,
|
|||||||
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl, addr[0], addr[1],
|
tlog(TLOG_DEBUG, "domain: %s TTL: %d IP: %.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x", name, ttl, addr[0], addr[1],
|
||||||
addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
|
||||||
|
|
||||||
|
if (_dns_server_ip_rule_check(request, addr, 16, DNS_T_A) == 0) {
|
||||||
|
_dns_server_request_release(request);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* bogus ip address, skip */
|
/* bogus ip address, skip */
|
||||||
if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_AAAA) == 0) {
|
if (_dns_server_bogus_nxdomain_exists(request, addr, DNS_T_AAAA) == 0) {
|
||||||
_dns_server_request_release(request);
|
_dns_server_request_release(request);
|
||||||
@@ -1023,10 +1057,10 @@ static struct dns_address *_dns_server_get_address_by_domain(char *domain, int q
|
|||||||
domain_key[domain_len] = 0;
|
domain_key[domain_len] = 0;
|
||||||
|
|
||||||
if (likely(dns_conf_log_level > TLOG_INFO)) {
|
if (likely(dns_conf_log_level > TLOG_INFO)) {
|
||||||
return art_substring(&dns_conf_address, (unsigned char *)domain_key, domain_len, NULL, NULL);
|
return art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
address = art_substring(&dns_conf_address, (unsigned char *)domain_key, domain_len, matched_key, &matched_key_len);
|
address = art_substring(&dns_conf_domain_rule, (unsigned char *)domain_key, domain_len, matched_key, &matched_key_len);
|
||||||
if (address == NULL) {
|
if (address == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
161
src/include/radix.h
Normal file
161
src/include/radix.h
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2000
|
||||||
|
*
|
||||||
|
* The Regents of the University of Michigan ("The Regents") and
|
||||||
|
* Merit Network, Inc. All rights reserved. Redistribution and use
|
||||||
|
* in source and binary forms, with or without modification, are
|
||||||
|
* permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. 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.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of
|
||||||
|
* this software must display the following acknowledgement:
|
||||||
|
*
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* Michigan, Merit Network, Inc., and their contributors.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the University, Merit Network, nor the
|
||||||
|
* names of their contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 TH E 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) HO WEVER 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.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Portions Copyright (c) 2004,2005 Damien Miller <djm@mindrot.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* $Id: radix.h,v 1.9 2007/10/24 06:03:08 djm Exp $ */
|
||||||
|
|
||||||
|
#ifndef _RADIX_H
|
||||||
|
#define _RADIX_H
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#else
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <netinet/in.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
# include <netdb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
# define snprintf _snprintf
|
||||||
|
typedef unsigned __int8 u_int8_t;
|
||||||
|
typedef unsigned __int16 u_int16_t;
|
||||||
|
typedef unsigned __int32 u_int32_t;
|
||||||
|
const char *inet_ntop(int af, const void *src, char *dst, size_t size);
|
||||||
|
size_t strlcpy(char *dst, const char *src, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Originally from MRT include/mrt.h
|
||||||
|
* $MRTId: mrt.h,v 1.1.1.1 2000/08/14 18:46:10 labovit Exp $
|
||||||
|
*/
|
||||||
|
typedef struct _prefix_t {
|
||||||
|
u_int family; /* AF_INET | AF_INET6 */
|
||||||
|
u_int bitlen; /* same as mask? */
|
||||||
|
int ref_count; /* reference count */
|
||||||
|
union {
|
||||||
|
struct in_addr sin;
|
||||||
|
struct in6_addr sin6;
|
||||||
|
} add;
|
||||||
|
} prefix_t;
|
||||||
|
|
||||||
|
void Deref_Prefix(prefix_t *prefix);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Originally from MRT include/radix.h
|
||||||
|
* $MRTId: radix.h,v 1.1.1.1 2000/08/14 18:46:10 labovit Exp $
|
||||||
|
*/
|
||||||
|
typedef struct _radix_node_t {
|
||||||
|
u_int bit; /* flag if this node used */
|
||||||
|
prefix_t *prefix; /* who we are in radix tree */
|
||||||
|
struct _radix_node_t *l, *r; /* left and right children */
|
||||||
|
struct _radix_node_t *parent; /* may be used */
|
||||||
|
void *data; /* pointer to data */
|
||||||
|
} radix_node_t;
|
||||||
|
|
||||||
|
typedef struct _radix_tree_t {
|
||||||
|
radix_node_t *head;
|
||||||
|
u_int maxbits; /* for IP, 32 bit addresses */
|
||||||
|
int num_active_node; /* for debug purpose */
|
||||||
|
} radix_tree_t;
|
||||||
|
|
||||||
|
/* Type of callback function */
|
||||||
|
typedef void (*rdx_cb_t)(radix_node_t *, void *);
|
||||||
|
|
||||||
|
radix_tree_t *New_Radix(void);
|
||||||
|
void Destroy_Radix(radix_tree_t *radix, rdx_cb_t func, void *cbctx);
|
||||||
|
radix_node_t *radix_lookup(radix_tree_t *radix, prefix_t *prefix);
|
||||||
|
void radix_remove(radix_tree_t *radix, radix_node_t *node);
|
||||||
|
radix_node_t *radix_search_exact(radix_tree_t *radix, prefix_t *prefix);
|
||||||
|
radix_node_t *radix_search_best(radix_tree_t *radix, prefix_t *prefix);
|
||||||
|
void radix_process(radix_tree_t *radix, rdx_cb_t func, void *cbctx);
|
||||||
|
|
||||||
|
#define RADIX_MAXBITS 128
|
||||||
|
|
||||||
|
#define RADIX_WALK(Xhead, Xnode) \
|
||||||
|
do { \
|
||||||
|
radix_node_t *Xstack[RADIX_MAXBITS+1]; \
|
||||||
|
radix_node_t **Xsp = Xstack; \
|
||||||
|
radix_node_t *Xrn = (Xhead); \
|
||||||
|
while ((Xnode = Xrn)) { \
|
||||||
|
if (Xnode->prefix)
|
||||||
|
|
||||||
|
#define RADIX_WALK_END \
|
||||||
|
if (Xrn->l) { \
|
||||||
|
if (Xrn->r) { \
|
||||||
|
*Xsp++ = Xrn->r; \
|
||||||
|
} \
|
||||||
|
Xrn = Xrn->l; \
|
||||||
|
} else if (Xrn->r) { \
|
||||||
|
Xrn = Xrn->r; \
|
||||||
|
} else if (Xsp != Xstack) { \
|
||||||
|
Xrn = *(--Xsp); \
|
||||||
|
} else { \
|
||||||
|
Xrn = (radix_node_t *) 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Local additions */
|
||||||
|
|
||||||
|
prefix_t *prefix_pton(const char *string, long len, prefix_t *prefix, const char **errmsg);
|
||||||
|
prefix_t *prefix_from_blob(unsigned char *blob, int len, int prefixlen, prefix_t *prefix);
|
||||||
|
const char *prefix_addr_ntop(prefix_t *prefix, char *buf, size_t len);
|
||||||
|
const char *prefix_ntop(prefix_t *prefix, char *buf, size_t len);
|
||||||
|
|
||||||
|
#endif /* _RADIX_H */
|
||||||
673
src/lib/radix.c
Normal file
673
src/lib/radix.c
Normal file
@@ -0,0 +1,673 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 1999-2000
|
||||||
|
*
|
||||||
|
* The Regents of the University of Michigan ("The Regents") and
|
||||||
|
* Merit Network, Inc. All rights reserved. Redistribution and use
|
||||||
|
* in source and binary forms, with or without modification, are
|
||||||
|
* permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above
|
||||||
|
* copyright notice, this list of conditions and the
|
||||||
|
* following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. 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.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of
|
||||||
|
* this software must display the following acknowledgement:
|
||||||
|
*
|
||||||
|
* This product includes software developed by the University of
|
||||||
|
* Michigan, Merit Network, Inc., and their contributors.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the University, Merit Network, nor the
|
||||||
|
* names of their contributors may be used to endorse or
|
||||||
|
* promote products derived from this software without
|
||||||
|
* specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 TH E 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) HO WEVER 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.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Portions Copyright (c) 2004,2005 Damien Miller <djm@mindrot.org>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "radix.h"
|
||||||
|
|
||||||
|
/* $Id: radix.c,v 1.17 2007/10/24 06:04:31 djm Exp $ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Originally from MRT include/defs.h
|
||||||
|
* $MRTId: defs.h,v 1.1.1.1 2000/08/14 18:46:10 labovit Exp $
|
||||||
|
*/
|
||||||
|
#define BIT_TEST(f, b) ((f) & (b))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Originally from MRT include/mrt.h
|
||||||
|
* $MRTId: mrt.h,v 1.1.1.1 2000/08/14 18:46:10 labovit Exp $
|
||||||
|
*/
|
||||||
|
#define prefix_tochar(prefix) ((char *)&(prefix)->add)
|
||||||
|
#define prefix_touchar(prefix) ((unsigned char *)&(prefix)->add)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Originally from MRT lib/mrt/prefix.c
|
||||||
|
* $MRTId: prefix.c,v 1.1.1.1 2000/08/14 18:46:11 labovit Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
comp_with_mask(unsigned char *addr, unsigned char *dest, unsigned int mask)
|
||||||
|
{
|
||||||
|
if (memcmp(addr, dest, mask / 8) == 0) {
|
||||||
|
unsigned int n = mask / 8;
|
||||||
|
unsigned int m = ((~0) << (8 - (mask % 8)));
|
||||||
|
|
||||||
|
if (mask % 8 == 0 || (addr[n] & m) == (dest[n] & m))
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static prefix_t
|
||||||
|
*New_Prefix2(int family, void *dest, int bitlen, prefix_t *prefix)
|
||||||
|
{
|
||||||
|
int dynamic_allocated = 0;
|
||||||
|
int default_bitlen = 32;
|
||||||
|
|
||||||
|
if (family == AF_INET6) {
|
||||||
|
default_bitlen = 128;
|
||||||
|
if (prefix == NULL) {
|
||||||
|
if ((prefix = malloc(sizeof(*prefix))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(prefix, '\0', sizeof(*prefix));
|
||||||
|
dynamic_allocated++;
|
||||||
|
}
|
||||||
|
memcpy(&prefix->add.sin6, dest, 16);
|
||||||
|
} else if (family == AF_INET) {
|
||||||
|
if (prefix == NULL) {
|
||||||
|
if ((prefix = malloc(sizeof(*prefix))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(prefix, '\0', sizeof(*prefix));
|
||||||
|
dynamic_allocated++;
|
||||||
|
}
|
||||||
|
memcpy(&prefix->add.sin, dest, 4);
|
||||||
|
} else
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
prefix->bitlen = (bitlen >= 0) ? bitlen : default_bitlen;
|
||||||
|
prefix->family = family;
|
||||||
|
prefix->ref_count = 0;
|
||||||
|
if (dynamic_allocated)
|
||||||
|
prefix->ref_count++;
|
||||||
|
return (prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static prefix_t
|
||||||
|
*Ref_Prefix(prefix_t *prefix)
|
||||||
|
{
|
||||||
|
if (prefix == NULL)
|
||||||
|
return (NULL);
|
||||||
|
if (prefix->ref_count == 0) {
|
||||||
|
/* make a copy in case of a static prefix */
|
||||||
|
return (New_Prefix2(prefix->family, &prefix->add,
|
||||||
|
prefix->bitlen, NULL));
|
||||||
|
}
|
||||||
|
prefix->ref_count++;
|
||||||
|
return (prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Deref_Prefix(prefix_t *prefix)
|
||||||
|
{
|
||||||
|
if (prefix == NULL)
|
||||||
|
return;
|
||||||
|
prefix->ref_count--;
|
||||||
|
if (prefix->ref_count <= 0) {
|
||||||
|
free(prefix);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Originally from MRT lib/radix/radix.c
|
||||||
|
* $MRTId: radix.c,v 1.1.1.1 2000/08/14 18:46:13 labovit Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* these routines support continuous mask only */
|
||||||
|
|
||||||
|
radix_tree_t
|
||||||
|
*New_Radix(void)
|
||||||
|
{
|
||||||
|
radix_tree_t *radix;
|
||||||
|
|
||||||
|
if ((radix = malloc(sizeof(*radix))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(radix, '\0', sizeof(*radix));
|
||||||
|
|
||||||
|
radix->maxbits = 128;
|
||||||
|
radix->head = NULL;
|
||||||
|
radix->num_active_node = 0;
|
||||||
|
return (radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if func is supplied, it will be called as func(node->data)
|
||||||
|
* before deleting the node
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
Clear_Radix(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
|
||||||
|
{
|
||||||
|
if (radix->head) {
|
||||||
|
radix_node_t *Xstack[RADIX_MAXBITS + 1];
|
||||||
|
radix_node_t **Xsp = Xstack;
|
||||||
|
radix_node_t *Xrn = radix->head;
|
||||||
|
|
||||||
|
while (Xrn) {
|
||||||
|
radix_node_t *l = Xrn->l;
|
||||||
|
radix_node_t *r = Xrn->r;
|
||||||
|
|
||||||
|
if (Xrn->prefix) {
|
||||||
|
Deref_Prefix(Xrn->prefix);
|
||||||
|
if (Xrn->data && func)
|
||||||
|
func(Xrn, cbctx);
|
||||||
|
}
|
||||||
|
free(Xrn);
|
||||||
|
radix->num_active_node--;
|
||||||
|
|
||||||
|
if (l) {
|
||||||
|
if (r)
|
||||||
|
*Xsp++ = r;
|
||||||
|
Xrn = l;
|
||||||
|
} else if (r) {
|
||||||
|
Xrn = r;
|
||||||
|
} else if (Xsp != Xstack) {
|
||||||
|
Xrn = *(--Xsp);
|
||||||
|
} else {
|
||||||
|
Xrn = (radix_node_t *) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Destroy_Radix(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
|
||||||
|
{
|
||||||
|
Clear_Radix(radix, func, cbctx);
|
||||||
|
free(radix);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if func is supplied, it will be called as func(node->prefix, node->data)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
radix_process(radix_tree_t *radix, rdx_cb_t func, void *cbctx)
|
||||||
|
{
|
||||||
|
radix_node_t *node;
|
||||||
|
|
||||||
|
RADIX_WALK(radix->head, node) {
|
||||||
|
func(node, cbctx);
|
||||||
|
} RADIX_WALK_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
radix_node_t
|
||||||
|
*radix_search_exact(radix_tree_t *radix, prefix_t *prefix)
|
||||||
|
{
|
||||||
|
radix_node_t *node;
|
||||||
|
unsigned char *addr;
|
||||||
|
unsigned int bitlen;
|
||||||
|
|
||||||
|
if (radix->head == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
node = radix->head;
|
||||||
|
addr = prefix_touchar(prefix);
|
||||||
|
bitlen = prefix->bitlen;
|
||||||
|
|
||||||
|
while (node->bit < bitlen) {
|
||||||
|
if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
|
||||||
|
node = node->r;
|
||||||
|
else
|
||||||
|
node = node->l;
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->bit > bitlen || node->prefix == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (comp_with_mask(prefix_touchar(node->prefix),
|
||||||
|
prefix_touchar(prefix), bitlen))
|
||||||
|
return (node);
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* if inclusive != 0, "best" may be the given prefix itself */
|
||||||
|
static radix_node_t
|
||||||
|
*radix_search_best2(radix_tree_t *radix, prefix_t *prefix, int inclusive)
|
||||||
|
{
|
||||||
|
radix_node_t *node;
|
||||||
|
radix_node_t *stack[RADIX_MAXBITS + 1];
|
||||||
|
unsigned char *addr;
|
||||||
|
unsigned int bitlen;
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
if (radix->head == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
node = radix->head;
|
||||||
|
addr = prefix_touchar(prefix);
|
||||||
|
bitlen = prefix->bitlen;
|
||||||
|
|
||||||
|
while (node->bit < bitlen) {
|
||||||
|
if (node->prefix)
|
||||||
|
stack[cnt++] = node;
|
||||||
|
if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07)))
|
||||||
|
node = node->r;
|
||||||
|
else
|
||||||
|
node = node->l;
|
||||||
|
|
||||||
|
if (node == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inclusive && node && node->prefix)
|
||||||
|
stack[cnt++] = node;
|
||||||
|
|
||||||
|
|
||||||
|
if (cnt <= 0)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
while (--cnt >= 0) {
|
||||||
|
node = stack[cnt];
|
||||||
|
if (comp_with_mask(prefix_touchar(node->prefix),
|
||||||
|
prefix_touchar(prefix), node->prefix->bitlen))
|
||||||
|
return (node);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
radix_node_t
|
||||||
|
*radix_search_best(radix_tree_t *radix, prefix_t *prefix)
|
||||||
|
{
|
||||||
|
return (radix_search_best2(radix, prefix, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
radix_node_t
|
||||||
|
*radix_lookup(radix_tree_t *radix, prefix_t *prefix)
|
||||||
|
{
|
||||||
|
radix_node_t *node, *new_node, *parent, *glue;
|
||||||
|
unsigned char *addr, *test_addr;
|
||||||
|
unsigned int bitlen, check_bit, differ_bit;
|
||||||
|
unsigned int i, j, r;
|
||||||
|
|
||||||
|
if (radix->head == NULL) {
|
||||||
|
if ((node = malloc(sizeof(*node))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(node, '\0', sizeof(*node));
|
||||||
|
node->bit = prefix->bitlen;
|
||||||
|
node->prefix = Ref_Prefix(prefix);
|
||||||
|
node->parent = NULL;
|
||||||
|
node->l = node->r = NULL;
|
||||||
|
node->data = NULL;
|
||||||
|
radix->head = node;
|
||||||
|
radix->num_active_node++;
|
||||||
|
return (node);
|
||||||
|
}
|
||||||
|
addr = prefix_touchar(prefix);
|
||||||
|
bitlen = prefix->bitlen;
|
||||||
|
node = radix->head;
|
||||||
|
|
||||||
|
while (node->bit < bitlen || node->prefix == NULL) {
|
||||||
|
if (node->bit < radix->maxbits && BIT_TEST(addr[node->bit >> 3],
|
||||||
|
0x80 >> (node->bit & 0x07))) {
|
||||||
|
if (node->r == NULL)
|
||||||
|
break;
|
||||||
|
node = node->r;
|
||||||
|
} else {
|
||||||
|
if (node->l == NULL)
|
||||||
|
break;
|
||||||
|
node = node->l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_addr = prefix_touchar(node->prefix);
|
||||||
|
/* find the first bit different */
|
||||||
|
check_bit = (node->bit < bitlen) ? node->bit : bitlen;
|
||||||
|
differ_bit = 0;
|
||||||
|
for (i = 0; i * 8 < check_bit; i++) {
|
||||||
|
if ((r = (addr[i] ^ test_addr[i])) == 0) {
|
||||||
|
differ_bit = (i + 1) * 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* I know the better way, but for now */
|
||||||
|
for (j = 0; j < 8; j++) {
|
||||||
|
if (BIT_TEST(r, (0x80 >> j)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* must be found */
|
||||||
|
differ_bit = i * 8 + j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (differ_bit > check_bit)
|
||||||
|
differ_bit = check_bit;
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
while (parent && parent->bit >= differ_bit) {
|
||||||
|
node = parent;
|
||||||
|
parent = node->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (differ_bit == bitlen && node->bit == bitlen) {
|
||||||
|
if (node->prefix == NULL)
|
||||||
|
node->prefix = Ref_Prefix(prefix);
|
||||||
|
return (node);
|
||||||
|
}
|
||||||
|
if ((new_node = malloc(sizeof(*new_node))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(new_node, '\0', sizeof(*new_node));
|
||||||
|
new_node->bit = prefix->bitlen;
|
||||||
|
new_node->prefix = Ref_Prefix(prefix);
|
||||||
|
new_node->parent = NULL;
|
||||||
|
new_node->l = new_node->r = NULL;
|
||||||
|
new_node->data = NULL;
|
||||||
|
radix->num_active_node++;
|
||||||
|
|
||||||
|
if (node->bit == differ_bit) {
|
||||||
|
new_node->parent = node;
|
||||||
|
if (node->bit < radix->maxbits && BIT_TEST(addr[node->bit >> 3],
|
||||||
|
0x80 >> (node->bit & 0x07)))
|
||||||
|
node->r = new_node;
|
||||||
|
else
|
||||||
|
node->l = new_node;
|
||||||
|
|
||||||
|
return (new_node);
|
||||||
|
}
|
||||||
|
if (bitlen == differ_bit) {
|
||||||
|
if (bitlen < radix->maxbits && BIT_TEST(test_addr[bitlen >> 3],
|
||||||
|
0x80 >> (bitlen & 0x07)))
|
||||||
|
new_node->r = node;
|
||||||
|
else
|
||||||
|
new_node->l = node;
|
||||||
|
|
||||||
|
new_node->parent = node->parent;
|
||||||
|
if (node->parent == NULL)
|
||||||
|
radix->head = new_node;
|
||||||
|
else if (node->parent->r == node)
|
||||||
|
node->parent->r = new_node;
|
||||||
|
else
|
||||||
|
node->parent->l = new_node;
|
||||||
|
|
||||||
|
node->parent = new_node;
|
||||||
|
} else {
|
||||||
|
if ((glue = malloc(sizeof(*glue))) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
memset(glue, '\0', sizeof(*glue));
|
||||||
|
glue->bit = differ_bit;
|
||||||
|
glue->prefix = NULL;
|
||||||
|
glue->parent = node->parent;
|
||||||
|
glue->data = NULL;
|
||||||
|
radix->num_active_node++;
|
||||||
|
if (differ_bit < radix->maxbits &&
|
||||||
|
BIT_TEST(addr[differ_bit >> 3],
|
||||||
|
0x80 >> (differ_bit & 0x07))) {
|
||||||
|
glue->r = new_node;
|
||||||
|
glue->l = node;
|
||||||
|
} else {
|
||||||
|
glue->r = node;
|
||||||
|
glue->l = new_node;
|
||||||
|
}
|
||||||
|
new_node->parent = glue;
|
||||||
|
|
||||||
|
if (node->parent == NULL)
|
||||||
|
radix->head = glue;
|
||||||
|
else if (node->parent->r == node)
|
||||||
|
node->parent->r = glue;
|
||||||
|
else
|
||||||
|
node->parent->l = glue;
|
||||||
|
|
||||||
|
node->parent = glue;
|
||||||
|
}
|
||||||
|
return (new_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
radix_remove(radix_tree_t *radix, radix_node_t *node)
|
||||||
|
{
|
||||||
|
radix_node_t *parent, *child;
|
||||||
|
|
||||||
|
if (node->r && node->l) {
|
||||||
|
/*
|
||||||
|
* this might be a placeholder node -- have to check and make
|
||||||
|
* sure there is a prefix aossciated with it !
|
||||||
|
*/
|
||||||
|
if (node->prefix != NULL)
|
||||||
|
Deref_Prefix(node->prefix);
|
||||||
|
node->prefix = NULL;
|
||||||
|
/* Also I needed to clear data pointer -- masaki */
|
||||||
|
node->data = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node->r == NULL && node->l == NULL) {
|
||||||
|
parent = node->parent;
|
||||||
|
Deref_Prefix(node->prefix);
|
||||||
|
free(node);
|
||||||
|
radix->num_active_node--;
|
||||||
|
|
||||||
|
if (parent == NULL) {
|
||||||
|
radix->head = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parent->r == node) {
|
||||||
|
parent->r = NULL;
|
||||||
|
child = parent->l;
|
||||||
|
} else {
|
||||||
|
parent->l = NULL;
|
||||||
|
child = parent->r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent->prefix)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* we need to remove parent too */
|
||||||
|
if (parent->parent == NULL)
|
||||||
|
radix->head = child;
|
||||||
|
else if (parent->parent->r == parent)
|
||||||
|
parent->parent->r = child;
|
||||||
|
else
|
||||||
|
parent->parent->l = child;
|
||||||
|
|
||||||
|
child->parent = parent->parent;
|
||||||
|
free(parent);
|
||||||
|
radix->num_active_node--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (node->r)
|
||||||
|
child = node->r;
|
||||||
|
else
|
||||||
|
child = node->l;
|
||||||
|
|
||||||
|
parent = node->parent;
|
||||||
|
child->parent = parent;
|
||||||
|
|
||||||
|
Deref_Prefix(node->prefix);
|
||||||
|
free(node);
|
||||||
|
radix->num_active_node--;
|
||||||
|
|
||||||
|
if (parent == NULL) {
|
||||||
|
radix->head = child;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parent->r == node)
|
||||||
|
parent->r = child;
|
||||||
|
else
|
||||||
|
parent->l = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Local additions */
|
||||||
|
static void
|
||||||
|
sanitise_mask(unsigned char *addr, unsigned int masklen, unsigned int maskbits)
|
||||||
|
{
|
||||||
|
unsigned int i = masklen / 8;
|
||||||
|
unsigned int j = masklen % 8;
|
||||||
|
|
||||||
|
if (j != 0) {
|
||||||
|
addr[i] &= (~0) << (8 - j);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (; i < maskbits / 8; i++)
|
||||||
|
addr[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix_t
|
||||||
|
*prefix_pton(const char *string, long len, prefix_t *prefix, const char **errmsg)
|
||||||
|
{
|
||||||
|
char save[256], *cp, *ep;
|
||||||
|
struct addrinfo hints, *ai;
|
||||||
|
void *addr;
|
||||||
|
prefix_t *ret;
|
||||||
|
size_t slen;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
ret = NULL;
|
||||||
|
|
||||||
|
/* Copy the string to parse, because we modify it */
|
||||||
|
if ((slen = strlen(string) + 1) > sizeof(save)) {
|
||||||
|
*errmsg = "string too long";
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
memcpy(save, string, slen);
|
||||||
|
|
||||||
|
if ((cp = strchr(save, '/')) != NULL) {
|
||||||
|
if (len != -1 ) {
|
||||||
|
*errmsg = "masklen specified twice";
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
*cp++ = '\0';
|
||||||
|
len = strtol(cp, &ep, 10);
|
||||||
|
if (*cp == '\0' || *ep != '\0' || len < 0) {
|
||||||
|
*errmsg = "could not parse masklen";
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
/* More checks below */
|
||||||
|
}
|
||||||
|
memset(&hints, '\0', sizeof(hints));
|
||||||
|
hints.ai_flags = AI_NUMERICHOST;
|
||||||
|
|
||||||
|
if ((r = getaddrinfo(save, NULL, &hints, &ai)) != 0) {
|
||||||
|
snprintf(save, sizeof(save), "getaddrinfo: %s:",
|
||||||
|
gai_strerror(r));
|
||||||
|
*errmsg = save;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (ai == NULL || ai->ai_addr == NULL) {
|
||||||
|
*errmsg = "getaddrinfo returned no result";
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
switch (ai->ai_addr->sa_family) {
|
||||||
|
case AF_INET:
|
||||||
|
if (len == -1)
|
||||||
|
len = 32;
|
||||||
|
else if (len < 0 || len > 32)
|
||||||
|
goto out;
|
||||||
|
addr = &((struct sockaddr_in *) ai->ai_addr)->sin_addr;
|
||||||
|
sanitise_mask(addr, len, 32);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
if (len == -1)
|
||||||
|
len = 128;
|
||||||
|
else if (len < 0 || len > 128)
|
||||||
|
goto out;
|
||||||
|
addr = &((struct sockaddr_in6 *) ai->ai_addr)->sin6_addr;
|
||||||
|
sanitise_mask(addr, len, 128);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = New_Prefix2(ai->ai_addr->sa_family, addr, len, prefix);
|
||||||
|
if (ret == NULL)
|
||||||
|
*errmsg = "New_Prefix2 failed";
|
||||||
|
out:
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix_t
|
||||||
|
*prefix_from_blob(unsigned char *blob, int len, int prefixlen, prefix_t *prefix)
|
||||||
|
{
|
||||||
|
int family, maxprefix;
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 4:
|
||||||
|
/* Assume AF_INET */
|
||||||
|
family = AF_INET;
|
||||||
|
maxprefix = 32;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
/* Assume AF_INET6 */
|
||||||
|
family = AF_INET6;
|
||||||
|
maxprefix = 128;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Who knows? */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (prefixlen == -1)
|
||||||
|
prefixlen = maxprefix;
|
||||||
|
if (prefixlen < 0 || prefixlen > maxprefix)
|
||||||
|
return NULL;
|
||||||
|
return (New_Prefix2(family, blob, prefixlen, prefix));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
prefix_addr_ntop(prefix_t *prefix, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
return (inet_ntop(prefix->family, &prefix->add, buf, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
prefix_ntop(prefix_t *prefix, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char addrbuf[128];
|
||||||
|
|
||||||
|
if (prefix_addr_ntop(prefix, addrbuf, sizeof(addrbuf)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
snprintf(buf, len, "%s/%d", addrbuf, prefix->bitlen);
|
||||||
|
|
||||||
|
return (buf);
|
||||||
|
}
|
||||||
@@ -138,19 +138,19 @@ int create_pid_file(const char *pid_file)
|
|||||||
/* create pid file, and lock this file */
|
/* create pid file, and lock this file */
|
||||||
fd = open(pid_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
fd = open(pid_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
fprintf(stderr, "create pid file failed, %s", strerror(errno));
|
fprintf(stderr, "create pid file failed, %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
flags = fcntl(fd, F_GETFD);
|
flags = fcntl(fd, F_GETFD);
|
||||||
if (flags < 0) {
|
if (flags < 0) {
|
||||||
fprintf(stderr, "Could not get flags for PID file %s", pid_file);
|
fprintf(stderr, "Could not get flags for PID file %s\n", pid_file);
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
flags |= FD_CLOEXEC;
|
flags |= FD_CLOEXEC;
|
||||||
if (fcntl(fd, F_SETFD, flags) == -1) {
|
if (fcntl(fd, F_SETFD, flags) == -1) {
|
||||||
fprintf(stderr, "Could not set flags for PID file %s", pid_file);
|
fprintf(stderr, "Could not set flags for PID file %s\n", pid_file);
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +326,6 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (create_pid_file(pid_file) != 0) {
|
if (create_pid_file(pid_file) != 0) {
|
||||||
fprintf(stderr, "create pid file failed, %s\n", strerror(errno));
|
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user