예제 #1
0
static isc_result_t
internal_current4(isc_interfaceiter_t *iter) {
	struct ifreq *ifrp;
	struct ifreq ifreq;
	int family;
	char strbuf[ISC_STRERRORSIZE];
#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
	struct lifreq lifreq;
#else
	char sabuf[256];
#endif
	int i, bits, prefixlen;

	REQUIRE(VALID_IFITER(iter));

	if (iter->ifc.ifc_len == 0 ||
	    iter->pos == (unsigned int)iter->ifc.ifc_len) {
#ifdef __linux
		return (linux_if_inet6_current(iter));
#else
		return (ISC_R_NOMORE);
#endif
	}

	INSIST( iter->pos < (unsigned int) iter->ifc.ifc_len);

	ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);

	memset(&ifreq, 0, sizeof(ifreq));
	memmove(&ifreq, ifrp, sizeof(ifreq));

	family = ifreq.ifr_addr.sa_family;
#if defined(ISC_PLATFORM_HAVEIPV6)
	if (family != AF_INET && family != AF_INET6)
#else
	if (family != AF_INET)
#endif
		return (ISC_R_IGNORE);

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

	INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
	memset(iter->current.name, 0, sizeof(iter->current.name));
	memmove(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));

	get_addr(family, &iter->current.address,
		 (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);

	/*
	 * If the interface does not have a address ignore it.
	 */
	switch (family) {
	case AF_INET:
		if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
			return (ISC_R_IGNORE);
		break;
	case AF_INET6:
		if (memcmp(&iter->current.address.type.in6, &in6addr_any,
			   sizeof(in6addr_any)) == 0)
			return (ISC_R_IGNORE);
		break;
	}

	/*
	 * Get interface flags.
	 */

	iter->current.flags = 0;

	/*
	 * Ignore the HP/UX warning about "integer overflow during
	 * conversion.  It comes from its own macro definition,
	 * and is really hard to shut up.
	 */
	if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "%s: getting interface flags: %s",
				 ifreq.ifr_name, strbuf);
		return (ISC_R_IGNORE);
	}

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

#ifdef IFF_POINTOPOINT
	if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
		iter->current.flags |= INTERFACE_F_POINTTOPOINT;
#endif

	if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
		iter->current.flags |= INTERFACE_F_LOOPBACK;

	if (family == AF_INET)
		goto inet;

#if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
	memset(&lifreq, 0, sizeof(lifreq));
	memmove(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
	memmove(&lifreq.lifr_addr, &iter->current.address.type.in6,
	       sizeof(iter->current.address.type.in6));

	if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "%s: getting interface address: %s",
				 ifreq.ifr_name, strbuf);
		return (ISC_R_IGNORE);
	}
	prefixlen = lifreq.lifr_addrlen;
#else
	isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
	isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
		      ISC_LOGMODULE_INTERFACE,
		      ISC_LOG_INFO,
		      isc_msgcat_get(isc_msgcat,
				     ISC_MSGSET_IFITERIOCTL,
				     ISC_MSG_GETIFCONFIG,
				     "prefix length for %s is unknown "
				     "(assume 128)"), sabuf);
	prefixlen = 128;
#endif

	/*
	 * Netmask already zeroed.
	 */
	iter->current.netmask.family = family;
	for (i = 0; i < 16; i++) {
		if (prefixlen > 8) {
			bits = 0;
			prefixlen -= 8;
		} else {
			bits = 8 - prefixlen;
			prefixlen = 0;
		}
		iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
	}
	return (ISC_R_SUCCESS);

 inet:
	if (family != AF_INET)
		return (ISC_R_IGNORE);
