static isc_boolean_t client_ok(const isc_sockaddr_t *fromaddr, void *arg) { ns_statschannel_t *listener = arg; isc_netaddr_t netaddr; char socktext[ISC_SOCKADDR_FORMATSIZE]; int match; REQUIRE(listener != NULL); isc_netaddr_fromsockaddr(&netaddr, fromaddr); LOCK(&listener->lock); if (dns_acl_match(&netaddr, NULL, listener->acl, &ns_g_server->aclenv, &match, NULL) == ISC_R_SUCCESS && match > 0) { UNLOCK(&listener->lock); return (ISC_TRUE); } UNLOCK(&listener->lock); isc_sockaddr_format(fromaddr, socktext, sizeof(socktext)); isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_SERVER, ISC_LOG_WARNING, "rejected statistics connection from %s", socktext); return (ISC_FALSE); }
void dns_dampening_score_qtype(dns_dampening_t * damp, const isc_sockaddr_t * addr, isc_stdtime_t now, dns_messageid_t message_id, int qtype) { isc_netaddr_t netaddr, prefix; dns_dampening_entry_t * entry; uint16_t points; dns_dampening_implementation_t *impl; RUNTIME_CHECK( damp != NULL ); RUNTIME_CHECK( addr != NULL ); isc_netaddr_fromsockaddr(&netaddr, addr); extract_prefix(&prefix, &netaddr, &(damp->prefixlen)); for(impl = damp->workers; impl - damp->workers < damp->workers_count; impl++) { if(damp->exempt != NULL) { int match; if (ISC_R_SUCCESS == dns_acl_match(&netaddr, NULL, damp->exempt, NULL, &match, NULL) && match > 0) { DAMPENING_STATISTICS_INC(impl,skipped); continue; } } DAMPENING_STATISTICS_DO(impl, lock, LOCK(&impl->lock)); DAMPENING_STATISTICS_DO(impl, search, entry = impl->search(impl->data, &prefix)); if(entry != NULL) { switch(qtype) { case dns_rdatatype_any: points = damp->score.qtype_any; break; default : points = 0; break; } if(entry->last_id == message_id) { points += (entry->last_id_count++)*damp->score.duplicates; } else { entry->last_id = message_id; entry->last_id_count = 1; } DAMPENING_STATISTICS_DO(impl, update, impl->update(impl->data, &entry, points, now)); } UNLOCK(&impl->lock); } }
int ns_sortlist_addrorder2(const isc_netaddr_t *addr, const void *arg) { const dns_acl_t *sortacl = (const dns_acl_t *) arg; int match; (void)dns_acl_match(addr, NULL, sortacl, &ns_g_server->aclenv, &match, NULL); if (match > 0) return (match); else if (match < 0) return (INT_MAX - (-match)); else return (INT_MAX / 2); }
static isc_boolean_t address_ok(isc_sockaddr_t *sockaddr, dns_acl_t *acl) { isc_netaddr_t netaddr; isc_result_t result; int match; isc_netaddr_fromsockaddr(&netaddr, sockaddr); result = dns_acl_match(&netaddr, NULL, acl, &ns_g_server->aclenv, &match, NULL); if (result != ISC_R_SUCCESS || match <= 0) return (ISC_FALSE); else return (ISC_TRUE); }
void dns_dampening_score_size(dns_dampening_t * damp, const isc_sockaddr_t * addr, isc_stdtime_t now, int length) { isc_netaddr_t netaddr, prefix; dns_dampening_entry_t * entry; uint16_t points; dns_dampening_implementation_t *impl; RUNTIME_CHECK( damp != NULL ); RUNTIME_CHECK( addr != NULL ); isc_netaddr_fromsockaddr(&netaddr, addr); extract_prefix(&prefix, &netaddr, &(damp->prefixlen)); for(impl = damp->workers; impl - damp->workers < damp->workers_count; impl++) { if(damp->exempt != NULL) { int match; if (ISC_R_SUCCESS == dns_acl_match(&netaddr, NULL, damp->exempt, NULL, &match, NULL) && match > 0) { DAMPENING_STATISTICS_INC(impl,skipped); continue; } } DAMPENING_STATISTICS_DO(impl, lock, LOCK(&impl->lock)); DAMPENING_STATISTICS_DO(impl, search, entry = impl->search(impl->data, &prefix)); if(entry != NULL) { length = ISC_MAX(length, damp->score.minimum_size); length = ISC_MIN(length, damp->score.maximum_size); points = damp->score.size_penalty * (length - damp->score.minimum_size) / (damp->score.maximum_size - damp->score.minimum_size); DAMPENING_STATISTICS_DO(impl, update, impl->update(impl->data, &entry, points, now)); } UNLOCK(&impl->lock); } }
static isc_result_t do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, isc_boolean_t verbose) { isc_interfaceiter_t *iter = NULL; isc_boolean_t scan_ipv4 = ISC_FALSE; isc_boolean_t scan_ipv6 = ISC_FALSE; isc_boolean_t adjusting = ISC_FALSE; isc_boolean_t ipv6only = ISC_TRUE; isc_boolean_t ipv6pktinfo = ISC_TRUE; isc_result_t result; isc_netaddr_t zero_address, zero_address6; ns_listenelt_t *le; isc_sockaddr_t listen_addr; ns_interface_t *ifp; isc_boolean_t log_explicit = ISC_FALSE; isc_boolean_t dolistenon; if (ext_listen != NULL) adjusting = ISC_TRUE; if (isc_net_probeipv6() == ISC_R_SUCCESS) scan_ipv6 = ISC_TRUE; #ifdef WANT_IPV6 else isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "no IPv6 interfaces found"); #endif if (isc_net_probeipv4() == ISC_R_SUCCESS) scan_ipv4 = ISC_TRUE; else isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "no IPv4 interfaces found"); /* * A special, but typical case; listen-on-v6 { any; }. * When we can make the socket IPv6-only, open a single wildcard * socket for IPv6 communication. Otherwise, make separate socket * for each IPv6 address in order to avoid accepting IPv4 packets * as the form of mapped addresses unintentionally unless explicitly * allowed. */ #ifndef ISC_ALLOW_MAPPED if (scan_ipv6 == ISC_TRUE && isc_net_probe_ipv6only() != ISC_R_SUCCESS) { ipv6only = ISC_FALSE; log_explicit = ISC_TRUE; } #endif if (scan_ipv6 == ISC_TRUE && isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) { ipv6pktinfo = ISC_FALSE; log_explicit = ISC_TRUE; } if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) { for (le = ISC_LIST_HEAD(mgr->listenon6->elts); le != NULL; le = ISC_LIST_NEXT(le, link)) { struct in6_addr in6a; if (!listenon_is_ip6_any(le)) continue; in6a = in6addr_any; isc_sockaddr_fromin6(&listen_addr, &in6a, le->port); ifp = find_matching_interface(mgr, &listen_addr); if (ifp != NULL) { ifp->generation = mgr->generation; } else { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, "listening on IPv6 " "interfaces, port %u", le->port); result = ns_interface_setup(mgr, &listen_addr, "<any>", &ifp, ISC_TRUE); if (result == ISC_R_SUCCESS) ifp->flags |= NS_INTERFACEFLAG_ANYADDR; else isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "listening on all IPv6 " "interfaces failed"); /* Continue. */ } } } isc_netaddr_any(&zero_address); isc_netaddr_any6(&zero_address6); result = isc_interfaceiter_create(mgr->mctx, &iter); if (result != ISC_R_SUCCESS) return (result); if (adjusting == ISC_FALSE) { result = clearacl(mgr->mctx, &mgr->aclenv.localhost); if (result != ISC_R_SUCCESS) goto cleanup_iter; result = clearacl(mgr->mctx, &mgr->aclenv.localnets); if (result != ISC_R_SUCCESS) goto cleanup_iter; clearlistenon(mgr); } for (result = isc_interfaceiter_first(iter); result == ISC_R_SUCCESS; result = isc_interfaceiter_next(iter)) { isc_interface_t interface; ns_listenlist_t *ll; unsigned int family; result = isc_interfaceiter_current(iter, &interface); if (result != ISC_R_SUCCESS) break; family = interface.address.family; if (family != AF_INET && family != AF_INET6) continue; if (scan_ipv4 == ISC_FALSE && family == AF_INET) continue; if (scan_ipv6 == ISC_FALSE && family == AF_INET6) continue; /* * Test for the address being nonzero rather than testing * INTERFACE_F_UP, because on some systems the latter * follows the media state and we could end up ignoring * the interface for an entire rescan interval due to * a temporary media glitch at rescan time. */ if (family == AF_INET && isc_netaddr_equal(&interface.address, &zero_address)) { continue; } if (family == AF_INET6 && isc_netaddr_equal(&interface.address, &zero_address6)) { continue; } if (adjusting == ISC_FALSE) { result = setup_locals(mgr, &interface); if (result != ISC_R_SUCCESS) goto ignore_interface; } ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6; dolistenon = ISC_TRUE; for (le = ISC_LIST_HEAD(ll->elts); le != NULL; le = ISC_LIST_NEXT(le, link)) { int match; isc_boolean_t ipv6_wildcard = ISC_FALSE; isc_netaddr_t listen_netaddr; isc_sockaddr_t listen_sockaddr; /* * Construct a socket address for this IP/port * combination. */ if (family == AF_INET) { isc_netaddr_fromin(&listen_netaddr, &interface.address.type.in); } else { isc_netaddr_fromin6(&listen_netaddr, &interface.address.type.in6); isc_netaddr_setzone(&listen_netaddr, interface.address.zone); } isc_sockaddr_fromnetaddr(&listen_sockaddr, &listen_netaddr, le->port); /* * See if the address matches the listen-on statement; * if not, ignore the interface. */ (void)dns_acl_match(&listen_netaddr, NULL, le->acl, &mgr->aclenv, &match, NULL); if (match <= 0) continue; if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) { setup_listenon(mgr, &interface, le->port); dolistenon = ISC_FALSE; } /* * The case of "any" IPv6 address will require * special considerations later, so remember it. */ if (family == AF_INET6 && ipv6only && ipv6pktinfo && listenon_is_ip6_any(le)) ipv6_wildcard = ISC_TRUE; /* * When adjusting interfaces with extra a listening * list, see if the address matches the extra list. * If it does, and is also covered by a wildcard * interface, we need to listen on the address * explicitly. */ if (adjusting == ISC_TRUE) { ns_listenelt_t *ele; match = 0; for (ele = ISC_LIST_HEAD(ext_listen->elts); ele != NULL; ele = ISC_LIST_NEXT(ele, link)) { (void)dns_acl_match(&listen_netaddr, NULL, ele->acl, NULL, &match, NULL); if (match > 0 && (ele->port == le->port || ele->port == 0)) break; else match = 0; } if (ipv6_wildcard == ISC_TRUE && match == 0) continue; } ifp = find_matching_interface(mgr, &listen_sockaddr); if (ifp != NULL) { ifp->generation = mgr->generation; } else { char sabuf[ISC_SOCKADDR_FORMATSIZE]; if (adjusting == ISC_FALSE && ipv6_wildcard == ISC_TRUE) continue; if (log_explicit && family == AF_INET6 && !adjusting && listenon_is_ip6_any(le)) { isc_log_write(IFMGR_COMMON_LOGARGS, verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), "IPv6 socket API is " "incomplete; explicitly " "binding to each IPv6 " "address separately"); log_explicit = ISC_FALSE; } isc_sockaddr_format(&listen_sockaddr, sabuf, sizeof(sabuf)); isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, "%s" "listening on %s interface " "%s, %s", (adjusting == ISC_TRUE) ? "additionally " : "", (family == AF_INET) ? "IPv4" : "IPv6", interface.name, sabuf); result = ns_interface_setup(mgr, &listen_sockaddr, interface.name, &ifp, (adjusting == ISC_TRUE) ? ISC_FALSE : ISC_TRUE); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "creating %s interface " "%s failed; interface " "ignored", (family == AF_INET) ? "IPv4" : "IPv6", interface.name); } /* Continue. */ } } continue; ignore_interface: isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "ignoring %s interface %s: %s", (family == AF_INET) ? "IPv4" : "IPv6", interface.name, isc_result_totext(result)); continue; } if (result != ISC_R_NOMORE) UNEXPECTED_ERROR(__FILE__, __LINE__, "interface iteration failed: %s", isc_result_totext(result)); else result = ISC_R_SUCCESS; cleanup_iter: isc_interfaceiter_destroy(&iter); return (result); }
/* * Like dns_acl_match, but matches against the single ACL element 'e' * rather than a complete ACL, and returns ISC_TRUE iff it matched. * * To determine whether the match was positive or negative, the * caller should examine e->negative. Since the element 'e' may be * a reference to a named ACL or a nested ACL, a matching element * returned through 'matchelt' is not necessarily 'e' itself. */ isc_boolean_t dns_aclelement_match(const isc_netaddr_t *reqaddr, const dns_name_t *reqsigner, const dns_aclelement_t *e, const dns_aclenv_t *env, const dns_aclelement_t **matchelt) { dns_acl_t *inner = NULL; int indirectmatch; isc_result_t result; switch (e->type) { case dns_aclelementtype_keyname: if (reqsigner != NULL && dns_name_equal(reqsigner, &e->keyname)) { if (matchelt != NULL) *matchelt = e; return (ISC_TRUE); } else { return (ISC_FALSE); } case dns_aclelementtype_nestedacl: inner = e->nestedacl; break; case dns_aclelementtype_localhost: if (env == NULL || env->localhost == NULL) return (ISC_FALSE); inner = env->localhost; break; case dns_aclelementtype_localnets: if (env == NULL || env->localnets == NULL) return (ISC_FALSE); inner = env->localnets; break; default: /* Should be impossible. */ INSIST(0); } result = dns_acl_match(reqaddr, reqsigner, inner, env, &indirectmatch, matchelt); INSIST(result == ISC_R_SUCCESS); /* * Treat negative matches in indirect ACLs as "no match". * That way, a negated indirect ACL will never become a * surprise positive match through double negation. * XXXDCL this should be documented. */ if (indirectmatch > 0) { if (matchelt != NULL) *matchelt = e; return (ISC_TRUE); } /* * A negative indirect match may have set *matchelt, but we don't * want it set when we return. */ if (matchelt != NULL) *matchelt = NULL; return (ISC_FALSE); }
isc_boolean_t dns_aclelement_match(isc_netaddr_t *reqaddr, dns_name_t *reqsigner, dns_aclelement_t *e, dns_aclenv_t *env, dns_aclelement_t **matchelt) { dns_acl_t *inner = NULL; isc_netaddr_t *addr; isc_netaddr_t v4addr; int indirectmatch; isc_result_t result; switch (e->type) { case dns_aclelementtype_ipprefix: if (env == NULL || env->match_mapped == ISC_FALSE || reqaddr->family != AF_INET6 || !IN6_IS_ADDR_V4MAPPED(&reqaddr->type.in6)) addr = reqaddr; else { isc_netaddr_fromv4mapped(&v4addr, reqaddr); addr = &v4addr; } if (isc_netaddr_eqprefix(addr, &e->u.ip_prefix.address, e->u.ip_prefix.prefixlen)) goto matched; break; case dns_aclelementtype_keyname: if (reqsigner != NULL && dns_name_equal(reqsigner, &e->u.keyname)) goto matched; break; case dns_aclelementtype_nestedacl: inner = e->u.nestedacl; nested: result = dns_acl_match(reqaddr, reqsigner, inner, env, &indirectmatch, matchelt); INSIST(result == ISC_R_SUCCESS); /* * Treat negative matches in indirect ACLs as * "no match". * That way, a negated indirect ACL will never become * a surprise positive match through double negation. * XXXDCL this should be documented. */ if (indirectmatch > 0) goto matchelt_set; /* * A negative indirect match may have set *matchelt, * but we don't want it set when we return. */ if (matchelt != NULL) *matchelt = NULL; break; case dns_aclelementtype_any: matched: if (matchelt != NULL) *matchelt = e; matchelt_set: return (ISC_TRUE); case dns_aclelementtype_localhost: if (env != NULL && env->localhost != NULL) { inner = env->localhost; goto nested; } else { break; } case dns_aclelementtype_localnets: if (env != NULL && env->localnets != NULL) { inner = env->localnets; goto nested; } else { break; } default: INSIST(0); break; } return (ISC_FALSE); }
dns_dampening_state_t dns_dampening_query(dns_dampening_t * damp, const isc_sockaddr_t * addr, isc_stdtime_t now, int * penalty) { isc_netaddr_t netaddr, prefix; dns_dampening_state_t final_state = DNS_DAMPENING_STATE_NORMAL, state = DNS_DAMPENING_STATE_NORMAL; dns_dampening_entry_t * entry; dns_dampening_implementation_t *impl; int max_penalty = -2; RUNTIME_CHECK( damp != NULL ); RUNTIME_CHECK( addr != NULL ); isc_netaddr_fromsockaddr(&netaddr, addr); extract_prefix(&prefix, &netaddr, &(damp->prefixlen)); for(impl = damp->workers; impl - damp->workers < damp->workers_count; impl++) { if(damp->exempt != NULL) { int match; if (ISC_R_SUCCESS == dns_acl_match(&netaddr, NULL, damp->exempt, NULL, &match, NULL) && match > 0) { max_penalty = ISC_MAX(max_penalty, -1); DAMPENING_STATISTICS_INC(impl,skipped); continue; } } DAMPENING_STATISTICS_DO(impl, lock, LOCK(&impl->lock)); if(damp->statistics.report_interval > 0 && damp->statistics.report_interval + impl->statistics.last_report <= now) { if(isc_log_wouldlog(dns_lctx, ISC_LOG_INFO)) isc_log_write(dns_lctx, DNS_LOGCATEGORY_DAMPENING, DNS_LOGMODULE_REQUEST, ISC_LOG_INFO, "Stats for #%d: queries %u/%u/%u: lock=%ld.%06ld, search=%ld.%06ld, update=%ld.%06ld, add=%ld.%06ld", impl - damp->workers, impl->statistics.allowed, impl->statistics.denied, impl->statistics.skipped, impl->statistics.lock.tv_sec, impl->statistics.lock.tv_usec, impl->statistics.search.tv_sec, impl->statistics.search.tv_usec, impl->statistics.update.tv_sec, impl->statistics.update.tv_usec, impl->statistics.add.tv_sec, impl->statistics.add.tv_usec); memset(&impl->statistics, 0, sizeof(impl->statistics)); impl->statistics.last_report = now; } DAMPENING_STATISTICS_DO(impl, search, entry = impl->search(impl->data, &prefix)); if(entry == NULL) { state = DNS_DAMPENING_STATE_NORMAL; DAMPENING_STATISTICS_DO(impl, add, impl->add(impl->data, &prefix, damp->score.first_query, now)); max_penalty = ISC_MAX(max_penalty, 0); } else { state = entry->dampening == 1 ? DNS_DAMPENING_STATE_SUPPRESS : DNS_DAMPENING_STATE_NORMAL; max_penalty = ISC_MAX(max_penalty, entry->penalty); DAMPENING_STATISTICS_DO(impl, update, impl->update(impl->data, &entry, damp->score.per_query, now)); } if(state == DNS_DAMPENING_STATE_NORMAL) { DAMPENING_STATISTICS_INC(impl, allowed); } else { DAMPENING_STATISTICS_INC(impl, denied); final_state = state; /* any dampening suffice */ } UNLOCK(&impl->lock); } if(penalty != NULL) *penalty = max_penalty; return final_state; }