/* * Copyright (C) 1999, 2000 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ /* $Id: confip.c,v 1.27 2000/06/06 15:21:46 tale Exp $ */ #include #include #include #include #include #include /* * 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; 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); 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 ; REQUIRE(list != NULL); REQUIRE(*list != NULL); l = *list; REQUIRE(DNS_C_IPLIST_VALID(l)); INSIST(l->refcount > 0); l->refcount--; if (l->refcount == 0) { 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); } 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]; } 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); } 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])); } 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); } isc_result_t dns_c_iplist_append(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); } if (list->nextidx == list->size) { isc_sockaddr_t *newlist; 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; list->size = newsize; } list->ips[i] = newaddr; list->nextidx++; return (ISC_R_SUCCESS); } 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[0], &newaddr, sizeof newaddr) == 0) { break; } } if (i == list->nextidx) { return (ISC_R_FAILURE); } list->nextidx--; for ( /* nothing */ ; i < list->nextidx ; i++) { list->ips[i] = list->ips[i + 1]; } 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); }