Initial commit for interface based ACL.

This commit is contained in:
George Thessalonikefs 2021-08-19 16:12:19 +02:00
parent 007db2c327
commit c30bdff939
32 changed files with 4865 additions and 4259 deletions

View File

@ -139,7 +139,7 @@ validator/val_sigcrypt.c validator/val_utils.c dns64/dns64.c \
edns-subnet/edns-subnet.c edns-subnet/subnetmod.c \
edns-subnet/addrtree.c edns-subnet/subnet-whitelist.c \
$(CACHEDB_SRC) respip/respip.c $(CHECKLOCK_SRC) \
$(DNSTAP_SRC) $(DNSCRYPT_SRC) $(IPSECMOD_SRC) $(IPSET_SRC)
$(DNSTAP_SRC) $(DNSCRYPT_SRC) $(IPSECMOD_SRC) $(IPSET_SRC) daemon/acl_list.c
COMMON_OBJ_WITHOUT_NETCALL=dns.lo infra.lo rrset.lo dname.lo msgencode.lo \
as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \
iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \
@ -154,7 +154,7 @@ val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo
COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \
outside_network.lo
outside_network.lo acl_list.lo
COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo
# set to $COMMON_OBJ or to "" if --enableallsymbols
COMMON_OBJ_ALL_SYMBOLS=@COMMON_OBJ_ALL_SYMBOLS@
@ -186,9 +186,9 @@ readhex.lo testpkts.lo unitldns.lo unitecs.lo unitauth.lo unitzonemd.lo \
unittcpreuse.lo
UNITTEST_OBJ_LINK=$(UNITTEST_OBJ) worker_cb.lo $(COMMON_OBJ) $(SLDNS_OBJ) \
$(COMPAT_OBJ)
DAEMON_SRC=daemon/acl_list.c daemon/cachedump.c daemon/daemon.c \
DAEMON_SRC=daemon/cachedump.c daemon/daemon.c \
daemon/remote.c daemon/stats.c daemon/unbound.c daemon/worker.c @WIN_DAEMON_SRC@
DAEMON_OBJ=acl_list.lo cachedump.lo daemon.lo \
DAEMON_OBJ=cachedump.lo daemon.lo \
shm_main.lo remote.lo stats.lo unbound.lo \
worker.lo @WIN_DAEMON_OBJ@
DAEMON_OBJ_LINK=$(DAEMON_OBJ) $(COMMON_OBJ_ALL_SYMBOLS) $(SLDNS_OBJ) \

View File

