confip.c revision 15a44745412679c30a6d022733925af70a38b715
1c3191528684f3dd93ebb122298c2f8ebfc6d397Mark Andrews/*
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Copyright (C) 1999, 2000 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence *
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * copyright notice and this permission notice appear in all copies.
1c3191528684f3dd93ebb122298c2f8ebfc6d397Mark Andrews *
1c3191528684f3dd93ebb122298c2f8ebfc6d397Mark Andrews * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
4be63b1fd8c18dbeca1648d6cf22fa14f057a469David Lawrence * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
4be63b1fd8c18dbeca1648d6cf22fa14f057a469David Lawrence * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
4be63b1fd8c18dbeca1648d6cf22fa14f057a469David Lawrence * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
70e5a7403f0e0a3bd292b8287c5fed5772c15270Automatic Updater * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
1c3191528684f3dd93ebb122298c2f8ebfc6d397Mark Andrews * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austein * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1c3191528684f3dd93ebb122298c2f8ebfc6d397Mark Andrews */
b186f1ab91faf6d46d102ecbfd55cbdb7e24feeeMark Andrews
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews/* $Id: confip.c,v 1.31 2000/07/27 09:47:02 tale Exp $ */
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews#include <config.h>
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews
b186f1ab91faf6d46d102ecbfd55cbdb7e24feeeMark Andrews
b186f1ab91faf6d46d102ecbfd55cbdb7e24feeeMark Andrews#include <isc/mem.h>
4be63b1fd8c18dbeca1648d6cf22fa14f057a469David Lawrence#include <isc/string.h>
4be63b1fd8c18dbeca1648d6cf22fa14f057a469David Lawrence#include <isc/util.h>
#include <dns/confip.h>
#include <dns/log.h>
/*
* Flag for dns_c_ipmatch_element.
*/
#define DNS_C_IPMATCH_NEGATE 0x01 /* match means deny access */
static isc_result_t checkmask(isc_sockaddr_t *address, isc_uint32_t bits);
static isc_result_t bits2v6mask(struct in6_addr *addr, isc_uint32_t bits);
isc_result_t
dns_c_ipmatchelement_new(isc_mem_t *mem, dns_c_ipmatchelement_t **result) {
dns_c_ipmatchelement_t *ime ;
REQUIRE(result != NULL);
*result = NULL;
ime = isc_mem_get(mem, sizeof *ime);
if (ime == NULL) {
return (ISC_R_NOMEMORY);
}
ime->magic = DNS_C_IPMELEM_MAGIC;
ime->type = dns_c_ipmatch_none;
ime->flags = 0;
memset(&ime->u, 0x0, sizeof ime->u);
ISC_LINK_INIT(ime, next);
*result = ime;
return (ISC_R_SUCCESS);
}
isc_boolean_t
dns_c_ipmatchelement_isneg(dns_c_ipmatchelement_t *elem) {
REQUIRE(DNS_C_IPMELEM_VALID(elem));
return (ISC_TF((elem->flags & DNS_C_IPMATCH_NEGATE) ==
DNS_C_IPMATCH_NEGATE));
}
isc_result_t
dns_c_ipmatchelement_delete(isc_mem_t *mem, dns_c_ipmatchelement_t **ipme) {
dns_c_ipmatchelement_t *elem;
REQUIRE(mem != NULL);
REQUIRE(ipme != NULL);
REQUIRE(*ipme != NULL);
elem = *ipme;
REQUIRE(DNS_C_IPMELEM_VALID(elem));
switch (elem->type) {
case dns_c_ipmatch_localhost:
case dns_c_ipmatch_localnets:
case dns_c_ipmatch_pattern:
/* nothing */
break;
case dns_c_ipmatch_indirect:
INSIST(elem->u.indirect.list != NULL);
if (elem->u.indirect.list != NULL)
dns_c_ipmatchlist_detach(&elem->u.indirect.list);
if (elem->u.indirect.refname.base != NULL) {
isc_mem_put(mem, elem->u.indirect.refname.base,
elem->u.indirect.refname.length);
}
break;
case dns_c_ipmatch_key:
isc_mem_free(mem, elem->u.key);
break;
case dns_c_ipmatch_acl:
isc_mem_free(mem, elem->u.aclname);
break;
case dns_c_ipmatch_any:
/* nothing */
break;
case dns_c_ipmatch_none:
isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
"dns_ipmath_none element type");
return (ISC_R_FAILURE);
}
elem->magic = 0;
isc_mem_put(mem, elem, sizeof *elem);
*ipme = NULL;
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_ipmatchelement_copy(isc_mem_t *mem,
dns_c_ipmatchelement_t **dest,
dns_c_ipmatchelement_t *src)
{
isc_result_t result;
dns_c_ipmatchelement_t *newel;
REQUIRE(mem != NULL);
REQUIRE(dest != NULL);
REQUIRE(DNS_C_IPMELEM_VALID(src));
result = dns_c_ipmatchelement_new(mem, &newel);
if (result != ISC_R_SUCCESS) {
return (result);
}
newel->type = src->type;
newel->flags = src->flags;
switch(src->type) {
case dns_c_ipmatch_pattern:
newel->u.direct.address = src->u.direct.address;
newel->u.direct.mask = src->u.direct.mask;
break;
case dns_c_ipmatch_indirect:
result = dns_c_ipmatchlist_copy(mem,
&newel->u.indirect.list,
src->u.indirect.list);
break;
case dns_c_ipmatch_localhost:
break;
case dns_c_ipmatch_localnets:
break;
case dns_c_ipmatch_key:
newel->u.key = isc_mem_strdup(mem, src->u.key);
break;
case dns_c_ipmatch_acl:
newel->u.aclname = isc_mem_strdup(mem, src->u.aclname);
break;
case dns_c_ipmatch_any:
break;
case dns_c_ipmatch_none:
isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
"ipmatch 'none' element type");
return (ISC_R_FAILURE);
}
*dest = newel;
return (ISC_R_SUCCESS);
}
isc_boolean_t
dns_c_ipmatchelement_equal(dns_c_ipmatchelement_t *e1,
dns_c_ipmatchelement_t *e2)
{
REQUIRE(DNS_C_IPMELEM_VALID(e1));
REQUIRE(DNS_C_IPMELEM_VALID(e2));
if ((e1->type != e2->type) || (e1->flags != e2->flags))
return (ISC_FALSE);
switch (e1->type) {
case dns_c_ipmatch_pattern:
if (e1->u.direct.mask != e2->u.direct.mask)
return (ISC_FALSE);
return (isc_sockaddr_equal(&e1->u.direct.address,
&e2->u.direct.address));
case dns_c_ipmatch_indirect:
return (dns_c_ipmatchlist_equal(e1->u.indirect.list,
e2->u.indirect.list));
case dns_c_ipmatch_localhost:
break;
case dns_c_ipmatch_localnets:
break;
case dns_c_ipmatch_key:
return (ISC_TF(strcmp(e1->u.key, e2->u.key) == 0));
case dns_c_ipmatch_acl:
return (ISC_TF(strcmp(e1->u.aclname, e2->u.aclname) == 0));
case dns_c_ipmatch_any:
break;
case dns_c_ipmatch_none:
break;
}
return (ISC_TRUE);
}
isc_result_t
dns_c_ipmatchlocalhost_new(isc_mem_t *mem, dns_c_ipmatchelement_t **result) {
dns_c_ipmatchelement_t *ime = NULL;
isc_result_t res;
REQUIRE(mem != NULL);
REQUIRE(result != NULL);
*result = NULL;
res = dns_c_ipmatchelement_new(mem, &ime);
if (res == ISC_R_SUCCESS) {
ime->type = dns_c_ipmatch_localhost;
}
*result = ime;
return (res);
}
isc_result_t
dns_c_ipmatchlocalnets_new(isc_mem_t *mem, dns_c_ipmatchelement_t **result) {
dns_c_ipmatchelement_t *ime = NULL;
isc_result_t res;
REQUIRE(mem != NULL);
REQUIRE(result != NULL);
*result = NULL;
res = dns_c_ipmatchelement_new(mem, &ime);
if (res == ISC_R_SUCCESS) {
ime->type = dns_c_ipmatch_localnets;
}
*result = ime;
return (res);
}
isc_result_t
dns_c_ipmatchany_new(isc_mem_t *mem, dns_c_ipmatchelement_t **result) {
dns_c_ipmatchelement_t *ime = NULL;
isc_result_t res;
REQUIRE(mem != NULL);
REQUIRE(result != NULL);
*result = NULL;
res = dns_c_ipmatchelement_new(mem, &ime);
if (res == ISC_R_SUCCESS) {
ime->type = dns_c_ipmatch_any;
}
*result = ime;
return (res);
}
isc_result_t
dns_c_ipmatchindirect_new(isc_mem_t *mem,
dns_c_ipmatchelement_t **result,
dns_c_ipmatchlist_t *iml,
const char *name)
{
dns_c_ipmatchelement_t *ime;
dns_c_ipmatchlist_t *iml_copy;
isc_result_t res;
REQUIRE(mem != NULL);
REQUIRE(result != NULL);
REQUIRE(DNS_C_IPMLIST_VALID(iml));
*result = NULL;
res = dns_c_ipmatchlist_copy(mem, &iml_copy, iml);
if (res != ISC_R_SUCCESS) {
return (res);
}
res = dns_c_ipmatchelement_new(mem, &ime);
if (res == ISC_R_SUCCESS) {
ime->type = dns_c_ipmatch_indirect;
ime->u.indirect.list = iml_copy;
if (name != NULL) {
ime->u.indirect.refname.length = strlen(name) + 1;
ime->u.indirect.refname.base =
isc_mem_get(mem,
ime->u.indirect.refname.length);
RUNTIME_CHECK(ime->u.indirect.refname.base != NULL);
strcpy(ime->u.indirect.refname.base, name);
}
} else {
dns_c_ipmatchlist_detach(&iml_copy);
}
*result = ime;
return (res);
}
isc_result_t
dns_c_ipmatchpattern_new(isc_mem_t *mem,
dns_c_ipmatchelement_t **result,
isc_sockaddr_t address,
isc_uint32_t maskbits)
{
dns_c_ipmatchelement_t *ime ;
isc_result_t res;
REQUIRE(result != NULL);
REQUIRE(mem != NULL);
*result = NULL;
res = checkmask(&address, maskbits);
if (res != ISC_R_SUCCESS) {
return (res);
}
res = dns_c_ipmatchelement_new(mem, &ime);
if (res != ISC_R_SUCCESS) {
return (res);
}
ime->type = dns_c_ipmatch_pattern;
ime->u.direct.address = address;
ime->u.direct.mask = maskbits;
*result = ime;
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_ipmatchkey_new(isc_mem_t *mem,
dns_c_ipmatchelement_t **result,
const char *key)
{
dns_c_ipmatchelement_t *ipme;
isc_result_t res;
REQUIRE(result != NULL);
REQUIRE(mem != NULL);
REQUIRE(key != NULL);
*result = NULL;
res = dns_c_ipmatchelement_new(mem, &ipme);
if (res != ISC_R_SUCCESS) {
return (res);
}
ipme->type = dns_c_ipmatch_key;
ipme->u.key = isc_mem_strdup(mem, key);
*result = ipme;
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_ipmatch_aclnew(isc_mem_t *mem,
dns_c_ipmatchelement_t **result,
const char *aclname)
{
dns_c_ipmatchelement_t *ipme;
isc_result_t res;
REQUIRE(result != NULL);
REQUIRE(mem != NULL);
REQUIRE(aclname != NULL);
REQUIRE(*aclname != '\0');
*result = NULL;
res = dns_c_ipmatchelement_new(mem, &ipme);
if (res != ISC_R_SUCCESS) {
return (res);
}
ipme->type = dns_c_ipmatch_acl;
ipme->u.aclname = isc_mem_strdup(mem, aclname);
*result = ipme;
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_ipmatch_negate(dns_c_ipmatchelement_t *ipe) {
REQUIRE(DNS_C_IPMELEM_VALID(ipe));
if ((ipe->flags & DNS_C_IPMATCH_NEGATE) == DNS_C_IPMATCH_NEGATE) {
ipe->flags &= ~DNS_C_IPMATCH_NEGATE;
} else {
ipe->flags |= DNS_C_IPMATCH_NEGATE;
}
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_ipmatchlist_new(isc_mem_t *mem, dns_c_ipmatchlist_t **ptr) {
dns_c_ipmatchlist_t *newlist;
REQUIRE(ptr != NULL);
REQUIRE(mem != NULL);
newlist = isc_mem_get(mem, sizeof *newlist);
if (newlist == NULL) {
return (ISC_R_NOMEMORY);
}
newlist->magic = DNS_C_IPMLIST_MAGIC;
newlist->mem = mem;
newlist->refcount = 1;
ISC_LIST_INIT(newlist->elements);
*ptr = newlist;
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_ipmatchlist_detach(dns_c_ipmatchlist_t **ml) {
dns_c_ipmatchelement_t *ime;
dns_c_ipmatchelement_t *iptr;
dns_c_ipmatchlist_t *iml;
isc_mem_t *mem;
REQUIRE(ml != NULL);
REQUIRE(*ml != NULL);
iml = *ml;
*ml = NULL;
REQUIRE(DNS_C_IPMLIST_VALID(iml));
INSIST(iml->refcount > 0);
iml->refcount--;
if (iml->refcount > 0) {
return (ISC_R_SUCCESS);
}
mem = iml->mem;
INSIST(mem != NULL);
ime = ISC_LIST_HEAD(iml->elements);
while (ime != NULL) {
iptr = ISC_LIST_NEXT(ime, next);
dns_c_ipmatchelement_delete(mem, &ime);
ime = iptr;
}
isc_mem_put(mem, iml, sizeof *iml);
return (ISC_R_SUCCESS);
}
void
dns_c_ipmatchlist_attach(dns_c_ipmatchlist_t *source,
dns_c_ipmatchlist_t **target)
{
REQUIRE(DNS_C_IPMLIST_VALID(source));
INSIST(source->refcount > 0);
source->refcount++;
*target = source;
}
isc_result_t
dns_c_ipmatchlist_empty(dns_c_ipmatchlist_t *ipml) {
dns_c_ipmatchelement_t *ime ;
dns_c_ipmatchelement_t *imptmp;
isc_result_t res = ISC_R_SUCCESS;
REQUIRE(DNS_C_IPMLIST_VALID(ipml));
ime = ISC_LIST_HEAD(ipml->elements);
while (ime != NULL) {
imptmp = ISC_LIST_NEXT(ime, next);
res = dns_c_ipmatchelement_delete(ipml->mem, &ime);
if (res != ISC_R_SUCCESS) {
break;
}
ime = imptmp;
}
return (res);
}
isc_result_t
dns_c_ipmatchlist_copy(isc_mem_t *mem,
dns_c_ipmatchlist_t **dest, dns_c_ipmatchlist_t *src)
{
dns_c_ipmatchelement_t *ime;
dns_c_ipmatchelement_t *ptr;
dns_c_ipmatchlist_t *newlist;
isc_result_t result;
REQUIRE(mem != NULL);
REQUIRE(dest != NULL);
REQUIRE(DNS_C_IPMLIST_VALID(src));
*dest = NULL;
result = dns_c_ipmatchlist_new(mem, &newlist);
if (result != ISC_R_SUCCESS) {
return (result);
}
ime = ISC_LIST_HEAD(src->elements);
while (ime != NULL) {
result = dns_c_ipmatchelement_copy(mem, &ptr, ime);
if (result != ISC_R_SUCCESS) {
dns_c_ipmatchlist_detach(&newlist);
return (result);
}
ISC_LIST_APPEND(newlist->elements, ptr, next);
ime = ISC_LIST_NEXT(ime, next);
}
*dest = newlist;
return (ISC_R_SUCCESS);
}
isc_boolean_t
dns_c_ipmatchlist_equal(dns_c_ipmatchlist_t *l1, dns_c_ipmatchlist_t *l2) {
dns_c_ipmatchelement_t *e1, *e2;
REQUIRE(l1 == NULL || DNS_C_IPMLIST_VALID(l1));
REQUIRE(l2 == NULL || DNS_C_IPMLIST_VALID(l2));
if (l1 == NULL && l2 == NULL)
return (ISC_TRUE);
if (l1 != NULL || l2 != NULL)
return (ISC_FALSE);
e1 = ISC_LIST_HEAD(l1->elements);
e2 = ISC_LIST_HEAD(l2->elements);
while (e1 != NULL && e2 != NULL) {
if (!dns_c_ipmatchelement_equal(e1, e2))
return (ISC_FALSE);
e1 = ISC_LIST_NEXT(e1, next);
e2 = ISC_LIST_NEXT(e2, next);
}
if (l1 != NULL || l2 != NULL)
return (ISC_FALSE);
return (ISC_TRUE);
}
isc_result_t
dns_c_ipmatchlist_append(dns_c_ipmatchlist_t *dest,
dns_c_ipmatchlist_t *src,
isc_boolean_t negate)
{
dns_c_ipmatchelement_t *ime;
dns_c_ipmatchelement_t *ime_copy;
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(DNS_C_IPMLIST_VALID(dest));
REQUIRE(DNS_C_IPMLIST_VALID(src));
ime = ISC_LIST_HEAD(src->elements);
while (ime != NULL) {
result = dns_c_ipmatchelement_copy(dest->mem,
&ime_copy,
ime);
if (result != ISC_R_SUCCESS) {
break;
}
if (negate) {
dns_c_ipmatch_negate(ime_copy);
}
ISC_LIST_APPEND(dest->elements, ime_copy, next);
ime = ISC_LIST_NEXT(ime, next);
}
return (result);
}
isc_result_t
dns_c_ipmatchelement_print(FILE *fp, int indent, dns_c_ipmatchelement_t *ipme)
{
int bits;
REQUIRE(fp != NULL);
REQUIRE(DNS_C_IPMELEM_VALID(ipme));
if (dns_c_ipmatchelement_isneg(ipme) &&
ipme->type != dns_c_ipmatch_any) {
/* a '!any' element gets printed as 'none' */
fputc('!', fp);
} else {
fputc(' ', fp);
}
switch (ipme->type) {
case dns_c_ipmatch_pattern:
dns_c_print_ipaddr(fp, &ipme->u.direct.address);
bits = ipme->u.direct.mask;
if (bits > 0) {
isc_uint32_t fam =
ipme->u.direct.address.type.sa.sa_family;
if ((fam == AF_INET && bits < 32) ||
(fam == AF_INET6 && bits < 128)) {
fprintf(fp, "/%d", bits);
}
}
break;
case dns_c_ipmatch_indirect:
if (ipme->u.indirect.refname.base != NULL) {
fprintf(fp, "%s", ipme->u.indirect.refname.base);
} else {
dns_c_ipmatchlist_print(fp, indent,
ipme->u.indirect.list);
}
break;
case dns_c_ipmatch_key:
fprintf(fp, "key %s", ipme->u.key);
break;
case dns_c_ipmatch_localhost:
fprintf(fp, "localhost");
break;
case dns_c_ipmatch_localnets:
fprintf(fp, "localnets");
break;
case dns_c_ipmatch_any:
if (dns_c_ipmatchelement_isneg(ipme)) {
fprintf(fp, "none");
} else {
fprintf(fp, "any");
}
break;
case dns_c_ipmatch_none:
isc_log_write(dns_lctx, DNS_LOGCATEGORY_CONFIG,
DNS_LOGMODULE_CONFIG, ISC_LOG_CRITICAL,
"dns_ipmatch_none element type");
return (ISC_R_FAILURE);
case dns_c_ipmatch_acl:
fprintf(fp, "%s", ipme->u.aclname);
break;
}
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_ipmatchlist_print(FILE *fp, int indent, dns_c_ipmatchlist_t *ml) {
dns_c_ipmatchelement_t *ipme ;
REQUIRE(DNS_C_IPMLIST_VALID(ml));
REQUIRE(fp != NULL);
/* no indent on first line. */
fprintf(fp, "{\n");
ipme = ISC_LIST_HEAD(ml->elements);
if (ipme == NULL) {
dns_c_printtabs(fp, indent);
fprintf(fp,
"/* this list intentionally left blank */\n");
} else {
while (ipme != NULL) {
dns_c_printtabs(fp, indent);
dns_c_ipmatchelement_print(fp, indent + 1, ipme);
fprintf(fp, ";\n");
ipme = ISC_LIST_NEXT(ipme, next);
}
}
dns_c_printtabs(fp, indent - 1);
fprintf(fp, "}");
return (ISC_R_SUCCESS);
}
isc_boolean_t
dns_c_ipmatchlist_walk(dns_c_ipmatchlist_t *list, dns_c_ipmlwalker func)
{
isc_boolean_t retval = ISC_TRUE;
dns_c_ipmatchelement_t *ipme ;
REQUIRE(DNS_C_IPMLIST_VALID(list));
ipme = ISC_LIST_HEAD(list->elements);
while (retval == ISC_TRUE && ipme != NULL) {
switch (ipme->type) {
case dns_c_ipmatch_pattern:
case dns_c_ipmatch_key:
case dns_c_ipmatch_localhost:
case dns_c_ipmatch_localnets:
case dns_c_ipmatch_any:
case dns_c_ipmatch_none:
retval = ISC_TF(retval && (*func)(ipme));
break;
case dns_c_ipmatch_indirect:
retval = ISC_TF(retval &&
dns_c_ipmatchlist_walk(ipme->
u.indirect.list,
func));
break;
default:
break;
}
ipme = ISC_LIST_NEXT(ipme, next);
}
return (retval);
}
isc_result_t
dns_c_iplist_new(isc_mem_t *mem, int length, dns_c_iplist_t **newlist) {
dns_c_iplist_t *list;
size_t bytes;
#ifndef NOMINUM_PUBLIC
int i;
#endif /* NOMINUM_PUBLIC */
REQUIRE(mem != NULL);
REQUIRE(length > 0);
REQUIRE(newlist != NULL);
list = isc_mem_get(mem, sizeof *list);
if (list == NULL) {
return (ISC_R_NOMEMORY);
}
bytes = sizeof (isc_sockaddr_t) * length;
list->ips = isc_mem_get(mem, bytes);
if (list->ips == NULL) {
isc_mem_put(mem, list, sizeof *list);
return (ISC_R_NOMEMORY);
}
memset(list->ips, 0x0, bytes);
bytes = sizeof (dns_name_t *) * length;
#ifndef NOMINUM_PUBLIC
list->keys = isc_mem_get(mem, bytes);
if (list->keys == NULL) {
isc_mem_put(mem, list->ips, sizeof (isc_sockaddr_t) * length);
isc_mem_put(mem, list, sizeof *list);
return (ISC_R_NOMEMORY);
}
for (i = 0 ; i < length ; i++)
list->keys[i] = NULL;
#endif /* NOMINUM_PUBLIC */
list->magic = DNS_C_IPLIST_MAGIC;
list->size = length;
list->nextidx = 0;
list->mem = mem;
list->refcount = 1;
*newlist = list;
return (ISC_R_SUCCESS);
}
isc_result_t
dns_c_iplist_detach(dns_c_iplist_t **list) {
dns_c_iplist_t *l ;
#ifndef NOMINUM_PUBLIC
unsigned int i;
#endif /* NOMINUM_PUBLIC */
REQUIRE(list != NULL);
REQUIRE(*list != NULL);
l = *list;
REQUIRE(DNS_C_IPLIST_VALID(l));
INSIST(l->refcount > 0);
l->refcount--;
if (l->refcount == 0) {
#ifndef NOMINUM_PUBLIC
for (i = 0 ; i < l->size ; i++) {
if (l->keys[i] != NULL) {
dns_name_free(l->keys[i], l->mem);
isc_mem_put(l->mem, l->keys[i],
sizeof (dns_name_t));
l->keys[i] = NULL;
}
}
isc_mem_put(l->mem, l->keys, sizeof (dns_name_t *) * l->size);
#endif /* NOMINUM_PUBLIC */
isc_mem_put(l->mem, l->ips, sizeof (isc_sockaddr_t) * l->size);
isc_mem_put(l->mem, l, sizeof *l);
}
*list = NULL;
return (ISC_R_SUCCESS);
}
#ifndef NOMINUM_PUBLIC
isc_boolean_t
dns_c_iplist_haskeys(dns_c_iplist_t *list)
{
unsigned int i;
if (list->keys == NULL) {
return (ISC_FALSE);
}
for (i = 0 ; i < list->nextidx ; i++) {
if (list->keys[i] != NULL) {
return (ISC_TRUE);
}
}
return (ISC_FALSE);
}
#endif /* NOMINUM_PUBLIC */
void
dns_c_iplist_attach(dns_c_iplist_t *source, dns_c_iplist_t **target) {
REQUIRE(DNS_C_IPLIST_VALID(source));
INSIST(source->refcount > 0);
source->refcount++;
*target = source;
}
isc_result_t
dns_c_iplist_copy(isc_mem_t *mem, dns_c_iplist_t **dest, dns_c_iplist_t *src) {
dns_c_iplist_t *newl;
isc_result_t res;
isc_uint32_t i;
REQUIRE(dest != NULL);
REQUIRE(DNS_C_IPLIST_VALID(src));
res = dns_c_iplist_new(mem, src->size, &newl);
if (res != ISC_R_SUCCESS) {
return (res);
}
for (i = 0 ; i < src->nextidx ; i++) {
newl->ips[i] = src->ips[i];
#ifndef NOMINUM_PUBLIC
if (src->keys[i] != NULL) {
newl->keys[i] = isc_mem_get(mem, sizeof (dns_name_t));
if (newl->keys[i] == NULL) {
dns_c_iplist_detach(&newl);
return (ISC_R_NOMEMORY);
} else {
res = dns_name_dup(src->keys[i], mem,
newl->keys[i]);
if (res != ISC_R_SUCCESS) {
dns_c_iplist_detach(&newl);
return (res);
}
}
}
#endif /* NOMINUM_PUBLIC */
}
newl->nextidx = src->nextidx;
*dest = newl;
return (ISC_R_SUCCESS);
}
isc_boolean_t
dns_c_iplist_equal(dns_c_iplist_t *list1, dns_c_iplist_t *list2) {
isc_uint32_t i;
REQUIRE(DNS_C_IPLIST_VALID(list1));
REQUIRE(DNS_C_IPLIST_VALID(list2));
if (list1->nextidx != list2->nextidx)
return (ISC_FALSE);
for (i = 0 ; i < list1->nextidx ; i++) {
if (!isc_sockaddr_equal(&list1->ips[i], &list2->ips[i]))
return (ISC_FALSE);
#ifndef NOMINUM_PUBLIC
if ((list1->keys[i] == NULL && list2->keys[i] != NULL) ||
(list1->keys[i] != NULL && list2->keys[i] == NULL))
return (ISC_FALSE);
if (list1->keys[i] != NULL &&
!dns_name_equal(list1->keys[i], list2->keys[i]))
return (ISC_FALSE);
#endif /* NOMINUM_PUBLIC */
}
return (ISC_TRUE);
}
void
dns_c_iplist_printfully(FILE *fp, int indent, isc_boolean_t porttoo,
dns_c_iplist_t *list)
{
isc_uint32_t i;
in_port_t port;
in_port_t tmpport;
isc_boolean_t athead = ISC_TRUE;
REQUIRE(DNS_C_IPLIST_VALID(list));
if (list->nextidx == 0) {
fputc('{', fp);
fputc('\n', fp);
dns_c_printtabs(fp, indent);
fprintf(fp, "/* no ip addresses defined */\n");
dns_c_printtabs(fp, indent - 1);
fputc('}', fp);
} else {
if (porttoo) {
port = isc_sockaddr_getport(&list->ips[0]);
for (i = 0 ; i < list->nextidx ; i++) {
tmpport = isc_sockaddr_getport(&list->ips[i]);
if (tmpport != port) {
athead = ISC_FALSE;
}
}
if (athead) {
fprintf(fp, "port %d ", port);
}
}
fputc('{', fp);
fputc('\n', fp);
for (i = 0 ; i < list->nextidx ; i++) {
dns_c_printtabs(fp, indent);
dns_c_print_ipaddr(fp, &list->ips[i]);
if (!athead) {
fprintf(fp, " port %d",
isc_sockaddr_getport(&list->ips[i]));
}
#ifndef NOMINUM_PUBLIC
if (list->keys[i] != NULL) {
fprintf(fp, " key \"");
dns_name_print(list->keys[i], fp);
fprintf(fp, "\" ");
}
#endif /* NOMINUM_PUBLIC */
fprintf(fp, ";\n");
}
dns_c_printtabs(fp, indent - 1);
fputc('}', fp);
}
fputc('\n', fp);
}
void
dns_c_iplist_print(FILE *fp, int indent, dns_c_iplist_t *list) {
dns_c_iplist_printfully(fp, indent, ISC_FALSE, list);
}
#ifndef NOMINUM_PUBLIC
isc_result_t
dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr,
const char *key)
{
#else /* NOMINUM_PUBLIC */
isc_result_t
dns_c_iplist_append(dns_c_iplist_t *list, isc_sockaddr_t newaddr) {
#endif /* NOMINUM_PUBLIC */
isc_uint32_t i;
isc_result_t res;
REQUIRE(DNS_C_IPLIST_VALID(list));
for (i = 0 ; i < list->nextidx ; i++) {
if (memcmp(&list->ips[i], &newaddr, sizeof newaddr) == 0) {
break;
}
}
if (i < list->nextidx) {
return (ISC_R_FAILURE);
}
if (list->nextidx == list->size) {
isc_sockaddr_t *newlist;
#ifndef NOMINUM_PUBLIC
dns_name_t **newkeys;
#endif /* NOMINUM_PUBLIC */
size_t newbytes;
size_t oldbytes = list->size * sizeof (list->ips[0]);
size_t newsize = list->size + 10;
newbytes = sizeof (list->ips[0]) * newsize;
newlist = isc_mem_get(list->mem, newbytes);
if (newlist == NULL) {
return (ISC_R_NOMEMORY);
}
memset(newlist, 0x0, newbytes);
memcpy(newlist, list->ips, oldbytes);
isc_mem_put(list->mem, list->ips, oldbytes);
list->ips = newlist;
#ifndef NOMINUM_PUBLIC
oldbytes = list->size * sizeof(list->keys[0]);
newbytes = sizeof (list->ips[0]) * newsize;
newkeys = isc_mem_get(list->mem, newbytes);
if (newkeys == NULL) {
return (ISC_R_NOMEMORY);
}
memcpy(newkeys, list->keys, oldbytes);
for (i = list->size ; i < newsize ; i++)
list->keys[i] = NULL;
isc_mem_put(list->mem, list->keys, oldbytes);
list->keys = newkeys;
#endif /* NOMINUM_PUBLIC */
i = list->size;
list->size = newsize;
}
list->ips[i] = newaddr;
list->nextidx++;
res = ISC_R_SUCCESS;
#ifndef NOMINUM_PUBLIC
if (key != NULL) {
if (list->keys[i] != NULL) {
dns_name_free(list->keys[i], list->mem);
isc_mem_put(list->mem, list->keys,
sizeof (dns_name_t));
list->keys[i] = NULL;
}
res = dns_c_charptoname(list->mem, key, &list->keys[i]);
}
#endif /* NOMINUM_PUBLIC */
return (res);
}
isc_result_t
dns_c_iplist_remove(dns_c_iplist_t *list, isc_sockaddr_t newaddr) {
isc_uint32_t i;
REQUIRE(DNS_C_IPLIST_VALID(list));
for (i = 0 ; i < list->nextidx ; i++) {
if (memcmp(&list->ips[i], &newaddr, sizeof newaddr) == 0) {
break;
}
}
if (i == list->nextidx) {
return (ISC_R_FAILURE);
}
list->nextidx--;
#ifndef NOMINUM_PUBLIC
if (list->keys[i] != NULL) {
dns_name_reset(list->keys[i]);
isc_mem_put(list->mem, list->keys[i], sizeof (dns_name_t));
}
#endif /* NOMINUM_PUBLIC */
for ( /* nothing */ ; i < list->nextidx ; i++) {
list->ips[i] = list->ips[i + 1];
#ifndef NOMINUM_PUBLIC
list->keys[i] = list->keys[i + 1];
#endif /* NOMINUM_PUBLIC */
}
return (ISC_R_SUCCESS);
}
/*
* Check that the address given is a network address with the given number
* of high order bits.
*/
static isc_result_t
checkmask(isc_sockaddr_t *address, isc_uint32_t bits) {
if (bits > 0) {
if (address->type.sa.sa_family == AF_INET) {
isc_uint32_t mask;
if (bits > 32) {
return (ISC_R_FAILURE);
}
mask = ntohl(0xffffffffU << (32 - bits));
if ((mask & address->type.sin.sin_addr.s_addr) !=
address->type.sin.sin_addr.s_addr) {
return (ISC_R_FAILURE);
}
} else if (address->type.sa.sa_family == AF_INET6) {
struct in6_addr iaddr;
unsigned char *maskp;
unsigned char *addrp;
int i;
if (bits > 128) {
return (ISC_R_FAILURE);
}
if (bits2v6mask(&iaddr, bits) != ISC_R_SUCCESS) {
return (ISC_R_FAILURE);
}
addrp = (unsigned char *)&address->type.sin6.sin6_addr;
maskp = (unsigned char *)&iaddr;
for (i = 0 ; i < 16 ; i++) {
if ((addrp[i] & maskp[i]) != addrp[i]) {
return (ISC_R_FAILURE);
}
}
}
}
return (ISC_R_SUCCESS);
}
/*
* Create a 128 bits mask in network byte order in the the IPv6 address
* section of the sockaddr. The bits argument is the number of high bits
* that are to be set to 1.
*/
static isc_result_t
bits2v6mask(struct in6_addr *addr, isc_uint32_t bits) {
int i;
isc_uint32_t bitmask[4];
char addrbuff [ sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" + 1 ];
INSIST(bits <= 128);
/* Break the 128 bits up into 32-bit sections */
bitmask[0] = bitmask[1] = bitmask[2] = bitmask[3] = 0U;
if (bits >= 32) {
bitmask[0] = 0xffffffffU;
} else if (bits > 0) {
bitmask[0] = 0xffffffffU << (32 - bits);
}
if (bits >= 64) {
bitmask[1] = 0xffffffffU;
} else if (bits > 32) {
bitmask[1] = 0xffffffffU << (64 - bits);
}
if (bits >= 96) {
bitmask[2] = 0xffffffffU;
bitmask[3] = 0xffffffffU << (128 - bits);
} else if (bits > 64) {
bitmask[2] = 0xffffffffU << (96 - bits);
}
memset(addr, 0x0, sizeof *addr);
sprintf(addrbuff, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
(((bitmask[0] & 0xffff0000U) >> 16) & 0xffffU),
(bitmask[0] & 0xffff),
(((bitmask[1] & 0xffff0000U) >> 16) & 0xffffU),
(bitmask[1] & 0xffff),
(((bitmask[2] & 0xffff0000U) >> 16) & 0xffffU),
(bitmask[2] & 0xffff),
(((bitmask[3] & 0xffff0000U) >> 16) & 0xffffU),
(bitmask[3] & 0xffff));
i = inet_pton(AF_INET6, addrbuff, addr);
return (i == 1 ? ISC_R_SUCCESS : ISC_R_FAILURE);
}