From: Wouter Wijngaards Date: Tue, 6 Feb 2018 09:32:41 +0000 (+0000) Subject: auth zone work. X-Git-Tag: release-1.7.0rc1~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3b87862c8a1d1fdcff4e187433eb63f0595b8eee;p=thirdparty%2Funbound.git auth zone work. git-svn-id: file:///svn/unbound/trunk@4512 be551aaa-1e26-0410-a405-d3ace91eadb9 --- diff --git a/services/authzone.c b/services/authzone.c index d280d9432..92f8ad048 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -1818,12 +1818,12 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c) if(x) { z->zone_is_slave = 1; /* set options on xfer zone */ - if(!xfer_set_masters(&x->task_probe->masters, c)) { + if(!xfer_set_masters(&x->task_probe->masters, c, 0)) { lock_basic_unlock(&x->lock); lock_rw_unlock(&z->lock); return 0; } - if(!xfer_set_masters(&x->task_transfer->masters, c)) { + if(!xfer_set_masters(&x->task_transfer->masters, c, 1)) { lock_basic_unlock(&x->lock); lock_rw_unlock(&z->lock); return 0; @@ -3443,7 +3443,8 @@ xfr_create_soa_probe_packet(struct auth_xfer* xfr, sldns_buffer* buf, /** create IXFR/AXFR packet for xfr */ static void -xfr_create_ixfr_packet(struct auth_xfer* xfr, sldns_buffer* buf, uint16_t id) +xfr_create_ixfr_packet(struct auth_xfer* xfr, sldns_buffer* buf, uint16_t id, + struct auth_master* master) { struct query_info qinfo; uint32_t serial; @@ -3460,7 +3461,7 @@ xfr_create_ixfr_packet(struct auth_xfer* xfr, sldns_buffer* buf, uint16_t id) xfr->task_transfer->on_ixfr_is_axfr = 0; xfr->task_transfer->on_ixfr = 1; qinfo.qtype = LDNS_RR_TYPE_IXFR; - if(!have_zone || xfr->task_transfer->ixfr_fail) { + if(!have_zone || xfr->task_transfer->ixfr_fail || !master->ixfr) { qinfo.qtype = LDNS_RR_TYPE_AXFR; xfr->task_transfer->ixfr_fail = 0; xfr->task_transfer->on_ixfr = 0; @@ -4137,11 +4138,34 @@ xfr_transfer_init_fetch(struct auth_xfer* xfr, struct module_env* env) xfr->task_transfer->cp = NULL; } + if(master->http) { + /* perform http fetch */ + /* store http port number into sockaddr, + * unless someone used unbound's host@port notation */ + if(strchr(master->host, '@') == NULL) + sockaddr_store_port(&addr, addrlen, master->port); + /* TODO + xfr->task_transfer->cp = outnet_comm_point_for_http(env->outnet, + auth_xfer_transfer_http_callback, xfr, &addr, addrlen, + env->scratch_buffer, AUTH_TRANSFER_TIMEOUT, + master->ssl, master->host, master->file); + */ + if(!xfr->task_transfer->cp) { + char zname[255+1]; + dname_str(xfr->name, zname); + verbose(VERB_ALGO, "cannot create http cp connection for " + "%s to %s", zname, master->host); + return 0; + } + return 1; + } + + /* perform AXFR/IXFR */ /* set the packet to be written */ /* create new ID */ xfr->task_transfer->id = (uint16_t)(ub_random(env->rnd)&0xffff); xfr_create_ixfr_packet(xfr, env->scratch_buffer, - xfr->task_transfer->id); + xfr->task_transfer->id, master); /* connect on fd */ xfr->task_transfer->cp = outnet_comm_point_for_tcp(env->outnet, @@ -4699,6 +4723,29 @@ auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err, return 0; } +/** callback for task_transfer http connections */ +int +auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err, + struct comm_reply* ATTR_UNUSED(repinfo)) +{ + struct auth_xfer* xfr = (struct auth_xfer*)arg; + struct module_env* env; + log_assert(xfr->task_transfer); + env = xfr->task_transfer->env; + lock_basic_lock(&xfr->lock); + /* TODO */ + (void)env; + (void)err; + /* if we want to read more messages, setup the commpoint to read + * a DNS packet, and the timeout */ + lock_basic_unlock(&xfr->lock); + c->tcp_is_reading = 1; + sldns_buffer_clear(c->buffer); + comm_point_start_listening(c, -1, AUTH_TRANSFER_TIMEOUT); + return 0; +} + + /** start transfer task by this worker , xfr is locked. */ static void xfr_start_transfer(struct auth_xfer* xfr, struct module_env* env, @@ -5325,8 +5372,115 @@ auth_master_new(struct auth_master*** list) return m; } +/** dup_prefix : create string from initial part of other string, malloced */ +static char* +dup_prefix(char* str, size_t num) +{ + char* result; + size_t len = strlen(str); + if(len < num) num = len; /* not more than strlen */ + result = (char*)malloc(num+1); + if(!result) { + log_err("malloc failure"); + return result; + } + memmove(result, str, num); + result[num] = 0; + return result; +} + +/** dup string and print error on error */ +static char* +dup_all(char* str) +{ + char* result = strdup(str); + if(!str) { + log_err("malloc failure"); + return NULL; + } + return result; +} + +/** find first of two characters */ +static char* +str_find_first_of_chars(char* s, char a, char b) +{ + char* ra = strchr(s, a); + char* rb = strchr(s, b); + if(!ra) return rb; + if(!rb) return ra; + if(ra < rb) return ra; + return rb; +} + +/** parse URL into host and file parts, false on malloc or parse error */ +static int +parse_url(char* url, char** host, char** file, int* port, int* ssl) +{ + char* p = url; + /* parse http://www.example.com/file.htm + * or http://127.0.0.1 (index.html) + * or https://[::1@1234]/a/b/c/d */ + *ssl = 0; + *port = 80; + + /* parse http:// or https:// */ + if(strncmp(p, "http://", 7) == 0) { + p += 7; + } else if(strncmp(p, "https://", 8) == 0) { + p += 8; + *ssl = 1; + *port = 443; + } + + /* parse hostname part */ + if(p[0] == '[') { + char* end = strchr(p, ']'); + p++; /* skip over [ */ + if(end) { + *host = dup_prefix(p, (end-p)); + if(!*host) return 0; + p = end+1; /* skip over ] */ + } else { + *host = dup_all(p); + if(!*host) return 0; + p = end; + } + } else { + char* end = str_find_first_of_chars(p, ':', '/'); + if(end) { + *host = dup_prefix(p, (end-p)); + if(!*host) return 0; + } else { + *host = dup_all(p); + if(!*host) return 0; + } + p = end; /* at next : or / or NULL */ + } + + /* parse port number */ + if(p && p[0] == ':') { + char* end = NULL; + *port = strtol(p+1, &end, 10); + p = end; + } + + /* parse filename part */ + while(p && *p == '/') + p++; + if(!p || p[0] == 0) + *file = strdup("index.html"); + else *file = strdup(p); + if(!*file) { + log_err("malloc failure"); + return 0; + } + return 1; +} + int -xfer_set_masters(struct auth_master** list, struct config_auth* c) +xfer_set_masters(struct auth_master** list, struct config_auth* c, + int with_http) { struct auth_master* m; struct config_strlist* p; @@ -5334,19 +5488,16 @@ xfer_set_masters(struct auth_master** list, struct config_auth* c) while(*list) { list = &( (*list)->next ); } - for(p = c->masters; p; p = p->next) { + if(with_http) + for(p = c->urls; p; p = p->next) { m = auth_master_new(&list); - m->ixfr = 1; - m->host = strdup(p->str); - if(!m->host) { - log_err("malloc failure"); + m->http = 1; + if(!parse_url(p->str, &m->host, &m->file, &m->port, &m->ssl)) return 0; - } } - for(p = c->urls; p; p = p->next) { + for(p = c->masters; p; p = p->next) { m = auth_master_new(&list); - m->http = 1; - /* TODO parse url, get host, file */ + m->ixfr = 1; /* this flag is not configurable */ m->host = strdup(p->str); if(!m->host) { log_err("malloc failure"); diff --git a/services/authzone.h b/services/authzone.h index 2b1766696..d54ef4b96 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -402,6 +402,8 @@ struct auth_master { int ixfr; /** use ssl for channel */ int ssl; + /** the port number (for urls) */ + int port; /** if the host is a hostname, the list of resolved addrs, if any*/ struct auth_addr* list; }; @@ -563,10 +565,11 @@ struct auth_xfer* auth_xfer_create(struct auth_zones* az, struct auth_zone* z); * Set masters in auth xfer structure from config. * @param list: pointer to start of list. The malloced list is returned here. * @param c: the config items to copy over. + * @param with_http: if true, http urls are also included, before the masters. * @return false on failure. */ -int xfer_set_masters(struct auth_master** list, struct config_auth* c); - +int xfer_set_masters(struct auth_master** list, struct config_auth* c, + int with_http); /** xfer nextprobe timeout callback, this is part of task_nextprobe */ void auth_xfer_timer(void* arg); @@ -577,6 +580,9 @@ int auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err, /** callback for task_transfer tcp connections */ int auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err, struct comm_reply* repinfo); +/** callback for task_transfer http connections */ +int auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err, + struct comm_reply* repinfo); /** xfer probe timeout callback, part of task_probe */ void auth_xfer_probe_timer_callback(void* arg); /** mesh callback for task_probe on lookup of host names */ diff --git a/util/net_help.c b/util/net_help.c index d99a2f974..84b9ba1ef 100644 --- a/util/net_help.c +++ b/util/net_help.c @@ -271,6 +271,19 @@ int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr, return 1; } +/** store port number into sockaddr structure */ +void +sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen, int port) +{ + if(addr_is_ip6(addr, addrlen)) { + struct sockaddr_in6* sa = (struct sockaddr_in6*)addr; + sa->sin6_port = (in_port_t)htons(port); + } else { + struct sockaddr_in* sa = (struct sockaddr_in*)addr; + sa->sin_port = (in_port_t)htons(port); + } +} + void log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name, uint16_t type, uint16_t dclass) diff --git a/util/net_help.h b/util/net_help.h index f0236e533..2d6fce91d 100644 --- a/util/net_help.h +++ b/util/net_help.h @@ -201,6 +201,15 @@ int ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr, int netblockstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr, socklen_t* addrlen, int* net); +/** + * Store port number into sockaddr structure + * @param addr: sockaddr structure, ip4 or ip6. + * @param addrlen: length of addr. + * @param port: port number to put into the addr. + */ +void sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen, + int port); + /** * Print string with neat domain name, type and class. * @param v: at what verbosity level to print this.