@ -46,9 +46,10 @@
#include "util/config_file.h"
#include "util/net_help.h"
#include "services/localzone.h"
#include "services/listen_dnsport.h"
#include "sldns/str2wire.h"
struct acl_list*
struct acl_list*
acl_list_create(void)
{
struct acl_list* acl = (struct acl_list*)calloc(1,
@ -63,10 +64,10 @@ acl_list_create(void)
return acl;
}
void
void
acl_list_delete(struct acl_list* acl)
{
if(!acl)
if(!acl)
return;
regional_destroy(acl->region);
free(acl);
@ -74,8 +75,8 @@ acl_list_delete(struct acl_list* acl)
/** insert new address into acl_list structure */
static struct acl_addr*
acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
socklen_t addrlen, int net, enum acl_access control,
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_zero(acl->region,
@ -90,6 +91,31 @@ acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
return node;
}
/** parse str to acl_access enum */
static int
parse_acl_access(const char* str, enum acl_access* control)
{
if(strcmp(str, "allow") == 0)
*control = acl_allow;
else if(strcmp(str, "deny") == 0)
*control = acl_deny;
else if(strcmp(str, "refuse") == 0)
*control = acl_refuse;
else if(strcmp(str, "deny_non_local") == 0)
*control = acl_deny_non_local;
else if(strcmp(str, "refuse_non_local") == 0)
*control = acl_refuse_non_local;
else if(strcmp(str, "allow_snoop") == 0)
*control = acl_allow_snoop;
else if(strcmp(str, "allow_setrd") == 0)
*control = acl_allow_setrd;
else {
log_err("access control type %s unknown", str);
return 0;
}
return 1;
}
/** apply acl_list string */
static int
acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
@ -99,29 +125,14 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
int net;
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 if(strcmp(s2, "deny_non_local") == 0)
control = acl_deny_non_local;
else if(strcmp(s2, "refuse_non_local") == 0)
control = acl_refuse_non_local;
else if(strcmp(s2, "allow_snoop") == 0)
control = acl_allow_snoop;
else if(strcmp(s2, "allow_setrd") == 0)
control = acl_allow_setrd;
else {
log_err("access control type %s unknown", str);
if(!parse_acl_access(s2, &control)) {
return 0;
}
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
log_err("cannot parse access control: %s %s", str, s2);
return 0;
}
if(!acl_list_insert(acl, &addr, addrlen, net, control,
if(!acl_list_insert(acl, &addr, addrlen, net, control,
complain_duplicates)) {
log_err("out of memory");
return 0;
@ -131,19 +142,27 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
/** find or create node (NULL on parse or error) */
static struct acl_addr*
acl_find_or_create(struct acl_list* acl, const char* str)
acl_find_or_create(struct acl_list* acl, const char* str, int is_interface,
int port)
{
struct acl_addr* node;
struct sockaddr_storage addr;
int net;
socklen_t addrlen;
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
log_err("cannot parse netblock: %s", str);
return NULL;
int net = (str_is_ip6(str)?128:32);
if(is_interface) {
if(!extstrtoaddr(str, &addr, &addrlen, port)) {
log_err("cannot parse interface: %s", str);
return NULL;
}
} else {
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
log_err("cannot parse netblock: %s", str);
return NULL;
}
}
/* find or create node */
if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr,
addrlen, net))) {
addrlen, net)) && !is_interface) {
/* create node, type 'allow' since otherwise tags are
* pointless, can override with specific access-control: cfg */
if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr,
@ -155,13 +174,54 @@ acl_find_or_create(struct acl_list* acl, const char* str)
return node;
}
/** apply acl_interface string */
static int
acl_interface_str_cfg(struct acl_list* acl_interface, const char* interface,
const char* s2, int port)
{
struct acl_addr* node;
enum acl_access control;
if(!parse_acl_access(s2, &control)) {
return 0;
}
if(!(node=acl_find_or_create(acl_interface, interface, 1, port))) {
log_err("cannot update ACL on non-existing interface: %s %d",
interface, port);
return 0;
}
node->control = control;
return 1;
}
struct acl_addr*
acl_interface_insert(struct acl_list* acl_interface, const char* interface,
const char* s2, int port)
{
struct acl_addr* node;
struct sockaddr_storage addr;
socklen_t addrlen;
enum acl_access control;
int net = (str_is_ip6(interface)?128:32);
if(!parse_acl_access(s2, &control)) {
return NULL;
}
if((node=acl_find_or_create(acl_interface, interface, 1, port))) {
return node;
}
if(!extstrtoaddr(interface, &addr, &addrlen, port)) {
log_err("cannot parse access control: %s %s", interface, s2);
return NULL;
}
return acl_list_insert(acl_interface, &addr, addrlen, net, control, 1);
}
/** apply acl_tag string */
static int
acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
size_t bitmaplen)
size_t bitmaplen, int is_interface, int port)
{
struct acl_addr* node;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create(acl, str, is_interface, port)))
return 0;
node->taglen = bitmaplen;
node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen);
@ -175,10 +235,10 @@ acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
/** apply acl_view string */
static int
acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
struct views* vs)
struct views* vs, int is_interface, int port)
{
struct acl_addr* node;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create(acl, str, is_interface, port)))
return 0;
node->view = views_find_view(vs, str2, 0 /* get read lock*/);
if(!node->view) {
@ -192,12 +252,13 @@ acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
/** apply acl_tag_action string */
static int
acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg,
const char* str, const char* tag, const char* action)
const char* str, const char* tag, const char* action,
int is_interface, int port)
{
struct acl_addr* node;
int tagid;
enum localzone_type t;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create(acl, str, is_interface, port)))
return 0;
/* allocate array if not yet */
if(!node->tag_actions) {
@ -281,12 +342,13 @@ check_data(const char* data, const struct config_strlist* head)
/** apply acl_tag_data string */
static int
acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
const char* str, const char* tag, const char* data)
const char* str, const char* tag, const char* data,
int is_interface, int port)
{
struct acl_addr* node;
int tagid;
char* dupdata;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create(acl, str, is_interface, port)))
return 0;
/* allocate array if not yet */
if(!node->tag_datas) {
@ -329,11 +391,11 @@ acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
}
/** read acl_list config */
static int
read_acl_list(struct acl_list* acl, struct config_file* cfg)
static int
read_acl_list(struct acl_list* acl, struct config_str2list* acls)
{
struct config_str2list* p;
for(p = cfg->acls; p; p = p->next) {
for(p = acls; p; p = p->next) {
log_assert(p->str && p->str2);
if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
return 0;
@ -341,15 +403,38 @@ read_acl_list(struct acl_list* acl, struct config_file* cfg)
return 1;
}
/** read acl tags config */
static int
read_acl_tags(struct acl_list* acl, struct config_file* cfg)
/** read acl view config */
static int
read_acl_view(struct acl_list* acl, struct config_str2list** acl_view,
struct views* v)
{
struct config_strbytelist* np, *p = cfg->acl_tags;
cfg->acl_tags = NULL;
struct config_str2list* np, *p = *acl_view;
*acl_view = NULL;
while(p) {
log_assert(p->str && p->str2);
if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len)) {
if(!acl_list_view_cfg(acl, p->str, p->str2, v, 0, 0)) {
config_deldblstrlist(p);
return 0;
}
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tags config */
static int
read_acl_tags(struct acl_list* acl, struct config_strbytelist** acl_tags)
{
struct config_strbytelist* np, *p = *acl_tags;
*acl_tags = NULL;
while(p) {
log_assert(p->str && p->str2);
if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len, 0, 0)) {
config_del_strbytelist(p);
return 0;
}
@ -363,38 +448,18 @@ read_acl_tags(struct acl_list* acl, struct config_file* cfg)
return 1;
}
/** read acl view config */
static int
read_acl_view(struct acl_list* acl, struct config_file* cfg, struct views* v)
{
struct config_str2list* np, *p = cfg->acl_view;
cfg->acl_view = NULL;
while(p) {
log_assert(p->str && p->str2);
if(!acl_list_view_cfg(acl, p->str, p->str2, v)) {
return 0;
}
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tag actions config */
static int
read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg)
static int
read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg,
struct config_str3list** acl_tag_actions)
{
struct config_str3list* p, *np;
p = cfg->acl_tag_actions;
cfg->acl_tag_actions = NULL;
p = *acl_tag_actions;
*acl_tag_actions = NULL;
while(p) {
log_assert(p->str && p->str2 && p->str3);
if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2,
p->str3)) {
p->str3, 0, 0)) {
config_deltrplstrlist(p);
return 0;
}
@ -410,15 +475,17 @@ read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg)
}
/** read acl tag datas config */
static int
read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg)
static int
read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg,
struct config_str3list** acl_tag_datas)
{
struct config_str3list* p, *np;
p = cfg->acl_tag_datas;
cfg->acl_tag_datas = NULL;
p = *acl_tag_datas;
*acl_tag_datas = NULL;
while(p) {
log_assert(p->str && p->str2 && p->str3);
if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3)) {
if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3,
0, 0)) {
config_deltrplstrlist(p);
return 0;
}
@ -433,30 +500,27 @@ read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg)
return 1;
}
int
int
acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
struct views* v)
{
regional_free_all(acl->region);
addr_tree_init(&acl->tree);
if(!read_acl_list(acl, cfg))
if(!read_acl_list(acl, cfg->acls))
return 0;
if(!read_acl_view(acl, cfg, v))
if(!read_acl_view(acl, &cfg->acl_view, v))
return 0;
if(!read_acl_tags(acl, cfg))
if(!read_acl_tags(acl, &cfg->acl_tags))
return 0;
if(!read_acl_tag_actions(acl, cfg))
if(!read_acl_tag_actions(acl, cfg, &cfg->acl_tag_actions))
return 0;
if(!read_acl_tag_datas(acl, cfg))
if(!read_acl_tag_datas(acl, cfg, &cfg->acl_tag_datas))
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;
/* the 'refuse' defaults for /0 are now done per interface instead */
if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
return 0;
if(cfg->do_ip6) {
if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0))
return 0;
if(!acl_list_str_cfg(acl, "::1", "allow", 0))
return 0;
if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
@ -466,7 +530,221 @@ acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
return 1;
}
enum acl_access
int
acl_interface_compare(const void* k1, const void* k2)
{
struct addr_tree_node* n1 = (struct addr_tree_node*)k1;
struct addr_tree_node* n2 = (struct addr_tree_node*)k2;
return sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr,
n2->addrlen);
/* We don't care about comparing node->net. All addresses in the
* acl_interface tree have either 32 (ipv4) or 128 (ipv6). */
}
void
acl_interface_init(struct acl_list* acl_interface)
{
regional_free_all(acl_interface->region);
/* We want comparison in the tree to include both IP and port.
* Initialise with the given compare fucntion but keep treating it as
* an addr_tree. */
rbtree_init(&acl_interface->tree, &acl_interface_compare);
}
static int
read_acl_interface_action(struct acl_list* acl_interface,
struct config_str2list* acls, int port)
{
struct config_str2list* p;
for(p = acls; p; p = p->next) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif))
return 0;
for(i = 0; i<num_resif; i++) {
if(!acl_interface_str_cfg(acl_interface, resif[i], p->str2, port)){
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
}
return 1;
}
/** read acl view config for interface */
static int
read_acl_interface_view(struct acl_list* acl_interface,
struct config_str2list** acl_view,
struct views* v, int port)
{
struct config_str2list* np, *p = *acl_view;
*acl_view = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_deldblstrlist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_view_cfg(acl_interface, p->str, p->str2,
v, 1, port)) {
config_del_strarray(resif, num_resif);
config_deldblstrlist(p);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tags config for interface */
static int
read_acl_interface_tags(struct acl_list* acl_interface,
struct config_strbytelist** acl_tags, int port)
{
struct config_strbytelist* np, *p = *acl_tags;
*acl_tags = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_del_strbytelist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_tags_cfg(acl_interface, p->str, p->str2,
p->str2len, 1, port)) {
config_del_strbytelist(p);
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tag actions config for interface*/
static int
read_acl_interface_tag_actions(struct acl_list* acl_interface,
struct config_file* cfg,
struct config_str3list** acl_tag_actions, int port)
{
struct config_str3list* p, *np;
p = *acl_tag_actions;
*acl_tag_actions = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2 && p->str3);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_deltrplstrlist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_tag_action_cfg(acl_interface, cfg, p->str,
p->str2, p->str3, 1, port)) {
config_deltrplstrlist(p);
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p->str3);
free(p);
p = np;
}
return 1;
}
/** read acl tag datas config for interface */
static int
read_acl_interface_tag_datas(struct acl_list* acl_interface,
struct config_file* cfg,
struct config_str3list** acl_tag_datas, int port)
{
struct config_str3list* p, *np;
p = *acl_tag_datas;
*acl_tag_datas = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2 && p->str3);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_deltrplstrlist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_tag_data_cfg(acl_interface, cfg, p->str,
p->str2, p->str3, 1, port)) {
config_deltrplstrlist(p);
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p->str3);
free(p);
p = np;
}
return 1;
}
int
acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
struct views* v)
{
if(!read_acl_interface_action(acl_interface, cfg->interface_actions,
cfg->port))
return 0;
if(!read_acl_interface_view(acl_interface, &cfg->interface_view, v,
cfg->port))
return 0;
if(!read_acl_interface_tags(acl_interface, &cfg->interface_tags,
cfg->port))
return 0;
if(!read_acl_interface_tag_actions(acl_interface, cfg,
&cfg->interface_tag_actions, cfg->port))
return 0;
if(!read_acl_interface_tag_datas(acl_interface, cfg,
&cfg->interface_tag_datas, cfg->port))
return 0;
addr_tree_init_parents(&acl_interface->tree);
return 1;
}
enum acl_access
acl_get_control(struct acl_addr* acl)
{
if(acl) return acl->control;
@ -481,7 +759,7 @@ acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
addr, addrlen);
}
size_t
size_t
acl_list_get_mem(struct acl_list* acl)
{
if(!acl) return 0;

View File

@ -36,7 +36,7 @@
/**
* \file
*
* This file keeps track of the list of clients that are allowed to
* This file keeps track of the list of clients that are allowed to
* access the server.
*/
@ -74,7 +74,7 @@ enum acl_access {
struct acl_list {
/** regional for allocation */
struct regional* region;
/**
/**
* Tree of the addresses that are allowed/blocked.
* contents of type acl_addr.
*/
@ -108,7 +108,7 @@ struct acl_addr {
};
/**
* Create acl structure
* Create acl structure
* @return new structure or NULL on error.
*/
struct acl_list* acl_list_create(void);
@ -119,6 +119,19 @@ struct acl_list* acl_list_create(void);
*/
void acl_list_delete(struct acl_list* acl);
/**
* Insert interface in the alc_list. This should happen when the listening
* interface is setup.
* @param acl_interface: acl_list to insert to.
* @param interface: interface (IP) in string format.
* @param s2: acl_access in string format.
* @param port: default port.
* @return new structure or NULL on error.
*/
struct acl_addr*
acl_interface_insert(struct acl_list* acl_interface, const char* interface,
const char* s2, int port);
/**
* Process access control config.
* @param acl: where to store.
@ -129,6 +142,25 @@ void acl_list_delete(struct acl_list* acl);
int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
struct views* v);
/** compare ACL interface "addr_tree" nodes (+port) */
int acl_interface_compare(const void* k1, const void* k2);
/**
* Initialise (also clean) the acl_interface struct.
* @param acl_interface: where to store.
*/
void acl_interface_init(struct acl_list* acl_interface);
/**
* Process interface control config.
* @param acl_interface: where to store.
* @param cfg: config options.
* @param v: views structure
* @return 0 on error.
*/
int acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
struct views* v);
/**
* Lookup access control status for acl structure.
* @param acl: structure for acl storage.

View File

@ -271,8 +271,17 @@ daemon_init(void)
free(daemon);
return NULL;
}
daemon->acl_interface = acl_list_create();
if(!daemon->acl_interface) {
acl_list_delete(daemon->acl);
edns_known_options_delete(daemon->env);
free(daemon->env);
free(daemon);
return NULL;
}
daemon->tcl = tcl_list_create();
if(!daemon->tcl) {
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
edns_known_options_delete(daemon->env);
free(daemon->env);
@ -284,6 +293,7 @@ daemon_init(void)
log_err("gettimeofday: %s", strerror(errno));
daemon->time_last_stat = daemon->time_boot;
if((daemon->env->auth_zones = auth_zones_create()) == 0) {
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
@ -293,6 +303,7 @@ daemon_init(void)
}
if(!(daemon->env->edns_strings = edns_strings_create())) {
auth_zones_delete(daemon->env->auth_zones);
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
@ -320,6 +331,8 @@ daemon_open_shared_ports(struct daemon* daemon)
free(daemon->ports);
daemon->ports = NULL;
}
/* clean acl_interface */
acl_interface_init(daemon->acl_interface);
if(!resolve_interface_names(daemon->cfg->ifs,
daemon->cfg->num_ifs, NULL, &resif, &num_resif))
return 0;
@ -329,7 +342,8 @@ daemon_open_shared_ports(struct daemon* daemon)
daemon->reuseport = 1;
#endif
/* try to use reuseport */
p0 = listening_ports_open(daemon->cfg, resif, num_resif, &daemon->reuseport);
p0 = listening_ports_open(daemon->cfg, daemon->acl_interface,
resif, num_resif, &daemon->reuseport);
if(!p0) {
listening_ports_free(p0);
config_del_strarray(resif, num_resif);
@ -355,6 +369,7 @@ daemon_open_shared_ports(struct daemon* daemon)
for(i=1; i<daemon->num_ports; i++) {
if(!(daemon->ports[i]=
listening_ports_open(daemon->cfg,
daemon->acl_interface,
resif, num_resif,
&daemon->reuseport))
|| !daemon->reuseport ) {
@ -604,6 +619,9 @@ daemon_fork(struct daemon* daemon)
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->views))
fatal_exit("Could not setup access control list");
if(!acl_interface_apply_cfg(daemon->acl_interface, daemon->cfg,
daemon->views))
fatal_exit("Could not setup interface control list");
if(!tcl_list_apply_cfg(daemon->tcl, daemon->cfg))
fatal_exit("Could not setup TCP connection limits");
if(daemon->cfg->dnscrypt) {
@ -780,6 +798,7 @@ daemon_delete(struct daemon* daemon)
ub_randfree(daemon->rand);
alloc_clear(&daemon->superalloc);
acl_list_delete(daemon->acl);
acl_list_delete(daemon->acl_interface);
tcl_list_delete(daemon->tcl);
listen_desetup_locks();
free(daemon->chroot);

View File

@ -113,6 +113,8 @@ struct daemon {
struct module_stack mods;
/** access control, which client IPs are allowed to connect */
struct acl_list* acl;
/** access control, which interfaces are allowed to connect */
struct acl_list* acl_interface;
/** TCP connection limit, limit connections from client IPs */
struct tcl_list* tcl;
/** local authority zones */

View File

@ -1330,6 +1330,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
#endif
acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr,
repinfo->addrlen);
/* If there is no ACL based on client IP use the interface ACL. */
if(!acladdr) {
acladdr = c->socket->acl;
}
acl = acl_get_control(acladdr);
if((ret=deny_refuse_all(c, acl, worker, repinfo, acladdr,

View File

@ -1960,7 +1960,7 @@ static int dtio_open_output_tcp(struct dt_io_thread* dtio)
memset(&addr, 0, sizeof(addr));
addrlen = (socklen_t)sizeof(addr);
if(!extstrtoaddr(dtio->ip_str, &addr, &addrlen)) {
if(!extstrtoaddr(dtio->ip_str, &addr, &addrlen, UNBOUND_DNS_PORT)) {
log_err("could not parse IP '%s'", dtio->ip_str);
return 0;
}

View File

@ -272,7 +272,7 @@ static int make_tcp_accept(char* ip)
memset(&addr, 0, sizeof(addr));
len = (socklen_t)sizeof(addr);
if(!extstrtoaddr(ip, &addr, &len)) {
if(!extstrtoaddr(ip, &addr, &len, UNBOUND_DNS_PORT)) {
log_err("could not parse IP '%s'", ip);
return -1;
}

View File

@ -17,7 +17,7 @@ server:
# whitespace is not necessary, but looks cleaner.
# verbosity number, 0 is least verbose. 1 is default.
verbosity: 1
# verbosity: 1
# print statistics to the log (for every thread) every N seconds.
# Set to "" or 0 to disable. Default is disabled.
@ -50,6 +50,7 @@ server:
# interface: 192.0.2.154
# interface: 192.0.2.154@5003
# interface: 2001:DB8::5
# interface: eth0@5003
# enable this feature to copy the source address of queries to reply.
# Socket options are not supported on all platforms. experimental.

View File

@ -118,7 +118,7 @@ The number of threads to create to serve clients. Use 1 for no threading.
.B port: \fI<port number>
The port number, default 53, on which the server responds to queries.
.TP
.B interface: \fI<ip address[@port]>
.B interface: \fI<ip address or interface name [@port]>
Interface to use to connect to the network. This interface is listened to
for queries from clients, and answers to clients are given from it.
Can be given multiple times to work on several interfaces. If none are
@ -129,7 +129,7 @@ A port number can be specified with @port (without spaces between
interface and port number), if not specified the default port (from
\fBport\fR) is used.
.TP
.B ip\-address: \fI<ip address[@port]>
.B ip\-address: \fI<ip address or interface name [@port]>
Same as interface: (for ease of compatibility with nsd.conf).
.TP
.B interface\-automatic: \fI<yes or no>
@ -1823,9 +1823,11 @@ section for options. To setup the correct self\-signed certificates use the
The option is used to enable remote control, default is "no".
If turned off, the server does not listen for control commands.
.TP 5
.B control\-interface: \fI<ip address or path>
.B control\-interface: \fI<ip address or interface name or path>
Give IPv4 or IPv6 addresses or local socket path to listen on for
control commands.
If an interface name is used instead of an ip address, the list of ip addresses
on that interface are used.
By default localhost (127.0.0.1 and ::1) is listened to.
Use 0.0.0.0 and ::0 to listen to all interfaces.
If you change this and permissions have been dropped, you must restart

View File

@ -100,7 +100,7 @@ ah(struct delegpt* dp, const char* sv, const char* ip)
return 0;
}
if(!delegpt_add_ns_mlc(dp, dname, 0, NULL, UNBOUND_DNS_PORT) ||
!extstrtoaddr(ip, &addr, &addrlen) ||
!extstrtoaddr(ip, &addr, &addrlen, UNBOUND_DNS_PORT) ||
!delegpt_add_target_mlc(dp, dname, dname_len,
&addr, addrlen, 0, 0)) {
free(dname);

View File

@ -951,7 +951,7 @@ ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
lock_basic_unlock(&ctx->cfglock);
/* check syntax for addr */
if(!extstrtoaddr(addr, &storage, &stlen)) {
if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) {
errno=EINVAL;
return UB_SYNTAX;
}
@ -1031,7 +1031,7 @@ int ub_ctx_set_stub(struct ub_ctx* ctx, const char* zone, const char* addr,
if(addr) {
struct sockaddr_storage storage;
socklen_t stlen;
if(!extstrtoaddr(addr, &storage, &stlen)) {
if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) {
errno=EINVAL;
return UB_SYNTAX;
}

View File

@ -3699,7 +3699,7 @@ addr_matches_master(struct auth_master* master, struct sockaddr_storage* addr,
/* compare address (but not port number, that is the destination
* port of the master, the port number of the received notify is
* allowed to by any port on that master) */
if(extstrtoaddr(master->host, &a, &alen) &&
if(extstrtoaddr(master->host, &a, &alen, UNBOUND_DNS_PORT) &&
sockaddr_cmp_addr(addr, addrlen, &a, alen)==0) {
*fromhost = master;
return 1;
@ -5381,7 +5381,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
struct edns_data edns;
sldns_buffer* buf = env->scratch_buffer;
if(!master) return 0;
if(extstrtoaddr(master->host, &addr, &addrlen)) {
if(extstrtoaddr(master->host, &addr, &addrlen, UNBOUND_DNS_PORT)) {
/* not needed, host is in IP addr format */
return 0;
}
@ -6572,7 +6572,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
struct edns_data edns;
sldns_buffer* buf = env->scratch_buffer;
if(!master) return 0;
if(extstrtoaddr(master->host, &addr, &addrlen)) {
if(extstrtoaddr(master->host, &addr, &addrlen, UNBOUND_DNS_PORT)) {
/* not needed, host is in IP addr format */
return 0;
}

View File

@ -124,12 +124,12 @@ verbose_print_addr(struct addrinfo *addr)
(void)strlcpy(buf, "(null)", sizeof(buf));
}
buf[sizeof(buf)-1] = 0;
verbose(VERB_ALGO, "creating %s%s socket %s %d",
verbose(VERB_ALGO, "creating %s%s socket %s %d",
addr->ai_socktype==SOCK_DGRAM?"udp":
addr->ai_socktype==SOCK_STREAM?"tcp":"otherproto",
addr->ai_family==AF_INET?"4":
addr->ai_family==AF_INET6?"6":
"_otherfam", buf,
"_otherfam", buf,
ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port));
}
}
@ -140,7 +140,9 @@ verbose_print_unbound_socket(struct unbound_socket* ub_sock)
if(verbosity >= VERB_ALGO) {
log_info("listing of unbound_socket structure:");
verbose_print_addr(ub_sock->addr);
log_info("s is: %d, fam is: %s", ub_sock->s, ub_sock->fam == AF_INET?"AF_INET":"AF_INET6");
log_info("s is: %d, fam is: %s, acl: %s", ub_sock->s,
ub_sock->fam == AF_INET?"AF_INET":"AF_INET6",
ub_sock->acl?"yes":"no");
}
}
@ -1046,6 +1048,7 @@ make_sock(int stype, const char* ifname, const char* port,
ub_sock->addr = res;
ub_sock->s = s;
ub_sock->fam = hints->ai_family;
ub_sock->acl = NULL;
return s;
}
@ -1193,6 +1196,7 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port,
* @param hints: for getaddrinfo. family and flags have to be set by caller.
* @param port: Port number to use (as string).
* @param list: list of open ports, appended to, changed to point to list head.
* @param acl_interface: acl list with options for the interface.
* @param rcv: receive buffer size for UDP
* @param snd: send buffer size for UDP
* @param ssl_port: ssl service port number
@ -1210,9 +1214,9 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port,
* @return: returns false on error.
*/
static int
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
struct addrinfo *hints, const char* port, struct listen_port** list,
size_t rcv, size_t snd, int ssl_port,
struct acl_list* acl_interface, size_t rcv, size_t snd, int ssl_port,
struct config_strlist* tls_additional_port, int https_port,
int* reuseport, int transparent, int tcp_mss, int freebind,
int http2_nodelay, int use_systemd, int dnscrypt_port, int dscp)
@ -1221,8 +1225,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
int is_https = if_is_https(ifname, port, https_port);
int nodelay = is_https && http2_nodelay;
struct unbound_socket* ub_sock;
struct acl_addr* acl_node;
#ifdef USE_DNSCRYPT
int is_dnscrypt = ((strchr(ifname, '@') &&
int is_dnscrypt = ((strchr(ifname, '@') &&
atoi(strchr(ifname, '@')+1) == dnscrypt_port) ||
(!strchr(ifname, '@') && atoi(port) == dnscrypt_port));
#else
@ -1235,9 +1240,10 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if(do_auto) {
ub_sock = calloc(1, sizeof(struct unbound_socket));
acl_node = NULL;
if(!ub_sock)
return 0;
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
freeaddrinfo(ub_sock->addr);
@ -1255,19 +1261,29 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
free(ub_sock);
return 0;
}
if(!port_insert(list, s,
is_dnscrypt?listen_type_udpancil_dnscrypt:listen_type_udpancil, ub_sock)) {
if(!port_insert(list, s, is_dnscrypt
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
ub_sock)) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
return 0;
}
if(!(acl_node = acl_interface_insert(acl_interface, ifname,
"refuse", ntohs(((struct sockaddr_in*)ub_sock->addr->ai_addr)->sin_port)))) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
return 0;
}
ub_sock->acl = acl_node;
} else if(do_udp) {
ub_sock = calloc(1, sizeof(struct unbound_socket));
acl_node = NULL;
if(!ub_sock)
return 0;
/* regular udp socket */
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
freeaddrinfo(ub_sock->addr);
@ -1278,19 +1294,28 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
}
return 0;
}
if(!port_insert(list, s,
is_dnscrypt?listen_type_udp_dnscrypt:listen_type_udp, ub_sock)) {
if(!port_insert(list, s, is_dnscrypt
?listen_type_udp_dnscrypt:listen_type_udp, ub_sock)) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
return 0;
}
if(!(acl_node = acl_interface_insert(acl_interface, ifname,
"refuse", ntohs(((struct sockaddr_in*)ub_sock->addr->ai_addr)->sin_port)))) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
return 0;
}
ub_sock->acl = acl_node;
}
if(do_tcp) {
int is_ssl = if_is_ssl(ifname, port, ssl_port,
tls_additional_port);
enum listen_type port_type;
ub_sock = calloc(1, sizeof(struct unbound_socket));
acl_node = NULL;
if(!ub_sock)
return 0;
if(is_ssl)
@ -1301,7 +1326,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
port_type = listen_type_tcp_dnscrypt;
else
port_type = listen_type_tcp;
if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
&noip6, 0, 0, reuseport, transparent, tcp_mss, nodelay,
freebind, use_systemd, dscp, ub_sock)) == -1) {
freeaddrinfo(ub_sock->addr);
@ -1320,6 +1345,14 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
free(ub_sock);
return 0;
}
if(!(acl_node = acl_interface_insert(acl_interface, ifname,
"refuse", ntohs(((struct sockaddr_in*)ub_sock->addr->ai_addr)->sin_port)))) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
return 0;
}
ub_sock->acl = acl_node;
}
return 1;
}
@ -1716,9 +1749,9 @@ int resolve_interface_names(char** ifs, int num_ifs,
#endif /* HAVE_GETIFADDRS */
}
struct listen_port*
listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
int* reuseport)
struct listen_port*
listening_ports_open(struct config_file* cfg, struct acl_list* acl_interface,
char** ifs, int num_ifs, int* reuseport)
{
struct listen_port* list = NULL;
struct addrinfo hints;
@ -1807,9 +1840,9 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
}
if(do_ip6) {
hints.ai_family = AF_INET6;
if(!ports_create_if(do_auto?"::0":"::1",
do_auto, cfg->do_udp, do_tcp,
&hints, portbuf, &list,
if(!ports_create_if(do_auto?"::0":"::1",
do_auto, cfg->do_udp, do_tcp,
&hints, portbuf, &list, acl_interface,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
@ -1822,9 +1855,9 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
}
if(do_ip4) {
hints.ai_family = AF_INET;
if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
do_auto, cfg->do_udp, do_tcp,
&hints, portbuf, &list,
if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
do_auto, cfg->do_udp, do_tcp,
&hints, portbuf, &list, acl_interface,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
@ -1841,7 +1874,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
continue;
hints.ai_family = AF_INET6;
if(!ports_create_if(ifs[i], 0, cfg->do_udp,
do_tcp, &hints, portbuf, &list,
do_tcp, &hints, portbuf, &list, acl_interface,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
@ -1856,7 +1889,7 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
continue;
hints.ai_family = AF_INET;
if(!ports_create_if(ifs[i], 0, cfg->do_udp,
do_tcp, &hints, portbuf, &list,
do_tcp, &hints, portbuf, &list, acl_interface,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,

View File

@ -43,6 +43,7 @@
#define LISTEN_DNSPORT_H
#include "util/netevent.h"
#include "daemon/acl_list.h"
#ifdef HAVE_NGHTTP2_NGHTTP2_H
#include <nghttp2/nghttp2.h>
#endif
@ -107,11 +108,13 @@ enum listen_type {
*/
struct unbound_socket {
/** socket-address structure */
struct addrinfo * addr;
struct addrinfo* addr;
/** socket descriptor returned by socket() syscall */
int s;
int s;
/** address family (AF_INET/IF_INET6) */
int fam;
int fam;
/** ACL on the socket (listening interface) */
struct acl_addr* acl;
};
/**
@ -135,6 +138,7 @@ struct listen_port {
* interfaces for IP4 and/or IP6, for UDP and/or TCP.
* On the given port number. It creates the sockets.
* @param cfg: settings on what ports to open.
* @param acl_interface: acl list for interface options.
* @param ifs: interfaces to open, array of IP addresses, "ip[@port]".
* @param num_ifs: length of ifs.
* @param reuseport: set to true if you want reuseport, or NULL to not have it,
@ -143,6 +147,7 @@ struct listen_port {
* @return: linked list of ports or NULL on error.
*/
struct listen_port* listening_ports_open(struct config_file* cfg,
struct acl_list* acl_interface,
char** ifs, int num_ifs, int* reuseport);
/**

View File

@ -316,7 +316,7 @@ warn_hosts(const char* typ, struct config_stub* list)
struct config_strlist* h;
for(s=list; s; s=s->next) {
for(h=s->hosts; h; h=h->next) {
if(extstrtoaddr(h->str, &a, &alen)) {
if(extstrtoaddr(h->str, &a, &alen, UNBOUND_DNS_PORT)) {
fprintf(stderr, "unbound-checkconf: warning:"
" %s %s: \"%s\" is an IP%s address, "
"and when looked up as a host name "
@ -361,7 +361,7 @@ interfacechecks(struct config_file* cfg)
}
/* search for duplicates in the returned addresses */
for(j=0; j<num_resif[i]; j++) {
if(!extstrtoaddr(resif[i][j], &a, &alen)) {
if(!extstrtoaddr(resif[i][j], &a, &alen, UNBOUND_DNS_PORT)) {
if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
fatal_exit("cannot parse interface address '%s' from the interface specified as '%s'",
resif[i][j], cfg->ifs[i]);

View File

@ -601,7 +601,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
struct sockaddr_storage addr2;
socklen_t addrlen2;
if(extstrtoaddr(cfg->control_ifs.first->str, &addr2,
&addrlen2)) {
&addrlen2, UNBOUND_DNS_PORT)) {
svr = cfg->control_ifs.first->str;
} else {
if(!resolve_interface_names(NULL, 0,
@ -629,7 +629,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
svr = "::1";
}
if(strchr(svr, '@')) {
if(!extstrtoaddr(svr, &addr, &addrlen))
if(!extstrtoaddr(svr, &addr, &addrlen, UNBOUND_DNS_PORT))
fatal_exit("could not parse IP@port: %s", svr);
#ifdef HAVE_SYS_UN_H
} else if(svr[0] == '/') {

View File

@ -974,7 +974,7 @@ service(const char* bind_str, int bindport, const char* serv_str,
dl_tv_add(&reuse, &delay);
if(reuse.tv_sec == 0)
reuse.tv_sec = 1;
if(!extstrtoaddr(serv_str, &srv_addr, &srv_len)) {
if(!extstrtoaddr(serv_str, &srv_addr, &srv_len, UNBOUND_DNS_PORT)) {
printf("cannot parse forward address: %s\n", serv_str);
exit(1);
}

View File

@ -1341,6 +1341,7 @@ int resolve_interface_names(char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs),
}
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg),
struct acl_list* ATTR_UNUSED(acl_interface),
char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs),
int* ATTR_UNUSED(reuseport))
{

View File

@ -618,7 +618,7 @@ int main(int argc, char* argv[])
printf("error: pass server IP address on commandline.\n");
usage(nm);
}
if(!extstrtoaddr(argv[0], &info.dest, &info.destlen)) {
if(!extstrtoaddr(argv[0], &info.dest, &info.destlen, UNBOUND_DNS_PORT)) {
printf("Could not parse ip: %s\n", argv[0]);
exit(1);
}

View File

@ -179,7 +179,8 @@ replay_range_read(char* remain, FILE* in, const char* name,
while(isspace((unsigned char)*parse))
parse++;
strip_end_white(parse);
if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen)) {
if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen,
UNBOUND_DNS_PORT)) {
log_err("Line %d: could not read ADDRESS: %s",
pstate->lineno, parse);
free(rng);
@ -287,7 +288,8 @@ replay_moment_read(char* remain, FILE* in, const char* name,
} else if(parse_keyword(&remain, "QUERY")) {
mom->evt_type = repevt_front_query;
readentry = 1;
if(!extstrtoaddr("127.0.0.1", &mom->addr, &mom->addrlen))
if(!extstrtoaddr("127.0.0.1", &mom->addr, &mom->addrlen,
UNBOUND_DNS_PORT))
fatal_exit("internal error");
} else if(parse_keyword(&remain, "CHECK_ANSWER")) {
mom->evt_type = repevt_front_reply;
@ -354,7 +356,7 @@ replay_moment_read(char* remain, FILE* in, const char* name,
m++;
while(isspace((unsigned char)*m))
m++;
if(!extstrtoaddr(s, &mom->addr, &mom->addrlen))
if(!extstrtoaddr(s, &mom->addr, &mom->addrlen, UNBOUND_DNS_PORT))
fatal_exit("bad infra_rtt address %s", s);
strip_end_white(m);
mom->variable = strdup(remain);
@ -372,7 +374,8 @@ replay_moment_read(char* remain, FILE* in, const char* name,
while(isspace((unsigned char)*remain))
remain++;
strip_end_white(remain);
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen)) {
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen,
UNBOUND_DNS_PORT)) {
log_err("line %d: could not parse ADDRESS: %s",
pstate->lineno, remain);
free(mom);

View File

@ -89,7 +89,7 @@ open_svr(const char* svr, int udp)
int fd = -1;
/* svr can be ip@port */
memset(&addr, 0, sizeof(addr));
if(!extstrtoaddr(svr, &addr, &addrlen)) {
if(!extstrtoaddr(svr, &addr, &addrlen, UNBOUND_DNS_PORT)) {
printf("fatal: bad server specs '%s'\n", svr);
exit(1);
}

View File

@ -822,7 +822,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
* stub-ssl-upstream, forward-zone, auth-zone
* name, forward-addr, forward-host,
* ratelimit-for-domain, ratelimit-below-domain,
* local-zone-tag, access-control-view,
* local-zone-tag, access-control-view, interface-*,
* send-client-subnet, client-subnet-always-forward,
* max-client-subnet-ipv4, max-client-subnet-ipv6,
* min-client-subnet-ipv4, min-client-subnet-ipv6,
@ -1252,6 +1252,11 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_LS3(opt, "access-control-tag-action", acl_tag_actions)
else O_LS3(opt, "access-control-tag-data", acl_tag_datas)
else O_LS2(opt, "access-control-view", acl_view)
else O_LS2(opt, "interface-action", interface_actions)
else O_LTG(opt, "interface-tag", interface_tags)
else O_LS3(opt, "interface-tag-action", interface_tag_actions)
else O_LS3(opt, "interface-tag-data", interface_tag_datas)
else O_LS2(opt, "interface-view", interface_view)
else O_YNO(opt, "pad-responses", pad_responses)
else O_DEC(opt, "pad-responses-block-size", pad_responses_block_size)
else O_YNO(opt, "pad-queries", pad_queries)
@ -1607,10 +1612,16 @@ config_delete(struct config_file* cfg)
config_deltrplstrlist(cfg->local_zone_overrides);
config_del_strarray(cfg->tagname, cfg->num_tags);
config_del_strbytelist(cfg->local_zone_tags);
config_del_strbytelist(cfg->acl_tags);
config_del_strbytelist(cfg->respip_tags);
config_deldblstrlist(cfg->acl_view);
config_del_strbytelist(cfg->acl_tags);
config_deltrplstrlist(cfg->acl_tag_actions);
config_deltrplstrlist(cfg->acl_tag_datas);
config_deldblstrlist(cfg->interface_actions);
config_deldblstrlist(cfg->interface_view);
config_del_strbytelist(cfg->interface_tags);
config_deltrplstrlist(cfg->interface_tag_actions);
config_deltrplstrlist(cfg->interface_tag_datas);
config_delstrlist(cfg->control_ifs.first);
free(cfg->server_key_file);
free(cfg->server_cert_file);

View File

@ -461,6 +461,16 @@ struct config_file {
struct config_str3list* acl_tag_datas;
/** list of aclname, view*/
struct config_str2list* acl_view;
/** list of interface action entries, linked list */
struct config_str2list* interface_actions;
/** list of interface, tagbitlist */
struct config_strbytelist* interface_tags;
/** list of interface, tagname, localzonetype */
struct config_str3list* interface_tag_actions;
/** list of interface, tagname, redirectdata */
struct config_str3list* interface_tag_datas;
/** list of interface, view*/
struct config_str2list* interface_view;
/** list of IP-netblock, tagbitlist */
struct config_strbytelist* respip_tags;
/** list of response-driven access control entries, linked list */

File diff suppressed because it is too large Load Diff

View File

@ -364,6 +364,7 @@ view-first{COLON} { YDVAR(1, VAR_VIEW_FIRST) }
do-not-query-address{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) }
do-not-query-localhost{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) }
access-control{COLON} { YDVAR(2, VAR_ACCESS_CONTROL) }
interface-action{COLON} { YDVAR(2, VAR_INTERFACE_ACTION) }
send-client-subnet{COLON} { YDVAR(1, VAR_SEND_CLIENT_SUBNET) }
client-subnet-zone{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ZONE) }
client-subnet-always-forward{COLON} { YDVAR(1, VAR_CLIENT_SUBNET_ALWAYS_FORWARD) }
@ -466,6 +467,10 @@ access-control-tag{COLON} { YDVAR(2, VAR_ACCESS_CONTROL_TAG) }
access-control-tag-action{COLON} { YDVAR(3, VAR_ACCESS_CONTROL_TAG_ACTION) }
access-control-tag-data{COLON} { YDVAR(3, VAR_ACCESS_CONTROL_TAG_DATA) }
access-control-view{COLON} { YDVAR(2, VAR_ACCESS_CONTROL_VIEW) }
interface-tag{COLON} { YDVAR(2, VAR_INTERFACE_TAG) }
interface-tag-action{COLON} { YDVAR(3, VAR_INTERFACE_TAG_ACTION) }
interface-tag-data{COLON} { YDVAR(3, VAR_INTERFACE_TAG_DATA) }
interface-view{COLON} { YDVAR(2, VAR_INTERFACE_VIEW) }
local-zone-override{COLON} { YDVAR(3, VAR_LOCAL_ZONE_OVERRIDE) }
dnstap{COLON} { YDVAR(0, VAR_DNSTAP) }
dnstap-enable{COLON} { YDVAR(1, VAR_DNSTAP_ENABLE) }

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* A Bison parser, made by GNU Bison 3.7.6. */
/* A Bison parser, made by GNU Bison 3.8.2. */
/* Bison interface for Yacc-like parsers in C
@ -378,7 +378,12 @@ extern int yydebug;
VAR_ZONEMD_REJECT_ABSENCE = 579, /* VAR_ZONEMD_REJECT_ABSENCE */
VAR_RPZ_SIGNAL_NXDOMAIN_RA = 580, /* VAR_RPZ_SIGNAL_NXDOMAIN_RA */
VAR_INTERFACE_AUTOMATIC_PORTS = 581, /* VAR_INTERFACE_AUTOMATIC_PORTS */
VAR_EDE = 582 /* VAR_EDE */
VAR_EDE = 582, /* VAR_EDE */
VAR_INTERFACE_ACTION = 583, /* VAR_INTERFACE_ACTION */
VAR_INTERFACE_VIEW = 584, /* VAR_INTERFACE_VIEW */
VAR_INTERFACE_TAG = 585, /* VAR_INTERFACE_TAG */
VAR_INTERFACE_TAG_ACTION = 586, /* VAR_INTERFACE_TAG_ACTION */
VAR_INTERFACE_TAG_DATA = 587 /* VAR_INTERFACE_TAG_DATA */
};
typedef enum yytokentype yytoken_kind_t;
#endif
@ -712,16 +717,21 @@ extern int yydebug;
#define VAR_RPZ_SIGNAL_NXDOMAIN_RA 580
#define VAR_INTERFACE_AUTOMATIC_PORTS 581
#define VAR_EDE 582
#define VAR_INTERFACE_ACTION 583
#define VAR_INTERFACE_VIEW 584
#define VAR_INTERFACE_TAG 585
#define VAR_INTERFACE_TAG_ACTION 586
#define VAR_INTERFACE_TAG_DATA 587
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 66 "./util/configparser.y"
#line 67 "./util/configparser.y"
char* str;
#line 725 "util/configparser.h"
#line 735 "util/configparser.h"
};
typedef union YYSTYPE YYSTYPE;
@ -732,6 +742,8 @@ typedef union YYSTYPE YYSTYPE;
extern YYSTYPE yylval;
int yyparse (void);
#endif /* !YY_YY_UTIL_CONFIGPARSER_H_INCLUDED */

View File

@ -52,6 +52,7 @@ int ub_c_lex(void);
void ub_c_error(const char *message);
static void validate_respip_action(const char* action);
static void validate_acl_action(const char* action);
/* these need to be global, otherwise they cannot be used inside yacc */
extern struct config_parser_state* cfg_parser;
@ -190,6 +191,8 @@ extern struct config_parser_state* cfg_parser;
%token VAR_EDNS_CLIENT_STRING_OPCODE VAR_NSID
%token VAR_ZONEMD_PERMISSIVE_MODE VAR_ZONEMD_CHECK VAR_ZONEMD_REJECT_ABSENCE
%token VAR_RPZ_SIGNAL_NXDOMAIN_RA VAR_INTERFACE_AUTOMATIC_PORTS VAR_EDE
%token VAR_INTERFACE_ACTION VAR_INTERFACE_VIEW VAR_INTERFACE_TAG
%token VAR_INTERFACE_TAG_ACTION VAR_INTERFACE_TAG_DATA
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -289,6 +292,8 @@ content_server: server_num_threads | server_verbosity | server_port |
server_disable_dnssec_lame_check | server_access_control_tag |
server_local_zone_override | server_access_control_tag_action |
server_access_control_tag_data | server_access_control_view |
server_interface_action | server_interface_view | server_interface_tag |
server_interface_tag_action | server_interface_tag_data |
server_qname_minimisation_strict |
server_pad_responses | server_pad_responses_block_size |
server_pad_queries | server_pad_queries_block_size |
@ -1849,21 +1854,18 @@ server_do_not_query_localhost: VAR_DO_NOT_QUERY_LOCALHOST STRING_ARG
server_access_control: VAR_ACCESS_CONTROL STRING_ARG STRING_ARG
{
OUTYY(("P(server_access_control:%s %s)\n", $2, $3));
if(strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 &&
strcmp($3, "deny_non_local")!=0 &&
strcmp($3, "refuse_non_local")!=0 &&
strcmp($3, "allow_setrd")!=0 &&
strcmp($3, "allow")!=0 &&
strcmp($3, "allow_snoop")!=0) {
yyerror("expected deny, refuse, deny_non_local, "
"refuse_non_local, allow, allow_setrd or "
"allow_snoop in access control action");
free($2);
free($3);
} else {
if(!cfg_str2list_insert(&cfg_parser->cfg->acls, $2, $3))
fatal_exit("out of memory adding acl");
}
validate_acl_action($3);
if(!cfg_str2list_insert(&cfg_parser->cfg->acls, $2, $3))
fatal_exit("out of memory adding acl");
}
;
server_interface_action: VAR_INTERFACE_ACTION STRING_ARG STRING_ARG
{
OUTYY(("P(server_interface_action:%s %s)\n", $2, $3));
validate_acl_action($3);
if(!cfg_str2list_insert(
&cfg_parser->cfg->interface_actions, $2, $3))
fatal_exit("out of memory adding acl");
}
;
server_module_conf: VAR_MODULE_CONF STRING_ARG
@ -2421,6 +2423,60 @@ server_access_control_view: VAR_ACCESS_CONTROL_VIEW STRING_ARG STRING_ARG
}
}
;
server_interface_tag: VAR_INTERFACE_TAG STRING_ARG STRING_ARG
{
size_t len = 0;
uint8_t* bitlist = config_parse_taglist(cfg_parser->cfg, $3,
&len);
free($3);
OUTYY(("P(server_interface_tag:%s)\n", $2));
if(!bitlist) {
yyerror("could not parse tags, (define-tag them first)");
free($2);
}
if(bitlist) {
if(!cfg_strbytelist_insert(
&cfg_parser->cfg->interface_tags,
$2, bitlist, len)) {
yyerror("out of memory");
free($2);
}
}
}
;
server_interface_tag_action: VAR_INTERFACE_TAG_ACTION STRING_ARG STRING_ARG STRING_ARG
{
OUTYY(("P(server_interface_tag_action:%s %s %s)\n", $2, $3, $4));
if(!cfg_str3list_insert(&cfg_parser->cfg->interface_tag_actions,
$2, $3, $4)) {
yyerror("out of memory");
free($2);
free($3);
free($4);
}
}
;
server_interface_tag_data: VAR_INTERFACE_TAG_DATA STRING_ARG STRING_ARG STRING_ARG
{
OUTYY(("P(server_interface_tag_data:%s %s %s)\n", $2, $3, $4));
if(!cfg_str3list_insert(&cfg_parser->cfg->interface_tag_datas,
$2, $3, $4)) {
yyerror("out of memory");
free($2);
free($3);
free($4);
}
}
;
server_interface_view: VAR_INTERFACE_VIEW STRING_ARG STRING_ARG
{
OUTYY(("P(server_interface_view:%s %s)\n", $2, $3));
if(!cfg_str2list_insert(&cfg_parser->cfg->interface_view,
$2, $3)) {
yyerror("out of memory");
}
}
;
server_response_ip_tag: VAR_RESPONSE_IP_TAG STRING_ARG STRING_ARG
{
size_t len = 0;
@ -3699,4 +3755,19 @@ validate_respip_action(const char* action)
}
}
static void
validate_acl_action(const char* action)
{
if(strcmp(action, "deny")!=0 &&
strcmp(action, "refuse")!=0 &&
strcmp(action, "deny_non_local")!=0 &&
strcmp(action, "refuse_non_local")!=0 &&
strcmp(action, "allow_setrd")!=0 &&
strcmp(action, "allow")!=0 &&
strcmp(action, "allow_snoop")!=0)
{
yyerror("expected deny, refuse, deny_non_local, "
"refuse_non_local, allow, allow_setrd or "
"allow_snoop as access control action");
}
}

View File

@ -44,6 +44,7 @@
* boundaries in the program.
*/
#include "config.h"
#include "daemon/acl_list.h"
#include "util/fptr_wlist.h"
#include "util/mini_event.h"
#include "services/outside_network.h"
@ -244,6 +245,7 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
else if(fptr == &auth_zone_cmp) return 1;
else if(fptr == &auth_data_cmp) return 1;
else if(fptr == &auth_xfer_cmp) return 1;
else if(fptr == &acl_interface_compare) return 1;
return 0;
}

View File

@ -233,12 +233,11 @@ log_addr(enum verbosity_value v, const char* str,
else verbose(v, "%s %s port %d", str, dest, (int)port);
}
int
int
extstrtoaddr(const char* str, struct sockaddr_storage* addr,
socklen_t* addrlen)
socklen_t* addrlen, int port)
{
char* s;
int port = UNBOUND_DNS_PORT;
if((s=strchr(str, '@'))) {
char buf[MAX_ADDR_STRLEN];
if(s-str >= MAX_ADDR_STRLEN) {
@ -255,7 +254,6 @@ extstrtoaddr(const char* str, struct sockaddr_storage* addr,
return ipstrtoaddr(str, port, addr, addrlen);
}
int
ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
socklen_t* addrlen)

View File

@ -183,10 +183,11 @@ void log_err_addr(const char* str, const char* err,
* @param str: the string
* @param addr: where to store sockaddr.
* @param addrlen: length of stored sockaddr is returned.
* @param port: default port.
* @return 0 on error.
*/
int extstrtoaddr(const char* str, struct sockaddr_storage* addr,
socklen_t* addrlen);
socklen_t* addrlen, int port);
/**
* Convert ip address string and port to sockaddr.