mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-23 02:04:55 +02:00
- Response actions based on IP address from Jinmei Tatuya (Infoblox).
git-svn-id: file:///svn/unbound/trunk@4035 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
@@ -558,6 +558,267 @@ rnd_test(void)
|
||||
ub_randfree(r);
|
||||
}
|
||||
|
||||
#include "respip/respip.h"
|
||||
#include "services/localzone.h"
|
||||
#include "util/data/packed_rrset.h"
|
||||
typedef struct addr_action {char* ip; char* sact; enum respip_action act;}
|
||||
addr_action_t;
|
||||
|
||||
/** Utility function that verifies that the respip set has actions as expected */
|
||||
static void
|
||||
verify_respip_set_actions(struct respip_set* set, addr_action_t actions[],
|
||||
int actions_len)
|
||||
{
|
||||
int i = 0;
|
||||
struct rbtree_type* tree = respip_set_get_tree(set);
|
||||
for (i=0; i<actions_len; i++) {
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
socklen_t addrlen;
|
||||
struct resp_addr* node;
|
||||
netblockstrtoaddr(actions[i].ip, UNBOUND_DNS_PORT, &addr,
|
||||
&addrlen, &net);
|
||||
node = (struct resp_addr*)addr_tree_find(tree, &addr, addrlen, net);
|
||||
|
||||
/** we have the node and the node has the correct action
|
||||
* and has no data */
|
||||
unit_assert(node);
|
||||
unit_assert(actions[i].act ==
|
||||
resp_addr_get_action(node));
|
||||
unit_assert(resp_addr_get_rrset(node) == NULL);
|
||||
}
|
||||
unit_assert(actions_len && i == actions_len);
|
||||
unit_assert(actions_len == (int)tree->count);
|
||||
}
|
||||
|
||||
/** Global respip actions test; apply raw config data and verify that
|
||||
* all the nodes in the respip set, looked up by address, have expected
|
||||
* actions */
|
||||
static void
|
||||
respip_conf_actions_test(void)
|
||||
{
|
||||
addr_action_t config_response_ip[] = {
|
||||
{"192.0.1.0/24", "deny", respip_deny},
|
||||
{"192.0.2.0/24", "redirect", respip_redirect},
|
||||
{"192.0.3.0/26", "inform", respip_inform},
|
||||
{"192.0.4.0/27", "inform_deny", respip_inform_deny},
|
||||
{"2001:db8:1::/48", "always_transparent", respip_always_transparent},
|
||||
{"2001:db8:2::/49", "always_refuse", respip_always_refuse},
|
||||
{"2001:db8:3::/50", "always_nxdomain", respip_always_nxdomain},
|
||||
};
|
||||
int i;
|
||||
struct respip_set* set = respip_set_create();
|
||||
struct config_file cfg;
|
||||
int clen = sizeof(config_response_ip) / sizeof(addr_action_t);
|
||||
|
||||
unit_assert(set);
|
||||
unit_show_feature("global respip config actions apply");
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
for(i=0; i<clen; i++) {
|
||||
char* ip = strdup(config_response_ip[i].ip);
|
||||
char* sact = strdup(config_response_ip[i].sact);
|
||||
unit_assert(ip && sact);
|
||||
if(!cfg_str2list_insert(&cfg.respip_actions, ip, sact))
|
||||
unit_assert(0);
|
||||
}
|
||||
unit_assert(respip_global_apply_cfg(set, &cfg));
|
||||
verify_respip_set_actions(set, config_response_ip, clen);
|
||||
}
|
||||
|
||||
/** Per-view respip actions test; apply raw configuration with two views
|
||||
* and verify that actions are as expected in respip sets of both views */
|
||||
static void
|
||||
respip_view_conf_actions_test(void)
|
||||
{
|
||||
addr_action_t config_response_ip_view1[] = {
|
||||
{"192.0.1.0/24", "deny", respip_deny},
|
||||
{"192.0.2.0/24", "redirect", respip_redirect},
|
||||
{"192.0.3.0/26", "inform", respip_inform},
|
||||
{"192.0.4.0/27", "inform_deny", respip_inform_deny},
|
||||
};
|
||||
addr_action_t config_response_ip_view2[] = {
|
||||
{"2001:db8:1::/48", "always_transparent", respip_always_transparent},
|
||||
{"2001:db8:2::/49", "always_refuse", respip_always_refuse},
|
||||
{"2001:db8:3::/50", "always_nxdomain", respip_always_nxdomain},
|
||||
};
|
||||
int i;
|
||||
struct config_file cfg;
|
||||
int clen1 = sizeof(config_response_ip_view1) / sizeof(addr_action_t);
|
||||
int clen2 = sizeof(config_response_ip_view2) / sizeof(addr_action_t);
|
||||
struct config_view* cv1;
|
||||
struct config_view* cv2;
|
||||
int have_respip_cfg = 0;
|
||||
struct views* views = NULL;
|
||||
struct view* v = NULL;
|
||||
|
||||
unit_show_feature("per-view respip config actions apply");
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cv1 = (struct config_view*)calloc(1, sizeof(struct config_view));
|
||||
cv2 = (struct config_view*)calloc(1, sizeof(struct config_view));
|
||||
unit_assert(cv1 && cv2);
|
||||
cv1->name = strdup("view1");
|
||||
cv2->name = strdup("view2");
|
||||
unit_assert(cv1->name && cv2->name);
|
||||
cv1->next = cv2;
|
||||
cfg.views = cv1;
|
||||
|
||||
for(i=0; i<clen1; i++) {
|
||||
char* ip = strdup(config_response_ip_view1[i].ip);
|
||||
char* sact = strdup(config_response_ip_view1[i].sact);
|
||||
unit_assert(ip && sact);
|
||||
if(!cfg_str2list_insert(&cv1->respip_actions, ip, sact))
|
||||
unit_assert(0);
|
||||
}
|
||||
for(i=0; i<clen2; i++) {
|
||||
char* ip = strdup(config_response_ip_view2[i].ip);
|
||||
char* sact = strdup(config_response_ip_view2[i].sact);
|
||||
unit_assert(ip && sact);
|
||||
if(!cfg_str2list_insert(&cv2->respip_actions, ip, sact))
|
||||
unit_assert(0);
|
||||
}
|
||||
views = views_create();
|
||||
unit_assert(views);
|
||||
unit_assert(views_apply_cfg(views, &cfg));
|
||||
unit_assert(respip_views_apply_cfg(views, &cfg, &have_respip_cfg));
|
||||
|
||||
/* now verify the respip sets in each view */
|
||||
v = views_find_view(views, "view1", 0);
|
||||
unit_assert(v);
|
||||
verify_respip_set_actions(v->respip_set, config_response_ip_view1, clen1);
|
||||
v = views_find_view(views, "view2", 0);
|
||||
unit_assert(v);
|
||||
verify_respip_set_actions(v->respip_set, config_response_ip_view2, clen2);
|
||||
}
|
||||
|
||||
typedef struct addr_data {char* ip; char* data;} addr_data_t;
|
||||
|
||||
/** find the respip address node in the specified tree (by address lookup)
|
||||
* and verify type and address of the specified rdata (by index) in this
|
||||
* node's rrset */
|
||||
static void
|
||||
verify_rrset(struct respip_set* set, const char* ipstr,
|
||||
const char* rdatastr, size_t rdi, uint16_t type)
|
||||
{
|
||||
struct sockaddr_storage addr;
|
||||
int net;
|
||||
char buf[65536];
|
||||
socklen_t addrlen;
|
||||
struct rbtree_type* tree;
|
||||
struct resp_addr* node;
|
||||
const struct ub_packed_rrset_key* rrs;
|
||||
|
||||
netblockstrtoaddr(ipstr, UNBOUND_DNS_PORT, &addr, &addrlen, &net);
|
||||
tree = respip_set_get_tree(set);
|
||||
node = (struct resp_addr*)addr_tree_find(tree, &addr, addrlen, net);
|
||||
unit_assert(node);
|
||||
unit_assert((rrs = resp_addr_get_rrset(node)));
|
||||
unit_assert(ntohs(rrs->rk.type) == type);
|
||||
packed_rr_to_string((struct ub_packed_rrset_key*)rrs,
|
||||
rdi, 0, buf, sizeof(buf));
|
||||
unit_assert(strstr(buf, rdatastr));
|
||||
}
|
||||
|
||||
/** Dataset used to test redirect rrset initialization for both
|
||||
* global and per-view respip redirect configuration */
|
||||
static addr_data_t config_response_ip_data[] = {
|
||||
{"192.0.1.0/24", "A 1.2.3.4"},
|
||||
{"192.0.1.0/24", "A 11.12.13.14"},
|
||||
{"192.0.2.0/24", "CNAME www.example.com."},
|
||||
{"2001:db8:1::/48", "AAAA 2001:db8:1::2:1"},
|
||||
};
|
||||
|
||||
/** Populate raw respip redirect config data, used for both global and
|
||||
* view-based respip redirect test case */
|
||||
static void
|
||||
cfg_insert_respip_data(struct config_str2list** respip_actions,
|
||||
struct config_str2list** respip_data)
|
||||
{
|
||||
int clen = sizeof(config_response_ip_data) / sizeof(addr_data_t);
|
||||
int i = 0;
|
||||
|
||||
/* insert actions (duplicate netblocks don't matter) */
|
||||
for(i=0; i<clen; i++) {
|
||||
char* ip = strdup(config_response_ip_data[i].ip);
|
||||
char* sact = strdup("redirect");
|
||||
unit_assert(ip && sact);
|
||||
if(!cfg_str2list_insert(respip_actions, ip, sact))
|
||||
unit_assert(0);
|
||||
}
|
||||
/* insert data */
|
||||
for(i=0; i<clen; i++) {
|
||||
char* ip = strdup(config_response_ip_data[i].ip);
|
||||
char* data = strdup(config_response_ip_data[i].data);
|
||||
unit_assert(ip && data);
|
||||
if(!cfg_str2list_insert(respip_data, ip, data))
|
||||
unit_assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
/** Test global respip redirect w/ data directives */
|
||||
static void
|
||||
respip_conf_data_test(void)
|
||||
{
|
||||
struct respip_set* set = respip_set_create();
|
||||
struct config_file cfg;
|
||||
|
||||
unit_show_feature("global respip config data apply");
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
|
||||
cfg_insert_respip_data(&cfg.respip_actions, &cfg.respip_data);
|
||||
|
||||
/* apply configuration and verify rrsets */
|
||||
unit_assert(respip_global_apply_cfg(set, &cfg));
|
||||
verify_rrset(set, "192.0.1.0/24", "1.2.3.4", 0, LDNS_RR_TYPE_A);
|
||||
verify_rrset(set, "192.0.1.0/24", "11.12.13.14", 1, LDNS_RR_TYPE_A);
|
||||
verify_rrset(set, "192.0.2.0/24", "www.example.com", 0, LDNS_RR_TYPE_CNAME);
|
||||
verify_rrset(set, "2001:db8:1::/48", "2001:db8:1::2:1", 0, LDNS_RR_TYPE_AAAA);
|
||||
}
|
||||
|
||||
/** Test per-view respip redirect w/ data directives */
|
||||
static void
|
||||
respip_view_conf_data_test(void)
|
||||
{
|
||||
struct config_file cfg;
|
||||
struct config_view* cv;
|
||||
int have_respip_cfg = 0;
|
||||
struct views* views = NULL;
|
||||
struct view* v = NULL;
|
||||
|
||||
unit_show_feature("per-view respip config data apply");
|
||||
memset(&cfg, 0, sizeof(cfg));
|
||||
cv = (struct config_view*)calloc(1, sizeof(struct config_view));
|
||||
unit_assert(cv);
|
||||
cv->name = strdup("view1");
|
||||
unit_assert(cv->name);
|
||||
cfg.views = cv;
|
||||
cfg_insert_respip_data(&cv->respip_actions, &cv->respip_data);
|
||||
views = views_create();
|
||||
unit_assert(views);
|
||||
unit_assert(views_apply_cfg(views, &cfg));
|
||||
|
||||
/* apply configuration and verify rrsets */
|
||||
unit_assert(respip_views_apply_cfg(views, &cfg, &have_respip_cfg));
|
||||
v = views_find_view(views, "view1", 0);
|
||||
unit_assert(v);
|
||||
verify_rrset(v->respip_set, "192.0.1.0/24", "1.2.3.4",
|
||||
0, LDNS_RR_TYPE_A);
|
||||
verify_rrset(v->respip_set, "192.0.1.0/24", "11.12.13.14",
|
||||
1, LDNS_RR_TYPE_A);
|
||||
verify_rrset(v->respip_set, "192.0.2.0/24", "www.example.com",
|
||||
0, LDNS_RR_TYPE_CNAME);
|
||||
verify_rrset(v->respip_set, "2001:db8:1::/48", "2001:db8:1::2:1",
|
||||
0, LDNS_RR_TYPE_AAAA);
|
||||
}
|
||||
|
||||
/** respip unit tests */
|
||||
static void respip_test(void)
|
||||
{
|
||||
respip_view_conf_data_test();
|
||||
respip_conf_data_test();
|
||||
respip_view_conf_actions_test();
|
||||
respip_conf_actions_test();
|
||||
}
|
||||
|
||||
void unit_show_func(const char* file, const char* func)
|
||||
{
|
||||
printf("test %s:%s\n", file, func);
|
||||
@@ -604,6 +865,7 @@ main(int argc, char* argv[])
|
||||
checklock_start();
|
||||
neg_test();
|
||||
rnd_test();
|
||||
respip_test();
|
||||
verify_test();
|
||||
net_test();
|
||||
config_memsize_test();
|
||||
|
||||
Reference in New Issue
Block a user