diff options
author | Cy Schubert <cy@FreeBSD.org> | 2020-08-21 22:56:05 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2020-08-21 22:56:05 +0000 |
commit | 7973006f41cdaf144441d1a39f9f075053435e2f (patch) | |
tree | 157d55b04796bb6f041656c0e84dd5106f4bc4be /services | |
parent | 6a53c00e64c4cf911eb00846733d9e6a47b2e7f4 (diff) | |
download | src-7973006f41cdaf144441d1a39f9f075053435e2f.tar.gz src-7973006f41cdaf144441d1a39f9f075053435e2f.zip |
Vendor import of Unbound 1.11.0.vendor/unbound/1.11.0
Notes
Notes:
svn path=/vendor/unbound/dist/; revision=364468
svn path=/vendor/unbound/1.11.0/; revision=364470; tag=vendor/unbound/1.11.0
Diffstat (limited to 'services')
-rw-r--r-- | services/authzone.c | 63 | ||||
-rw-r--r-- | services/authzone.h | 9 | ||||
-rw-r--r-- | services/listen_dnsport.c | 90 | ||||
-rw-r--r-- | services/listen_dnsport.h | 9 | ||||
-rw-r--r-- | services/localzone.c | 2 | ||||
-rw-r--r-- | services/mesh.c | 107 | ||||
-rw-r--r-- | services/modstack.c | 9 | ||||
-rw-r--r-- | services/outside_network.c | 121 | ||||
-rw-r--r-- | services/outside_network.h | 14 | ||||
-rw-r--r-- | services/rpz.c | 33 | ||||
-rw-r--r-- | services/rpz.h | 8 |
11 files changed, 315 insertions, 150 deletions
diff --git a/services/authzone.c b/services/authzone.c index 34170abaf4a2..a26d1003abe2 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -392,12 +392,12 @@ auth_zone_delete(struct auth_zone* z, struct auth_zones* az) if(az && z->rpz) { /* keep RPZ linked list intact */ lock_rw_wrlock(&az->rpz_lock); - if(z->rpz->prev) - z->rpz->prev->next = z->rpz->next; + if(z->rpz_az_prev) + z->rpz_az_prev->rpz_az_next = z->rpz_az_next; else - az->rpz_first = z->rpz->next; - if(z->rpz->next) - z->rpz->next->prev = z->rpz->prev; + az->rpz_first = z->rpz_az_next; + if(z->rpz_az_next) + z->rpz_az_next->rpz_az_prev = z->rpz_az_prev; lock_rw_unlock(&az->rpz_lock); } if(z->rpz) @@ -426,9 +426,11 @@ auth_zone_create(struct auth_zones* az, uint8_t* nm, size_t nmlen, } rbtree_init(&z->data, &auth_data_cmp); lock_rw_init(&z->lock); - lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type)); + lock_protect(&z->lock, &z->name, sizeof(*z)-sizeof(rbnode_type)- + sizeof(&z->rpz_az_next)-sizeof(&z->rpz_az_prev)); lock_rw_wrlock(&z->lock); - /* z lock protects all, except rbtree itself, which is az->lock */ + /* z lock protects all, except rbtree itself and the rpz linked list + * pointers, which are protected using az->lock */ if(!rbtree_insert(&az->ztree, &z->node)) { lock_rw_unlock(&z->lock); auth_zone_delete(z, NULL); @@ -1178,9 +1180,9 @@ az_insert_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len, return 0; } if(z->rpz) { - if(!(rpz_insert_rr(z->rpz, z->namelen, dname, dname_len, - rr_type, rr_class, rr_ttl, rdata, rdatalen, rr, - rr_len))) + if(!(rpz_insert_rr(z->rpz, z->name, z->namelen, dname, + dname_len, rr_type, rr_class, rr_ttl, rdata, rdatalen, + rr, rr_len))) return 0; } return 1; @@ -1864,15 +1866,26 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c) struct auth_xfer* x = NULL; /* create zone */ + if(c->isrpz) { + /* if the rpz lock is needed, grab it before the other + * locks to avoid a lock dependency cycle */ + lock_rw_wrlock(&az->rpz_lock); + } lock_rw_wrlock(&az->lock); if(!(z=auth_zones_find_or_add_zone(az, c->name))) { lock_rw_unlock(&az->lock); + if(c->isrpz) { + lock_rw_unlock(&az->rpz_lock); + } return 0; } if(c->masters || c->urls) { if(!(x=auth_zones_find_or_add_xfer(az, z))) { lock_rw_unlock(&az->lock); lock_rw_unlock(&z->lock); + if(c->isrpz) { + lock_rw_unlock(&az->rpz_lock); + } return 0; } } @@ -1887,6 +1900,9 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c) lock_basic_unlock(&x->lock); } lock_rw_unlock(&z->lock); + if(c->isrpz) { + lock_rw_unlock(&az->rpz_lock); + } return 0; } z->for_downstream = c->for_downstream; @@ -1897,11 +1913,14 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c) fatal_exit("Could not setup RPZ zones"); return 0; } - lock_rw_wrlock(&az->rpz_lock); - z->rpz->next = az->rpz_first; + lock_protect(&z->lock, &z->rpz->local_zones, sizeof(*z->rpz)); + /* the az->rpz_lock is locked above */ + z->rpz_az_next = az->rpz_first; if(az->rpz_first) - az->rpz_first->prev = z->rpz; - az->rpz_first = z->rpz; + az->rpz_first->rpz_az_prev = z; + az->rpz_first = z; + } + if(c->isrpz) { lock_rw_unlock(&az->rpz_lock); } @@ -5331,7 +5350,7 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf, log_assert(xfr->task_transfer); lock_basic_lock(&xfr->lock); env = xfr->task_transfer->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return; /* stop on quit */ } @@ -5770,7 +5789,7 @@ auth_xfer_transfer_timer_callback(void* arg) log_assert(xfr->task_transfer); lock_basic_lock(&xfr->lock); env = xfr->task_transfer->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return; /* stop on quit */ } @@ -5812,7 +5831,7 @@ auth_xfer_transfer_tcp_callback(struct comm_point* c, void* arg, int err, log_assert(xfr->task_transfer); lock_basic_lock(&xfr->lock); env = xfr->task_transfer->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return 0; /* stop on quit */ } @@ -5893,7 +5912,7 @@ auth_xfer_transfer_http_callback(struct comm_point* c, void* arg, int err, log_assert(xfr->task_transfer); lock_basic_lock(&xfr->lock); env = xfr->task_transfer->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return 0; /* stop on quit */ } @@ -6107,7 +6126,7 @@ auth_xfer_probe_timer_callback(void* arg) log_assert(xfr->task_probe); lock_basic_lock(&xfr->lock); env = xfr->task_probe->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return; /* stop on quit */ } @@ -6143,7 +6162,7 @@ auth_xfer_probe_udp_callback(struct comm_point* c, void* arg, int err, log_assert(xfr->task_probe); lock_basic_lock(&xfr->lock); env = xfr->task_probe->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return 0; /* stop on quit */ } @@ -6388,7 +6407,7 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf, log_assert(xfr->task_probe); lock_basic_lock(&xfr->lock); env = xfr->task_probe->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return; /* stop on quit */ } @@ -6465,7 +6484,7 @@ auth_xfer_timer(void* arg) log_assert(xfr->task_nextprobe); lock_basic_lock(&xfr->lock); env = xfr->task_nextprobe->env; - if(env->outnet->want_to_quit) { + if(!env || env->outnet->want_to_quit) { lock_basic_unlock(&xfr->lock); return; /* stop on quit */ } diff --git a/services/authzone.h b/services/authzone.h index 9bb131ad8b39..3d94f30d6202 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -82,8 +82,8 @@ struct auth_zones { size_t num_query_up; /** number of queries downstream */ size_t num_query_down; - /** first rpz item in linked list */ - struct rpz* rpz_first; + /** first auth zone containing rpz item in linked list */ + struct auth_zone* rpz_first; /** rw lock for rpz linked list, needed when iterating or editing linked * list. */ lock_rw_type rpz_lock; @@ -138,6 +138,11 @@ struct auth_zone { int zone_deleted; /** deletelist pointer, unused normally except during delete */ struct auth_zone* delete_next; + /* not protected by auth_zone lock, must be last items in struct */ + /** next auth zone containing RPZ data, or NULL */ + struct auth_zone* rpz_az_next; + /** previous auth zone containing RPZ data, or NULL */ + struct auth_zone* rpz_az_prev; }; /** diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index 7e2afd843be8..cc56d3fd3167 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -179,9 +179,10 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, int snd, int listen, int* reuseport, int transparent, - int freebind, int use_systemd) + int freebind, int use_systemd, int dscp) { int s; + char* err; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_USE_MIN_MTU) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined (SO_BINDANY) int on=1; #endif @@ -451,6 +452,9 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, # endif #endif /* SO_SNDBUF */ } + err = set_ip_dscp(s, family, dscp); + if(err != NULL) + log_warn("error setting IP DiffServ codepoint %d on UDP socket: %s", dscp, err); if(family == AF_INET6) { # if defined(IPV6_V6ONLY) if(v6only) { @@ -638,9 +642,10 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr, int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport, int transparent, int mss, int freebind, int use_systemd) + int* reuseport, int transparent, int mss, int freebind, int use_systemd, int dscp) { int s; + char* err; #if defined(SO_REUSEADDR) || defined(SO_REUSEPORT) || defined(IPV6_V6ONLY) || defined(IP_TRANSPARENT) || defined(IP_BINDANY) || defined(IP_FREEBIND) || defined(SO_BINDANY) int on = 1; #endif @@ -793,6 +798,9 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, strerror(errno)); } #endif /* IP_TRANSPARENT || IP_BINDANY || SO_BINDANY */ + err = set_ip_dscp(s, addr->ai_family, dscp); + if(err != NULL) + log_warn("error setting IP DiffServ codepoint %d on TCP socket: %s", dscp, err); if( #ifdef HAVE_SYSTEMD !got_fd_from_systemd && @@ -866,6 +874,55 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, return s; } +char* +set_ip_dscp(int socket, int addrfamily, int dscp) +{ + int ds; + + if(dscp == 0) + return NULL; + ds = dscp << 2; + switch(addrfamily) { + case AF_INET6: + if(setsockopt(socket, IPPROTO_IPV6, IPV6_TCLASS, (void*)&ds, sizeof(ds)) < 0) + return sock_strerror(errno); + break; + default: + if(setsockopt(socket, IPPROTO_IP, IP_TOS, (void*)&ds, sizeof(ds)) < 0) + return sock_strerror(errno); + break; + } + return NULL; +} + +# ifndef USE_WINSOCK +char* +sock_strerror(int errn) +{ + return strerror(errn); +} + +void +sock_close(int socket) +{ + close(socket); +} + +# else +char* +sock_strerror(int ATTR_UNUSED(errn)) +{ + return wsa_strerror(WSAGetLastError()); +} + +void +sock_close(int socket) +{ + closesocket(socket); +} + +# endif /* USE_WINSOCK */ + int create_local_accept_sock(const char *path, int* noproto, int use_systemd) { @@ -952,7 +1009,7 @@ err: static int make_sock(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd) + int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd, int dscp) { struct addrinfo *res = NULL; int r, s, inuse, noproto; @@ -980,7 +1037,7 @@ make_sock(int stype, const char* ifname, const char* port, s = create_udp_sock(res->ai_family, res->ai_socktype, (struct sockaddr*)res->ai_addr, res->ai_addrlen, v6only, &inuse, &noproto, (int)rcv, (int)snd, 1, - reuseport, transparent, freebind, use_systemd); + reuseport, transparent, freebind, use_systemd, dscp); if(s == -1 && inuse) { log_err("bind: address already in use"); } else if(s == -1 && noproto && hints->ai_family == AF_INET6){ @@ -988,7 +1045,7 @@ make_sock(int stype, const char* ifname, const char* port, } } else { s = create_tcp_accept_sock(res, v6only, &noproto, reuseport, - transparent, tcp_mss, freebind, use_systemd); + transparent, tcp_mss, freebind, use_systemd, dscp); if(s == -1 && noproto && hints->ai_family == AF_INET6){ *noip6 = 1; } @@ -1001,7 +1058,7 @@ make_sock(int stype, const char* ifname, const char* port, static int make_sock_port(int stype, const char* ifname, const char* port, struct addrinfo *hints, int v6only, int* noip6, size_t rcv, size_t snd, - int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd) + int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd, int dscp) { char* s = strchr(ifname, '@'); if(s) { @@ -1023,10 +1080,10 @@ make_sock_port(int stype, const char* ifname, const char* port, (void)strlcpy(p, s+1, sizeof(p)); p[strlen(s+1)]=0; return make_sock(stype, newif, p, hints, v6only, noip6, - rcv, snd, reuseport, transparent, tcp_mss, freebind, use_systemd); + rcv, snd, reuseport, transparent, tcp_mss, freebind, use_systemd, dscp); } return make_sock(stype, ifname, port, hints, v6only, noip6, rcv, snd, - reuseport, transparent, tcp_mss, freebind, use_systemd); + reuseport, transparent, tcp_mss, freebind, use_systemd, dscp); } /** @@ -1146,6 +1203,7 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port, * @param freebind: set IP_FREEBIND socket option. * @param use_systemd: if true, fetch sockets from systemd. * @param dnscrypt_port: dnscrypt service port number + * @param dscp: DSCP to use. * @return: returns false on error. */ static int @@ -1154,7 +1212,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, size_t rcv, size_t snd, int ssl_port, struct config_strlist* tls_additional_port, int* reuseport, int transparent, int tcp_mss, int freebind, int use_systemd, - int dnscrypt_port) + int dnscrypt_port, int dscp) { int s, noip6=0; #ifdef USE_DNSCRYPT @@ -1171,7 +1229,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, if(do_auto) { if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, freebind, use_systemd)) == -1) { + tcp_mss, freebind, use_systemd, dscp)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -1200,7 +1258,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, /* regular udp socket */ if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, &noip6, rcv, snd, reuseport, transparent, - tcp_mss, freebind, use_systemd)) == -1) { + tcp_mss, freebind, use_systemd, dscp)) == -1) { if(noip6) { log_warn("IPv6 protocol not available"); return 1; @@ -1222,7 +1280,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, tls_additional_port); if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1, &noip6, 0, 0, reuseport, transparent, tcp_mss, - freebind, use_systemd)) == -1) { + freebind, use_systemd, dscp)) == -1) { if(noip6) { /*log_warn("IPv6 protocol not available");*/ return 1; @@ -1421,7 +1479,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } @@ -1435,7 +1493,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } @@ -1451,7 +1509,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } @@ -1465,7 +1523,7 @@ listening_ports_open(struct config_file* cfg, int* reuseport) cfg->ssl_port, cfg->tls_additional_port, reuseport, cfg->ip_transparent, cfg->tcp_mss, cfg->ip_freebind, cfg->use_systemd, - cfg->dnscrypt_port)) { + cfg->dnscrypt_port, cfg->ip_dscp)) { listening_ports_free(list); return NULL; } diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index ad84d8322643..ddd1b63a4d95 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -205,11 +205,12 @@ void listen_start_accept(struct listen_dnsport* listen); * @param transparent: set IP_TRANSPARENT socket option. * @param freebind: set IP_FREEBIND socket option. * @param use_systemd: if true, fetch sockets from systemd. + * @param dscp: DSCP to use. * @return: the socket. -1 on error. */ int create_udp_sock(int family, int socktype, struct sockaddr* addr, socklen_t addrlen, int v6only, int* inuse, int* noproto, int rcv, - int snd, int listen, int* reuseport, int transparent, int freebind, int use_systemd); + int snd, int listen, int* reuseport, int transparent, int freebind, int use_systemd, int dscp); /** * Create and bind TCP listening socket @@ -222,10 +223,11 @@ int create_udp_sock(int family, int socktype, struct sockaddr* addr, * @param mss: maximum segment size of the socket. if zero, leaves the default. * @param freebind: set IP_FREEBIND socket option. * @param use_systemd: if true, fetch sockets from systemd. + * @param dscp: DSCP to use. * @return: the socket. -1 on error. */ int create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto, - int* reuseport, int transparent, int mss, int freebind, int use_systemd); + int* reuseport, int transparent, int mss, int freebind, int use_systemd, int dscp); /** * Create and bind local listening socket @@ -367,4 +369,7 @@ int tcp_req_info_handle_read_close(struct tcp_req_info* req); /** get the size of currently used tcp stream wait buffers (in bytes) */ size_t tcp_req_info_get_stream_buffer_size(void); +char* set_ip_dscp(int socket, int addrfamily, int ds); +char* sock_strerror(int errn); + #endif /* LISTEN_DNSPORT_H */ diff --git a/services/localzone.c b/services/localzone.c index 18407832ff41..6aaf0c05518c 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -518,7 +518,7 @@ local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen, } /** enter data RR into auth zone */ -int +static int lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr) { uint8_t* nm; diff --git a/services/mesh.c b/services/mesh.c index 9114ef4c4e2d..4b0c5db418f7 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -159,16 +159,28 @@ client_info_compare(const struct respip_client_info* ci_a, return 1; if(ci_a->taglen != ci_b->taglen) return (ci_a->taglen < ci_b->taglen) ? -1 : 1; - cmp = memcmp(ci_a->taglist, ci_b->taglist, ci_a->taglen); - if(cmp != 0) - return cmp; + if(ci_a->taglist && !ci_b->taglist) + return -1; + if(!ci_a->taglist && ci_b->taglist) + return 1; + if(ci_a->taglist && ci_b->taglist) { + cmp = memcmp(ci_a->taglist, ci_b->taglist, ci_a->taglen); + if(cmp != 0) + return cmp; + } if(ci_a->tag_actions_size != ci_b->tag_actions_size) return (ci_a->tag_actions_size < ci_b->tag_actions_size) ? -1 : 1; - cmp = memcmp(ci_a->tag_actions, ci_b->tag_actions, - ci_a->tag_actions_size); - if(cmp != 0) - return cmp; + if(ci_a->tag_actions && !ci_b->tag_actions) + return -1; + if(!ci_a->tag_actions && ci_b->tag_actions) + return 1; + if(ci_a->tag_actions && ci_b->tag_actions) { + cmp = memcmp(ci_a->tag_actions, ci_b->tag_actions, + ci_a->tag_actions_size); + if(cmp != 0) + return cmp; + } if(ci_a->tag_datas != ci_b->tag_datas) return ci_a->tag_datas < ci_b->tag_datas ? -1 : 1; if(ci_a->view != ci_b->view) @@ -1284,7 +1296,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, void mesh_query_done(struct mesh_state* mstate) { - struct mesh_reply* r, *reply_list = NULL; + struct mesh_reply* r; struct mesh_reply* prev = NULL; struct sldns_buffer* prev_buffer = NULL; struct mesh_cb* c; @@ -1308,27 +1320,7 @@ void mesh_query_done(struct mesh_state* mstate) free(err); } } - if(mstate->reply_list) { - /* set the reply_list to NULL during the mesh_query_done - * processing, so that calls back into the mesh from - * tcp_req_info (deciding to drop the reply and thus - * unregister the mesh_reply from the mstate) are stopped - * because the list is empty. - * The mstate is then likely not a reply_state, and maybe - * also a detached_state. - */ - reply_list = mstate->reply_list; - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - /* was a reply state, not anymore */ - log_assert(mstate->s.env->mesh->num_reply_states > 0); - mstate->s.env->mesh->num_reply_states--; - } - if(!mstate->reply_list && !mstate->cb_list && - mstate->super_set.count == 0) - mstate->s.env->mesh->num_detached_states++; - } - for(r = reply_list; r; r = r->next) { + for(r = mstate->reply_list; r; r = r->next) { /* if a response-ip address block has been stored the * information should be logged for each client. */ if(mstate->s.respip_action_info && @@ -1352,15 +1344,31 @@ void mesh_query_done(struct mesh_state* mstate) /* if this query is determined to be dropped during the * mesh processing, this is the point to take that action. */ if(mstate->s.is_drop) { + /* briefly set the reply_list to NULL, so that the + * tcp req info cleanup routine that calls the mesh + * to deregister the meshstate for it is not done + * because the list is NULL and also accounting is not + * done there, but instead we do that here. */ + struct mesh_reply* reply_list = mstate->reply_list; + mstate->reply_list = NULL; comm_point_drop_reply(&r->query_reply); + mstate->reply_list = reply_list; } else { struct sldns_buffer* r_buffer = r->query_reply.c->buffer; + struct mesh_reply* rlist = mstate->reply_list; if(r->query_reply.c->tcp_req_info) { r_buffer = r->query_reply.c->tcp_req_info->spool_buffer; prev_buffer = NULL; } + /* briefly set the replylist to null in case the + * meshsendreply calls tcpreqinfo sendreply that + * comm_point_drops because of size, and then the + * null stops the mesh state remove and thus + * reply_list modification and accounting */ + mstate->reply_list = NULL; mesh_send_reply(mstate, mstate->s.return_rcode, rep, r, r_buffer, prev, prev_buffer); + mstate->reply_list = rlist; if(r->query_reply.c->tcp_req_info) { tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); r_buffer = NULL; @@ -1369,6 +1377,17 @@ void mesh_query_done(struct mesh_state* mstate) prev_buffer = r_buffer; } } + if(mstate->reply_list) { + mstate->reply_list = NULL; + if(!mstate->reply_list && !mstate->cb_list) { + /* was a reply state, not anymore */ + log_assert(mstate->s.env->mesh->num_reply_states > 0); + mstate->s.env->mesh->num_reply_states--; + } + if(!mstate->reply_list && !mstate->cb_list && + mstate->super_set.count == 0) + mstate->s.env->mesh->num_detached_states++; + } mstate->replies_sent = 1; while((c = mstate->cb_list) != NULL) { /* take this cb off the list; so that the list can be @@ -1863,7 +1882,7 @@ mesh_serve_expired_callback(void* arg) { struct mesh_state* mstate = (struct mesh_state*) arg; struct module_qstate* qstate = &mstate->s; - struct mesh_reply* r; + struct mesh_reply* r, *rlist; struct mesh_area* mesh = qstate->env->mesh; struct dns_msg* msg; struct mesh_cb* c; @@ -1946,16 +1965,7 @@ mesh_serve_expired_callback(void* arg) if(verbosity >= VERB_ALGO) log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep); - r = mstate->reply_list; - mstate->reply_list = NULL; - if(!mstate->reply_list && !mstate->cb_list) { - log_assert(mesh->num_reply_states > 0); - mesh->num_reply_states--; - if(mstate->super_set.count == 0) { - mesh->num_detached_states++; - } - } - for(; r; r = r->next) { + for(r = mstate->reply_list; r; r = r->next) { /* If address info is returned, it means the action should be an * 'inform' variant and the information should be logged. */ if(actinfo.addrinfo) { @@ -1977,8 +1987,15 @@ mesh_serve_expired_callback(void* arg) r_buffer = r->query_reply.c->buffer; if(r->query_reply.c->tcp_req_info) r_buffer = r->query_reply.c->tcp_req_info->spool_buffer; + /* briefly set the replylist to null in case the meshsendreply + * calls tcpreqinfo sendreply that comm_point_drops because + * of size, and then the null stops the mesh state remove and + * thus reply_list modification and accounting */ + rlist = mstate->reply_list; + mstate->reply_list = NULL; mesh_send_reply(mstate, LDNS_RCODE_NOERROR, msg->rep, r, r_buffer, prev, prev_buffer); + mstate->reply_list = rlist; if(r->query_reply.c->tcp_req_info) tcp_req_info_remove_mesh_state(r->query_reply.c->tcp_req_info, mstate); prev = r; @@ -1988,6 +2005,16 @@ mesh_serve_expired_callback(void* arg) mesh->ans_expired++; } + if(mstate->reply_list) { + mstate->reply_list = NULL; + if(!mstate->reply_list && !mstate->cb_list) { + log_assert(mesh->num_reply_states > 0); + mesh->num_reply_states--; + if(mstate->super_set.count == 0) { + mesh->num_detached_states++; + } + } + } while((c = mstate->cb_list) != NULL) { /* take this cb off the list; so that the list can be * changed, eg. by adds from the callback routine */ diff --git a/services/modstack.c b/services/modstack.c index 68e5928146dd..a600549b16c3 100644 --- a/services/modstack.c +++ b/services/modstack.c @@ -51,6 +51,9 @@ #ifdef WITH_PYTHONMODULE #include "pythonmod/pythonmod.h" #endif +#ifdef WITH_DYNLIBMODULE +#include "dynlibmod/dynlibmod.h" +#endif #ifdef USE_CACHEDB #include "cachedb/cachedb.h" #endif @@ -140,6 +143,9 @@ module_list_avail(void) #ifdef WITH_PYTHONMODULE "python", #endif +#ifdef WITH_DYNLIBMODULE + "dynlib", +#endif #ifdef USE_CACHEDB "cachedb", #endif @@ -171,6 +177,9 @@ module_funcs_avail(void) #ifdef WITH_PYTHONMODULE &pythonmod_get_funcblock, #endif +#ifdef WITH_DYNLIBMODULE + &dynlibmod_get_funcblock, +#endif #ifdef USE_CACHEDB &cachedb_get_funcblock, #endif diff --git a/services/outside_network.c b/services/outside_network.c index 80b1f12454d6..44e01d7450cb 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -205,18 +205,25 @@ pick_outgoing_tcp(struct waiting_tcp* w, int s) /** get TCP file descriptor for address, returns -1 on failure, * tcp_mss is 0 or maxseg size to set for TCP packets. */ int -outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss) +outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss, int dscp) { int s; + int af; + char* err; #ifdef SO_REUSEADDR int on = 1; #endif #ifdef INET6 - if(addr_is_ip6(addr, addrlen)) + if(addr_is_ip6(addr, addrlen)){ s = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); - else + af = AF_INET6; + } else { +#else + { #endif + af = AF_INET; s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + } if(s == -1) { #ifndef USE_WINSOCK log_err_addr("outgoing tcp: socket", strerror(errno), @@ -236,6 +243,12 @@ outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss) } #endif + err = set_ip_dscp(s, af, dscp); + if(err != NULL) { + verbose(VERB_ALGO, "outgoing tcp:" + "error setting IP DiffServ codepoint on socket"); + } + if(tcp_mss > 0) { #if defined(IPPROTO_TCP) && defined(TCP_MAXSEG) if(setsockopt(s, IPPROTO_TCP, TCP_MAXSEG, @@ -291,7 +304,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len) log_assert(pkt); log_assert(w->addrlen > 0); /* open socket */ - s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss); + s = outnet_get_tcp_fd(&w->addr, w->addrlen, w->outnet->tcp_mss, w->outnet->ip_dscp); if(s == -1) return 0; @@ -373,45 +386,16 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt, size_t pkt_len) comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl); #endif pend->c->ssl_shake_state = comm_ssl_shake_write; - if(w->tls_auth_name) { + if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name, + w->outnet->tls_use_sni)) { + pend->c->fd = s; #ifdef HAVE_SSL - (void)SSL_set_tlsext_host_name(pend->c->ssl, w->tls_auth_name); + SSL_free(pend->c->ssl); #endif + pend->c->ssl = NULL; + comm_point_close(pend->c); + return 0; } -#ifdef HAVE_SSL_SET1_HOST - if(w->tls_auth_name) { - SSL_set_verify(pend->c->ssl, SSL_VERIFY_PEER, NULL); - /* setting the hostname makes openssl verify the - * host name in the x509 certificate in the - * SSL connection*/ - if(!SSL_set1_host(pend->c->ssl, w->tls_auth_name)) { - log_err("SSL_set1_host failed"); - pend->c->fd = s; - SSL_free(pend->c->ssl); - pend->c->ssl = NULL; - comm_point_close(pend->c); - return 0; - } - } -#elif defined(HAVE_X509_VERIFY_PARAM_SET1_HOST) - /* openssl 1.0.2 has this function that can be used for - * set1_host like verification */ - if(w->tls_auth_name) { - X509_VERIFY_PARAM* param = SSL_get0_param(pend->c->ssl); - X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); - if(!X509_VERIFY_PARAM_set1_host(param, w->tls_auth_name, strlen(w->tls_auth_name))) { - log_err("X509_VERIFY_PARAM_set1_host failed"); - pend->c->fd = s; - SSL_free(pend->c->ssl); - pend->c->ssl = NULL; - comm_point_close(pend->c); - return 0; - } - SSL_set_verify(pend->c->ssl, SSL_VERIFY_PEER, NULL); - } -#else - verbose(VERB_ALGO, "the query has an auth_name, but libssl has no call to perform TLS authentication"); -#endif /* HAVE_SSL_SET1_HOST */ } w->pkt = NULL; w->next_waiting = (void*)pend; @@ -512,7 +496,9 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc) comm_point_close(pc->cp); pif = pc->pif; log_assert(pif->inuse > 0); +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pif->avail_ports[pif->avail_total - pif->inuse] = pc->number; +#endif pif->inuse--; pif->out[pc->index] = pif->out[pif->inuse]; pif->out[pc->index]->index = pc->index; @@ -725,10 +711,12 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize) static int setup_if(struct port_if* pif, const char* addrstr, int* avail, int numavail, size_t numfd) { +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pif->avail_total = numavail; pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int)); if(!pif->avail_ports) return 0; +#endif if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) && !netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen, &pif->pfxlen)) @@ -745,11 +733,11 @@ static int setup_if(struct port_if* pif, const char* addrstr, struct outside_network* outside_network_create(struct comm_base *base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, int do_ip4, - int do_ip6, size_t num_tcp, struct infra_cache* infra, + int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, struct ub_randstate* rnd, int use_caps_for_id, int* availports, int numavailports, size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, - void* sslctx, int delayclose, struct dt_env* dtenv) + void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv) { struct outside_network* outnet = (struct outside_network*) calloc(1, sizeof(struct outside_network)); @@ -765,6 +753,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, outnet->infra = infra; outnet->rnd = rnd; outnet->sslctx = sslctx; + outnet->tls_use_sni = tls_use_sni; #ifdef USE_DNSTAP outnet->dtenv = dtenv; #else @@ -778,6 +767,7 @@ outside_network_create(struct comm_base *base, size_t bufsize, outnet->use_caps_for_id = use_caps_for_id; outnet->do_udp = do_udp; outnet->tcp_mss = tcp_mss; + outnet->ip_dscp = dscp; #ifndef S_SPLINT_S if(delayclose) { outnet->delayclose = 1; @@ -955,7 +945,9 @@ outside_network_delete(struct outside_network* outnet) comm_point_delete(pc->cp); free(pc); } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION free(outnet->ip4_ifs[i].avail_ports); +#endif free(outnet->ip4_ifs[i].out); } free(outnet->ip4_ifs); @@ -969,7 +961,9 @@ outside_network_delete(struct outside_network* outnet) comm_point_delete(pc->cp); free(pc); } +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION free(outnet->ip6_ifs[i].avail_ports); +#endif free(outnet->ip6_ifs[i].out); } free(outnet->ip6_ifs); @@ -1059,11 +1053,12 @@ sai6_putrandom(struct sockaddr_in6 *sa, int pfxlen, struct ub_randstate *rnd) * @param port: port override for addr. * @param inuse: if -1 is returned, this bool means the port was in use. * @param rnd: random state (for address randomisation). + * @param dscp: DSCP to use. * @return fd or -1 */ static int udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, - int port, int* inuse, struct ub_randstate* rnd) + int port, int* inuse, struct ub_randstate* rnd, int dscp) { int fd, noproto; if(addr_is_ip6(addr, addrlen)) { @@ -1078,13 +1073,13 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen, } fd = create_udp_sock(AF_INET6, SOCK_DGRAM, (struct sockaddr*)&sa, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL, 0, freebind, 0); + 0, 0, 0, NULL, 0, freebind, 0, dscp); } else { struct sockaddr_in* sa = (struct sockaddr_in*)addr; sa->sin_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET, SOCK_DGRAM, (struct sockaddr*)addr, addrlen, 1, inuse, &noproto, - 0, 0, 0, NULL, 0, 0, 0); + 0, 0, 0, NULL, 0, 0, 0, dscp); } return fd; } @@ -1133,6 +1128,7 @@ select_ifport(struct outside_network* outnet, struct pending* pend, while(1) { my_if = ub_random_max(outnet->rnd, num_if); pif = &ifs[my_if]; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION my_port = ub_random_max(outnet->rnd, pif->avail_total); if(my_port < pif->inuse) { /* port already open */ @@ -1144,8 +1140,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend, /* try to open new port, if fails, loop to try again */ log_assert(pif->inuse < pif->maxout); portno = pif->avail_ports[my_port - pif->inuse]; +#else + my_port = portno = 0; +#endif fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen, - portno, &inuse, outnet->rnd); + portno, &inuse, outnet->rnd, outnet->ip_dscp); if(fd == -1 && !inuse) { /* nonrecoverable error making socket */ return 0; @@ -1167,8 +1166,10 @@ select_ifport(struct outside_network* outnet, struct pending* pend, /* grab port in interface */ pif->out[pif->inuse] = pend->pc; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pif->avail_ports[my_port - pif->inuse] = pif->avail_ports[pif->avail_total-pif->inuse-1]; +#endif pif->inuse++; break; } @@ -2192,10 +2193,11 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, { struct sockaddr_storage* addr; socklen_t addrlen; - int i, try, pnum; + int i, try, pnum, dscp; struct port_if* pif; /* create fd */ + dscp = outnet->ip_dscp; for(try = 0; try<1000; try++) { int port = 0; int freebind = 0; @@ -2225,6 +2227,7 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, } addr = &pif->addr; addrlen = pif->addrlen; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION pnum = ub_random_max(outnet->rnd, pif->avail_total); if(pnum < pif->inuse) { /* port already open */ @@ -2233,19 +2236,21 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr, /* unused ports in start part of array */ port = pif->avail_ports[pnum - pif->inuse]; } - +#else + pnum = port = 0; +#endif if(addr_is_ip6(to_addr, to_addrlen)) { struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr; sa.sin6_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET6, SOCK_DGRAM, (struct sockaddr*)&sa, addrlen, 1, &inuse, &noproto, - 0, 0, 0, NULL, 0, freebind, 0); + 0, 0, 0, NULL, 0, freebind, 0, dscp); } else { struct sockaddr_in* sa = (struct sockaddr_in*)addr; sa->sin_port = (in_port_t)htons((uint16_t)port); fd = create_udp_sock(AF_INET, SOCK_DGRAM, (struct sockaddr*)addr, addrlen, 1, &inuse, &noproto, - 0, 0, 0, NULL, 0, freebind, 0); + 0, 0, 0, NULL, 0, freebind, 0, dscp); } if(fd != -1) { return fd; @@ -2294,6 +2299,11 @@ setup_comm_ssl(struct comm_point* cp, struct outside_network* outnet, #endif cp->ssl_shake_state = comm_ssl_shake_write; /* https verification */ +#ifdef HAVE_SSL + if(outnet->tls_use_sni) { + (void)SSL_set_tlsext_host_name(cp->ssl, host); + } +#endif #ifdef HAVE_SSL_SET1_HOST if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { /* because we set SSL_VERIFY_PEER, in netevent in @@ -2316,7 +2326,9 @@ setup_comm_ssl(struct comm_point* cp, struct outside_network* outnet, * set1_host like verification */ if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) { X509_VERIFY_PARAM* param = SSL_get0_param(cp->ssl); +# ifdef X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); +# endif if(!X509_VERIFY_PARAM_set1_host(param, host, strlen(host))) { log_err("X509_VERIFY_PARAM_set1_host failed"); return 0; @@ -2335,7 +2347,7 @@ outnet_comm_point_for_tcp(struct outside_network* outnet, sldns_buffer* query, int timeout, int ssl, char* host) { struct comm_point* cp; - int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss); + int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss, outnet->ip_dscp); if(fd == -1) { return 0; } @@ -2397,7 +2409,7 @@ outnet_comm_point_for_http(struct outside_network* outnet, { /* cp calls cb with err=NETEVENT_DONE when transfer is done */ struct comm_point* cp; - int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss); + int fd = outnet_get_tcp_fd(to_addr, to_addrlen, outnet->tcp_mss, outnet->ip_dscp); if(fd == -1) { return 0; } @@ -2455,7 +2467,10 @@ if_get_mem(struct port_if* pif) { size_t s; int i; - s = sizeof(*pif) + sizeof(int)*pif->avail_total + + s = sizeof(*pif) + +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION + sizeof(int)*pif->avail_total + +#endif sizeof(struct port_comm*)*pif->maxout; for(i=0; i<pif->inuse; i++) s += sizeof(*pif->out[i]) + diff --git a/services/outside_network.h b/services/outside_network.h index 3456a3da38b0..c8f6d5724a87 100644 --- a/services/outside_network.h +++ b/services/outside_network.h @@ -132,12 +132,16 @@ struct outside_network { struct ub_randstate* rnd; /** ssl context to create ssl wrapped TCP with DNS connections */ void* sslctx; + /** if SNI will be used for TLS connections */ + int tls_use_sni; #ifdef USE_DNSTAP /** dnstap environment */ struct dt_env* dtenv; #endif /** maximum segment size of tcp socket */ int tcp_mss; + /** IP_TOS socket option requested on the sockets */ + int ip_dscp; /** * Array of tcp pending used for outgoing TCP connections. @@ -172,11 +176,13 @@ struct port_if { * if 0, no randomisation. */ int pfxlen; +#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION /** the available ports array. These are unused. * Only the first total-inuse part is filled. */ int* avail_ports; /** the total number of available ports (size of the array) */ int avail_total; +#endif /** array of the commpoints currently in use. * allocated for max number of fds, first part in use. */ @@ -399,6 +405,7 @@ struct serviced_query { * @param do_ip4: service IP4. * @param do_ip6: service IP6. * @param num_tcp: number of outgoing tcp buffers to preallocate. + * @param dscp: DSCP to use. * @param infra: pointer to infra cached used for serviced queries. * @param rnd: stored to create random numbers for serviced queries. * @param use_caps_for_id: enable to use 0x20 bits to encode id randomness. @@ -412,16 +419,17 @@ struct serviced_query { * @param sslctx: context to create outgoing connections with (if enabled). * @param delayclose: if not 0, udp sockets are delayed before timeout closure. * msec to wait on timeouted udp sockets. + * @param tls_use_sni: if SNI is used for TLS connections. * @param dtenv: environment to send dnstap events with (if enabled). * @return: the new structure (with no pending answers) or NULL on error. */ struct outside_network* outside_network_create(struct comm_base* base, size_t bufsize, size_t num_ports, char** ifs, int num_ifs, - int do_ip4, int do_ip6, size_t num_tcp, struct infra_cache* infra, + int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra, struct ub_randstate* rnd, int use_caps_for_id, int* availports, int numavailports, size_t unwanted_threshold, int tcp_mss, void (*unwanted_action)(void*), void* unwanted_param, int do_udp, - void* sslctx, int delayclose, struct dt_env *dtenv); + void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv); /** * Delete outside_network structure. @@ -540,7 +548,7 @@ size_t serviced_get_mem(struct serviced_query* sq); /** get TCP file descriptor for address, returns -1 on failure, * tcp_mss is 0 or maxseg size to set for TCP packets. */ -int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss); +int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen, int tcp_mss, int dscp); /** * Create udp commpoint suitable for sending packets to the destination. diff --git a/services/rpz.c b/services/rpz.c index 643b20c91d20..105f238d0a6d 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -586,7 +586,7 @@ rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, } int -rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, +rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname, size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl, uint8_t* rdatawl, size_t rdatalen, uint8_t* rr, size_t rr_len) { @@ -596,9 +596,17 @@ rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, enum rpz_action a; uint8_t* policydname; + if(!dname_subdomain_c(dname, azname)) { + log_err("RPZ: name of record to insert into RPZ is not a " + "subdomain of the configured name of the RPZ zone"); + return 0; + } + log_assert(dnamelen >= aznamelen); - if(!(policydname = calloc(1, (dnamelen-aznamelen)+1))) + if(!(policydname = calloc(1, (dnamelen-aznamelen)+1))) { + log_err("malloc error while inserting RPZ RR"); return 0; + } a = rpz_rr_to_action(rr_type, rdatawl, rdatalen); if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen, @@ -826,6 +834,8 @@ rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen, delete_zone = rpz_data_delete_rr(z, dname, dnamelen, rr_type, rdatawl, rdatalen); else if(a != localzone_type_to_rpz_action(z->type)) { + lock_rw_unlock(&z->lock); + lock_rw_unlock(&r->local_zones->lock); return; } lock_rw_unlock(&z->lock); @@ -931,13 +941,16 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist, size_t taglen, struct ub_server_stats* stats) { - struct rpz* r; + struct rpz* r = NULL; + struct auth_zone* a; int ret; enum localzone_type lzt; struct local_zone* z = NULL; struct local_data* ld = NULL; lock_rw_rdlock(&az->rpz_lock); - for(r = az->rpz_first; r; r = r->next) { + for(a = az->rpz_first; a; a = a->rpz_az_next) { + lock_rw_rdlock(&a->lock); + r = a->rpz; if(!r->taglist || taglist_intersect(r->taglist, r->taglistlen, taglist, taglen)) { z = rpz_find_zone(r, qinfo->qname, qinfo->qname_len, @@ -955,13 +968,14 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, } if(z) break; - } + } + lock_rw_unlock(&a->lock); /* not found in this auth_zone */ } lock_rw_unlock(&az->rpz_lock); if(!z) - return 0; + return 0; /* not holding auth_zone.lock anymore */ - + log_assert(r); if(r->action_override == RPZ_NO_OVERRIDE_ACTION) lzt = z->type; else @@ -972,6 +986,7 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, regional_alloc_zero(temp, sizeof(struct local_rrset)); if(!qinfo->local_alias) { lock_rw_unlock(&z->lock); + lock_rw_unlock(&a->lock); return 0; /* out of memory */ } qinfo->local_alias->rrset = @@ -979,6 +994,7 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, sizeof(*r->cname_override)); if(!qinfo->local_alias->rrset) { lock_rw_unlock(&z->lock); + lock_rw_unlock(&a->lock); return 0; /* out of memory */ } qinfo->local_alias->rrset->rk.dname = qinfo->qname; @@ -988,6 +1004,7 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, qinfo, repinfo, r->log_name); stats->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++; lock_rw_unlock(&z->lock); + lock_rw_unlock(&a->lock); return 0; } @@ -1000,6 +1017,7 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, repinfo, r->log_name); stats->rpz_action[localzone_type_to_rpz_action(lzt)]++; lock_rw_unlock(&z->lock); + lock_rw_unlock(&a->lock); return !qinfo->local_alias; } @@ -1010,6 +1028,7 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, qinfo, repinfo, r->log_name); stats->rpz_action[localzone_type_to_rpz_action(lzt)]++; lock_rw_unlock(&z->lock); + lock_rw_unlock(&a->lock); return ret; } diff --git a/services/rpz.h b/services/rpz.h index 676a4f2a8406..77a2db55ced4 100644 --- a/services/rpz.h +++ b/services/rpz.h @@ -86,7 +86,8 @@ enum rpz_action { /** * RPZ containing policies. Pointed to from corresponding auth-zone. Part of a * linked list to keep configuration order. Iterating or changing the linked - * list requires the rpz_lock from struct auth_zones. + * list requires the rpz_lock from struct auth_zones. Changing items in this + * struct require the lock from struct auth_zone. */ struct rpz { struct local_zones* local_zones; @@ -97,14 +98,13 @@ struct rpz { struct ub_packed_rrset_key* cname_override; int log; char* log_name; - struct rpz* next; - struct rpz* prev; struct regional* region; }; /** * Create policy from RR and add to this RPZ. * @param r: the rpz to add the policy to. + * @param azname: dname of the auth-zone * @param aznamelen: the length of the auth-zone name * @param dname: dname of the RR * @param dnamelen: length of the dname @@ -117,7 +117,7 @@ struct rpz { * @param rr_len: the length of the complete RR * @return: 0 on error */ -int rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, +int rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname, size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl, uint8_t* rdatawl, size_t rdatalen, uint8_t* rr, size_t rr_len); |