On 10/05/2009 03:55 PM, Marcus Alves Grando wrote:
> Hello guys,
>
> We started to test unbound in our internal DNS servers, but when has
> some zone update we need to wait until ttl expire to had a fresh
> information. To solve this problem I implemented NOTIFY part in unbound
> to flush qname in cache.
>
> I think that can be used in many cases, since most of times we need to
> propagate fast DNS modifications to our DNS internals.
>
> I need to implement acl yet (notify-access-control), but what
> maintainers think about?
Complete version with acl attached. Need flex/bison to recreate related
files.
Regards
--
Marcus Alves Grando
marcus(at)sbh.eng.br | Personal
mnag(at)FreeBSD.org | FreeBSD.org
Index: daemon/acl_list.h
===================================================================
--- daemon/acl_list.h (revision 1868)
+++ daemon/acl_list.h (working copy)
@@ -45,6 +45,7 @@
#include "util/storage/dnstree.h"
struct config_file;
struct regional;
+struct config_str2list;
/**
* Enumeration of access control options for an address range.
@@ -100,10 +101,11 @@
/**
* Process access control config.
* @param acl: where to store.
- * @param cfg: config options.
+ * @param acllist: linked acl list.
* @return 0 on error.
*/
-int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg);
+int acl_list_apply_cfg(struct acl_list* acl, struct config_str2list* acllist,
+ int do_ip6);
/**
* Lookup address to see its access control status.
Index: daemon/remote.h
===================================================================
--- daemon/remote.h (revision 1868)
+++ daemon/remote.h (working copy)
@@ -133,6 +133,14 @@
struct listen_port* ports, struct worker* worker);
/**
+ * Remove all rrsets and keys from zone from cache.
+ * @param ssl: the SSL connection to print to.
+ * @param worker: worker with communication base. and links to command
channels.
+ * @param arg: argument to find out and flush.
+ */
+void do_flush_zone(SSL* ssl, struct worker* worker, char* arg);
+
+/**
* Handle nonthreaded remote cmd execution.
* @param worker: this worker (the remote worker).
*/
Index: daemon/daemon.c
===================================================================
--- daemon/daemon.c (revision 1868)
+++ daemon/daemon.c (working copy)
@@ -201,7 +201,8 @@
}
alloc_init(&daemon->superalloc, NULL, 0);
daemon->acl = acl_list_create();
- if(!daemon->acl) {
+ daemon->acl_notify = acl_list_create();
+ if(!daemon->acl || !daemon->acl_notify) {
free(daemon->env);
free(daemon);
return NULL;
@@ -416,8 +417,10 @@
daemon_fork(struct daemon* daemon)
{
log_assert(daemon);
- if(!acl_list_apply_cfg(daemon->acl, daemon->cfg))
+ if(!acl_list_apply_cfg(daemon->acl, daemon->cfg->acls,
daemon->cfg->do_ip6))
fatal_exit("Could not setup access control list");
+ if(!acl_list_apply_cfg(daemon->acl_notify, daemon->cfg->acls_notify,
daemon->cfg->do_ip6))
+ fatal_exit("Could not setup notify access control list");
if(!(daemon->local_zones = local_zones_create()))
fatal_exit("Could not create local zones: out of memory");
if(!local_zones_apply_cfg(daemon->local_zones, daemon->cfg))
Index: daemon/daemon.h
===================================================================
--- daemon/daemon.h (revision 1868)
+++ daemon/daemon.h (working copy)
@@ -96,6 +96,8 @@
struct module_stack mods;
/** access control, which client IPs are allowed to connect */
struct acl_list* acl;
+ /** access control, which client IPs are allowed to notify */
+ struct acl_list* acl_notify;
/** local authority zones */
struct local_zones* local_zones;
/** last time of statistics printout */
Index: daemon/worker.c
===================================================================
--- daemon/worker.c (revision 1868)
+++ daemon/worker.c (working copy)
@@ -295,7 +295,8 @@
verbose(VERB_QUERY, "request bad, has TC bit on");
return LDNS_RCODE_FORMERR;
}
- if(LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
+ if(LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY &&
+ LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY)
{
verbose(VERB_QUERY, "request unknown opcode %d",
LDNS_OPCODE_WIRE(ldns_buffer_begin(pkt)));
return LDNS_RCODE_NOTIMPL;
@@ -689,6 +690,7 @@
struct query_info qinfo;
struct edns_data edns;
enum acl_access acl;
+ char buf[257];
if(error != NETEVENT_NOERROR) {
/* some bad tcp query DNS formats give these error calls */
@@ -727,7 +729,6 @@
comm_point_drop_reply(repinfo);
return 0;
}
- worker->stats.num_queries++;
/* see if query is in the cache */
if(!query_info_parse(&qinfo, c->buffer)) {
verbose(VERB_ALGO, "worker parse request: formerror.");
@@ -739,6 +740,32 @@
server_stats_insrcode(&worker->stats, c->buffer);
return 1;
}
+ if(LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) ==
LDNS_PACKET_NOTIFY) {
+ acl = acl_list_lookup(worker->daemon->acl_notify,
&repinfo->addr,
+ repinfo->addrlen);
+ if(acl == acl_deny) {
+ comm_point_drop_reply(repinfo);
+ return 0;
+ } else if(acl == acl_refuse) {
+ ldns_buffer_rewind(c->buffer);
+ LDNS_QR_SET(ldns_buffer_begin(c->buffer));
+ LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
+ LDNS_RCODE_REFUSED);
+ log_addr(VERB_ALGO, "refused notify from",
+ &repinfo->addr, repinfo->addrlen);
+ log_buf(VERB_ALGO, "refuse", c->buffer);
+ return 1;
+ }
+ verbose(VERB_ALGO, "received notify.");
+ log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ dname_str(qinfo.qname, buf);
+ do_flush_zone(NULL, worker, buf);
+ LDNS_QR_SET(ldns_buffer_begin(c->buffer));
+ ldns_buffer_rewind(c->buffer);
+ comm_point_send_reply(repinfo);
+ return 0;
+ }
+ worker->stats.num_queries++;
if(qinfo.qtype == LDNS_RR_TYPE_AXFR ||
qinfo.qtype == LDNS_RR_TYPE_IXFR) {
verbose(VERB_ALGO, "worker request: refused zone transfer.");
Index: daemon/acl_list.c
===================================================================
--- daemon/acl_list.c (revision 1868)
+++ daemon/acl_list.c (working copy)
@@ -123,10 +123,10 @@
/** read acl_list config */
static int
-read_acl_list(struct acl_list* acl, struct config_file* cfg)
+read_acl_list(struct acl_list* acl, struct config_str2list* acllist)
{
struct config_str2list* p;
- for(p = cfg->acls; p; p = p->next) {
+ for(p = acllist; p; p = p->next) {
log_assert(p->str && p->str2);
if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
return 0;
@@ -135,18 +135,18 @@
}
int
-acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg)
+acl_list_apply_cfg(struct acl_list* acl, struct config_str2list* acllist, int
do_ip6)
{
regional_free_all(acl->region);
addr_tree_init(&acl->tree);
- if(!read_acl_list(acl, cfg))
+ if(!read_acl_list(acl, acllist))
return 0;
/* insert defaults, with '0' to ignore them if they are duplicates */
if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0))
return 0;
if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
return 0;
- if(cfg->do_ip6) {
+ if(do_ip6) {
if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0))
return 0;
if(!acl_list_str_cfg(acl, "::1", "allow", 0))
Index: daemon/remote.c
===================================================================
--- daemon/remote.c (revision 1868)
+++ daemon/remote.c (working copy)
@@ -1161,7 +1161,7 @@
}
/** remove all rrsets and keys from zone from cache */
-static void
+void
do_flush_zone(SSL* ssl, struct worker* worker, char* arg)
{
uint8_t* nm;
Index: util/config_file.c
===================================================================
--- util/config_file.c (revision 1868)
+++ util/config_file.c (working copy)
@@ -131,6 +131,7 @@
cfg->stubs = NULL;
cfg->forwards = NULL;
cfg->acls = NULL;
+ cfg->acls_notify = NULL;
cfg->harden_short_bufsize = 0;
cfg->harden_large_queries = 0;
cfg->harden_glue = 1;
@@ -564,6 +565,7 @@
free(cfg->dlv_anchor_file);
config_delstrlist(cfg->dlv_anchor_list);
config_deldblstrlist(cfg->acls);
+ config_deldblstrlist(cfg->acls_notify);
free(cfg->val_nsec3_key_iterations);
config_deldblstrlist(cfg->local_zones);
config_delstrlist(cfg->local_zones_nodefault);
Index: util/configparser.y
===================================================================
--- util/configparser.y (revision 1868)
+++ util/configparser.y (working copy)
@@ -87,9 +87,9 @@
%token VAR_VAL_NSEC3_KEYSIZE_ITERATIONS VAR_USE_SYSLOG
%token VAR_OUTGOING_INTERFACE VAR_ROOT_HINTS VAR_DO_NOT_QUERY_LOCALHOST
%token VAR_CACHE_MAX_TTL VAR_HARDEN_DNNSEC_STRIPPED VAR_ACCESS_CONTROL
-%token VAR_LOCAL_ZONE VAR_LOCAL_DATA VAR_INTERFACE_AUTOMATIC
-%token VAR_STATISTICS_INTERVAL VAR_DO_DAEMONIZE VAR_USE_CAPS_FOR_ID
-%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
+%token VAR_ACCESS_CONTROL_NOTIFY VAR_LOCAL_ZONE VAR_LOCAL_DATA
+%token VAR_INTERFACE_AUTOMATIC VAR_STATISTICS_INTERVAL VAR_DO_DAEMONIZE
+%token VAR_USE_CAPS_FOR_ID VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
%token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR
%token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS
%token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
@@ -140,7 +140,8 @@
server_use_syslog | server_outgoing_interface | server_root_hints |
server_do_not_query_localhost | server_cache_max_ttl |
server_harden_dnssec_stripped | server_access_control |
- server_local_zone | server_local_data | server_interface_automatic |
+ server_access_control_notify | server_local_zone |
+ server_local_data | server_interface_automatic |
server_statistics_interval | server_do_daemonize |
server_use_caps_for_id | server_statistics_cumulative |
server_outgoing_port_permit | server_outgoing_port_avoid |
@@ -768,6 +769,19 @@
}
}
;
+server_access_control_notify: VAR_ACCESS_CONTROL_NOTIFY STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(server_access_control_notify:%s %s)\n", $2, $3));
+ if(strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 &&
+ strcmp($3, "allow")!=0) {
+ yyerror("expected deny, refuse or allow "
+ "in access control action");
+ } else {
+ if(!cfg_str2list_insert(&cfg_parser->cfg->acls_notify,
$2, $3))
+ fatal_exit("out of memory adding acl");
+ }
+ }
+ ;
server_module_conf: VAR_MODULE_CONF STRING_ARG
{
OUTYY(("P(server_module_conf:%s)\n", $2));
Index: util/config_file.h
===================================================================
--- util/config_file.h (revision 1868)
+++ util/config_file.h (working copy)
@@ -138,6 +138,8 @@
struct config_strlist* donotqueryaddrs;
/** list of access control entries, linked list */
struct config_str2list* acls;
+ /** list of notify access control entries, linked list */
+ struct config_str2list* acls_notify;
/** use default localhost donotqueryaddr entries */
int donotquery_localhost;
Index: util/data/msgreply.c
===================================================================
--- util/data/msgreply.c (revision 1868)
+++ util/data/msgreply.c (working copy)
@@ -498,7 +498,8 @@
/* minimum size: header + \0 + qtype + qclass */
if(ldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
return 0;
- if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY ||
+ if((LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY &&
+ LDNS_OPCODE_WIRE(q) != LDNS_PACKET_NOTIFY) ||
LDNS_QDCOUNT(q) != 1 || ldns_buffer_position(query) != 0)
return 0;
ldns_buffer_skip(query, LDNS_HEADER_SIZE);
Index: util/configlexer.lex
===================================================================
--- util/configlexer.lex (revision 1868)
+++ util/configlexer.lex (working copy)
@@ -184,6 +184,7 @@
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) }
+access-control-notify{COLON} { YDVAR(2, VAR_ACCESS_CONTROL_NOTIFY) }
hide-identity{COLON} { YDVAR(1, VAR_HIDE_IDENTITY) }
hide-version{COLON} { YDVAR(1, VAR_HIDE_VERSION) }
identity{COLON} { YDVAR(1, VAR_IDENTITY) }
_______________________________________________
Unbound-users mailing list
[email protected]
http://unbound.nlnetlabs.nl/mailman/listinfo/unbound-users