rdata.c revision 170223
160484Sobrien/* 260484Sobrien * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") 360484Sobrien * Copyright (C) 1998-2003 Internet Software Consortium. 460484Sobrien * 560484Sobrien * Permission to use, copy, modify, and distribute this software for any 660484Sobrien * purpose with or without fee is hereby granted, provided that the above 760484Sobrien * copyright notice and this permission notice appear in all copies. 860484Sobrien * 9218822Sdim * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 1060484Sobrien * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 1160484Sobrien * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 1260484Sobrien * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 1360484Sobrien * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 1460484Sobrien * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 1560484Sobrien * PERFORMANCE OF THIS SOFTWARE. 1660484Sobrien */ 1760484Sobrien 1860484Sobrien/* $Id: rdata.c,v 1.184.18.9 2006/07/21 02:05:57 marka Exp $ */ 1960484Sobrien 2060484Sobrien/*! \file */ 2160484Sobrien 2260484Sobrien#include <config.h> 2360484Sobrien#include <ctype.h> 2460484Sobrien 2560484Sobrien#include <isc/base64.h> 2660484Sobrien#include <isc/hex.h> 2760484Sobrien#include <isc/lex.h> 2860484Sobrien#include <isc/mem.h> 2960484Sobrien#include <isc/parseint.h> 3060484Sobrien#include <isc/print.h> 3160484Sobrien#include <isc/string.h> 3260484Sobrien#include <isc/stdlib.h> 3360484Sobrien#include <isc/util.h> 3460484Sobrien 3560484Sobrien#include <dns/callbacks.h> 3660484Sobrien#include <dns/cert.h> 3760484Sobrien#include <dns/compress.h> 38218822Sdim#include <dns/enumtype.h> 3960484Sobrien#include <dns/keyflags.h> 4060484Sobrien#include <dns/keyvalues.h> 4160484Sobrien#include <dns/rcode.h> 4260484Sobrien#include <dns/rdata.h> 4360484Sobrien#include <dns/rdataclass.h> 4460484Sobrien#include <dns/rdatastruct.h> 4560484Sobrien#include <dns/rdatatype.h> 4660484Sobrien#include <dns/result.h> 4760484Sobrien#include <dns/secalg.h> 4860484Sobrien#include <dns/secproto.h> 4960484Sobrien#include <dns/time.h> 5060484Sobrien#include <dns/ttl.h> 5160484Sobrien 5260484Sobrien#define RETERR(x) \ 5360484Sobrien do { \ 5460484Sobrien isc_result_t _r = (x); \ 5560484Sobrien if (_r != ISC_R_SUCCESS) \ 5660484Sobrien return (_r); \ 5760484Sobrien } while (0) 5860484Sobrien 5960484Sobrien#define RETTOK(x) \ 6060484Sobrien do { \ 6160484Sobrien isc_result_t _r = (x); \ 6260484Sobrien if (_r != ISC_R_SUCCESS) { \ 6360484Sobrien isc_lex_ungettoken(lexer, &token); \ 6460484Sobrien return (_r); \ 6560484Sobrien } \ 6660484Sobrien } while (0) 6760484Sobrien 6860484Sobrien#define DNS_AS_STR(t) ((t).value.as_textregion.base) 6960484Sobrien 7060484Sobrien#define ARGS_FROMTEXT int rdclass, dns_rdatatype_t type, \ 7160484Sobrien isc_lex_t *lexer, dns_name_t *origin, \ 7260484Sobrien unsigned int options, isc_buffer_t *target, \ 7360484Sobrien dns_rdatacallbacks_t *callbacks 7460484Sobrien 7560484Sobrien#define ARGS_TOTEXT dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, \ 7660484Sobrien isc_buffer_t *target 7760484Sobrien 7860484Sobrien#define ARGS_FROMWIRE int rdclass, dns_rdatatype_t type, \ 7960484Sobrien isc_buffer_t *source, dns_decompress_t *dctx, \ 8060484Sobrien unsigned int options, isc_buffer_t *target 8160484Sobrien 8260484Sobrien#define ARGS_TOWIRE dns_rdata_t *rdata, dns_compress_t *cctx, \ 8360484Sobrien isc_buffer_t *target 8460484Sobrien 8560484Sobrien#define ARGS_COMPARE const dns_rdata_t *rdata1, const dns_rdata_t *rdata2 8660484Sobrien 8760484Sobrien#define ARGS_FROMSTRUCT int rdclass, dns_rdatatype_t type, \ 8860484Sobrien void *source, isc_buffer_t *target 8960484Sobrien 9060484Sobrien#define ARGS_TOSTRUCT dns_rdata_t *rdata, void *target, isc_mem_t *mctx 9160484Sobrien 9260484Sobrien#define ARGS_FREESTRUCT void *source 9360484Sobrien 9460484Sobrien#define ARGS_ADDLDATA dns_rdata_t *rdata, dns_additionaldatafunc_t add, \ 9560484Sobrien void *arg 9660484Sobrien 9760484Sobrien#define ARGS_DIGEST dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg 9860484Sobrien 9960484Sobrien#define ARGS_CHECKOWNER dns_name_t *name, dns_rdataclass_t rdclass, \ 10060484Sobrien dns_rdatatype_t type, isc_boolean_t wildcard 10160484Sobrien 10260484Sobrien#define ARGS_CHECKNAMES dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad 10360484Sobrien 10460484Sobrien 10560484Sobrien/*% 106218822Sdim * Context structure for the totext_ functions. 10760484Sobrien * Contains formatting options for rdata-to-text 10860484Sobrien * conversion. 10960484Sobrien */ 11060484Sobrientypedef struct dns_rdata_textctx { 11160484Sobrien dns_name_t *origin; /*%< Current origin, or NULL. */ 11260484Sobrien unsigned int flags; /*%< DNS_STYLEFLAG_* */ 11360484Sobrien unsigned int width; /*%< Width of rdata column. */ 11460484Sobrien const char *linebreak; /*%< Line break string. */ 11560484Sobrien} dns_rdata_textctx_t; 11660484Sobrien 11760484Sobrienstatic isc_result_t 11860484Sobrientxt_totext(isc_region_t *source, isc_buffer_t *target); 11960484Sobrien 12060484Sobrienstatic isc_result_t 12160484Sobrientxt_fromtext(isc_textregion_t *source, isc_buffer_t *target); 12260484Sobrien 12360484Sobrienstatic isc_result_t 12460484Sobrientxt_fromwire(isc_buffer_t *source, isc_buffer_t *target); 12560484Sobrien 12660484Sobrienstatic isc_boolean_t 12760484Sobrienname_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target); 12860484Sobrien 12960484Sobrienstatic unsigned int 13060484Sobrienname_length(dns_name_t *name); 13160484Sobrien 13260484Sobrienstatic isc_result_t 13360484Sobrienstr_totext(const char *source, isc_buffer_t *target); 13460484Sobrien 135218822Sdimstatic isc_result_t 13660484Sobrieninet_totext(int af, isc_region_t *src, isc_buffer_t *target); 13760484Sobrien 13860484Sobrienstatic isc_boolean_t 13960484Sobrienbuffer_empty(isc_buffer_t *source); 14060484Sobrien 14160484Sobrienstatic void 14260484Sobrienbuffer_fromregion(isc_buffer_t *buffer, isc_region_t *region); 14360484Sobrien 14460484Sobrienstatic isc_result_t 14560484Sobrienuint32_tobuffer(isc_uint32_t, isc_buffer_t *target); 14660484Sobrien 14760484Sobrienstatic isc_result_t 14860484Sobrienuint16_tobuffer(isc_uint32_t, isc_buffer_t *target); 14960484Sobrien 15060484Sobrienstatic isc_result_t 15160484Sobrienuint8_tobuffer(isc_uint32_t, isc_buffer_t *target); 15260484Sobrien 15360484Sobrienstatic isc_result_t 15460484Sobrienname_tobuffer(dns_name_t *name, isc_buffer_t *target); 15560484Sobrien 15660484Sobrienstatic isc_uint32_t 15760484Sobrienuint32_fromregion(isc_region_t *region); 15860484Sobrien 15960484Sobrienstatic isc_uint16_t 16060484Sobrienuint16_fromregion(isc_region_t *region); 16160484Sobrien 16260484Sobrienstatic isc_uint8_t 16360484Sobrienuint8_fromregion(isc_region_t *region); 16460484Sobrien 16560484Sobrienstatic isc_result_t 16660484Sobrienmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length); 16760484Sobrien 16860484Sobrienstatic int 16960484Sobrienhexvalue(char value); 17060484Sobrien 17160484Sobrienstatic int 17260484Sobriendecvalue(char value); 17360484Sobrien 17460484Sobrienstatic isc_result_t 17560484Sobrienbtoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target); 17660484Sobrien 17760484Sobrienstatic isc_result_t 17860484Sobrienatob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target); 17960484Sobrien 18060484Sobrienstatic void 18160484Sobriendefault_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *, ...) 18260484Sobrien ISC_FORMAT_PRINTF(2, 3); 18360484Sobrien 18460484Sobrienstatic void 18560484Sobrienfromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...), 18660484Sobrien dns_rdatacallbacks_t *callbacks, const char *name, 18760484Sobrien unsigned long line, isc_token_t *token, isc_result_t result); 18860484Sobrien 18960484Sobrienstatic void 19060484Sobrienfromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks); 19160484Sobrien 19260484Sobrienstatic isc_result_t 19360484Sobrienrdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, 19460484Sobrien isc_buffer_t *target); 19560484Sobrien 19660484Sobrienstatic void 19760484Sobrienwarn_badname(dns_name_t *name, isc_lex_t *lexer, 19860484Sobrien dns_rdatacallbacks_t *callbacks); 19960484Sobrien 20060484Sobrienstatic void 20160484Sobrienwarn_badmx(isc_token_t *token, isc_lex_t *lexer, 202218822Sdim dns_rdatacallbacks_t *callbacks); 20360484Sobrien 20460484Sobrienstatic inline int 20560484Sobriengetquad(const void *src, struct in_addr *dst, 20660484Sobrien isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) 20760484Sobrien{ 20860484Sobrien int result; 209104834Sobrien struct in_addr *tmp; 21060484Sobrien 21160484Sobrien result = inet_aton(src, dst); 21260484Sobrien if (result == 1 && callbacks != NULL && 21360484Sobrien inet_pton(AF_INET, src, &tmp) != 1) { 21460484Sobrien const char *name = isc_lex_getsourcename(lexer); 21560484Sobrien if (name == NULL) 21660484Sobrien name = "UNKNOWN"; 21760484Sobrien (*callbacks->warn)(callbacks, "%s:%lu: \"%s\" " 21860484Sobrien "is not a decimal dotted quad", name, 21960484Sobrien isc_lex_getsourceline(lexer), src); 22060484Sobrien } 22160484Sobrien return (result); 22260484Sobrien} 22360484Sobrien 22460484Sobrienstatic inline isc_result_t 22560484Sobrienname_duporclone(dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) { 22660484Sobrien 227104834Sobrien if (mctx != NULL) 22860484Sobrien return (dns_name_dup(source, mctx, target)); 22960484Sobrien dns_name_clone(source, target); 23060484Sobrien return (ISC_R_SUCCESS); 23160484Sobrien} 23260484Sobrien 23360484Sobrienstatic inline void * 23460484Sobrienmem_maybedup(isc_mem_t *mctx, void *source, size_t length) { 23560484Sobrien void *new; 23660484Sobrien 23760484Sobrien if (mctx == NULL) 23860484Sobrien return (source); 23960484Sobrien new = isc_mem_allocate(mctx, length); 24060484Sobrien if (new != NULL) 24160484Sobrien memcpy(new, source, length); 24260484Sobrien 24360484Sobrien return (new); 244218822Sdim} 24560484Sobrien 24660484Sobrienstatic const char hexdigits[] = "0123456789abcdef"; 24760484Sobrienstatic const char decdigits[] = "0123456789"; 24860484Sobrien 24960484Sobrien#include "code.h" 250104834Sobrien 25160484Sobrien#define META 0x0001 25260484Sobrien#define RESERVED 0x0002 25360484Sobrien 25460484Sobrien/*** 25560484Sobrien *** Initialization 25660484Sobrien ***/ 25760484Sobrien 25860484Sobrienvoid 25960484Sobriendns_rdata_init(dns_rdata_t *rdata) { 26060484Sobrien 26160484Sobrien REQUIRE(rdata != NULL); 26260484Sobrien 26360484Sobrien rdata->data = NULL; 26460484Sobrien rdata->length = 0; 265218822Sdim rdata->rdclass = 0; 26660484Sobrien rdata->type = 0; 26760484Sobrien rdata->flags = 0; 26860484Sobrien ISC_LINK_INIT(rdata, link); 26960484Sobrien /* ISC_LIST_INIT(rdata->list); */ 27060484Sobrien} 271104834Sobrien 27260484Sobrien#if 0 27360484Sobrien#define DNS_RDATA_INITIALIZED(rdata) \ 27460484Sobrien ((rdata)->data == NULL && (rdata)->length == 0 && \ 27560484Sobrien (rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \ 27660484Sobrien !ISC_LINK_LINKED((rdata), link)) 27760484Sobrien#else 27860484Sobrien#ifdef ISC_LIST_CHECKINIT 27960484Sobrien#define DNS_RDATA_INITIALIZED(rdata) \ 28060484Sobrien (!ISC_LINK_LINKED((rdata), link)) 28160484Sobrien#else 28260484Sobrien#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE 28360484Sobrien#endif 28460484Sobrien#endif 28560484Sobrien#define DNS_RDATA_VALIDFLAGS(rdata) \ 28660484Sobrien (((rdata)->flags & ~DNS_RDATA_UPDATE) == 0) 287218822Sdim 28860484Sobrienvoid 28960484Sobriendns_rdata_reset(dns_rdata_t *rdata) { 29060484Sobrien 29160484Sobrien REQUIRE(rdata != NULL); 29260484Sobrien 293104834Sobrien REQUIRE(!ISC_LINK_LINKED(rdata, link)); 29460484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 29560484Sobrien 29660484Sobrien rdata->data = NULL; 29760484Sobrien rdata->length = 0; 29860484Sobrien rdata->rdclass = 0; 29960484Sobrien rdata->type = 0; 30060484Sobrien rdata->flags = 0; 30160484Sobrien} 30260484Sobrien 30360484Sobrien/*** 30460484Sobrien *** 30560484Sobrien ***/ 306104834Sobrien 30760484Sobrienvoid 30860484Sobriendns_rdata_clone(const dns_rdata_t *src, dns_rdata_t *target) { 30960484Sobrien 31060484Sobrien REQUIRE(src != NULL); 31160484Sobrien REQUIRE(target != NULL); 31260484Sobrien 31360484Sobrien REQUIRE(DNS_RDATA_INITIALIZED(target)); 31460484Sobrien 31560484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(src)); 31660484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(target)); 31760484Sobrien 31860484Sobrien target->data = src->data; 319104834Sobrien target->length = src->length; 32060484Sobrien target->rdclass = src->rdclass; 32160484Sobrien target->type = src->type; 32260484Sobrien target->flags = src->flags; 32360484Sobrien} 32460484Sobrien 32560484Sobrien 32660484Sobrien/*** 32760484Sobrien *** Comparisons 32860484Sobrien ***/ 32960484Sobrien 33060484Sobrienint 33160484Sobriendns_rdata_compare(const dns_rdata_t *rdata1, const dns_rdata_t *rdata2) { 33260484Sobrien int result = 0; 33360484Sobrien isc_boolean_t use_default = ISC_FALSE; 33460484Sobrien 33560484Sobrien REQUIRE(rdata1 != NULL); 33660484Sobrien REQUIRE(rdata2 != NULL); 33760484Sobrien REQUIRE(rdata1->data != NULL); 338218822Sdim REQUIRE(rdata2->data != NULL); 33960484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata1)); 34060484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata2)); 34160484Sobrien 34260484Sobrien if (rdata1->rdclass != rdata2->rdclass) 34360484Sobrien return (rdata1->rdclass < rdata2->rdclass ? -1 : 1); 34460484Sobrien 345104834Sobrien if (rdata1->type != rdata2->type) 34660484Sobrien return (rdata1->type < rdata2->type ? -1 : 1); 34760484Sobrien 34860484Sobrien COMPARESWITCH 34960484Sobrien 35060484Sobrien if (use_default) { 35160484Sobrien isc_region_t r1; 35260484Sobrien isc_region_t r2; 35360484Sobrien 35460484Sobrien dns_rdata_toregion(rdata1, &r1); 35560484Sobrien dns_rdata_toregion(rdata2, &r2); 35660484Sobrien result = isc_region_compare(&r1, &r2); 35760484Sobrien } 35860484Sobrien return (result); 35960484Sobrien} 36060484Sobrien 36160484Sobrien/*** 36260484Sobrien *** Conversions 363104834Sobrien ***/ 36460484Sobrien 36560484Sobrienvoid 36660484Sobriendns_rdata_fromregion(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 36760484Sobrien dns_rdatatype_t type, isc_region_t *r) 36860484Sobrien{ 36960484Sobrien 37060484Sobrien REQUIRE(rdata != NULL); 37160484Sobrien REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 37260484Sobrien REQUIRE(r != NULL); 37360484Sobrien 37460484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 37560484Sobrien 37660484Sobrien rdata->data = r->base; 37760484Sobrien rdata->length = r->length; 378218822Sdim rdata->rdclass = rdclass; 37960484Sobrien rdata->type = type; 38060484Sobrien rdata->flags = 0; 38160484Sobrien} 38260484Sobrien 38360484Sobrienvoid 38460484Sobriendns_rdata_toregion(const dns_rdata_t *rdata, isc_region_t *r) { 38560484Sobrien 38660484Sobrien REQUIRE(rdata != NULL); 38760484Sobrien REQUIRE(r != NULL); 38860484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 38960484Sobrien 39060484Sobrien r->base = rdata->data; 391104834Sobrien r->length = rdata->length; 39260484Sobrien} 39360484Sobrien 39460484Sobrienisc_result_t 39560484Sobriendns_rdata_fromwire(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 39660484Sobrien dns_rdatatype_t type, isc_buffer_t *source, 39760484Sobrien dns_decompress_t *dctx, unsigned int options, 39860484Sobrien isc_buffer_t *target) 39960484Sobrien{ 40060484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 40160484Sobrien isc_region_t region; 40260484Sobrien isc_buffer_t ss; 40360484Sobrien isc_buffer_t st; 40460484Sobrien isc_boolean_t use_default = ISC_FALSE; 40560484Sobrien isc_uint32_t activelength; 40660484Sobrien 40760484Sobrien REQUIRE(dctx != NULL); 40860484Sobrien if (rdata != NULL) { 40960484Sobrien REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 41060484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 41160484Sobrien } 41260484Sobrien 41360484Sobrien if (type == 0) 41460484Sobrien return (DNS_R_FORMERR); 41560484Sobrien 41660484Sobrien ss = *source; 41760484Sobrien st = *target; 41860484Sobrien 41960484Sobrien activelength = isc_buffer_activelength(source); 42060484Sobrien INSIST(activelength < 65536); 42160484Sobrien 42260484Sobrien FROMWIRESWITCH 423104834Sobrien 42460484Sobrien if (use_default) { 42560484Sobrien if (activelength > isc_buffer_availablelength(target)) 42660484Sobrien result = ISC_R_NOSPACE; 42760484Sobrien else { 42860484Sobrien isc_buffer_putmem(target, isc_buffer_current(source), 42960484Sobrien activelength); 43060484Sobrien isc_buffer_forward(source, activelength); 43160484Sobrien result = ISC_R_SUCCESS; 43260484Sobrien } 43360484Sobrien } 43460484Sobrien 43560484Sobrien /* 43660484Sobrien * We should have consumed all of our buffer. 43760484Sobrien */ 43860484Sobrien if (result == ISC_R_SUCCESS && !buffer_empty(source)) 43960484Sobrien result = DNS_R_EXTRADATA; 44060484Sobrien 44160484Sobrien if (rdata != NULL && result == ISC_R_SUCCESS) { 44260484Sobrien region.base = isc_buffer_used(&st); 44360484Sobrien region.length = isc_buffer_usedlength(target) - 44460484Sobrien isc_buffer_usedlength(&st); 44560484Sobrien dns_rdata_fromregion(rdata, rdclass, type, ®ion); 44660484Sobrien } 44760484Sobrien 44860484Sobrien if (result != ISC_R_SUCCESS) { 44960484Sobrien *source = ss; 45060484Sobrien *target = st; 45160484Sobrien } 45260484Sobrien return (result); 45360484Sobrien} 45460484Sobrien 45560484Sobrienisc_result_t 45660484Sobriendns_rdata_towire(dns_rdata_t *rdata, dns_compress_t *cctx, 45760484Sobrien isc_buffer_t *target) 45860484Sobrien{ 45960484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 460218822Sdim isc_boolean_t use_default = ISC_FALSE; 46160484Sobrien isc_region_t tr; 46260484Sobrien isc_buffer_t st; 46360484Sobrien 46460484Sobrien REQUIRE(rdata != NULL); 46560484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 466104834Sobrien 46760484Sobrien /* 46860484Sobrien * Some DynDNS meta-RRs have empty rdata. 46960484Sobrien */ 47060484Sobrien if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 47160484Sobrien INSIST(rdata->length == 0); 47260484Sobrien return (ISC_R_SUCCESS); 47360484Sobrien } 47460484Sobrien 47560484Sobrien st = *target; 47660484Sobrien 47760484Sobrien TOWIRESWITCH 47860484Sobrien 47960484Sobrien if (use_default) { 480218822Sdim isc_buffer_availableregion(target, &tr); 48160484Sobrien if (tr.length < rdata->length) 48260484Sobrien return (ISC_R_NOSPACE); 48360484Sobrien memcpy(tr.base, rdata->data, rdata->length); 48460484Sobrien isc_buffer_add(target, rdata->length); 48560484Sobrien return (ISC_R_SUCCESS); 486104834Sobrien } 48760484Sobrien if (result != ISC_R_SUCCESS) { 48860484Sobrien *target = st; 48960484Sobrien INSIST(target->used < 65536); 49060484Sobrien dns_compress_rollback(cctx, (isc_uint16_t)target->used); 49160484Sobrien } 49260484Sobrien return (result); 49360484Sobrien} 49460484Sobrien 49560484Sobrien/* 49660484Sobrien * If the binary data in 'src' is valid uncompressed wire format 49760484Sobrien * rdata of class 'rdclass' and type 'type', return ISC_R_SUCCESS 49860484Sobrien * and copy the validated rdata to 'dest'. Otherwise return an error. 49960484Sobrien */ 50060484Sobrienstatic isc_result_t 501218822Sdimrdata_validate(isc_buffer_t *src, isc_buffer_t *dest, dns_rdataclass_t rdclass, 50260484Sobrien dns_rdatatype_t type) 50360484Sobrien{ 50460484Sobrien dns_decompress_t dctx; 50560484Sobrien dns_rdata_t rdata = DNS_RDATA_INIT; 50660484Sobrien isc_result_t result; 50760484Sobrien 50860484Sobrien dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE); 509104834Sobrien isc_buffer_setactive(src, isc_buffer_usedlength(src)); 51060484Sobrien result = dns_rdata_fromwire(&rdata, rdclass, type, src, 51160484Sobrien &dctx, 0, dest); 51260484Sobrien dns_decompress_invalidate(&dctx); 51360484Sobrien 51460484Sobrien return (result); 51560484Sobrien} 51660484Sobrien 51760484Sobrienstatic isc_result_t 51860484Sobrienunknown_fromtext(dns_rdataclass_t rdclass, dns_rdatatype_t type, 51960484Sobrien isc_lex_t *lexer, isc_mem_t *mctx, isc_buffer_t *target) 52060484Sobrien{ 52160484Sobrien isc_result_t result; 52260484Sobrien isc_buffer_t *buf = NULL; 52360484Sobrien isc_token_t token; 524104834Sobrien 52560484Sobrien if (type == 0 || dns_rdatatype_ismeta(type)) 52660484Sobrien return (DNS_R_METATYPE); 52760484Sobrien 52860484Sobrien result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 52960484Sobrien ISC_FALSE); 53060484Sobrien if (result == ISC_R_SUCCESS && token.value.as_ulong > 65535U) 53160484Sobrien return (ISC_R_RANGE); 53260484Sobrien result = isc_buffer_allocate(mctx, &buf, token.value.as_ulong); 53360484Sobrien if (result != ISC_R_SUCCESS) 53460484Sobrien return (result); 53560484Sobrien 53660484Sobrien result = isc_hex_tobuffer(lexer, buf, 53760484Sobrien (unsigned int)token.value.as_ulong); 53860484Sobrien if (result != ISC_R_SUCCESS) 539104834Sobrien goto failure; 54060484Sobrien if (isc_buffer_usedlength(buf) != token.value.as_ulong) { 54160484Sobrien result = ISC_R_UNEXPECTEDEND; 54260484Sobrien goto failure; 54360484Sobrien } 54460484Sobrien 54560484Sobrien if (dns_rdatatype_isknown(type)) { 54660484Sobrien result = rdata_validate(buf, target, rdclass, type); 54760484Sobrien } else { 54860484Sobrien isc_region_t r; 54960484Sobrien isc_buffer_usedregion(buf, &r); 55060484Sobrien result = isc_buffer_copyregion(target, &r); 55160484Sobrien } 55260484Sobrien if (result != ISC_R_SUCCESS) 55360484Sobrien goto failure; 55460484Sobrien 55560484Sobrien isc_buffer_free(&buf); 556104834Sobrien return (ISC_R_SUCCESS); 55760484Sobrien 55860484Sobrien failure: 55960484Sobrien isc_buffer_free(&buf); 56060484Sobrien return (result); 56160484Sobrien} 56260484Sobrien 56360484Sobrienisc_result_t 56460484Sobriendns_rdata_fromtext(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 56560484Sobrien dns_rdatatype_t type, isc_lex_t *lexer, 56660484Sobrien dns_name_t *origin, unsigned int options, isc_mem_t *mctx, 56760484Sobrien isc_buffer_t *target, dns_rdatacallbacks_t *callbacks) 56860484Sobrien{ 56960484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 57060484Sobrien isc_region_t region; 57160484Sobrien isc_buffer_t st; 57260484Sobrien isc_token_t token; 57360484Sobrien unsigned int lexoptions = ISC_LEXOPT_EOL | ISC_LEXOPT_EOF | 574104834Sobrien ISC_LEXOPT_DNSMULTILINE | ISC_LEXOPT_ESCAPE; 57560484Sobrien char *name; 57660484Sobrien unsigned long line; 57760484Sobrien void (*callback)(dns_rdatacallbacks_t *, const char *, ...); 57860484Sobrien isc_result_t tresult; 57960484Sobrien 58060484Sobrien REQUIRE(origin == NULL || dns_name_isabsolute(origin) == ISC_TRUE); 58160484Sobrien if (rdata != NULL) { 58260484Sobrien REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 58360484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 58460484Sobrien } 58560484Sobrien if (callbacks != NULL) { 58660484Sobrien REQUIRE(callbacks->warn != NULL); 58760484Sobrien REQUIRE(callbacks->error != NULL); 58860484Sobrien } 58960484Sobrien 59060484Sobrien st = *target; 59160484Sobrien 59260484Sobrien if (callbacks != NULL) 59360484Sobrien callback = callbacks->error; 594218822Sdim else 59560484Sobrien callback = default_fromtext_callback; 59660484Sobrien 59760484Sobrien result = isc_lex_getmastertoken(lexer, &token, isc_tokentype_qstring, 59860484Sobrien ISC_FALSE); 59960484Sobrien if (result != ISC_R_SUCCESS) { 600104834Sobrien name = isc_lex_getsourcename(lexer); 60160484Sobrien line = isc_lex_getsourceline(lexer); 60260484Sobrien fromtext_error(callback, callbacks, name, line, 60360484Sobrien &token, result); 60460484Sobrien return (result); 60560484Sobrien } 60660484Sobrien 60760484Sobrien if (strcmp(DNS_AS_STR(token), "\\#") == 0) 60860484Sobrien result = unknown_fromtext(rdclass, type, lexer, mctx, target); 60960484Sobrien else { 61060484Sobrien isc_lex_ungettoken(lexer, &token); 61160484Sobrien 61260484Sobrien FROMTEXTSWITCH 61360484Sobrien } 61460484Sobrien 61560484Sobrien /* 616104834Sobrien * Consume to end of line / file. 61760484Sobrien * If not at end of line initially set error code. 61860484Sobrien * Call callback via fromtext_error once if there was an error. 61960484Sobrien */ 62060484Sobrien do { 62160484Sobrien name = isc_lex_getsourcename(lexer); 62260484Sobrien line = isc_lex_getsourceline(lexer); 62360484Sobrien tresult = isc_lex_gettoken(lexer, lexoptions, &token); 62460484Sobrien if (tresult != ISC_R_SUCCESS) { 62560484Sobrien if (result == ISC_R_SUCCESS) 62660484Sobrien result = tresult; 62760484Sobrien if (callback != NULL) 62860484Sobrien fromtext_error(callback, callbacks, name, 62960484Sobrien line, NULL, result); 63060484Sobrien break; 631104834Sobrien } else if (token.type != isc_tokentype_eol && 63260484Sobrien token.type != isc_tokentype_eof) { 63360484Sobrien if (result == ISC_R_SUCCESS) 63460484Sobrien result = DNS_R_EXTRATOKEN; 63560484Sobrien if (callback != NULL) { 63660484Sobrien fromtext_error(callback, callbacks, name, 63760484Sobrien line, &token, result); 63860484Sobrien callback = NULL; 63960484Sobrien } 64060484Sobrien } else if (result != ISC_R_SUCCESS && callback != NULL) { 64160484Sobrien fromtext_error(callback, callbacks, name, line, 64260484Sobrien &token, result); 64360484Sobrien break; 64460484Sobrien } else { 64560484Sobrien if (token.type == isc_tokentype_eof) 646104834Sobrien fromtext_warneof(lexer, callbacks); 64760484Sobrien break; 64860484Sobrien } 64960484Sobrien } while (1); 65060484Sobrien 65160484Sobrien if (rdata != NULL && result == ISC_R_SUCCESS) { 65260484Sobrien region.base = isc_buffer_used(&st); 65360484Sobrien region.length = isc_buffer_usedlength(target) - 65460484Sobrien isc_buffer_usedlength(&st); 65560484Sobrien dns_rdata_fromregion(rdata, rdclass, type, ®ion); 65660484Sobrien } 65760484Sobrien if (result != ISC_R_SUCCESS) { 65860484Sobrien *target = st; 65960484Sobrien } 66060484Sobrien return (result); 661104834Sobrien} 66260484Sobrien 66360484Sobrienstatic isc_result_t 66460484Sobrienrdata_totext(dns_rdata_t *rdata, dns_rdata_textctx_t *tctx, 66560484Sobrien isc_buffer_t *target) 66660484Sobrien{ 66760484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 66860484Sobrien isc_boolean_t use_default = ISC_FALSE; 66960484Sobrien char buf[sizeof("65535")]; 67060484Sobrien isc_region_t sr; 67160484Sobrien 67260484Sobrien REQUIRE(rdata != NULL); 67360484Sobrien REQUIRE(tctx->origin == NULL || 67460484Sobrien dns_name_isabsolute(tctx->origin) == ISC_TRUE); 675104834Sobrien 67660484Sobrien /* 67760484Sobrien * Some DynDNS meta-RRs have empty rdata. 67860484Sobrien */ 67960484Sobrien if ((rdata->flags & DNS_RDATA_UPDATE) != 0) { 68060484Sobrien INSIST(rdata->length == 0); 68160484Sobrien return (ISC_R_SUCCESS); 68260484Sobrien } 68360484Sobrien 68460484Sobrien TOTEXTSWITCH 685104834Sobrien 68660484Sobrien if (use_default) { 68760484Sobrien strlcpy(buf, "\\# ", sizeof(buf)); 68860484Sobrien result = str_totext(buf, target); 68960484Sobrien dns_rdata_toregion(rdata, &sr); 69060484Sobrien INSIST(sr.length < 65536); 69160484Sobrien snprintf(buf, sizeof(buf), "%u", sr.length); 69260484Sobrien result = str_totext(buf, target); 69360484Sobrien if (sr.length != 0 && result == ISC_R_SUCCESS) { 694104834Sobrien if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 69560484Sobrien result = str_totext(" ( ", target); 69660484Sobrien else 69760484Sobrien result = str_totext(" ", target); 69860484Sobrien if (result == ISC_R_SUCCESS) 69960484Sobrien result = isc_hex_totext(&sr, tctx->width - 2, 70060484Sobrien tctx->linebreak, 70160484Sobrien target); 70260484Sobrien if (result == ISC_R_SUCCESS && 703104834Sobrien (tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) 70460484Sobrien result = str_totext(" )", target); 70560484Sobrien } 70660484Sobrien } 70760484Sobrien 70860484Sobrien return (result); 70960484Sobrien} 71060484Sobrien 71160484Sobrienisc_result_t 712104834Sobriendns_rdata_totext(dns_rdata_t *rdata, dns_name_t *origin, isc_buffer_t *target) 71360484Sobrien{ 71460484Sobrien dns_rdata_textctx_t tctx; 71560484Sobrien 71660484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 71760484Sobrien 71860484Sobrien /* 71960484Sobrien * Set up formatting options for single-line output. 72060484Sobrien */ 72160484Sobrien tctx.origin = origin; 72260484Sobrien tctx.flags = 0; 72360484Sobrien tctx.width = 60; 72460484Sobrien tctx.linebreak = " "; 72560484Sobrien return (rdata_totext(rdata, &tctx, target)); 72660484Sobrien} 72760484Sobrien 72860484Sobrienisc_result_t 72960484Sobriendns_rdata_tofmttext(dns_rdata_t *rdata, dns_name_t *origin, 73060484Sobrien unsigned int flags, unsigned int width, 73160484Sobrien char *linebreak, isc_buffer_t *target) 73260484Sobrien{ 73360484Sobrien dns_rdata_textctx_t tctx; 73460484Sobrien 73560484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 73660484Sobrien 73760484Sobrien /* 73860484Sobrien * Set up formatting options for formatted output. 73960484Sobrien */ 74060484Sobrien tctx.origin = origin; 74160484Sobrien tctx.flags = flags; 74260484Sobrien if ((flags & DNS_STYLEFLAG_MULTILINE) != 0) { 74360484Sobrien tctx.width = width; 74460484Sobrien tctx.linebreak = linebreak; 74560484Sobrien } else { 74660484Sobrien tctx.width = 60; /* Used for hex word length only. */ 74760484Sobrien tctx.linebreak = " "; 74860484Sobrien } 74960484Sobrien return (rdata_totext(rdata, &tctx, target)); 75060484Sobrien} 75160484Sobrien 75260484Sobrienisc_result_t 75360484Sobriendns_rdata_fromstruct(dns_rdata_t *rdata, dns_rdataclass_t rdclass, 75460484Sobrien dns_rdatatype_t type, void *source, 755218822Sdim isc_buffer_t *target) 75660484Sobrien{ 75760484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 75860484Sobrien isc_buffer_t st; 75960484Sobrien isc_region_t region; 76060484Sobrien isc_boolean_t use_default = ISC_FALSE; 76160484Sobrien 76260484Sobrien REQUIRE(source != NULL); 76360484Sobrien if (rdata != NULL) { 76460484Sobrien REQUIRE(DNS_RDATA_INITIALIZED(rdata)); 76560484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 76660484Sobrien } 76760484Sobrien 76860484Sobrien st = *target; 76960484Sobrien 77060484Sobrien FROMSTRUCTSWITCH 77160484Sobrien 77260484Sobrien if (use_default) 77360484Sobrien (void)NULL; 77460484Sobrien 77560484Sobrien if (rdata != NULL && result == ISC_R_SUCCESS) { 77660484Sobrien region.base = isc_buffer_used(&st); 77760484Sobrien region.length = isc_buffer_usedlength(target) - 77860484Sobrien isc_buffer_usedlength(&st); 77960484Sobrien dns_rdata_fromregion(rdata, rdclass, type, ®ion); 78060484Sobrien } 78160484Sobrien if (result != ISC_R_SUCCESS) 78260484Sobrien *target = st; 78360484Sobrien return (result); 78460484Sobrien} 78560484Sobrien 78660484Sobrienisc_result_t 78760484Sobriendns_rdata_tostruct(dns_rdata_t *rdata, void *target, isc_mem_t *mctx) { 78860484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 78960484Sobrien isc_boolean_t use_default = ISC_FALSE; 79060484Sobrien 791218822Sdim REQUIRE(rdata != NULL); 79260484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 79360484Sobrien 79460484Sobrien TOSTRUCTSWITCH 79560484Sobrien 79660484Sobrien if (use_default) 79760484Sobrien (void)NULL; 79860484Sobrien 79960484Sobrien return (result); 80060484Sobrien} 80160484Sobrien 80260484Sobrienvoid 80360484Sobriendns_rdata_freestruct(void *source) { 80460484Sobrien dns_rdatacommon_t *common = source; 80560484Sobrien REQUIRE(source != NULL); 80660484Sobrien 80760484Sobrien FREESTRUCTSWITCH 80860484Sobrien} 80960484Sobrien 81060484Sobrienisc_result_t 81160484Sobriendns_rdata_additionaldata(dns_rdata_t *rdata, dns_additionaldatafunc_t add, 812218822Sdim void *arg) 81360484Sobrien{ 81460484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 81560484Sobrien isc_boolean_t use_default = ISC_FALSE; 81660484Sobrien 81760484Sobrien /* 81860484Sobrien * Call 'add' for each name and type from 'rdata' which is subject to 81960484Sobrien * additional section processing. 82060484Sobrien */ 82160484Sobrien 82260484Sobrien REQUIRE(rdata != NULL); 82360484Sobrien REQUIRE(add != NULL); 82460484Sobrien REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 82560484Sobrien 82660484Sobrien ADDITIONALDATASWITCH 82760484Sobrien 82860484Sobrien /* No additional processing for unknown types */ 82960484Sobrien if (use_default) 83060484Sobrien result = ISC_R_SUCCESS; 83160484Sobrien 83260484Sobrien return (result); 83360484Sobrien} 83460484Sobrien 83560484Sobrienisc_result_t 83660484Sobriendns_rdata_digest(dns_rdata_t *rdata, dns_digestfunc_t digest, void *arg) { 83760484Sobrien isc_result_t result = ISC_R_NOTIMPLEMENTED; 83860484Sobrien isc_boolean_t use_default = ISC_FALSE; 83960484Sobrien isc_region_t r; 84060484Sobrien 84160484Sobrien /* 84260484Sobrien * Send 'rdata' in DNSSEC canonical form to 'digest'. 84360484Sobrien */ 84460484Sobrien 84560484Sobrien REQUIRE(rdata != NULL); 84660484Sobrien REQUIRE(digest != NULL); 847218822Sdim REQUIRE(DNS_RDATA_VALIDFLAGS(rdata)); 84860484Sobrien 84960484Sobrien DIGESTSWITCH 85060484Sobrien 85160484Sobrien if (use_default) { 852218822Sdim dns_rdata_toregion(rdata, &r); 85360484Sobrien result = (digest)(arg, &r); 85460484Sobrien } 85560484Sobrien 85660484Sobrien return (result); 85760484Sobrien} 85860484Sobrien 85960484Sobrienisc_boolean_t 86060484Sobriendns_rdata_checkowner(dns_name_t *name, dns_rdataclass_t rdclass, 861104834Sobrien dns_rdatatype_t type, isc_boolean_t wildcard) 86260484Sobrien{ 863104834Sobrien isc_boolean_t result; 86460484Sobrien 86560484Sobrien CHECKOWNERSWITCH 86660484Sobrien return (result); 86760484Sobrien} 86860484Sobrien 86960484Sobrienisc_boolean_t 87060484Sobriendns_rdata_checknames(dns_rdata_t *rdata, dns_name_t *owner, dns_name_t *bad) 87160484Sobrien{ 87260484Sobrien isc_boolean_t result; 873104834Sobrien 87460484Sobrien CHECKNAMESSWITCH 87560484Sobrien return (result); 87660484Sobrien} 87760484Sobrien 87860484Sobrienunsigned int 87960484Sobriendns_rdatatype_attributes(dns_rdatatype_t type) 88060484Sobrien{ 88160484Sobrien RDATATYPE_ATTRIBUTE_SW 88260484Sobrien if (type >= (dns_rdatatype_t)128 && type < (dns_rdatatype_t)255) 88360484Sobrien return (DNS_RDATATYPEATTR_UNKNOWN | DNS_RDATATYPEATTR_META); 88460484Sobrien return (DNS_RDATATYPEATTR_UNKNOWN); 88560484Sobrien} 88660484Sobrien 88760484Sobrienisc_result_t 88860484Sobriendns_rdatatype_fromtext(dns_rdatatype_t *typep, isc_textregion_t *source) { 88960484Sobrien unsigned int hash; 89060484Sobrien unsigned int n; 89160484Sobrien unsigned char a, b; 89260484Sobrien 89360484Sobrien n = source->length; 894104834Sobrien 89560484Sobrien if (n == 0) 89660484Sobrien return (DNS_R_UNKNOWN); 89760484Sobrien 89860484Sobrien a = tolower((unsigned char)source->base[0]); 89960484Sobrien b = tolower((unsigned char)source->base[n - 1]); 90060484Sobrien 90160484Sobrien hash = ((a + n) * b) % 256; 90260484Sobrien 90360484Sobrien /* 90460484Sobrien * This switch block is inlined via #define, and will use "return" 90560484Sobrien * to return a result to the caller if it is a valid (known) 90660484Sobrien * rdatatype name. 90760484Sobrien */ 90860484Sobrien RDATATYPE_FROMTEXT_SW(hash, source->base, n, typep); 90960484Sobrien 91060484Sobrien if (source->length > 4 && source->length < (4 + sizeof("65000")) && 91160484Sobrien strncasecmp("type", source->base, 4) == 0) { 91260484Sobrien char buf[sizeof("65000")]; 91360484Sobrien char *endp; 91460484Sobrien unsigned int val; 91560484Sobrien 91660484Sobrien strncpy(buf, source->base + 4, source->length - 4); 91760484Sobrien buf[source->length - 4] = '\0'; 91860484Sobrien val = strtoul(buf, &endp, 10); 91960484Sobrien if (*endp == '\0' && val <= 0xffff) { 92060484Sobrien *typep = (dns_rdatatype_t)val; 92160484Sobrien return (ISC_R_SUCCESS); 92260484Sobrien } 92360484Sobrien } 92460484Sobrien 92560484Sobrien return (DNS_R_UNKNOWN); 92660484Sobrien} 92760484Sobrien 92860484Sobrienisc_result_t 92960484Sobriendns_rdatatype_totext(dns_rdatatype_t type, isc_buffer_t *target) { 93060484Sobrien char buf[sizeof("TYPE65535")]; 93160484Sobrien 93260484Sobrien RDATATYPE_TOTEXT_SW 93360484Sobrien snprintf(buf, sizeof(buf), "TYPE%u", type); 93460484Sobrien return (str_totext(buf, target)); 93560484Sobrien} 93660484Sobrien 93760484Sobrienvoid 938218822Sdimdns_rdatatype_format(dns_rdatatype_t rdtype, 93960484Sobrien char *array, unsigned int size) 94060484Sobrien{ 94160484Sobrien isc_result_t result; 94260484Sobrien isc_buffer_t buf; 94360484Sobrien 94460484Sobrien isc_buffer_init(&buf, array, size); 94560484Sobrien result = dns_rdatatype_totext(rdtype, &buf); 94660484Sobrien /* 94760484Sobrien * Null terminate. 94860484Sobrien */ 94960484Sobrien if (result == ISC_R_SUCCESS) { 95060484Sobrien if (isc_buffer_availablelength(&buf) >= 1) 95160484Sobrien isc_buffer_putuint8(&buf, 0); 95260484Sobrien else 953104834Sobrien result = ISC_R_NOSPACE; 95460484Sobrien } 95560484Sobrien if (result != ISC_R_SUCCESS) { 95660484Sobrien snprintf(array, size, "<unknown>"); 95760484Sobrien array[size - 1] = '\0'; 95860484Sobrien } 95960484Sobrien} 96060484Sobrien 96160484Sobrien/* 962104834Sobrien * Private function. 963104834Sobrien */ 964104834Sobrien 96560484Sobrienstatic unsigned int 966104834Sobrienname_length(dns_name_t *name) { 96760484Sobrien return (name->length); 96860484Sobrien} 969104834Sobrien 970104834Sobrienstatic isc_result_t 971104834Sobrientxt_totext(isc_region_t *source, isc_buffer_t *target) { 972104834Sobrien unsigned int tl; 97360484Sobrien unsigned int n; 97460484Sobrien unsigned char *sp; 97560484Sobrien char *tp; 97660484Sobrien isc_region_t region; 97760484Sobrien 97860484Sobrien isc_buffer_availableregion(target, ®ion); 97960484Sobrien sp = source->base; 98060484Sobrien tp = (char *)region.base; 98160484Sobrien tl = region.length; 98260484Sobrien 98360484Sobrien n = *sp++; 98460484Sobrien 98560484Sobrien REQUIRE(n + 1 <= source->length); 98660484Sobrien 98760484Sobrien if (tl < 1) 988104834Sobrien return (ISC_R_NOSPACE); 989104834Sobrien *tp++ = '"'; 990104834Sobrien tl--; 99160484Sobrien while (n--) { 992104834Sobrien if (*sp < 0x20 || *sp >= 0x7f) { 99360484Sobrien if (tl < 4) 99460484Sobrien return (ISC_R_NOSPACE); 995104834Sobrien *tp++ = 0x5c; 996104834Sobrien *tp++ = 0x30 + ((*sp / 100) % 10); 997104834Sobrien *tp++ = 0x30 + ((*sp / 10) % 10); 998104834Sobrien *tp++ = 0x30 + (*sp % 10); 99960484Sobrien sp++; 100060484Sobrien tl -= 4; 100160484Sobrien continue; 100260484Sobrien } 100360484Sobrien /* double quote, semi-colon, backslash */ 100460484Sobrien if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c) { 100560484Sobrien if (tl < 2) 100660484Sobrien return (ISC_R_NOSPACE); 100760484Sobrien *tp++ = '\\'; 100860484Sobrien tl--; 100960484Sobrien } 101060484Sobrien if (tl < 1) 101160484Sobrien return (ISC_R_NOSPACE); 101260484Sobrien *tp++ = *sp++; 101360484Sobrien tl--; 101460484Sobrien } 101560484Sobrien if (tl < 1) 101660484Sobrien return (ISC_R_NOSPACE); 101760484Sobrien *tp++ = '"'; 101860484Sobrien tl--; 101960484Sobrien isc_buffer_add(target, tp - (char *)region.base); 102060484Sobrien isc_region_consume(source, *source->base + 1); 102160484Sobrien return (ISC_R_SUCCESS); 102260484Sobrien} 102360484Sobrien 102460484Sobrienstatic isc_result_t 102560484Sobrientxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { 102660484Sobrien isc_region_t tregion; 1027218822Sdim isc_boolean_t escape; 102860484Sobrien unsigned int n, nrem; 102960484Sobrien char *s; 103060484Sobrien unsigned char *t; 103160484Sobrien int d; 103260484Sobrien int c; 103360484Sobrien 103460484Sobrien isc_buffer_availableregion(target, &tregion); 103560484Sobrien s = source->base; 103660484Sobrien n = source->length; 103760484Sobrien t = tregion.base; 103860484Sobrien nrem = tregion.length; 103960484Sobrien escape = ISC_FALSE; 104060484Sobrien if (nrem < 1) 104160484Sobrien return (ISC_R_NOSPACE); 104260484Sobrien /* 104360484Sobrien * Length byte. 104460484Sobrien */ 104560484Sobrien nrem--; 104660484Sobrien t++; 104760484Sobrien /* 104860484Sobrien * Maximum text string length. 104960484Sobrien */ 105060484Sobrien if (nrem > 255) 105160484Sobrien nrem = 255; 105260484Sobrien while (n-- != 0) { 105360484Sobrien c = (*s++) & 0xff; 105460484Sobrien if (escape && (d = decvalue((char)c)) != -1) { 105560484Sobrien c = d; 105660484Sobrien if (n == 0) 105760484Sobrien return (DNS_R_SYNTAX); 105860484Sobrien n--; 105960484Sobrien if ((d = decvalue(*s++)) != -1) 106060484Sobrien c = c * 10 + d; 106160484Sobrien else 106277298Sobrien return (DNS_R_SYNTAX); 106360484Sobrien if (n == 0) 106460484Sobrien return (DNS_R_SYNTAX); 106560484Sobrien n--; 106660484Sobrien if ((d = decvalue(*s++)) != -1) 106760484Sobrien c = c * 10 + d; 106860484Sobrien else 106960484Sobrien return (DNS_R_SYNTAX); 107060484Sobrien if (c > 255) 107160484Sobrien return (DNS_R_SYNTAX); 107260484Sobrien } else if (!escape && c == '\\') { 1073218822Sdim escape = ISC_TRUE; 107460484Sobrien continue; 107560484Sobrien } 107660484Sobrien escape = ISC_FALSE; 107760484Sobrien if (nrem == 0) 1078218822Sdim return (ISC_R_NOSPACE); 107960484Sobrien *t++ = c; 108060484Sobrien nrem--; 108160484Sobrien } 108260484Sobrien if (escape) 108360484Sobrien return (DNS_R_SYNTAX); 108460484Sobrien *tregion.base = t - tregion.base - 1; 108560484Sobrien isc_buffer_add(target, *tregion.base + 1); 108660484Sobrien return (ISC_R_SUCCESS); 108760484Sobrien} 1088104834Sobrien 108960484Sobrienstatic isc_result_t 109060484Sobrientxt_fromwire(isc_buffer_t *source, isc_buffer_t *target) { 109160484Sobrien unsigned int n; 109260484Sobrien isc_region_t sregion; 109360484Sobrien isc_region_t tregion; 109460484Sobrien 109560484Sobrien isc_buffer_activeregion(source, &sregion); 109660484Sobrien if (sregion.length == 0) 109760484Sobrien return(ISC_R_UNEXPECTEDEND); 109860484Sobrien n = *sregion.base + 1; 109960484Sobrien if (n > sregion.length) 1100104834Sobrien return (ISC_R_UNEXPECTEDEND); 110160484Sobrien 1102104834Sobrien isc_buffer_availableregion(target, &tregion); 110360484Sobrien if (n > tregion.length) 110460484Sobrien return (ISC_R_NOSPACE); 110560484Sobrien 110660484Sobrien memcpy(tregion.base, sregion.base, n); 110760484Sobrien isc_buffer_forward(source, n); 110860484Sobrien isc_buffer_add(target, n); 110960484Sobrien return (ISC_R_SUCCESS); 111060484Sobrien} 111160484Sobrien 1112104834Sobrienstatic isc_boolean_t 111360484Sobrienname_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target) { 111460484Sobrien int l1, l2; 111560484Sobrien 111660484Sobrien if (origin == NULL) 111760484Sobrien goto return_false; 111860484Sobrien 111960484Sobrien if (dns_name_compare(origin, dns_rootname) == 0) 112060484Sobrien goto return_false; 112160484Sobrien 112260484Sobrien if (!dns_name_issubdomain(name, origin)) 112360484Sobrien goto return_false; 112460484Sobrien 112560484Sobrien l1 = dns_name_countlabels(name); 112660484Sobrien l2 = dns_name_countlabels(origin); 112760484Sobrien 112860484Sobrien if (l1 == l2) 112960484Sobrien goto return_false; 113060484Sobrien 113160484Sobrien dns_name_getlabelsequence(name, 0, l1 - l2, target); 113260484Sobrien return (ISC_TRUE); 1133104834Sobrien 113460484Sobrienreturn_false: 113560484Sobrien *target = *name; 113660484Sobrien return (ISC_FALSE); 113760484Sobrien} 113860484Sobrien 113960484Sobrienstatic isc_result_t 114060484Sobrienstr_totext(const char *source, isc_buffer_t *target) { 114160484Sobrien unsigned int l; 114260484Sobrien isc_region_t region; 114360484Sobrien 114460484Sobrien isc_buffer_availableregion(target, ®ion); 114560484Sobrien l = strlen(source); 114660484Sobrien 114760484Sobrien if (l > region.length) 114860484Sobrien return (ISC_R_NOSPACE); 114960484Sobrien 115060484Sobrien memcpy(region.base, source, l); 115160484Sobrien isc_buffer_add(target, l); 115260484Sobrien return (ISC_R_SUCCESS); 115360484Sobrien} 115460484Sobrien 115560484Sobrienstatic isc_result_t 115660484Sobrieninet_totext(int af, isc_region_t *src, isc_buffer_t *target) { 115760484Sobrien char tmpbuf[64]; 115860484Sobrien 115960484Sobrien /* Note - inet_ntop doesn't do size checking on its input. */ 116060484Sobrien if (inet_ntop(af, src->base, tmpbuf, sizeof(tmpbuf)) == NULL) 116160484Sobrien return (ISC_R_NOSPACE); 116260484Sobrien if (strlen(tmpbuf) > isc_buffer_availablelength(target)) 116360484Sobrien return (ISC_R_NOSPACE); 116460484Sobrien isc_buffer_putstr(target, tmpbuf); 116560484Sobrien return (ISC_R_SUCCESS); 116660484Sobrien} 116760484Sobrien 116860484Sobrienstatic isc_boolean_t 116960484Sobrienbuffer_empty(isc_buffer_t *source) { 117060484Sobrien return((source->current == source->active) ? ISC_TRUE : ISC_FALSE); 1171218822Sdim} 117260484Sobrien 117360484Sobrienstatic void 117460484Sobrienbuffer_fromregion(isc_buffer_t *buffer, isc_region_t *region) { 117560484Sobrien isc_buffer_init(buffer, region->base, region->length); 117660484Sobrien isc_buffer_add(buffer, region->length); 117760484Sobrien isc_buffer_setactive(buffer, region->length); 117860484Sobrien} 117960484Sobrien 118060484Sobrienstatic isc_result_t 118160484Sobrienuint32_tobuffer(isc_uint32_t value, isc_buffer_t *target) { 118260484Sobrien isc_region_t region; 118360484Sobrien 118460484Sobrien isc_buffer_availableregion(target, ®ion); 118560484Sobrien if (region.length < 4) 1186104834Sobrien return (ISC_R_NOSPACE); 118760484Sobrien isc_buffer_putuint32(target, value); 118860484Sobrien return (ISC_R_SUCCESS); 118960484Sobrien} 119060484Sobrien 119160484Sobrienstatic isc_result_t 119260484Sobrienuint16_tobuffer(isc_uint32_t value, isc_buffer_t *target) { 119360484Sobrien isc_region_t region; 119460484Sobrien 1195104834Sobrien if (value > 0xffff) 1196104834Sobrien return (ISC_R_RANGE); 1197104834Sobrien isc_buffer_availableregion(target, ®ion); 119860484Sobrien if (region.length < 2) 1199104834Sobrien return (ISC_R_NOSPACE); 120060484Sobrien isc_buffer_putuint16(target, (isc_uint16_t)value); 120160484Sobrien return (ISC_R_SUCCESS); 1202104834Sobrien} 1203104834Sobrien 1204104834Sobrienstatic isc_result_t 1205104834Sobrienuint8_tobuffer(isc_uint32_t value, isc_buffer_t *target) { 120660484Sobrien isc_region_t region; 120760484Sobrien 120860484Sobrien if (value > 0xff) 120960484Sobrien return (ISC_R_RANGE); 121060484Sobrien isc_buffer_availableregion(target, ®ion); 121160484Sobrien if (region.length < 1) 121260484Sobrien return (ISC_R_NOSPACE); 121360484Sobrien isc_buffer_putuint8(target, (isc_uint8_t)value); 121460484Sobrien return (ISC_R_SUCCESS); 121560484Sobrien} 121660484Sobrien 121760484Sobrienstatic isc_result_t 121860484Sobrienname_tobuffer(dns_name_t *name, isc_buffer_t *target) { 121960484Sobrien isc_region_t r; 122060484Sobrien dns_name_toregion(name, &r); 1221104834Sobrien return (isc_buffer_copyregion(target, &r)); 1222104834Sobrien} 1223104834Sobrien 122460484Sobrienstatic isc_uint32_t 1225104834Sobrienuint32_fromregion(isc_region_t *region) { 122660484Sobrien isc_uint32_t value; 122760484Sobrien 1228104834Sobrien REQUIRE(region->length >= 4); 1229104834Sobrien value = region->base[0] << 24; 1230104834Sobrien value |= region->base[1] << 16; 1231104834Sobrien value |= region->base[2] << 8; 123260484Sobrien value |= region->base[3]; 123360484Sobrien return(value); 123460484Sobrien} 123560484Sobrien 123660484Sobrienstatic isc_uint16_t 123760484Sobrienuint16_fromregion(isc_region_t *region) { 123860484Sobrien 123960484Sobrien REQUIRE(region->length >= 2); 124060484Sobrien 124160484Sobrien return ((region->base[0] << 8) | region->base[1]); 124260484Sobrien} 124360484Sobrien 124460484Sobrienstatic isc_uint8_t 124560484Sobrienuint8_fromregion(isc_region_t *region) { 124660484Sobrien 124760484Sobrien REQUIRE(region->length >= 1); 124860484Sobrien 124960484Sobrien return (region->base[0]); 125060484Sobrien} 125160484Sobrien 125260484Sobrienstatic isc_result_t 125360484Sobrienmem_tobuffer(isc_buffer_t *target, void *base, unsigned int length) { 125460484Sobrien isc_region_t tr; 125560484Sobrien 125660484Sobrien isc_buffer_availableregion(target, &tr); 125760484Sobrien if (length > tr.length) 125860484Sobrien return (ISC_R_NOSPACE); 125960484Sobrien memcpy(tr.base, base, length); 1260218822Sdim isc_buffer_add(target, length); 126160484Sobrien return (ISC_R_SUCCESS); 126260484Sobrien} 126360484Sobrien 126460484Sobrienstatic int 126560484Sobrienhexvalue(char value) { 126660484Sobrien char *s; 126760484Sobrien unsigned char c; 126860484Sobrien 126960484Sobrien c = (unsigned char)value; 127060484Sobrien 127160484Sobrien if (!isascii(c)) 127260484Sobrien return (-1); 127360484Sobrien if (isupper(c)) 127460484Sobrien c = tolower(c); 127560484Sobrien if ((s = strchr(hexdigits, c)) == NULL) 127660484Sobrien return (-1); 127760484Sobrien return (s - hexdigits); 127860484Sobrien} 127960484Sobrien 128060484Sobrienstatic int 128160484Sobriendecvalue(char value) { 128260484Sobrien char *s; 128360484Sobrien 128460484Sobrien /* 128560484Sobrien * isascii() is valid for full range of int values, no need to 128660484Sobrien * mask or cast. 128760484Sobrien */ 128860484Sobrien if (!isascii(value)) 128960484Sobrien return (-1); 1290218822Sdim if ((s = strchr(decdigits, value)) == NULL) 129160484Sobrien return (-1); 129260484Sobrien return (s - decdigits); 129360484Sobrien} 129460484Sobrien 129560484Sobrienstatic const char atob_digits[86] = 1296218822Sdim "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`" \ 129760484Sobrien "abcdefghijklmnopqrstu"; 129860484Sobrien/* 129960484Sobrien * Subroutines to convert between 8 bit binary bytes and printable ASCII. 130060484Sobrien * Computes the number of bytes, and three kinds of simple checksums. 130160484Sobrien * Incoming bytes are collected into 32-bit words, then printed in base 85: 130260484Sobrien * exp(85,5) > exp(2,32) 130360484Sobrien * The ASCII characters used are between '!' and 'u'; 130460484Sobrien * 'z' encodes 32-bit zero; 'x' is used to mark the end of encoded data. 1305104834Sobrien * 130660484Sobrien * Originally by Paul Rutter (philabs!per) and Joe Orost (petsd!joe) for 1307104834Sobrien * the atob/btoa programs, released with the compress program, in mod.sources. 130860484Sobrien * Modified by Mike Schwartz 8/19/86 for use in BIND. 130960484Sobrien * Modified to be re-entrant 3/2/99. 131060484Sobrien */ 131160484Sobrien 131260484Sobrien 131360484Sobrienstruct state { 131460484Sobrien isc_int32_t Ceor; 131560484Sobrien isc_int32_t Csum; 131660484Sobrien isc_int32_t Crot; 1317104834Sobrien isc_int32_t word; 131860484Sobrien isc_int32_t bcount; 131960484Sobrien}; 132060484Sobrien 132160484Sobrien#define Ceor state->Ceor 132260484Sobrien#define Csum state->Csum 132360484Sobrien#define Crot state->Crot 132460484Sobrien#define word state->word 132560484Sobrien#define bcount state->bcount 132660484Sobrien 132760484Sobrien#define times85(x) ((((((x<<2)+x)<<2)+x)<<2)+x) 132860484Sobrien 132960484Sobrienstatic isc_result_t byte_atob(int c, isc_buffer_t *target, 133060484Sobrien struct state *state); 133160484Sobrienstatic isc_result_t putbyte(int c, isc_buffer_t *, struct state *state); 133260484Sobrienstatic isc_result_t byte_btoa(int c, isc_buffer_t *, struct state *state); 133360484Sobrien 133460484Sobrien/* 133560484Sobrien * Decode ASCII-encoded byte c into binary representation and 133660484Sobrien * place into *bufp, advancing bufp. 133760484Sobrien */ 1338104834Sobrienstatic isc_result_t 133960484Sobrienbyte_atob(int c, isc_buffer_t *target, struct state *state) { 134060484Sobrien char *s; 134160484Sobrien if (c == 'z') { 134260484Sobrien if (bcount != 0) 134360484Sobrien return(DNS_R_SYNTAX); 134460484Sobrien else { 134560484Sobrien RETERR(putbyte(0, target, state)); 134660484Sobrien RETERR(putbyte(0, target, state)); 134760484Sobrien RETERR(putbyte(0, target, state)); 134860484Sobrien RETERR(putbyte(0, target, state)); 134960484Sobrien } 135060484Sobrien } else if ((s = strchr(atob_digits, c)) != NULL) { 135160484Sobrien if (bcount == 0) { 135260484Sobrien word = s - atob_digits; 135360484Sobrien ++bcount; 135460484Sobrien } else if (bcount < 4) { 135560484Sobrien word = times85(word); 135660484Sobrien word += s - atob_digits; 135760484Sobrien ++bcount; 135860484Sobrien } else { 135960484Sobrien word = times85(word); 136060484Sobrien word += s - atob_digits; 136160484Sobrien RETERR(putbyte((word >> 24) & 0xff, target, state)); 136260484Sobrien RETERR(putbyte((word >> 16) & 0xff, target, state)); 136360484Sobrien RETERR(putbyte((word >> 8) & 0xff, target, state)); 136460484Sobrien RETERR(putbyte(word & 0xff, target, state)); 136560484Sobrien word = 0; 136660484Sobrien bcount = 0; 136760484Sobrien } 136860484Sobrien } else 136960484Sobrien return(DNS_R_SYNTAX); 1370218822Sdim return(ISC_R_SUCCESS); 137160484Sobrien} 137260484Sobrien 137360484Sobrien/* 137460484Sobrien * Compute checksum info and place c into target. 137560484Sobrien */ 137660484Sobrienstatic isc_result_t 137760484Sobrienputbyte(int c, isc_buffer_t *target, struct state *state) { 137860484Sobrien isc_region_t tr; 137960484Sobrien 138060484Sobrien Ceor ^= c; 138160484Sobrien Csum += c; 138260484Sobrien Csum += 1; 1383104834Sobrien if ((Crot & 0x80000000)) { 138460484Sobrien Crot <<= 1; 138560484Sobrien Crot += 1; 1386104834Sobrien } else { 138760484Sobrien Crot <<= 1; 138860484Sobrien } 138960484Sobrien Crot += c; 139060484Sobrien isc_buffer_availableregion(target, &tr); 139160484Sobrien if (tr.length < 1) 139260484Sobrien return (ISC_R_NOSPACE); 139360484Sobrien tr.base[0] = c; 139460484Sobrien isc_buffer_add(target, 1); 139560484Sobrien return (ISC_R_SUCCESS); 139660484Sobrien} 139760484Sobrien 139860484Sobrien/* 139960484Sobrien * Read the ASCII-encoded data from inbuf, of length inbuflen, and convert 140060484Sobrien * it into T_UNSPEC (binary data) in outbuf, not to exceed outbuflen bytes; 140160484Sobrien * outbuflen must be divisible by 4. (Note: this is because outbuf is filled 1402104834Sobrien * in 4 bytes at a time. If the actual data doesn't end on an even 4-byte 140360484Sobrien * boundary, there will be no problem...it will be padded with 0 bytes, and 1404104834Sobrien * numbytes will indicate the correct number of bytes. The main point is 140560484Sobrien * that since the buffer is filled in 4 bytes at a time, even if there is 140660484Sobrien * not a full 4 bytes of data at the end, there has to be room to 0-pad the 140760484Sobrien * data, so the buffer must be of size divisible by 4). Place the number of 140860484Sobrien * output bytes in numbytes, and return a failure/success status. 140960484Sobrien */ 141060484Sobrien 141160484Sobrienstatic isc_result_t 141260484Sobrienatob_tobuffer(isc_lex_t *lexer, isc_buffer_t *target) { 141360484Sobrien long oeor, osum, orot; 141460484Sobrien struct state statebuf, *state= &statebuf; 141560484Sobrien isc_token_t token; 141660484Sobrien char c; 141760484Sobrien char *e; 1418104834Sobrien 141960484Sobrien Ceor = Csum = Crot = word = bcount = 0; 142060484Sobrien 1421104834Sobrien RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 142260484Sobrien ISC_FALSE)); 142360484Sobrien while (token.value.as_textregion.length != 0) { 142460484Sobrien if ((c = token.value.as_textregion.base[0]) == 'x') { 142560484Sobrien break; 142660484Sobrien } else 142760484Sobrien RETERR(byte_atob(c, target, state)); 142860484Sobrien isc_textregion_consume(&token.value.as_textregion, 1); 142960484Sobrien } 143060484Sobrien 143160484Sobrien /* 143260484Sobrien * Number of bytes. 1433104834Sobrien */ 143460484Sobrien RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 1435104834Sobrien ISC_FALSE)); 143660484Sobrien if ((token.value.as_ulong % 4) != 0U) 143760484Sobrien isc_buffer_subtract(target, 4 - (token.value.as_ulong % 4)); 143860484Sobrien 143960484Sobrien /* 144060484Sobrien * Checksum. 144160484Sobrien */ 144260484Sobrien RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 144360484Sobrien ISC_FALSE)); 144460484Sobrien oeor = strtol(DNS_AS_STR(token), &e, 16); 144560484Sobrien if (*e != 0) 144660484Sobrien return (DNS_R_SYNTAX); 144760484Sobrien 144860484Sobrien /* 144960484Sobrien * Checksum. 145060484Sobrien */ 145160484Sobrien RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 145260484Sobrien ISC_FALSE)); 145360484Sobrien osum = strtol(DNS_AS_STR(token), &e, 16); 145460484Sobrien if (*e != 0) 145560484Sobrien return (DNS_R_SYNTAX); 145660484Sobrien 1457218822Sdim /* 145860484Sobrien * Checksum. 145960484Sobrien */ 146060484Sobrien RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 146160484Sobrien ISC_FALSE)); 146260484Sobrien orot = strtol(DNS_AS_STR(token), &e, 16); 146360484Sobrien if (*e != 0) 146460484Sobrien return (DNS_R_SYNTAX); 146560484Sobrien 1466104834Sobrien if ((oeor != Ceor) || (osum != Csum) || (orot != Crot)) 146760484Sobrien return(DNS_R_BADCKSUM); 1468104834Sobrien return (ISC_R_SUCCESS); 146960484Sobrien} 147060484Sobrien 147160484Sobrien/* 147260484Sobrien * Encode binary byte c into ASCII representation and place into *bufp, 147360484Sobrien * advancing bufp. 147460484Sobrien */ 147560484Sobrienstatic isc_result_t 147660484Sobrienbyte_btoa(int c, isc_buffer_t *target, struct state *state) { 147760484Sobrien isc_region_t tr; 147860484Sobrien 147960484Sobrien isc_buffer_availableregion(target, &tr); 148060484Sobrien Ceor ^= c; 148160484Sobrien Csum += c; 148260484Sobrien Csum += 1; 148360484Sobrien if ((Crot & 0x80000000)) { 148460484Sobrien Crot <<= 1; 148560484Sobrien Crot += 1; 148660484Sobrien } else { 148760484Sobrien Crot <<= 1; 148860484Sobrien } 1489104834Sobrien Crot += c; 149060484Sobrien 149160484Sobrien word <<= 8; 149260484Sobrien word |= c; 149360484Sobrien if (bcount == 3) { 149460484Sobrien if (word == 0) { 149560484Sobrien if (tr.length < 1) 149660484Sobrien return (ISC_R_NOSPACE); 149760484Sobrien tr.base[0] = 'z'; 149860484Sobrien isc_buffer_add(target, 1); 149960484Sobrien } else { 150060484Sobrien register int tmp = 0; 150160484Sobrien register isc_int32_t tmpword = word; 150260484Sobrien 150360484Sobrien if (tmpword < 0) { 150460484Sobrien /* 150560484Sobrien * Because some don't support u_long. 150660484Sobrien */ 150760484Sobrien tmp = 32; 150860484Sobrien tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32); 150960484Sobrien } 151060484Sobrien if (tmpword < 0) { 151160484Sobrien tmp = 64; 151260484Sobrien tmpword -= (isc_int32_t)(85 * 85 * 85 * 85 * 32); 151360484Sobrien } 151460484Sobrien if (tr.length < 5) 151560484Sobrien return (ISC_R_NOSPACE); 151660484Sobrien tr.base[0] = atob_digits[(tmpword / 151760484Sobrien (isc_int32_t)(85 * 85 * 85 * 85)) 151860484Sobrien + tmp]; 1519218822Sdim tmpword %= (isc_int32_t)(85 * 85 * 85 * 85); 152060484Sobrien tr.base[1] = atob_digits[tmpword / (85 * 85 * 85)]; 152160484Sobrien tmpword %= (85 * 85 * 85); 152260484Sobrien tr.base[2] = atob_digits[tmpword / (85 * 85)]; 152360484Sobrien tmpword %= (85 * 85); 152460484Sobrien tr.base[3] = atob_digits[tmpword / 85]; 152560484Sobrien tmpword %= 85; 152660484Sobrien tr.base[4] = atob_digits[tmpword]; 152760484Sobrien isc_buffer_add(target, 5); 1528104834Sobrien } 152960484Sobrien bcount = 0; 1530104834Sobrien } else { 153160484Sobrien bcount += 1; 153260484Sobrien } 153360484Sobrien return (ISC_R_SUCCESS); 153460484Sobrien} 153560484Sobrien 153660484Sobrien 153760484Sobrien/* 153860484Sobrien * Encode the binary data from inbuf, of length inbuflen, into a 153960484Sobrien * target. Return success/failure status 154060484Sobrien */ 154160484Sobrienstatic isc_result_t 154260484Sobrienbtoa_totext(unsigned char *inbuf, int inbuflen, isc_buffer_t *target) { 154360484Sobrien int inc; 154460484Sobrien struct state statebuf, *state = &statebuf; 154560484Sobrien char buf[sizeof("x 2000000000 ffffffff ffffffff ffffffff")]; 154660484Sobrien 154760484Sobrien Ceor = Csum = Crot = word = bcount = 0; 154860484Sobrien for (inc = 0; inc < inbuflen; inbuf++, inc++) 154960484Sobrien RETERR(byte_btoa(*inbuf, target, state)); 155060484Sobrien 1551104834Sobrien while (bcount != 0) 155260484Sobrien RETERR(byte_btoa(0, target, state)); 155360484Sobrien 155460484Sobrien /* 155560484Sobrien * Put byte count and checksum information at end of buffer, 155660484Sobrien * delimited by 'x' 155760484Sobrien */ 155860484Sobrien snprintf(buf, sizeof(buf), "x %d %x %x %x", inbuflen, Ceor, Csum, Crot); 155960484Sobrien return (str_totext(buf, target)); 156060484Sobrien} 156160484Sobrien 1562104834Sobrien 156360484Sobrienstatic void 156460484Sobriendefault_fromtext_callback(dns_rdatacallbacks_t *callbacks, const char *fmt, 156560484Sobrien ...) 156660484Sobrien{ 156760484Sobrien va_list ap; 156860484Sobrien 156960484Sobrien UNUSED(callbacks); 157060484Sobrien 157160484Sobrien va_start(ap, fmt); 157260484Sobrien vfprintf(stderr, fmt, ap); 157360484Sobrien va_end(ap); 157460484Sobrien fprintf(stderr, "\n"); 157560484Sobrien} 157660484Sobrien 157760484Sobrienstatic void 157860484Sobrienfromtext_warneof(isc_lex_t *lexer, dns_rdatacallbacks_t *callbacks) { 157960484Sobrien if (isc_lex_isfile(lexer) && callbacks != NULL) { 158060484Sobrien const char *name = isc_lex_getsourcename(lexer); 158160484Sobrien if (name == NULL) 158260484Sobrien name = "UNKNOWN"; 158360484Sobrien (*callbacks->warn)(callbacks, 158460484Sobrien "%s:%lu: file does not end with newline", 1585218822Sdim name, isc_lex_getsourceline(lexer)); 158660484Sobrien } 158760484Sobrien} 158860484Sobrien 1589218822Sdimstatic void 159060484Sobrienwarn_badmx(isc_token_t *token, isc_lex_t *lexer, 159160484Sobrien dns_rdatacallbacks_t *callbacks) 159260484Sobrien{ 159360484Sobrien const char *file; 159460484Sobrien unsigned long line; 159560484Sobrien 159660484Sobrien if (lexer != NULL) { 159760484Sobrien file = isc_lex_getsourcename(lexer); 1598104834Sobrien line = isc_lex_getsourceline(lexer); 159960484Sobrien (*callbacks->warn)(callbacks, "%s:%u: warning: '%s': %s", 1600104834Sobrien file, line, DNS_AS_STR(*token), 160160484Sobrien dns_result_totext(DNS_R_MXISADDRESS)); 160260484Sobrien } 160360484Sobrien} 160460484Sobrien 160560484Sobrienstatic void 160660484Sobrienwarn_badname(dns_name_t *name, isc_lex_t *lexer, 160760484Sobrien dns_rdatacallbacks_t *callbacks) 160860484Sobrien{ 160960484Sobrien const char *file; 1610104834Sobrien unsigned long line; 161160484Sobrien char namebuf[DNS_NAME_FORMATSIZE]; 161260484Sobrien 161360484Sobrien if (lexer != NULL) { 161460484Sobrien file = isc_lex_getsourcename(lexer); 161560484Sobrien line = isc_lex_getsourceline(lexer); 161660484Sobrien dns_name_format(name, namebuf, sizeof(namebuf)); 161760484Sobrien (*callbacks->warn)(callbacks, "%s:%u: warning: %s: %s", 161860484Sobrien file, line, namebuf, 161960484Sobrien dns_result_totext(DNS_R_BADNAME)); 162060484Sobrien } 162160484Sobrien} 162260484Sobrien 162360484Sobrienstatic void 162460484Sobrienfromtext_error(void (*callback)(dns_rdatacallbacks_t *, const char *, ...), 162560484Sobrien dns_rdatacallbacks_t *callbacks, const char *name, 162660484Sobrien unsigned long line, isc_token_t *token, isc_result_t result) 162760484Sobrien{ 162860484Sobrien if (name == NULL) 162960484Sobrien name = "UNKNOWN"; 163060484Sobrien 1631104834Sobrien if (token != NULL) { 163260484Sobrien switch (token->type) { 163360484Sobrien case isc_tokentype_eol: 163460484Sobrien (*callback)(callbacks, "%s: %s:%lu: near eol: %s", 163560484Sobrien "dns_rdata_fromtext", name, line, 163660484Sobrien dns_result_totext(result)); 163760484Sobrien break; 163860484Sobrien case isc_tokentype_eof: 163960484Sobrien (*callback)(callbacks, "%s: %s:%lu: near eof: %s", 164060484Sobrien "dns_rdata_fromtext", name, line, 164160484Sobrien dns_result_totext(result)); 164260484Sobrien break; 164360484Sobrien case isc_tokentype_number: 164460484Sobrien (*callback)(callbacks, "%s: %s:%lu: near %lu: %s", 164560484Sobrien "dns_rdata_fromtext", name, line, 164660484Sobrien token->value.as_ulong, 164760484Sobrien dns_result_totext(result)); 164860484Sobrien break; 164960484Sobrien case isc_tokentype_string: 165060484Sobrien case isc_tokentype_qstring: 165160484Sobrien (*callback)(callbacks, "%s: %s:%lu: near '%s': %s", 165260484Sobrien "dns_rdata_fromtext", name, line, 165360484Sobrien DNS_AS_STR(*token), 165460484Sobrien dns_result_totext(result)); 165560484Sobrien break; 165660484Sobrien default: 165760484Sobrien (*callback)(callbacks, "%s: %s:%lu: %s", 165860484Sobrien "dns_rdata_fromtext", name, line, 165960484Sobrien dns_result_totext(result)); 166060484Sobrien break; 166160484Sobrien } 166260484Sobrien } else { 166360484Sobrien (*callback)(callbacks, "dns_rdata_fromtext: %s:%lu: %s", 166460484Sobrien name, line, dns_result_totext(result)); 166560484Sobrien } 1666218822Sdim} 166760484Sobrien 166860484Sobriendns_rdatatype_t 166960484Sobriendns_rdata_covers(dns_rdata_t *rdata) { 167060484Sobrien if (rdata->type == 46) 167160484Sobrien return (covers_rrsig(rdata)); 167260484Sobrien return (covers_sig(rdata)); 167360484Sobrien} 167460484Sobrien 167560484Sobrienisc_boolean_t 167660484Sobriendns_rdatatype_ismeta(dns_rdatatype_t type) { 167760484Sobrien if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_META) != 0) 167860484Sobrien return (ISC_TRUE); 167960484Sobrien return (ISC_FALSE); 168060484Sobrien} 168160484Sobrien 168260484Sobrienisc_boolean_t 168360484Sobriendns_rdatatype_issingleton(dns_rdatatype_t type) { 1684104834Sobrien if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_SINGLETON) 168560484Sobrien != 0) 168660484Sobrien return (ISC_TRUE); 168760484Sobrien return (ISC_FALSE); 168860484Sobrien} 168960484Sobrien 169060484Sobrienisc_boolean_t 169160484Sobriendns_rdatatype_notquestion(dns_rdatatype_t type) { 169260484Sobrien if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_NOTQUESTION) 169360484Sobrien != 0) 169460484Sobrien return (ISC_TRUE); 169560484Sobrien return (ISC_FALSE); 169660484Sobrien} 169760484Sobrien 169860484Sobrienisc_boolean_t 169960484Sobriendns_rdatatype_questiononly(dns_rdatatype_t type) { 1700104834Sobrien if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_QUESTIONONLY) 170160484Sobrien != 0) 170260484Sobrien return (ISC_TRUE); 170360484Sobrien return (ISC_FALSE); 170460484Sobrien} 170560484Sobrien 170660484Sobrienisc_boolean_t 170760484Sobriendns_rdatatype_atparent(dns_rdatatype_t type) { 170860484Sobrien if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_ATPARENT) != 0) 1709104834Sobrien return (ISC_TRUE); 171060484Sobrien return (ISC_FALSE); 171160484Sobrien} 171260484Sobrien 171360484Sobrienisc_boolean_t 171460484Sobriendns_rdataclass_ismeta(dns_rdataclass_t rdclass) { 171560484Sobrien 171660484Sobrien if (rdclass == dns_rdataclass_reserved0 171760484Sobrien || rdclass == dns_rdataclass_none 171860484Sobrien || rdclass == dns_rdataclass_any) 171960484Sobrien return (ISC_TRUE); 1720104834Sobrien 172160484Sobrien return (ISC_FALSE); /* Assume it is not a meta class. */ 172260484Sobrien} 172360484Sobrien 172460484Sobrienisc_boolean_t 172560484Sobriendns_rdatatype_isdnssec(dns_rdatatype_t type) { 172660484Sobrien if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_DNSSEC) != 0) 172760484Sobrien return (ISC_TRUE); 172860484Sobrien return (ISC_FALSE); 172960484Sobrien} 173060484Sobrien 173160484Sobrienisc_boolean_t 173260484Sobriendns_rdatatype_iszonecutauth(dns_rdatatype_t type) { 173360484Sobrien if ((dns_rdatatype_attributes(type) 173460484Sobrien & (DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH)) 173560484Sobrien != 0) 173660484Sobrien return (ISC_TRUE); 173760484Sobrien return (ISC_FALSE); 173860484Sobrien} 173960484Sobrien 1740218822Sdimisc_boolean_t 174160484Sobriendns_rdatatype_isknown(dns_rdatatype_t type) { 174260484Sobrien if ((dns_rdatatype_attributes(type) & DNS_RDATATYPEATTR_UNKNOWN) 174360484Sobrien == 0) 174460484Sobrien return (ISC_TRUE); 174560484Sobrien return (ISC_FALSE); 174660484Sobrien} 174760484Sobrien