Ejemplo n.º 1
0
isc_boolean_t
isc_sockaddr_eqaddrprefix(const isc_sockaddr_t *a, const isc_sockaddr_t *b,
			  unsigned int prefixlen)
{
	isc_netaddr_t na, nb;
	isc_netaddr_fromsockaddr(&na, a);
	isc_netaddr_fromsockaddr(&nb, b);
	return (isc_netaddr_eqprefix(&na, &nb, prefixlen));
}
Ejemplo n.º 2
0
static unsigned char
GAA_find_prefix(isc_interfaceiter_t *iter) {
	IP_ADAPTER_PREFIX *	ipap;
	IP_ADAPTER_PREFIX *	ipap_match;
	int			match_len;
	int			max_len;
	isc_netaddr_t		target;
	u_short			af;
	isc_netaddr_t		pfx;
	int			pfx_len;
	size_t			nbytes;
	unsigned char		nbits;
	unsigned char *		pbits;
	unsigned int		octets;

	match_len = 0;
	ipap_match = NULL;
	isc_netaddr_fromsockaddr(&target,
	    (isc_sockaddr_t *)iter->ipuaCur->Address.lpSockaddr);
	af = (u_short)target.family;
	INSIST(AF_INET == af || AF_INET6 == af);
	max_len = (AF_INET6 == af) ? 128 : 32;
	iter->current.netmask.family = af;
	for (ipap = iter->ipaaCur->FirstPrefix;
	     ipap != NULL;
	     ipap = ipap->Next) {
		if (ipap->Address.lpSockaddr->sa_family != af)
			continue;
		isc_netaddr_fromsockaddr(&pfx,
		    (isc_sockaddr_t *)ipap->Address.lpSockaddr);
		pfx_len = ipap->PrefixLength;
		INSIST(0 <= pfx_len && pfx_len <= max_len);
		if (pfx_len > match_len && pfx_len < max_len &&
		    isc_netaddr_eqprefix(&target, &pfx, pfx_len)) {
			ipap_match = ipap;
			match_len = pfx_len;
		}
	}
	if (NULL == ipap_match) {
		/* presume all-ones mask */
		if (AF_INET6 == af)
			octets = sizeof(iter->current.netmask.type.in6);
		else
			octets = sizeof(iter->current.netmask.type.in);
		memset(&iter->current.netmask.type, 0xFF, octets);
		return (8 * (unsigned char)octets);
	}
	nbytes = match_len / 8;
	nbits = match_len % 8;
	memset(&iter->current.netmask.type.in6, 0xFF, nbytes);
	pbits = (void *)&iter->current.netmask.type.in6;
	pbits += nbytes;
	*pbits |= 0xFF << (8 - nbits);
	return ((unsigned char)match_len);
}
Ejemplo n.º 3
0
isc_boolean_t
isc_sockaddr_ismulticast(isc_sockaddr_t *sockaddr) {
	isc_netaddr_t netaddr;

	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
	return (isc_netaddr_ismulticast(&netaddr));
}
Ejemplo n.º 4
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);
}
Ejemplo n.º 5
0
isc_boolean_t
isc_sockaddr_islinklocal(const isc_sockaddr_t *sockaddr) {
	isc_netaddr_t netaddr;

	if (sockaddr->type.sa.sa_family == AF_INET6) {
		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
		return (isc_netaddr_islinklocal(&netaddr));
	}
	return (ISC_FALSE);
}
Ejemplo n.º 6
0
isc_boolean_t
isc_sockaddr_isexperimental(isc_sockaddr_t *sockaddr) {
	isc_netaddr_t netaddr;

	if (sockaddr->type.sa.sa_family == AF_INET) {
		isc_netaddr_fromsockaddr(&netaddr, sockaddr);
		return (isc_netaddr_isexperimental(&netaddr));
	}
	return (ISC_FALSE);
}
Ejemplo n.º 7
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);
   }
}
Ejemplo n.º 8
0
static isc_result_t
internal_current_GAA(isc_interfaceiter_t *iter) {
	IP_ADAPTER_ADDRESSES *adap;
	IP_ADAPTER_UNICAST_ADDRESS *addr;
	unsigned char prefix_len;

	REQUIRE(iter->ipaaCur != NULL);
	REQUIRE(iter->ipuaCur != NULL);
	adap = iter->ipaaCur;
	addr = iter->ipuaCur;
	if (IpDadStatePreferred != addr->DadState)
		return (ISC_R_IGNORE);
	memset(&iter->current, 0, sizeof(iter->current));
	iter->current.af = addr->Address.lpSockaddr->sa_family;
	isc_netaddr_fromsockaddr(&iter->current.address,
	    (isc_sockaddr_t *)addr->Address.lpSockaddr);
	if (AF_INET6 == iter->current.af)
		iter->current.ifindex = adap->Ipv6IfIndex;
	iter->current.name[0] = '\0';
	WideCharToMultiByte(
		CP_ACP, 
		0, 
		adap->FriendlyName,
		-1,
		iter->current.name,
		sizeof(iter->current.name),
		NULL,
		NULL);
	iter->current.name[sizeof(iter->current.name) - 1] = '\0';
	if (IfOperStatusUp == adap->OperStatus)
		iter->current.flags |= INTERFACE_F_UP;
	if (IF_TYPE_PPP == adap->IfType)
		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
	else if (IF_TYPE_SOFTWARE_LOOPBACK == adap->IfType)
		iter->current.flags |= INTERFACE_F_LOOPBACK;
	if ((IP_ADAPTER_NO_MULTICAST & adap->Flags) == 0)
		iter->current.flags |= INTERFACE_F_MULTICAST;
	if (IpSuffixOriginRandom == addr->SuffixOrigin)
		iter->current.flags |= INTERFACE_F_PRIVACY;

	prefix_len = GAA_find_prefix(iter);
	/* I'm failing to see a broadcast flag via GAA */
	if (AF_INET == iter->current.af && prefix_len < 32 &&
	    (INTERFACE_F_LOOPBACK & iter->current.flags) == 0) {
		iter->current.flags |= INTERFACE_F_BROADCAST;
		get_broadcastaddr(&iter->current.broadcast,
				  &iter->current.address,
				  &iter->current.netmask);
	}
	return (ISC_R_SUCCESS);
}
Ejemplo n.º 9
0
static void
print_addresses(dns_adbfind_t *adbfind) {
	dns_adbaddrinfo_t *address;

	for (address = ISC_LIST_HEAD(adbfind->list);
	     address != NULL;
	     address = ISC_LIST_NEXT(address, publink)) {
		isc_netaddr_t netaddr;
		char text[ISC_NETADDR_FORMATSIZE];
		isc_netaddr_fromsockaddr(&netaddr, &address->sockaddr);
		isc_netaddr_format(&netaddr, text, sizeof(text));
		printf("%s\n", text);
	}
}
Ejemplo n.º 10
0
isc_result_t
isc_sockaddr_totext(const isc_sockaddr_t *sockaddr, isc_buffer_t *target) {
	isc_result_t result;
	isc_netaddr_t netaddr;
	char pbuf[sizeof("65000")];
	unsigned int plen;
	isc_region_t avail;

	REQUIRE(sockaddr != NULL);

	/*
	 * Do the port first, giving us the opportunity to check for
	 * unsupported address families before calling
	 * isc_netaddr_fromsockaddr().
	 */
	switch (sockaddr->type.sa.sa_family) {
	case AF_INET:
		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin.sin_port));
		break;
	case AF_INET6:
		snprintf(pbuf, sizeof(pbuf), "%u", ntohs(sockaddr->type.sin6.sin6_port));
		break;
	default:
		return (ISC_R_FAILURE);
	}

	plen = strlen(pbuf);
	INSIST(plen < sizeof(pbuf));

	isc_netaddr_fromsockaddr(&netaddr, sockaddr);
	result = isc_netaddr_totext(&netaddr, target);
	if (result != ISC_R_SUCCESS)
		return (result);

	if (1 + plen + 1 > isc_buffer_availablelength(target))
		return (ISC_R_NOSPACE);

	isc_buffer_putmem(target, (const unsigned char *)"#", 1);
	isc_buffer_putmem(target, (const unsigned char *)pbuf, plen);

	/*
	 * Null terminate after used region.
	 */
	isc_buffer_availableregion(target, &avail);
	INSIST(avail.length >= 1);
	avail.base[0] = '\0';

	return (ISC_R_SUCCESS);
}
Ejemplo n.º 11
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);
}
Ejemplo n.º 12
0
static void
sort_addresses(ns_lwdclient_t *client) {
	unsigned int naddrs;
	rankedaddress *addrs;
	isc_netaddr_t remote;
	dns_addressorderfunc_t order;
	const void *arg;
	ns_lwresd_t *lwresd = client->clientmgr->listener->manager;
	unsigned int i;
	isc_result_t result;

	naddrs = client->gabn.naddrs;

	if (naddrs <= 1 || lwresd->view->sortlist == NULL)
		return;

	addrs = isc_mem_get(lwresd->mctx, sizeof(rankedaddress) * naddrs);
	if (addrs == NULL)
		return;

	isc_netaddr_fromsockaddr(&remote, &client->address);
	ns_sortlist_byaddrsetup(lwresd->view->sortlist,
				&remote, &order, &arg);
	if (order == NULL) {
		isc_mem_put(lwresd->mctx, addrs,
			    sizeof(rankedaddress) * naddrs);
		return;
	}
	for (i = 0; i < naddrs; i++) {
		result = lwaddr_netaddr_fromlwresaddr(&addrs[i].address,
						      &client->addrs[i]);
		INSIST(result == ISC_R_SUCCESS);
		addrs[i].rank = (*order)(&addrs[i].address, arg);
	}
	qsort(addrs, naddrs, sizeof(rankedaddress), addr_compare);
	for (i = 0; i < naddrs; i++) {
		result = lwaddr_lwresaddr_fromnetaddr(&client->addrs[i],
						      &addrs[i].address);
		INSIST(result == ISC_R_SUCCESS);
	}

	isc_mem_put(lwresd->mctx, addrs, sizeof(rankedaddress) * naddrs);
}
Ejemplo n.º 13
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);
   }
}
Ejemplo n.º 14
0
int
sockaddr_masktoprefixlen(
	const sockaddr_u *	psa
	)
{
	isc_netaddr_t	isc_na;
	isc_sockaddr_t	isc_sa;
	u_int		pfxlen;
	bool		result;
	int		rc;

	ZERO(isc_sa);
	memcpy(&isc_sa.type, psa,
	       min(sizeof(isc_sa.type), sizeof(*psa)));
	isc_netaddr_fromsockaddr(&isc_na, &isc_sa);
	result = isc_netaddr_masktoprefixlen_bool(&isc_na, &pfxlen);
	rc = (result)
		 ? (int)pfxlen
		 : -1;

	return rc;
}
Ejemplo n.º 15
0
static void
getaddresses(dig_lookup_t *lookup, const char *host) {
	isc_result_t result;
	isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
	isc_netaddr_t netaddr;
	int count, i;
	dig_server_t *srv;
	char tmp[ISC_NETADDR_FORMATSIZE];

	result = bind9_getaddresses(host, 0, sockaddrs,
				    DIG_MAX_ADDRESSES, &count);
	if (result != ISC_R_SUCCESS)
	fatal("couldn't get address for '%s': %s",
	      host, isc_result_totext(result));

	for (i = 0; i < count; i++) {
		isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
		isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
		srv = make_server(tmp, host);
		ISC_LIST_APPEND(lookup->my_server_list, srv, link);
	}
	addresscount = count;
}
Ejemplo n.º 16
0
isc_result_t
lwaddr_lwresaddr_fromsockaddr(lwres_addr_t *la, isc_sockaddr_t *sa) {
	isc_netaddr_t na;
	isc_netaddr_fromsockaddr(&na, sa);
	return (lwaddr_lwresaddr_fromnetaddr(la, &na));
}
Ejemplo n.º 17
0
static isc_result_t
internal_current(isc_interfaceiter_t *iter) {
	BOOL ifNamed = FALSE;
	unsigned long flags;

	REQUIRE(VALID_IFITER(iter));
	REQUIRE(iter->numIF >= 0);

	memset(&iter->current, 0, sizeof(iter->current));
	iter->current.af = AF_INET;

	isc_netaddr_fromsockaddr(&iter->current.address,
	    (isc_sockaddr_t *)&(iter->IFData.iiAddress));

	/*
	 * Get interface flags.
	 */

	iter->current.flags = 0;
	flags = iter->IFData.iiFlags;

	if ((flags & IFF_UP) != 0)
		iter->current.flags |= INTERFACE_F_UP;

	if ((flags & IFF_BROADCAST) != 0)
		iter->current.flags |= INTERFACE_F_BROADCAST;

	if ((flags & IFF_MULTICAST) != 0)
		iter->current.flags |= INTERFACE_F_MULTICAST;

	if ((flags & IFF_POINTTOPOINT) != 0) {
		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
		snprintf(iter->current.name, sizeof(iter->current.name),
			 "PPP %d", iter->numIF);
		ifNamed = TRUE;
	}

	if ((flags & IFF_LOOPBACK) != 0) {
		iter->current.flags |= INTERFACE_F_LOOPBACK;
		snprintf(iter->current.name, sizeof(iter->current.name),
			"v4loop %d", iter->numIF);
		ifNamed = TRUE;
	}

	/*
	 * If the interface is point-to-point, get the destination address.
	 */
	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
		isc_netaddr_fromsockaddr(&iter->current.dstaddress,
		    (isc_sockaddr_t *)&(iter->IFData.iiBroadcastAddress));

	/*
	 * Get the network mask.
	 */
	isc_netaddr_fromsockaddr(&iter->current.netmask,
	    (isc_sockaddr_t *)&(iter->IFData.iiNetmask));

	/*
	 * If the interface is broadcast, get the broadcast address,
	 * based on the unicast address and network mask.
	 */
	if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0)
		get_broadcastaddr(&iter->current.broadcast,
				  &iter->current.address,
				  &iter->current.netmask);

	if (ifNamed == FALSE)
		snprintf(iter->current.name, sizeof(iter->current.name),
			"IPv4 %d", iter->numIF);

	return (ISC_R_SUCCESS);
}
Ejemplo n.º 18
0
/*%
 * Configure an apex NS with glues for a static-stub zone.
 * For example, for the zone named "example.com", the following RRs will be
 * added to the zone DB:
 * example.com. NS example.com.
 * example.com. A 192.0.2.1
 * example.com. AAAA 2001:db8::1
 */
