Example #1
0
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);
}
Example #2
0
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);
   }
}
Example #3
0
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);
}
Example #4
0
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);
}
Example #5
0
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);
   }
}
Example #6
0
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);
}
Example #7
0
/*
 * 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);
}
Example #8
0
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);
}	
Example #9
0
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;
}