#ifdef IFF_POINTOPOINT
	/*
	 * If the interface is point-to-point, get the destination address.
	 */
	if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
		/*
		 * Ignore the HP/UX warning about "integer overflow during
		 * conversion.  It comes from its own macro definition,
		 * and is really hard to shut up.
		 */
		if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
		    < 0) {
			isc__strerror(errno, strbuf, sizeof(strbuf));
			UNEXPECTED_ERROR(__FILE__, __LINE__,
				isc_msgcat_get(isc_msgcat,
					       ISC_MSGSET_IFITERIOCTL,
					       ISC_MSG_GETDESTADDR,
					       "%s: getting "
					       "destination address: %s"),
					 ifreq.ifr_name, strbuf);
			return (ISC_R_IGNORE);
		}
		get_addr(family, &iter->current.dstaddress,
			 (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
	}
#endif

	/*
	 * Get the network mask.
	 */
	memset(&ifreq, 0, sizeof(ifreq));
	memmove(&ifreq, ifrp, sizeof(ifreq));
	/*
	 * Ignore the HP/UX warning about "integer overflow during
	 * conversion.  It comes from its own macro definition,
	 * and is really hard to shut up.
	 */
	if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
		isc__strerror(errno, strbuf, sizeof(strbuf));
		UNEXPECTED_ERROR(__FILE__, __LINE__,
			isc_msgcat_get(isc_msgcat,
				       ISC_MSGSET_IFITERIOCTL,
				       ISC_MSG_GETNETMASK,
				       "%s: getting netmask: %s"),
				       ifreq.ifr_name, strbuf);
		return (ISC_R_IGNORE);
	}
	get_addr(family, &iter->current.netmask,
		 (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
	return (ISC_R_SUCCESS);
}
예제 #2
0
파일: lwresd.c 프로젝트: ElRevo/xia-core
/*
 * 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);
}
예제 #3
0
/*
 * Perform an update-policy rule check against an external application
 * over a socket.
 *
 * This currently only supports local: for unix domain datagram sockets.
 *
 * Note that by using a datagram socket and creating a new socket each
 * time we avoid the need for locking and allow for parallel access to
 * the authorization server.
 */
isc_boolean_t
dns_ssu_external_match(dns_name_t *identity,
		       dns_name_t *signer, dns_name_t *name,
		       isc_netaddr_t *tcpaddr, dns_rdatatype_t type,
		       const dst_key_t *key, isc_mem_t *mctx)
{
	char b_identity[DNS_NAME_FORMATSIZE];
	char b_signer[DNS_NAME_FORMATSIZE];
	char b_name[DNS_NAME_FORMATSIZE];
	char b_addr[ISC_NETADDR_FORMATSIZE];
	char b_type[DNS_RDATATYPE_FORMATSIZE];
	char b_key[DST_KEY_FORMATSIZE];
	isc_buffer_t *tkey_token = NULL;
	int fd;
	const char *sock_path;
	unsigned int req_len;
	isc_region_t token_region;
	unsigned char *data;
	isc_buffer_t buf;
	isc_uint32_t token_len = 0;
	isc_uint32_t reply;
	ssize_t ret;

	/* The identity contains local:/path/to/socket */
	dns_name_format(identity, b_identity, sizeof(b_identity));

	/* For now only local: is supported */
	if (strncmp(b_identity, "local:", 6) != 0) {
		ssu_e_log(3, "ssu_external: invalid socket path '%s'",
			  b_identity);
		return (ISC_FALSE);
	}
	sock_path = &b_identity[6];

	fd = ux_socket_connect(sock_path);
	if (fd == -1)
		return (ISC_FALSE);

	if (key != NULL) {
		dst_key_format(key, b_key, sizeof(b_key));
		tkey_token = dst_key_tkeytoken(key);
	} else
		b_key[0] = 0;

	if (tkey_token != NULL) {
		isc_buffer_region(tkey_token, &token_region);
		token_len = token_region.length;
	}

	/* Format the request elements */
	if (signer != NULL)
		dns_name_format(signer, b_signer, sizeof(b_signer));
	else
		b_signer[0] = 0;

	dns_name_format(name, b_name, sizeof(b_name));

	if (tcpaddr != NULL)
		isc_netaddr_format(tcpaddr, b_addr, sizeof(b_addr));
	else
		b_addr[0] = 0;

	dns_rdatatype_format(type, b_type, sizeof(b_type));

	/* Work out how big the request will be */
	req_len = sizeof(isc_uint32_t)     + /* Format version */
		  sizeof(isc_uint32_t)     + /* Length */
		  strlen(b_signer) + 1 + /* Signer */
		  strlen(b_name) + 1   + /* Name */
		  strlen(b_addr) + 1   + /* Address */
		  strlen(b_type) + 1   + /* Type */
		  strlen(b_key) + 1    + /* Key */
		  sizeof(isc_uint32_t)     + /* tkey_token length */
		  token_len;             /* tkey_token */


	/* format the buffer */
	data = isc_mem_allocate(mctx, req_len);
	if (data == NULL) {
		close(fd);
		return (ISC_FALSE);
	}

	isc_buffer_init(&buf, data, req_len);
	isc_buffer_putuint32(&buf, SSU_EXTERNAL_VERSION);
	isc_buffer_putuint32(&buf, req_len);

	/* Strings must be null-terminated */
	isc_buffer_putstr(&buf, b_signer);
	isc_buffer_putuint8(&buf, 0);
	isc_buffer_putstr(&buf, b_name);
	isc_buffer_putuint8(&buf, 0);
	isc_buffer_putstr(&buf, b_addr);
	isc_buffer_putuint8(&buf, 0);
	isc_buffer_putstr(&buf, b_type);
	isc_buffer_putuint8(&buf, 0);
	isc_buffer_putstr(&buf, b_key);
	isc_buffer_putuint8(&buf, 0);

	isc_buffer_putuint32(&buf, token_len);
	if (tkey_token && token_len != 0)
		isc_buffer_putmem(&buf, token_region.base, token_len);

	ENSURE(isc_buffer_availablelength(&buf) == 0);

	/* Send the request */
	ret = write(fd, data, req_len);
	isc_mem_free(mctx, data);
	if (ret != (ssize_t) req_len) {
		char strbuf[ISC_STRERRORSIZE];
		isc__strerror(errno, strbuf, sizeof(strbuf));
		ssu_e_log(3, "ssu_external: unable to send request - %s",
			  strbuf);
		close(fd);
		return (ISC_FALSE);
	}

	/* Receive the reply */
	ret = read(fd, &reply, sizeof(isc_uint32_t));
	if (ret != (ssize_t) sizeof(isc_uint32_t)) {
		char strbuf[ISC_STRERRORSIZE];
		isc__strerror(errno, strbuf, sizeof(strbuf));
		ssu_e_log(3, "ssu_external: unable to receive reply - %s",
			  strbuf);
		close(fd);
		return (ISC_FALSE);
	}

	close(fd);

	reply = ntohl(reply);

	if (reply == 0) {
		ssu_e_log(3, "ssu_external: denied external auth for '%s'",
			  b_name);
		return (ISC_FALSE);
	} else if (reply == 1) {
		ssu_e_log(3, "ssu_external: allowed external auth for '%s'",
			  b_name);
		return (ISC_TRUE);
	}

	ssu_e_log(3, "ssu_external: invalid reply 0x%08x", reply);

	return (ISC_FALSE);
}
예제 #4
0
isc_result_t
cfg_acl_fromconfig2(const cfg_obj_t *caml, const cfg_obj_t *cctx,
		   isc_log_t *lctx, cfg_aclconfctx_t *ctx,
		   isc_mem_t *mctx, unsigned int nest_level,
		   isc_uint16_t family, dns_acl_t **target)
{
	isc_result_t result;
	dns_acl_t *dacl = NULL, *inneracl = NULL;
	dns_aclelement_t *de;
	const cfg_listelt_t *elt;
	dns_iptable_t *iptab;
	int new_nest_level = 0;

	if (nest_level != 0)
		new_nest_level = nest_level - 1;

	REQUIRE(target != NULL);
	REQUIRE(*target == NULL || DNS_ACL_VALID(*target));

	if (*target != NULL) {
		/*
		 * If target already points to an ACL, then we're being
		 * called recursively to configure a nested ACL.  The
		 * nested ACL's contents should just be absorbed into its
		 * parent ACL.
		 */
		dns_acl_attach(*target, &dacl);
		dns_acl_detach(target);
	} else {
		/*
		 * Need to allocate a new ACL structure.  Count the items
		 * in the ACL definition that will require space in the
		 * elements table.  (Note that if nest_level is nonzero,
		 * *everything* goes in the elements table.)
		 */
		isc_uint32_t nelem;

		if (nest_level == 0) {
			result = count_acl_elements(caml, cctx, lctx, ctx,
						    mctx, &nelem, NULL);
			if (result != ISC_R_SUCCESS)
				return (result);
		} else
			nelem = cfg_list_length(caml, ISC_FALSE);

		result = dns_acl_create(mctx, nelem, &dacl);
		if (result != ISC_R_SUCCESS)
			return (result);
	}

	de = dacl->elements;
	for (elt = cfg_list_first(caml);
	     elt != NULL;
	     elt = cfg_list_next(elt)) {
		const cfg_obj_t *ce = cfg_listelt_value(elt);
		isc_boolean_t neg = ISC_FALSE;

		INSIST(dacl->length <= dacl->alloc);

		if (cfg_obj_istuple(ce)) {
			/* Might be a negated element */
			const cfg_obj_t *negated =
				cfg_tuple_get(ce, "negated");
			if (! cfg_obj_isvoid(negated)) {
				neg = ISC_TRUE;
				dacl->has_negatives = ISC_TRUE;
				ce = negated;
			}
		}

		/*
		 * If nest_level is nonzero, then every element is
		 * to be stored as a separate, nested ACL rather than
		 * merged into the main iptable.
		 */
		iptab = dacl->iptable;

		if (nest_level != 0) {
			result = dns_acl_create(mctx,
						cfg_list_length(ce, ISC_FALSE),
						&de->nestedacl);
			if (result != ISC_R_SUCCESS)
				goto cleanup;
			iptab = de->nestedacl->iptable;
		}

		if (cfg_obj_isnetprefix(ce)) {
			/* Network prefix */
			isc_netaddr_t	addr;
			unsigned int	bitlen;

			cfg_obj_asnetprefix(ce, &addr, &bitlen);
			if (family != 0 && family != addr.family) {
				char buf[ISC_NETADDR_FORMATSIZE + 1];
				isc_netaddr_format(&addr, buf, sizeof(buf));
				cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
					    "'%s': incorrect address family; "
					    "ignoring", buf);
				if (nest_level != 0)
					dns_acl_detach(&de->nestedacl);
				continue;
			}
			result = isc_netaddr_prefixok(&addr, bitlen);
			if (result != ISC_R_SUCCESS) {
				char buf[ISC_NETADDR_FORMATSIZE + 1];
				isc_netaddr_format(&addr, buf, sizeof(buf));
				cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
					    "'%s/%u': address/prefix length "
					    "mismatch", buf, bitlen);
			}

			/*
			 * If nesting ACLs (nest_level != 0), we negate
			 * the nestedacl element, not the iptable entry.
			 */
			result = dns_iptable_addprefix(iptab, &addr, bitlen,
					      ISC_TF(nest_level != 0 || !neg));
			if (result != ISC_R_SUCCESS)
				goto cleanup;

			if (nest_level > 0) {
				INSIST(dacl->length < dacl->alloc);
				de->type = dns_aclelementtype_nestedacl;
				de->negative = neg;
			} else
				continue;
		} else if (cfg_obj_islist(ce)) {
			/*
			 * If we're nesting ACLs, put the nested
			 * ACL onto the elements list; otherwise
			 * merge it into *this* ACL.  We nest ACLs
			 * in two cases: 1) sortlist, 2) if the
			 * nested ACL contains negated members.
			 */
			if (inneracl != NULL)
				dns_acl_detach(&inneracl);
			result = cfg_acl_fromconfig(ce, cctx, lctx,
						    ctx, mctx, new_nest_level,
						    &inneracl);
			if (result != ISC_R_SUCCESS)
				goto cleanup;
nested_acl:
			if (nest_level > 0 || inneracl->has_negatives) {
				INSIST(dacl->length < dacl->alloc);
				de->type = dns_aclelementtype_nestedacl;
				de->negative = neg;
				if (de->nestedacl != NULL)
					dns_acl_detach(&de->nestedacl);
				dns_acl_attach(inneracl,
					       &de->nestedacl);
				dns_acl_detach(&inneracl);
				/* Fall through. */
			} else {
				INSIST(dacl->length + inneracl->length
				       <= dacl->alloc);
				dns_acl_merge(dacl, inneracl,
					      ISC_TF(!neg));
				de += inneracl->length;  /* elements added */
				dns_acl_detach(&inneracl);
				INSIST(dacl->length <= dacl->alloc);
				continue;
			}
		} else if (cfg_obj_istype(ce, &cfg_type_keyref)) {
			/* Key name. */
			INSIST(dacl->length < dacl->alloc);
			de->type = dns_aclelementtype_keyname;
			de->negative = neg;
			dns_name_init(&de->keyname, NULL);
			result = convert_keyname(ce, lctx, mctx,
						 &de->keyname);
			if (result != ISC_R_SUCCESS)
				goto cleanup;
#ifdef HAVE_GEOIP
		} else if (cfg_obj_istuple(ce) &&
			   cfg_obj_isvoid(cfg_tuple_get(ce, "negated")))
		{
			INSIST(dacl->length < dacl->alloc);
			result = parse_geoip_element(ce, lctx, ctx, de);
			if (result != ISC_R_SUCCESS)
				goto cleanup;
			de->type = dns_aclelementtype_geoip;
			de->negative = neg;
#endif /* HAVE_GEOIP */
		} else if (cfg_obj_isstring(ce)) {
			/* ACL name. */
			const char *name = cfg_obj_asstring(ce);
			if (strcasecmp(name, "any") == 0) {
				/* Iptable entry with zero bit length. */
				result = dns_iptable_addprefix(iptab, NULL, 0,
					      ISC_TF(nest_level != 0 || !neg));
				if (result != ISC_R_SUCCESS)
					goto cleanup;

				if (nest_level != 0) {
					INSIST(dacl->length < dacl->alloc);
					de->type = dns_aclelementtype_nestedacl;
					de->negative = neg;
				} else
					continue;
			} else if (strcasecmp(name, "none") == 0) {
				/* none == !any */
				/*
				 * We don't unconditional set
				 * dacl->has_negatives and
				 * de->negative to true so we can handle
				 * "!none;".
				 */
				result = dns_iptable_addprefix(iptab, NULL, 0,
					      ISC_TF(nest_level != 0 || neg));
				if (result != ISC_R_SUCCESS)
					goto cleanup;

				if (!neg)
					dacl->has_negatives = !neg;

				if (nest_level != 0) {
					INSIST(dacl->length < dacl->alloc);
					de->type = dns_aclelementtype_nestedacl;
					de->negative = !neg;
				} else
					continue;
			} else if (strcasecmp(name, "localhost") == 0) {
				INSIST(dacl->length < dacl->alloc);
				de->type = dns_aclelementtype_localhost;
				de->negative = neg;
			} else if (strcasecmp(name, "localnets") == 0) {
				INSIST(dacl->length < dacl->alloc);
				de->type = dns_aclelementtype_localnets;
				de->negative = neg;
			} else {
				if (inneracl != NULL)
					dns_acl_detach(&inneracl);
				/*
				 * This call should just find the cached
				 * of the named acl.
				 */
				result = convert_named_acl(ce, cctx, lctx, ctx,
							   mctx, new_nest_level,
							   &inneracl);
				if (result != ISC_R_SUCCESS)
					goto cleanup;

				goto nested_acl;
			}
		} else {
			cfg_obj_log(ce, lctx, ISC_LOG_WARNING,
				    "address match list contains "
				    "unsupported element type");
			result = ISC_R_FAILURE;
			goto cleanup;
		}

		/*
		 * This should only be reached for localhost, localnets
		 * and keyname elements, and nested ACLs if nest_level is
		 * nonzero (i.e., in sortlists).
		 */
		if (de->nestedacl != NULL &&
		    de->type != dns_aclelementtype_nestedacl)
			dns_acl_detach(&de->nestedacl);

		dacl->node_count++;
		de->node_num = dacl->node_count;

		dacl->length++;
		de++;
		INSIST(dacl->length <= dacl->alloc);
	}

	dns_acl_attach(dacl, target);
	result = ISC_R_SUCCESS;

 cleanup:
	if (inneracl != NULL)
		dns_acl_detach(&inneracl);
	dns_acl_detach(&dacl);
	return (result);
}