static isc_result_t
configure_staticstub_serveraddrs(const cfg_obj_t *zconfig, dns_zone_t *zone,
				 dns_rdatalist_t *rdatalist_ns,
				 dns_rdatalist_t *rdatalist_a,
				 dns_rdatalist_t *rdatalist_aaaa)
{
	const cfg_listelt_t *element;
	isc_mem_t *mctx = dns_zone_getmctx(zone);
	isc_region_t region, sregion;
	dns_rdata_t *rdata;
	isc_result_t result = ISC_R_SUCCESS;

	for (element = cfg_list_first(zconfig);
	     element != NULL;
	     element = cfg_list_next(element))
	{
		const isc_sockaddr_t* sa;
		isc_netaddr_t na;
		const cfg_obj_t *address = cfg_listelt_value(element);
		dns_rdatalist_t *rdatalist;

		sa = cfg_obj_assockaddr(address);
		if (isc_sockaddr_getport(sa) != 0) {
			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
				    "port is not configurable for "
				    "static stub server-addresses");
			return (ISC_R_FAILURE);
		}
		isc_netaddr_fromsockaddr(&na, sa);
		if (isc_netaddr_getzone(&na) != 0) {
			cfg_obj_log(zconfig, ns_g_lctx, ISC_LOG_ERROR,
					    "scoped address is not allowed "
					    "for static stub "
					    "server-addresses");
			return (ISC_R_FAILURE);
		}

		switch (na.family) {
		case AF_INET:
			region.length = sizeof(na.type.in);
			rdatalist = rdatalist_a;
			break;
		default:
			INSIST(na.family == AF_INET6);
			region.length = sizeof(na.type.in6);
			rdatalist = rdatalist_aaaa;
			break;
		}

		rdata = isc_mem_get(mctx, sizeof(*rdata) + region.length);
		if (rdata == NULL)
			return (ISC_R_NOMEMORY);
		region.base = (unsigned char *)(rdata + 1);
		memcpy(region.base, &na.type, region.length);
		dns_rdata_init(rdata);
		dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
				     rdatalist->type, &region);
		ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
	}

	/*
	 * If no address is specified (unlikely in this context, but possible),
	 * there's nothing to do anymore.
	 */
	if (ISC_LIST_EMPTY(rdatalist_a->rdata) &&
	    ISC_LIST_EMPTY(rdatalist_aaaa->rdata)) {
		return (ISC_R_SUCCESS);
	}

	/* Add to the list an apex NS with the ns name being the origin name */
	dns_name_toregion(dns_zone_getorigin(zone), &sregion);
	rdata = isc_mem_get(mctx, sizeof(*rdata) + sregion.length);
	if (rdata == NULL) {
		/*
		 * Already allocated data will be freed in the caller, so
		 * we can simply return here.
		 */
		return (ISC_R_NOMEMORY);
	}
	region.length = sregion.length;
	region.base = (unsigned char *)(rdata + 1);
	memcpy(region.base, sregion.base, region.length);
	dns_rdata_init(rdata);
	dns_rdata_fromregion(rdata, dns_zone_getclass(zone),
			     dns_rdatatype_ns, &region);
	ISC_LIST_APPEND(rdatalist_ns->rdata, rdata, link);

	return (result);
}
Ejemplo n.º 19
0
static isc_result_t
internal_current6(isc_interfaceiter_t *iter) {
	BOOL ifNamed = FALSE;
	struct sockaddr_in6 *psa6;
	BOOL localhostSeen;
	int i;

	REQUIRE(VALID_IFITER(iter));
	REQUIRE(iter->pos6 >= 0);
	REQUIRE(iter->buf6 != 0);

	memset(&iter->current, 0, sizeof(iter->current));
	iter->current.af = AF_INET6;

	/*
	 * synthesize localhost ::1 before returning the rest, if ::1
	 * is not on the list.
	 */
	if (iter->pos6 >= (unsigned)iter->buf6->iAddressCount) {
		localhostSeen = FALSE;
		for (i = 0; i < iter->buf6->iAddressCount; i++) {
			psa6 = (struct sockaddr_in6 *)
			       iter->buf6->Address[i].lpSockaddr;
			if (!memcmp(&iter->loop__1, &psa6->sin6_addr,
				    sizeof(iter->loop__1))) {
				localhostSeen = TRUE;
				break;
			}
		}
		if (localhostSeen)
			iter->pos6 = iter->buf6->iAddressCount - 1;
	}

	if (iter->pos6 < (unsigned)iter->buf6->iAddressCount) {
		isc_netaddr_fromsockaddr(&iter->current.address,
		    (isc_sockaddr_t *)iter->buf6->Address[iter->pos6].lpSockaddr);
	} else {
		iter->current.address.family = AF_INET6;
		memcpy(&iter->current.address.type.in6, &iter->loop__1,
		       sizeof(iter->current.address.type.in6));
	}

	/*
	 * Get interface flags.
	 */

	iter->current.flags = INTERFACE_F_UP | INTERFACE_F_MULTICAST;

	if (!memcmp(&iter->current.address.type.in6, &iter->loop__1,
		    sizeof(iter->current.address.type.in6)) ||
	    !memcmp(&iter->current.address.type.in6, &iter->loopfe80__1,
	            sizeof(iter->current.address.type.in6))) {

		iter->current.flags |= INTERFACE_F_LOOPBACK;
		snprintf(iter->current.name, sizeof(iter->current.name),
			 "v6loop %d",
			 iter->buf6->iAddressCount - iter->pos6);
		ifNamed = TRUE;
	}

	if (ifNamed == FALSE)
		snprintf(iter->current.name, sizeof(iter->current.name),
			 "IPv6 %d",
			 iter->buf6->iAddressCount - iter->pos6);

	memset(iter->current.netmask.type.in6.s6_addr, 0xff,
	       sizeof(iter->current.netmask.type.in6.s6_addr));
	iter->current.netmask.family = AF_INET6;
	return (ISC_R_SUCCESS);
}
Ejemplo n.º 20
0
void
ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype) {
	isc_result_t result;
	dns_name_t *question_name;
	dns_rdataset_t *question_rdataset;
	dns_zone_t *zone = NULL, *raw = NULL, *mayberaw;
	dns_db_t *db = NULL;
	dns_dbversion_t *ver = NULL;
	dns_rdataclass_t question_class;
	rrstream_t *soa_stream = NULL;
	rrstream_t *data_stream = NULL;
	rrstream_t *stream = NULL;
	dns_difftuple_t *current_soa_tuple = NULL;
	dns_name_t *soa_name;
	dns_rdataset_t *soa_rdataset;
	dns_rdata_t soa_rdata = DNS_RDATA_INIT;
	isc_boolean_t have_soa = ISC_FALSE;
	const char *mnemonic = NULL;
	isc_mem_t *mctx = client->mctx;
	dns_message_t *request = client->message;
	xfrout_ctx_t *xfr = NULL;
	isc_quota_t *quota = NULL;
	dns_transfer_format_t format = client->view->transfer_format;
	isc_netaddr_t na;
	dns_peer_t *peer = NULL;
	isc_buffer_t *tsigbuf = NULL;
	char *journalfile;
	char msg[NS_CLIENT_ACLMSGSIZE("zone transfer")];
	char keyname[DNS_NAME_FORMATSIZE];
	isc_boolean_t is_poll = ISC_FALSE;
	isc_boolean_t is_dlz = ISC_FALSE;
	isc_boolean_t is_ixfr = ISC_FALSE;
	isc_uint32_t begin_serial = 0, current_serial;

	switch (reqtype) {
	case dns_rdatatype_axfr:
		mnemonic = "AXFR";
		break;
	case dns_rdatatype_ixfr:
		mnemonic = "IXFR";
		break;
	default:
		INSIST(0);
		break;
	}

	ns_client_log(client,
		      DNS_LOGCATEGORY_XFER_OUT, NS_LOGMODULE_XFER_OUT,
		      ISC_LOG_DEBUG(6), "%s request", mnemonic);
	/*
	 * Apply quota.
	 */
	result = isc_quota_attach(&ns_g_server->xfroutquota, &quota);
	if (result != ISC_R_SUCCESS) {
		isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING,
			      "%s request denied: %s", mnemonic,
			      isc_result_totext(result));
		goto failure;
	}

	/*
	 * Interpret the question section.
	 */
	result = dns_message_firstname(request, DNS_SECTION_QUESTION);
	INSIST(result == ISC_R_SUCCESS);

	/*
	 * The question section must contain exactly one question, and
	 * it must be for AXFR/IXFR as appropriate.
	 */
	question_name = NULL;
	dns_message_currentname(request, DNS_SECTION_QUESTION, &question_name);
	question_rdataset = ISC_LIST_HEAD(question_name->list);
	question_class = question_rdataset->rdclass;
	INSIST(question_rdataset->type == reqtype);
	if (ISC_LIST_NEXT(question_rdataset, link) != NULL)
		FAILC(DNS_R_FORMERR, "multiple questions");
	result = dns_message_nextname(request, DNS_SECTION_QUESTION);
	if (result != ISC_R_NOMORE)
		FAILC(DNS_R_FORMERR, "multiple questions");

	result = dns_zt_find(client->view->zonetable, question_name, 0, NULL,
			     &zone);

	if (result != ISC_R_SUCCESS) {
		/*
		 * Normal zone table does not have a match.
		 * Try the DLZ database
		 */
		// Temporary: only searching the first DLZ database
		if (! ISC_LIST_EMPTY(client->view->dlz_searched)) {
			result = dns_dlzallowzonexfr(client->view,
						     question_name,
						     &client->peeraddr,
						     &db);

			pfilter_notify(result, client, "zonexfr");
			if (result == ISC_R_NOPERM) {
				char _buf1[DNS_NAME_FORMATSIZE];
				char _buf2[DNS_RDATACLASS_FORMATSIZE];

				result = DNS_R_REFUSED;
				dns_name_format(question_name, _buf1,
						sizeof(_buf1));
				dns_rdataclass_format(question_class,
						      _buf2, sizeof(_buf2));
				ns_client_log(client, DNS_LOGCATEGORY_SECURITY,
					      NS_LOGMODULE_XFER_OUT,
					      ISC_LOG_ERROR,
					      "zone transfer '%s/%s' denied",
					      _buf1, _buf2);
				goto failure;
			}
			if (result != ISC_R_SUCCESS)
				FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
				      question_name, question_class);
			is_dlz = ISC_TRUE;
		} else {
			/*
			 * not DLZ and not in normal zone table, we are
			 * not authoritative
			 */
			FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
			      question_name, question_class);
		}
	} else {
		/* zone table has a match */
		switch(dns_zone_gettype(zone)) {
			/* Master and slave zones are OK for transfer. */
			case dns_zone_master:
			case dns_zone_slave:
			case dns_zone_dlz:
				break;
			default:
				FAILQ(DNS_R_NOTAUTH, "non-authoritative zone",
				      question_name, question_class);
			}
		CHECK(dns_zone_getdb(zone, &db));
		dns_db_currentversion(db, &ver);
	}

	xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6),
		    "%s question section OK", mnemonic);

	/*
	 * Check the authority section.  Look for a SOA record with
	 * the same name and class as the question.
	 */
	for (result = dns_message_firstname(request, DNS_SECTION_AUTHORITY);
	     result == ISC_R_SUCCESS;
	     result = dns_message_nextname(request, DNS_SECTION_AUTHORITY))
	{
		soa_name = NULL;
		dns_message_currentname(request, DNS_SECTION_AUTHORITY,
					&soa_name);

		/*
		 * Ignore data whose owner name is not the zone apex.
		 */
		if (! dns_name_equal(soa_name, question_name))
			continue;

		for (soa_rdataset = ISC_LIST_HEAD(soa_name->list);
		     soa_rdataset != NULL;
		     soa_rdataset = ISC_LIST_NEXT(soa_rdataset, link))
		{
			/*
			 * Ignore non-SOA data.
			 */
			if (soa_rdataset->type != dns_rdatatype_soa)
				continue;
			if (soa_rdataset->rdclass != question_class)
				continue;

			CHECK(dns_rdataset_first(soa_rdataset));
			dns_rdataset_current(soa_rdataset, &soa_rdata);
			result = dns_rdataset_next(soa_rdataset);
			if (result == ISC_R_SUCCESS)
				FAILC(DNS_R_FORMERR,
				      "IXFR authority section "
				      "has multiple SOAs");
			have_soa = ISC_TRUE;
			goto got_soa;
		}
	}
 got_soa:
	if (result != ISC_R_NOMORE)
		CHECK(result);

	xfrout_log1(client, question_name, question_class, ISC_LOG_DEBUG(6),
		    "%s authority section OK", mnemonic);

	/*
	 * If not a DLZ zone, decide whether to allow this transfer.
	 */
	if (!is_dlz) {
		ns_client_aclmsg("zone transfer", question_name, reqtype,
				 client->view->rdclass, msg, sizeof(msg));
		CHECK(ns_client_checkacl(client, NULL, msg,
					 dns_zone_getxfracl(zone),
					 ISC_TRUE, ISC_LOG_ERROR));
	}

	/*
	 * AXFR over UDP is not possible.
	 */
	if (reqtype == dns_rdatatype_axfr &&
	    (client->attributes & NS_CLIENTATTR_TCP) == 0)
		FAILC(DNS_R_FORMERR, "attempted AXFR over UDP");

	/*
	 * Look up the requesting server in the peer table.
	 */
	isc_netaddr_fromsockaddr(&na, &client->peeraddr);
	(void)dns_peerlist_peerbyaddr(client->view->peers, &na, &peer);

	/*
	 * Decide on the transfer format (one-answer or many-answers).
	 */
	if (peer != NULL)
		(void)dns_peer_gettransferformat(peer, &format);

	/*
	 * Get a dynamically allocated copy of the current SOA.
	 */
	if (is_dlz)
		dns_db_currentversion(db, &ver);

	CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_EXISTS,
				    &current_soa_tuple));

	current_serial = dns_soa_getserial(&current_soa_tuple->rdata);
	if (reqtype == dns_rdatatype_ixfr) {
		isc_boolean_t provide_ixfr;

		/*
		 * Outgoing IXFR may have been disabled for this peer
		 * or globally.
		 */
		provide_ixfr = client->view->provideixfr;
		if (peer != NULL)
			(void) dns_peer_getprovideixfr(peer, &provide_ixfr);
		if (provide_ixfr == ISC_FALSE)
			goto axfr_fallback;

		if (! have_soa)
			FAILC(DNS_R_FORMERR,
			      "IXFR request missing SOA");

		begin_serial = dns_soa_getserial(&soa_rdata);

		/*
		 * RFC1995 says "If an IXFR query with the same or
		 * newer version number than that of the server
		 * is received, it is replied to with a single SOA
		 * record of the server's current version, just as
		 * in AXFR".  The claim about AXFR is incorrect,
		 * but other than that, we do as the RFC says.
		 *
		 * Sending a single SOA record is also how we refuse
		 * IXFR over UDP (currently, we always do).
		 */
		if (DNS_SERIAL_GE(begin_serial, current_serial) ||
		    (client->attributes & NS_CLIENTATTR_TCP) == 0)
		{
			CHECK(soa_rrstream_create(mctx, db, ver, &stream));
			is_poll = ISC_TRUE;
			goto have_stream;
		}
		journalfile = is_dlz ? NULL : dns_zone_getjournal(zone);
		if (journalfile != NULL)
			result = ixfr_rrstream_create(mctx,
						      journalfile,
						      begin_serial,
						      current_serial,
						      &data_stream);
		else
			result = ISC_R_NOTFOUND;
		if (result == ISC_R_NOTFOUND ||
		    result == ISC_R_RANGE) {
			xfrout_log1(client, question_name, question_class,
				    ISC_LOG_DEBUG(4),
				    "IXFR version not in journal, "
				    "falling back to AXFR");
			mnemonic = "AXFR-style IXFR";
			goto axfr_fallback;
		}
		CHECK(result);
		is_ixfr = ISC_TRUE;
	} else {
	axfr_fallback:
		CHECK(axfr_rrstream_create(mctx, db, ver, &data_stream));
	}

	/*
	 * Bracket the data stream with SOAs.
	 */
	CHECK(soa_rrstream_create(mctx, db, ver, &soa_stream));
	CHECK(compound_rrstream_create(mctx, &soa_stream, &data_stream,
				       &stream));
	soa_stream = NULL;
	data_stream = NULL;

 have_stream:
	CHECK(dns_message_getquerytsig(request, mctx, &tsigbuf));
	/*
	 * Create the xfrout context object.  This transfers the ownership
	 * of "stream", "db", "ver", and "quota" to the xfrout context object.
	 */



	if (is_dlz)
		CHECK(xfrout_ctx_create(mctx, client, request->id,
					question_name, reqtype, question_class,
					zone, db, ver, quota, stream,
					dns_message_gettsigkey(request),
					tsigbuf,
					3600,
					3600,
					(format == dns_many_answers) ?
					ISC_TRUE : ISC_FALSE,
					&xfr));
	else
		CHECK(xfrout_ctx_create(mctx, client, request->id,
					question_name, reqtype, question_class,
					zone, db, ver, quota, stream,
					dns_message_gettsigkey(request),
					tsigbuf,
					dns_zone_getmaxxfrout(zone),
					dns_zone_getidleout(zone),
					(format == dns_many_answers) ?
					ISC_TRUE : ISC_FALSE,
					&xfr));

	xfr->mnemonic = mnemonic;
	stream = NULL;
	quota = NULL;

	CHECK(xfr->stream->methods->first(xfr->stream));

	if (xfr->tsigkey != NULL)
		dns_name_format(&xfr->tsigkey->name, keyname, sizeof(keyname));
	else
		keyname[0] = '\0';
	if (is_poll)
		xfrout_log1(client, question_name, question_class,
			    ISC_LOG_DEBUG(1), "IXFR poll up to date%s%s",
			    (xfr->tsigkey != NULL) ? ": TSIG " : "", keyname);
	else if (is_ixfr)
		xfrout_log1(client, question_name, question_class,
			    ISC_LOG_INFO, "%s started%s%s (serial %u -> %u)",
			    mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "",
			    keyname, begin_serial, current_serial);
	else
		xfrout_log1(client, question_name, question_class,
			    ISC_LOG_INFO, "%s started%s%s (serial %u)",
			    mnemonic, (xfr->tsigkey != NULL) ? ": TSIG " : "",
			    keyname, current_serial);


	if (zone != NULL) {
		dns_zone_getraw(zone, &raw);
		mayberaw = (raw != NULL) ? raw : zone;
		if ((client->attributes & NS_CLIENTATTR_WANTEXPIRE) != 0 &&
		    dns_zone_gettype(mayberaw) == dns_zone_slave) {
			isc_time_t expiretime;
			isc_uint32_t secs;
			dns_zone_getexpiretime(zone, &expiretime);
			secs = isc_time_seconds(&expiretime);
			if (secs >= client->now && result == ISC_R_SUCCESS) {
				client->attributes |= NS_CLIENTATTR_HAVEEXPIRE;
				client->expire = secs - client->now;
			}
		}
		if (raw != NULL)
			dns_zone_detach(&raw);
	}

	/*
	 * Hand the context over to sendstream().  Set xfr to NULL;
	 * sendstream() is responsible for either passing the
	 * context on to a later event handler or destroying it.
	 */
	sendstream(xfr);
	xfr = NULL;

	result = ISC_R_SUCCESS;

 failure:
	if (result == DNS_R_REFUSED)
		inc_stats(zone, dns_nsstatscounter_xfrrej);
	if (quota != NULL)
		isc_quota_detach(&quota);
	if (current_soa_tuple != NULL)
		dns_difftuple_free(&current_soa_tuple);
	if (stream != NULL)
		stream->methods->destroy(&stream);
	if (soa_stream != NULL)
		soa_stream->methods->destroy(&soa_stream);
	if (data_stream != NULL)
		data_stream->methods->destroy(&data_stream);
	if (ver != NULL)
		dns_db_closeversion(db, &ver, ISC_FALSE);
	if (db != NULL)
		dns_db_detach(&db);
	if (zone != NULL)
		dns_zone_detach(&zone);
	/* XXX kludge */
	if (xfr != NULL) {
		xfrout_fail(xfr, result, "setting up zone transfer");
	} else if (result != ISC_R_SUCCESS) {
		ns_client_log(client, DNS_LOGCATEGORY_XFER_OUT,
			      NS_LOGMODULE_XFER_OUT,
			      ISC_LOG_DEBUG(3), "zone transfer setup failed");
		ns_client_error(client, result);
	}
}
Ejemplo n.º 21
0
/*
 * Convert a resolv.conf file into a config structure.
 */
isc_result_t
ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx,
			   cfg_obj_t **configp)
{
	char text[4096];
	char str[16];
	isc_buffer_t b;
	lwres_context_t *lwctx = NULL;
	lwres_conf_t *lwc = NULL;
	isc_sockaddr_t sa;
	isc_netaddr_t na;
	int i;
	isc_result_t result;
	lwres_result_t lwresult;

	lwctx = NULL;
	lwresult = lwres_context_create(&lwctx, mctx, ns__lwresd_memalloc,
					ns__lwresd_memfree,
					LWRES_CONTEXT_SERVERMODE);
	if (lwresult != LWRES_R_SUCCESS) {
		result = ISC_R_NOMEMORY;
		goto cleanup;
	}

	lwresult = lwres_conf_parse(lwctx, lwresd_g_resolvconffile);
	if (lwresult != LWRES_R_SUCCESS) {
		result = DNS_R_SYNTAX;
		goto cleanup;
	}

	lwc = lwres_conf_get(lwctx);
	INSIST(lwc != NULL);

	isc_buffer_init(&b, text, sizeof(text));

	CHECK(buffer_putstr(&b, "options {\n"));

	/*
	 * Build the list of forwarders.
	 */
	if (lwc->nsnext > 0) {
		CHECK(buffer_putstr(&b, "\tforwarders {\n"));

		for (i = 0; i < lwc->nsnext; i++) {
			CHECK(lwaddr_sockaddr_fromlwresaddr(
							&sa,
							&lwc->nameservers[i],
							ns_g_port));
			isc_netaddr_fromsockaddr(&na, &sa);
			CHECK(buffer_putstr(&b, "\t\t"));
			CHECK(isc_netaddr_totext(&na, &b));
			CHECK(buffer_putstr(&b, ";\n"));
		}
		CHECK(buffer_putstr(&b, "\t};\n"));
	}

	/*
	 * Build the sortlist
	 */
	if (lwc->sortlistnxt > 0) {
		CHECK(buffer_putstr(&b, "\tsortlist {\n"));
		CHECK(buffer_putstr(&b, "\t\t{\n"));
		CHECK(buffer_putstr(&b, "\t\t\tany;\n"));
		CHECK(buffer_putstr(&b, "\t\t\t{\n"));
		for (i = 0; i < lwc->sortlistnxt; i++) {
			lwres_addr_t *lwaddr = &lwc->sortlist[i].addr;
			lwres_addr_t *lwmask = &lwc->sortlist[i].mask;
			unsigned int mask;

			CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwmask, 0));
			isc_netaddr_fromsockaddr(&na, &sa);
			result = isc_netaddr_masktoprefixlen(&na, &mask);
			if (result != ISC_R_SUCCESS) {
				char addrtext[ISC_NETADDR_FORMATSIZE];
				isc_netaddr_format(&na, addrtext,
						   sizeof(addrtext));
				isc_log_write(ns_g_lctx,
					      NS_LOGCATEGORY_GENERAL,
					      NS_LOGMODULE_LWRESD,
					      ISC_LOG_ERROR,
					      "processing sortlist: '%s' is "
					      "not a valid netmask",
					      addrtext);
				goto cleanup;
			}

			CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwaddr, 0));
			isc_netaddr_fromsockaddr(&na, &sa);

			CHECK(buffer_putstr(&b, "\t\t\t\t"));
			CHECK(isc_netaddr_totext(&na, &b));
			snprintf(str, sizeof(str), "%u", mask);
			CHECK(buffer_putstr(&b, "/"));
			CHECK(buffer_putstr(&b, str));
			CHECK(buffer_putstr(&b, ";\n"));
		}
		CHECK(buffer_putstr(&b, "\t\t\t};\n"));
		CHECK(buffer_putstr(&b, "\t\t};\n"));
		CHECK(buffer_putstr(&b, "\t};\n"));
	}

	CHECK(buffer_putstr(&b, "};\n\n"));

	CHECK(buffer_putstr(&b, "lwres {\n"));

	/*
	 * Build the search path
	 */
	if (lwc->searchnxt > 0) {
		if (lwc->searchnxt > 0) {
			CHECK(buffer_putstr(&b, "\tsearch {\n"));
			for (i = 0; i < lwc->searchnxt; i++) {
				CHECK(buffer_putstr(&b, "\t\t\""));
				CHECK(buffer_putstr(&b, lwc->search[i]));
				CHECK(buffer_putstr(&b, "\";\n"));
			}
			CHECK(buffer_putstr(&b, "\t};\n"));
		}
	}

	/*
	 * Build the ndots line
	 */
	if (lwc->ndots != 1) {
		CHECK(buffer_putstr(&b, "\tndots "));
		snprintf(str, sizeof(str), "%u", lwc->ndots);
		CHECK(buffer_putstr(&b, str));
		CHECK(buffer_putstr(&b, ";\n"));
	}

	/*
	 * Build the listen-on line
	 */
	if (lwc->lwnext > 0) {
		CHECK(buffer_putstr(&b, "\tlisten-on {\n"));

		for (i = 0; i < lwc->lwnext; i++) {
			CHECK(lwaddr_sockaddr_fromlwresaddr(&sa,
							    &lwc->lwservers[i],
							    0));
			isc_netaddr_fromsockaddr(&na, &sa);
			CHECK(buffer_putstr(&b, "\t\t"));
			CHECK(isc_netaddr_totext(&na, &b));
			CHECK(buffer_putstr(&b, ";\n"));
		}
		CHECK(buffer_putstr(&b, "\t};\n"));
	}

	CHECK(buffer_putstr(&b, "};\n"));

#if 0
	printf("%.*s\n",
	       (int)isc_buffer_usedlength(&b),
	       (char *)isc_buffer_base(&b));
#endif

	lwres_conf_clear(lwctx);
	lwres_context_destroy(&lwctx);

	return (cfg_parse_buffer(pctx, &b, &cfg_type_namedconf, configp));

 cleanup:

	if (lwctx != NULL) {
		lwres_conf_clear(lwctx);
		lwres_context_destroy(&lwctx);
	}

	return (result);
}
Ejemplo n.º 22
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;
}