1266077Sdes/* 2266077Sdes * wire2str.c 3266077Sdes * 4266077Sdes * conversion routines from the wire format 5266077Sdes * to the presentation format (strings) 6266077Sdes * 7266077Sdes * (c) NLnet Labs, 2004-2006 8266077Sdes * 9266077Sdes * See the file LICENSE for the license 10266077Sdes */ 11266077Sdes/** 12266077Sdes * \file 13266077Sdes * 14266077Sdes * Contains functions to translate the wireformat to text 15266077Sdes * representation, as well as functions to print them. 16266077Sdes */ 17266077Sdes#include "config.h" 18287915Sdes#include "sldns/wire2str.h" 19287915Sdes#include "sldns/str2wire.h" 20287915Sdes#include "sldns/rrdef.h" 21287915Sdes#include "sldns/pkthdr.h" 22287915Sdes#include "sldns/parseutil.h" 23287915Sdes#include "sldns/sbuffer.h" 24287915Sdes#include "sldns/keyraw.h" 25356345Scy#include "util/data/dname.h" 26266077Sdes#ifdef HAVE_TIME_H 27266077Sdes#include <time.h> 28266077Sdes#endif 29266077Sdes#include <sys/time.h> 30266077Sdes#include <stdarg.h> 31266077Sdes#include <ctype.h> 32266077Sdes#ifdef HAVE_NETDB_H 33266077Sdes#include <netdb.h> 34266077Sdes#endif 35266077Sdes 36266077Sdes/* lookup tables for standard DNS stuff */ 37266077Sdes/* Taken from RFC 2535, section 7. */ 38266077Sdesstatic sldns_lookup_table sldns_algorithms_data[] = { 39266077Sdes { LDNS_RSAMD5, "RSAMD5" }, 40266077Sdes { LDNS_DH, "DH" }, 41266077Sdes { LDNS_DSA, "DSA" }, 42266077Sdes { LDNS_ECC, "ECC" }, 43266077Sdes { LDNS_RSASHA1, "RSASHA1" }, 44266077Sdes { LDNS_DSA_NSEC3, "DSA-NSEC3-SHA1" }, 45266077Sdes { LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" }, 46266077Sdes { LDNS_RSASHA256, "RSASHA256"}, 47266077Sdes { LDNS_RSASHA512, "RSASHA512"}, 48266077Sdes { LDNS_ECC_GOST, "ECC-GOST"}, 49266077Sdes { LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"}, 50266077Sdes { LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"}, 51356345Scy { LDNS_ED25519, "ED25519"}, 52356345Scy { LDNS_ED448, "ED448"}, 53266077Sdes { LDNS_INDIRECT, "INDIRECT" }, 54266077Sdes { LDNS_PRIVATEDNS, "PRIVATEDNS" }, 55266077Sdes { LDNS_PRIVATEOID, "PRIVATEOID" }, 56266077Sdes { 0, NULL } 57266077Sdes}; 58266077Sdessldns_lookup_table* sldns_algorithms = sldns_algorithms_data; 59266077Sdes 60266077Sdes/* hash algorithms in DS record */ 61266077Sdesstatic sldns_lookup_table sldns_hashes_data[] = { 62266077Sdes { LDNS_SHA1, "SHA1" }, 63266077Sdes { LDNS_SHA256, "SHA256" }, 64266077Sdes { LDNS_HASH_GOST, "HASH-GOST" }, 65266077Sdes { LDNS_SHA384, "SHA384" }, 66266077Sdes { 0, NULL } 67266077Sdes}; 68266077Sdessldns_lookup_table* sldns_hashes = sldns_hashes_data; 69266077Sdes 70266077Sdes/* Taken from RFC 4398 */ 71266077Sdesstatic sldns_lookup_table sldns_cert_algorithms_data[] = { 72266077Sdes { LDNS_CERT_PKIX, "PKIX" }, 73266077Sdes { LDNS_CERT_SPKI, "SPKI" }, 74266077Sdes { LDNS_CERT_PGP, "PGP" }, 75266077Sdes { LDNS_CERT_IPKIX, "IPKIX" }, 76266077Sdes { LDNS_CERT_ISPKI, "ISPKI" }, 77266077Sdes { LDNS_CERT_IPGP, "IPGP" }, 78266077Sdes { LDNS_CERT_ACPKIX, "ACPKIX" }, 79266077Sdes { LDNS_CERT_IACPKIX, "IACPKIX" }, 80266077Sdes { LDNS_CERT_URI, "URI" }, 81266077Sdes { LDNS_CERT_OID, "OID" }, 82266077Sdes { 0, NULL } 83266077Sdes}; 84266077Sdessldns_lookup_table* sldns_cert_algorithms = sldns_cert_algorithms_data; 85266077Sdes 86266077Sdes/* if these are used elsewhere */ 87266077Sdesstatic sldns_lookup_table sldns_rcodes_data[] = { 88266077Sdes { LDNS_RCODE_NOERROR, "NOERROR" }, 89266077Sdes { LDNS_RCODE_FORMERR, "FORMERR" }, 90266077Sdes { LDNS_RCODE_SERVFAIL, "SERVFAIL" }, 91266077Sdes { LDNS_RCODE_NXDOMAIN, "NXDOMAIN" }, 92266077Sdes { LDNS_RCODE_NOTIMPL, "NOTIMPL" }, 93266077Sdes { LDNS_RCODE_REFUSED, "REFUSED" }, 94266077Sdes { LDNS_RCODE_YXDOMAIN, "YXDOMAIN" }, 95266077Sdes { LDNS_RCODE_YXRRSET, "YXRRSET" }, 96266077Sdes { LDNS_RCODE_NXRRSET, "NXRRSET" }, 97266077Sdes { LDNS_RCODE_NOTAUTH, "NOTAUTH" }, 98266077Sdes { LDNS_RCODE_NOTZONE, "NOTZONE" }, 99266077Sdes { 0, NULL } 100266077Sdes}; 101266077Sdessldns_lookup_table* sldns_rcodes = sldns_rcodes_data; 102266077Sdes 103266077Sdesstatic sldns_lookup_table sldns_opcodes_data[] = { 104266077Sdes { LDNS_PACKET_QUERY, "QUERY" }, 105266077Sdes { LDNS_PACKET_IQUERY, "IQUERY" }, 106266077Sdes { LDNS_PACKET_STATUS, "STATUS" }, 107266077Sdes { LDNS_PACKET_NOTIFY, "NOTIFY" }, 108266077Sdes { LDNS_PACKET_UPDATE, "UPDATE" }, 109266077Sdes { 0, NULL } 110266077Sdes}; 111266077Sdessldns_lookup_table* sldns_opcodes = sldns_opcodes_data; 112266077Sdes 113266077Sdesstatic sldns_lookup_table sldns_wireparse_errors_data[] = { 114266077Sdes { LDNS_WIREPARSE_ERR_OK, "no parse error" }, 115266077Sdes { LDNS_WIREPARSE_ERR_GENERAL, "parse error" }, 116266077Sdes { LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, "Domainname length overflow" }, 117266077Sdes { LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, "Domainname length underflow (zero length)" }, 118266077Sdes { LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, "buffer too small" }, 119266077Sdes { LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, "Label length overflow" }, 120266077Sdes { LDNS_WIREPARSE_ERR_EMPTY_LABEL, "Empty label" }, 121266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, "Syntax error, bad escape sequence" }, 122266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX, "Syntax error, could not parse the RR" }, 123266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_TTL, "Syntax error, could not parse the RR's TTL" }, 124266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_TYPE, "Syntax error, could not parse the RR's type" }, 125266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_CLASS, "Syntax error, could not parse the RR's class" }, 126266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_RDATA, "Syntax error, could not parse the RR's rdata" }, 127266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE, "Syntax error, value expected" }, 128266077Sdes { LDNS_WIREPARSE_ERR_INVALID_STR, "Conversion error, string expected" }, 129266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_B64, "Conversion error, b64 encoding expected" }, 130266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT, "Conversion error, b32 ext encoding expected" }, 131266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_HEX, "Conversion error, hex encoding expected" }, 132266077Sdes { LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM, "Bad algorithm type for CERT record" }, 133266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_TIME, "Conversion error, time encoding expected" }, 134266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, "Conversion error, time period encoding expected" }, 135266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_ILNP64, "Conversion error, 4 colon separated hex numbers expected" }, 136266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_EUI48, 137266077Sdes "Conversion error, 6 two character hex numbers " 138266077Sdes "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx" }, 139266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_EUI64, 140266077Sdes "Conversion error, 8 two character hex numbers " 141266077Sdes "separated by dashes expected (i.e. xx-xx-xx-xx-xx-xx-xx-xx" }, 142266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_TAG, 143266077Sdes "Conversion error, a non-zero sequence of US-ASCII letters " 144266077Sdes "and numbers in lower case expected" }, 145266077Sdes { LDNS_WIREPARSE_ERR_NOT_IMPL, "not implemented" }, 146266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_INT, "Conversion error, integer expected" }, 147266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_IP4, "Conversion error, ip4 addr expected" }, 148266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_IP6, "Conversion error, ip6 addr expected" }, 149266077Sdes { LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW, "Syntax error, integer overflow" }, 150266077Sdes { LDNS_WIREPARSE_ERR_INCLUDE, "$INCLUDE directive was seen in the zone" }, 151266077Sdes { LDNS_WIREPARSE_ERR_PARENTHESIS, "Parse error, parenthesis mismatch" }, 152266077Sdes { 0, NULL } 153266077Sdes}; 154266077Sdessldns_lookup_table* sldns_wireparse_errors = sldns_wireparse_errors_data; 155266077Sdes 156266077Sdesstatic sldns_lookup_table sldns_edns_flags_data[] = { 157266077Sdes { 3600, "do"}, 158266077Sdes { 0, NULL} 159266077Sdes}; 160266077Sdessldns_lookup_table* sldns_edns_flags = sldns_edns_flags_data; 161266077Sdes 162266077Sdesstatic sldns_lookup_table sldns_edns_options_data[] = { 163266077Sdes { 1, "LLQ" }, 164266077Sdes { 2, "UL" }, 165266077Sdes { 3, "NSID" }, 166266077Sdes /* 4 draft-cheshire-edns0-owner-option */ 167266077Sdes { 5, "DAU" }, 168266077Sdes { 6, "DHU" }, 169266077Sdes { 7, "N3U" }, 170266077Sdes { 8, "edns-client-subnet" }, 171356345Scy { 11, "edns-tcp-keepalive"}, 172307729Sdes { 12, "Padding" }, 173266077Sdes { 0, NULL} 174266077Sdes}; 175266077Sdessldns_lookup_table* sldns_edns_options = sldns_edns_options_data; 176266077Sdes 177356345Scystatic sldns_lookup_table sldns_tsig_errors_data[] = { 178356345Scy { LDNS_TSIG_ERROR_NOERROR, "NOERROR" }, 179356345Scy { LDNS_RCODE_FORMERR, "FORMERR" }, 180356345Scy { LDNS_RCODE_SERVFAIL, "SERVFAIL" }, 181356345Scy { LDNS_RCODE_NXDOMAIN, "NXDOMAIN" }, 182356345Scy { LDNS_RCODE_NOTIMPL, "NOTIMPL" }, 183356345Scy { LDNS_RCODE_REFUSED, "REFUSED" }, 184356345Scy { LDNS_RCODE_YXDOMAIN, "YXDOMAIN" }, 185356345Scy { LDNS_RCODE_YXRRSET, "YXRRSET" }, 186356345Scy { LDNS_RCODE_NXRRSET, "NXRRSET" }, 187356345Scy { LDNS_RCODE_NOTAUTH, "NOTAUTH" }, 188356345Scy { LDNS_RCODE_NOTZONE, "NOTZONE" }, 189356345Scy { LDNS_TSIG_ERROR_BADSIG, "BADSIG" }, 190356345Scy { LDNS_TSIG_ERROR_BADKEY, "BADKEY" }, 191356345Scy { LDNS_TSIG_ERROR_BADTIME, "BADTIME" }, 192356345Scy { LDNS_TSIG_ERROR_BADMODE, "BADMODE" }, 193356345Scy { LDNS_TSIG_ERROR_BADNAME, "BADNAME" }, 194356345Scy { LDNS_TSIG_ERROR_BADALG, "BADALG" }, 195356345Scy { 0, NULL } 196356345Scy}; 197356345Scysldns_lookup_table* sldns_tsig_errors = sldns_tsig_errors_data; 198356345Scy 199266077Sdeschar* sldns_wire2str_pkt(uint8_t* data, size_t len) 200266077Sdes{ 201266077Sdes size_t slen = (size_t)sldns_wire2str_pkt_buf(data, len, NULL, 0); 202266077Sdes char* result = (char*)malloc(slen+1); 203266077Sdes if(!result) return NULL; 204266077Sdes sldns_wire2str_pkt_buf(data, len, result, slen+1); 205266077Sdes return result; 206266077Sdes} 207266077Sdes 208266077Sdeschar* sldns_wire2str_rr(uint8_t* rr, size_t len) 209266077Sdes{ 210266077Sdes size_t slen = (size_t)sldns_wire2str_rr_buf(rr, len, NULL, 0); 211266077Sdes char* result = (char*)malloc(slen+1); 212266077Sdes if(!result) return NULL; 213266077Sdes sldns_wire2str_rr_buf(rr, len, result, slen+1); 214266077Sdes return result; 215266077Sdes} 216266077Sdes 217266077Sdeschar* sldns_wire2str_type(uint16_t rrtype) 218266077Sdes{ 219266077Sdes char buf[16]; 220266077Sdes sldns_wire2str_type_buf(rrtype, buf, sizeof(buf)); 221266077Sdes return strdup(buf); 222266077Sdes} 223266077Sdes 224266077Sdeschar* sldns_wire2str_class(uint16_t rrclass) 225266077Sdes{ 226266077Sdes char buf[16]; 227266077Sdes sldns_wire2str_class_buf(rrclass, buf, sizeof(buf)); 228266077Sdes return strdup(buf); 229266077Sdes} 230266077Sdes 231266077Sdeschar* sldns_wire2str_dname(uint8_t* dname, size_t dname_len) 232266077Sdes{ 233266077Sdes size_t slen=(size_t)sldns_wire2str_dname_buf(dname, dname_len, NULL, 0); 234266077Sdes char* result = (char*)malloc(slen+1); 235266077Sdes if(!result) return NULL; 236266077Sdes sldns_wire2str_dname_buf(dname, dname_len, result, slen+1); 237266077Sdes return result; 238266077Sdes} 239266077Sdes 240266077Sdeschar* sldns_wire2str_rcode(int rcode) 241266077Sdes{ 242266077Sdes char buf[16]; 243266077Sdes sldns_wire2str_rcode_buf(rcode, buf, sizeof(buf)); 244266077Sdes return strdup(buf); 245266077Sdes} 246266077Sdes 247266077Sdesint sldns_wire2str_pkt_buf(uint8_t* d, size_t dlen, char* s, size_t slen) 248266077Sdes{ 249266077Sdes /* use arguments as temporary variables */ 250266077Sdes return sldns_wire2str_pkt_scan(&d, &dlen, &s, &slen); 251266077Sdes} 252266077Sdes 253266077Sdesint sldns_wire2str_rr_buf(uint8_t* d, size_t dlen, char* s, size_t slen) 254266077Sdes{ 255266077Sdes /* use arguments as temporary variables */ 256356345Scy return sldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0, NULL); 257266077Sdes} 258266077Sdes 259356345Scyint sldns_wire2str_rrquestion_buf(uint8_t* d, size_t dlen, char* s, size_t slen) 260356345Scy{ 261356345Scy /* use arguments as temporary variables */ 262356345Scy return sldns_wire2str_rrquestion_scan(&d, &dlen, &s, &slen, NULL, 0, NULL); 263356345Scy} 264356345Scy 265266077Sdesint sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str, 266266077Sdes size_t str_len, uint16_t rrtype) 267266077Sdes{ 268266077Sdes /* use arguments as temporary variables */ 269266077Sdes return sldns_wire2str_rdata_scan(&rdata, &rdata_len, &str, &str_len, 270356345Scy rrtype, NULL, 0, NULL); 271266077Sdes} 272266077Sdes 273266077Sdesint sldns_wire2str_rr_unknown_buf(uint8_t* d, size_t dlen, char* s, size_t slen) 274266077Sdes{ 275266077Sdes /* use arguments as temporary variables */ 276356345Scy return sldns_wire2str_rr_unknown_scan(&d, &dlen, &s, &slen, NULL, 0, NULL); 277266077Sdes} 278266077Sdes 279266077Sdesint sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rrlen, size_t dname_len, 280266077Sdes char* s, size_t slen) 281266077Sdes{ 282266077Sdes uint16_t rrtype = sldns_wirerr_get_type(rr, rrlen, dname_len); 283266077Sdes return sldns_wire2str_rr_comment_print(&s, &slen, rr, rrlen, dname_len, 284266077Sdes rrtype); 285266077Sdes} 286266077Sdes 287266077Sdesint sldns_wire2str_type_buf(uint16_t rrtype, char* s, size_t slen) 288266077Sdes{ 289266077Sdes /* use arguments as temporary variables */ 290266077Sdes return sldns_wire2str_type_print(&s, &slen, rrtype); 291266077Sdes} 292266077Sdes 293266077Sdesint sldns_wire2str_class_buf(uint16_t rrclass, char* s, size_t slen) 294266077Sdes{ 295266077Sdes /* use arguments as temporary variables */ 296266077Sdes return sldns_wire2str_class_print(&s, &slen, rrclass); 297266077Sdes} 298266077Sdes 299266077Sdesint sldns_wire2str_rcode_buf(int rcode, char* s, size_t slen) 300266077Sdes{ 301266077Sdes /* use arguments as temporary variables */ 302266077Sdes return sldns_wire2str_rcode_print(&s, &slen, rcode); 303266077Sdes} 304266077Sdes 305356345Scyint sldns_wire2str_opcode_buf(int opcode, char* s, size_t slen) 306356345Scy{ 307356345Scy /* use arguments as temporary variables */ 308356345Scy return sldns_wire2str_opcode_print(&s, &slen, opcode); 309356345Scy} 310356345Scy 311266077Sdesint sldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen) 312266077Sdes{ 313266077Sdes /* use arguments as temporary variables */ 314356345Scy return sldns_wire2str_dname_scan(&d, &dlen, &s, &slen, NULL, 0, NULL); 315266077Sdes} 316266077Sdes 317266077Sdesint sldns_str_vprint(char** str, size_t* slen, const char* format, va_list args) 318266077Sdes{ 319266077Sdes int w = vsnprintf(*str, *slen, format, args); 320266077Sdes if(w < 0) { 321266077Sdes /* error in printout */ 322266077Sdes return 0; 323266077Sdes } else if((size_t)w >= *slen) { 324266077Sdes *str = NULL; /* we do not want str to point outside of buffer*/ 325266077Sdes *slen = 0; 326266077Sdes } else { 327266077Sdes *str += w; 328266077Sdes *slen -= w; 329266077Sdes } 330266077Sdes return w; 331266077Sdes} 332266077Sdes 333266077Sdesint sldns_str_print(char** str, size_t* slen, const char* format, ...) 334266077Sdes{ 335266077Sdes int w; 336266077Sdes va_list args; 337266077Sdes va_start(args, format); 338266077Sdes w = sldns_str_vprint(str, slen, format, args); 339266077Sdes va_end(args); 340266077Sdes return w; 341266077Sdes} 342266077Sdes 343266077Sdes/** print hex format into text buffer for specified length */ 344266077Sdesstatic int print_hex_buf(char** s, size_t* slen, uint8_t* buf, size_t len) 345266077Sdes{ 346266077Sdes const char* hex = "0123456789ABCDEF"; 347266077Sdes size_t i; 348266077Sdes for(i=0; i<len; i++) { 349266077Sdes (void)sldns_str_print(s, slen, "%c%c", hex[(buf[i]&0xf0)>>4], 350266077Sdes hex[buf[i]&0x0f]); 351266077Sdes } 352266077Sdes return (int)len*2; 353266077Sdes} 354266077Sdes 355266077Sdes/** print remainder of buffer in hex format with prefixed text */ 356266077Sdesstatic int print_remainder_hex(const char* pref, uint8_t** d, size_t* dlen, 357266077Sdes char** s, size_t* slen) 358266077Sdes{ 359266077Sdes int w = 0; 360266077Sdes w += sldns_str_print(s, slen, "%s", pref); 361266077Sdes w += print_hex_buf(s, slen, *d, *dlen); 362266077Sdes *d += *dlen; 363266077Sdes *dlen = 0; 364266077Sdes return w; 365266077Sdes} 366266077Sdes 367266077Sdesint sldns_wire2str_pkt_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen) 368266077Sdes{ 369356345Scy int w = 0, comprloop = 0; 370266077Sdes unsigned qdcount, ancount, nscount, arcount, i; 371266077Sdes uint8_t* pkt = *d; 372266077Sdes size_t pktlen = *dlen; 373266077Sdes if(*dlen >= LDNS_HEADER_SIZE) { 374266077Sdes qdcount = (unsigned)LDNS_QDCOUNT(*d); 375266077Sdes ancount = (unsigned)LDNS_ANCOUNT(*d); 376266077Sdes nscount = (unsigned)LDNS_NSCOUNT(*d); 377266077Sdes arcount = (unsigned)LDNS_ARCOUNT(*d); 378266077Sdes } else { 379266077Sdes qdcount = ancount = nscount = arcount = 0; 380266077Sdes } 381266077Sdes w += sldns_wire2str_header_scan(d, dlen, s, slen); 382266077Sdes w += sldns_str_print(s, slen, "\n"); 383266077Sdes w += sldns_str_print(s, slen, ";; QUESTION SECTION:\n"); 384266077Sdes for(i=0; i<qdcount; i++) { 385266077Sdes w += sldns_wire2str_rrquestion_scan(d, dlen, s, slen, 386356345Scy pkt, pktlen, &comprloop); 387266077Sdes if(!*dlen) break; 388266077Sdes } 389266077Sdes w += sldns_str_print(s, slen, "\n"); 390266077Sdes w += sldns_str_print(s, slen, ";; ANSWER SECTION:\n"); 391266077Sdes for(i=0; i<ancount; i++) { 392356345Scy w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen, &comprloop); 393266077Sdes if(!*dlen) break; 394266077Sdes } 395266077Sdes w += sldns_str_print(s, slen, "\n"); 396266077Sdes w += sldns_str_print(s, slen, ";; AUTHORITY SECTION:\n"); 397266077Sdes for(i=0; i<nscount; i++) { 398356345Scy w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen, &comprloop); 399266077Sdes if(!*dlen) break; 400266077Sdes } 401266077Sdes w += sldns_str_print(s, slen, "\n"); 402266077Sdes w += sldns_str_print(s, slen, ";; ADDITIONAL SECTION:\n"); 403266077Sdes for(i=0; i<arcount; i++) { 404356345Scy w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen, &comprloop); 405266077Sdes if(!*dlen) break; 406266077Sdes } 407266077Sdes /* other fields: WHEN(time), SERVER(IP) not available here. */ 408266077Sdes w += sldns_str_print(s, slen, ";; MSG SIZE rcvd: %d\n", (int)pktlen); 409266077Sdes if(*dlen > 0) { 410266077Sdes w += print_remainder_hex(";; trailing garbage 0x", 411266077Sdes d, dlen, s, slen); 412266077Sdes w += sldns_str_print(s, slen, "\n"); 413266077Sdes } 414266077Sdes return w; 415266077Sdes} 416266077Sdes 417266077Sdes/** scan type, class and ttl and printout, for rr */ 418266077Sdesstatic int sldns_rr_tcttl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 419266077Sdes{ 420266077Sdes int w = 0; 421266077Sdes uint16_t t, c; 422266077Sdes uint32_t ttl; 423266077Sdes if(*dl < 8) { 424266077Sdes if(*dl < 4) 425266077Sdes return w + print_remainder_hex("; Error malformed 0x", 426266077Sdes d, dl, s, sl); 427266077Sdes /* these print values or 0x.. if none left */ 428266077Sdes t = sldns_read_uint16(*d); 429266077Sdes c = sldns_read_uint16((*d)+2); 430266077Sdes (*d)+=4; 431266077Sdes (*dl)-=4; 432266077Sdes w += sldns_wire2str_class_print(s, sl, c); 433266077Sdes w += sldns_str_print(s, sl, "\t"); 434266077Sdes w += sldns_wire2str_type_print(s, sl, t); 435266077Sdes if(*dl == 0) 436266077Sdes return w + sldns_str_print(s, sl, "; Error no ttl"); 437266077Sdes return w + print_remainder_hex( 438266077Sdes "; Error malformed ttl 0x", d, dl, s, sl); 439266077Sdes } 440266077Sdes t = sldns_read_uint16(*d); 441266077Sdes c = sldns_read_uint16((*d)+2); 442266077Sdes ttl = sldns_read_uint32((*d)+4); 443266077Sdes (*d)+=8; 444266077Sdes (*dl)-=8; 445266077Sdes w += sldns_str_print(s, sl, "%lu\t", (unsigned long)ttl); 446266077Sdes w += sldns_wire2str_class_print(s, sl, c); 447266077Sdes w += sldns_str_print(s, sl, "\t"); 448266077Sdes w += sldns_wire2str_type_print(s, sl, t); 449266077Sdes return w; 450266077Sdes} 451266077Sdes 452266077Sdesint sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen, 453356345Scy uint8_t* pkt, size_t pktlen, int* comprloop) 454266077Sdes{ 455266077Sdes int w = 0; 456266077Sdes uint8_t* rr = *d; 457266077Sdes size_t rrlen = *dlen, dname_off, rdlen, ordlen; 458266077Sdes uint16_t rrtype = 0; 459266077Sdes 460266077Sdes if(*dlen >= 3 && (*d)[0]==0 && 461266077Sdes sldns_read_uint16((*d)+1)==LDNS_RR_TYPE_OPT) { 462266077Sdes /* perform EDNS OPT processing */ 463266077Sdes return sldns_wire2str_edns_scan(d, dlen, s, slen, pkt, pktlen); 464266077Sdes } 465266077Sdes 466266077Sdes /* try to scan the rdata with pretty-printing, but if that fails, then 467266077Sdes * scan the rdata as an unknown RR type */ 468356345Scy w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop); 469266077Sdes w += sldns_str_print(s, slen, "\t"); 470266077Sdes dname_off = rrlen-(*dlen); 471266077Sdes if(*dlen == 4) { 472266077Sdes /* like a question-RR */ 473266077Sdes uint16_t t = sldns_read_uint16(*d); 474266077Sdes uint16_t c = sldns_read_uint16((*d)+2); 475266077Sdes (*d)+=4; 476266077Sdes (*dlen)-=4; 477266077Sdes w += sldns_wire2str_class_print(s, slen, c); 478266077Sdes w += sldns_str_print(s, slen, "\t"); 479266077Sdes w += sldns_wire2str_type_print(s, slen, t); 480266077Sdes w += sldns_str_print(s, slen, " ; Error no ttl,rdata\n"); 481266077Sdes return w; 482266077Sdes } 483266077Sdes if(*dlen < 8) { 484266077Sdes if(*dlen == 0) 485266077Sdes return w + sldns_str_print(s, slen, ";Error missing RR\n"); 486266077Sdes w += print_remainder_hex(";Error partial RR 0x", d, dlen, s, slen); 487266077Sdes return w + sldns_str_print(s, slen, "\n"); 488266077Sdes } 489266077Sdes rrtype = sldns_read_uint16(*d); 490266077Sdes w += sldns_rr_tcttl_scan(d, dlen, s, slen); 491266077Sdes w += sldns_str_print(s, slen, "\t"); 492266077Sdes 493266077Sdes /* rdata */ 494266077Sdes if(*dlen < 2) { 495266077Sdes if(*dlen == 0) 496266077Sdes return w + sldns_str_print(s, slen, ";Error missing rdatalen\n"); 497266077Sdes w += print_remainder_hex(";Error missing rdatalen 0x", 498266077Sdes d, dlen, s, slen); 499266077Sdes return w + sldns_str_print(s, slen, "\n"); 500266077Sdes } 501266077Sdes rdlen = sldns_read_uint16(*d); 502266077Sdes ordlen = rdlen; 503266077Sdes (*d)+=2; 504266077Sdes (*dlen)-=2; 505266077Sdes if(*dlen < rdlen) { 506266077Sdes w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen); 507266077Sdes if(*dlen == 0) 508266077Sdes return w + sldns_str_print(s, slen, ";Error missing rdata\n"); 509266077Sdes w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen); 510266077Sdes return w + sldns_str_print(s, slen, "\n"); 511266077Sdes } 512356345Scy w += sldns_wire2str_rdata_scan(d, &rdlen, s, slen, rrtype, pkt, pktlen, 513356345Scy comprloop); 514266077Sdes (*dlen) -= (ordlen-rdlen); 515266077Sdes 516266077Sdes /* default comment */ 517266077Sdes w += sldns_wire2str_rr_comment_print(s, slen, rr, rrlen, dname_off, 518266077Sdes rrtype); 519266077Sdes w += sldns_str_print(s, slen, "\n"); 520266077Sdes return w; 521266077Sdes} 522266077Sdes 523266077Sdesint sldns_wire2str_rrquestion_scan(uint8_t** d, size_t* dlen, char** s, 524356345Scy size_t* slen, uint8_t* pkt, size_t pktlen, int* comprloop) 525266077Sdes{ 526266077Sdes int w = 0; 527266077Sdes uint16_t t, c; 528356345Scy w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop); 529266077Sdes w += sldns_str_print(s, slen, "\t"); 530266077Sdes if(*dlen < 4) { 531266077Sdes if(*dlen == 0) 532266077Sdes return w + sldns_str_print(s, slen, "Error malformed\n"); 533266077Sdes w += print_remainder_hex("Error malformed 0x", d, dlen, s, slen); 534266077Sdes return w + sldns_str_print(s, slen, "\n"); 535266077Sdes } 536266077Sdes t = sldns_read_uint16(*d); 537266077Sdes c = sldns_read_uint16((*d)+2); 538266077Sdes (*d)+=4; 539266077Sdes (*dlen)-=4; 540266077Sdes w += sldns_wire2str_class_print(s, slen, c); 541266077Sdes w += sldns_str_print(s, slen, "\t"); 542266077Sdes w += sldns_wire2str_type_print(s, slen, t); 543266077Sdes w += sldns_str_print(s, slen, "\n"); 544266077Sdes return w; 545266077Sdes} 546266077Sdes 547266077Sdesint sldns_wire2str_rr_unknown_scan(uint8_t** d, size_t* dlen, char** s, 548356345Scy size_t* slen, uint8_t* pkt, size_t pktlen, int* comprloop) 549266077Sdes{ 550266077Sdes size_t rdlen, ordlen; 551266077Sdes int w = 0; 552356345Scy w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop); 553266077Sdes w += sldns_str_print(s, slen, "\t"); 554266077Sdes w += sldns_rr_tcttl_scan(d, dlen, s, slen); 555266077Sdes w += sldns_str_print(s, slen, "\t"); 556266077Sdes if(*dlen < 2) { 557266077Sdes if(*dlen == 0) 558266077Sdes return w + sldns_str_print(s, slen, ";Error missing rdatalen\n"); 559266077Sdes w += print_remainder_hex(";Error missing rdatalen 0x", 560266077Sdes d, dlen, s, slen); 561266077Sdes return w + sldns_str_print(s, slen, "\n"); 562266077Sdes } 563266077Sdes rdlen = sldns_read_uint16(*d); 564266077Sdes ordlen = rdlen; 565266077Sdes (*d) += 2; 566266077Sdes (*dlen) -= 2; 567266077Sdes if(*dlen < rdlen) { 568266077Sdes w += sldns_str_print(s, slen, "\\# %u ", (unsigned)rdlen); 569266077Sdes if(*dlen == 0) 570266077Sdes return w + sldns_str_print(s, slen, ";Error missing rdata\n"); 571266077Sdes w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen); 572266077Sdes return w + sldns_str_print(s, slen, "\n"); 573266077Sdes } 574266077Sdes w += sldns_wire2str_rdata_unknown_scan(d, &rdlen, s, slen); 575266077Sdes (*dlen) -= (ordlen-rdlen); 576266077Sdes w += sldns_str_print(s, slen, "\n"); 577266077Sdes return w; 578266077Sdes} 579266077Sdes 580266077Sdes/** print rr comment for type DNSKEY */ 581266077Sdesstatic int rr_comment_dnskey(char** s, size_t* slen, uint8_t* rr, 582266077Sdes size_t rrlen, size_t dname_off) 583266077Sdes{ 584266077Sdes size_t rdlen; 585266077Sdes uint8_t* rdata; 586266077Sdes int flags, w = 0; 587266077Sdes if(rrlen < dname_off + 10) return 0; 588266077Sdes rdlen = sldns_read_uint16(rr+dname_off+8); 589266077Sdes if(rrlen < dname_off + 10 + rdlen) return 0; 590356345Scy if(rdlen < 2) return 0; 591266077Sdes rdata = rr + dname_off + 10; 592266077Sdes flags = (int)sldns_read_uint16(rdata); 593266077Sdes w += sldns_str_print(s, slen, " ;{"); 594266077Sdes 595266077Sdes /* id */ 596266077Sdes w += sldns_str_print(s, slen, "id = %u", 597266077Sdes sldns_calc_keytag_raw(rdata, rdlen)); 598266077Sdes 599266077Sdes /* flags */ 600266077Sdes if((flags&LDNS_KEY_ZONE_KEY)) { 601266077Sdes if((flags&LDNS_KEY_SEP_KEY)) 602266077Sdes w += sldns_str_print(s, slen, " (ksk)"); 603266077Sdes else w += sldns_str_print(s, slen, " (zsk)"); 604266077Sdes } 605266077Sdes 606266077Sdes /* keysize */ 607266077Sdes if(rdlen > 4) { 608266077Sdes w += sldns_str_print(s, slen, ", "); 609266077Sdes w += sldns_str_print(s, slen, "size = %db", 610266077Sdes (int)sldns_rr_dnskey_key_size_raw( 611266077Sdes (unsigned char*)rdata+4, rdlen-4, (int)(rdata[3]))); 612266077Sdes } 613266077Sdes 614266077Sdes w += sldns_str_print(s, slen, "}"); 615266077Sdes return w; 616266077Sdes} 617266077Sdes 618266077Sdes/** print rr comment for type RRSIG */ 619266077Sdesstatic int rr_comment_rrsig(char** s, size_t* slen, uint8_t* rr, 620266077Sdes size_t rrlen, size_t dname_off) 621266077Sdes{ 622266077Sdes size_t rdlen; 623266077Sdes uint8_t* rdata; 624266077Sdes if(rrlen < dname_off + 10) return 0; 625266077Sdes rdlen = sldns_read_uint16(rr+dname_off+8); 626266077Sdes if(rrlen < dname_off + 10 + rdlen) return 0; 627266077Sdes rdata = rr + dname_off + 10; 628266077Sdes if(rdlen < 18) return 0; 629266077Sdes return sldns_str_print(s, slen, " ;{id = %d}", 630266077Sdes (int)sldns_read_uint16(rdata+16)); 631266077Sdes} 632266077Sdes 633266077Sdes/** print rr comment for type NSEC3 */ 634266077Sdesstatic int rr_comment_nsec3(char** s, size_t* slen, uint8_t* rr, 635266077Sdes size_t rrlen, size_t dname_off) 636266077Sdes{ 637266077Sdes size_t rdlen; 638266077Sdes uint8_t* rdata; 639266077Sdes int w = 0; 640266077Sdes if(rrlen < dname_off + 10) return 0; 641266077Sdes rdlen = sldns_read_uint16(rr+dname_off+8); 642266077Sdes if(rrlen < dname_off + 10 + rdlen) return 0; 643266077Sdes rdata = rr + dname_off + 10; 644266077Sdes if(rdlen < 2) return 0; 645266077Sdes if((rdata[1] & LDNS_NSEC3_VARS_OPTOUT_MASK)) 646266077Sdes w += sldns_str_print(s, slen, " ;{flags: optout}"); 647266077Sdes return w; 648266077Sdes} 649266077Sdes 650266077Sdesint sldns_wire2str_rr_comment_print(char** s, size_t* slen, uint8_t* rr, 651266077Sdes size_t rrlen, size_t dname_off, uint16_t rrtype) 652266077Sdes{ 653266077Sdes if(rrtype == LDNS_RR_TYPE_DNSKEY) { 654266077Sdes return rr_comment_dnskey(s, slen, rr, rrlen, dname_off); 655266077Sdes } else if(rrtype == LDNS_RR_TYPE_RRSIG) { 656266077Sdes return rr_comment_rrsig(s, slen, rr, rrlen, dname_off); 657266077Sdes } else if(rrtype == LDNS_RR_TYPE_NSEC3) { 658266077Sdes return rr_comment_nsec3(s, slen, rr, rrlen, dname_off); 659266077Sdes } 660266077Sdes return 0; 661266077Sdes} 662266077Sdes 663266077Sdesint sldns_wire2str_header_scan(uint8_t** d, size_t* dlen, char** s, 664266077Sdes size_t* slen) 665266077Sdes{ 666266077Sdes int w = 0; 667266077Sdes int opcode, rcode; 668266077Sdes w += sldns_str_print(s, slen, ";; ->>HEADER<<- "); 669266077Sdes if(*dlen == 0) 670266077Sdes return w+sldns_str_print(s, slen, "Error empty packet"); 671266077Sdes if(*dlen < 4) 672266077Sdes return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen); 673266077Sdes opcode = (int)LDNS_OPCODE_WIRE(*d); 674266077Sdes rcode = (int)LDNS_RCODE_WIRE(*d); 675266077Sdes w += sldns_str_print(s, slen, "opcode: "); 676266077Sdes w += sldns_wire2str_opcode_print(s, slen, opcode); 677266077Sdes w += sldns_str_print(s, slen, ", "); 678266077Sdes w += sldns_str_print(s, slen, "rcode: "); 679266077Sdes w += sldns_wire2str_rcode_print(s, slen, rcode); 680266077Sdes w += sldns_str_print(s, slen, ", "); 681266077Sdes w += sldns_str_print(s, slen, "id: %d\n", (int)LDNS_ID_WIRE(*d)); 682266077Sdes w += sldns_str_print(s, slen, ";; flags:"); 683266077Sdes if(LDNS_QR_WIRE(*d)) w += sldns_str_print(s, slen, " qr"); 684266077Sdes if(LDNS_AA_WIRE(*d)) w += sldns_str_print(s, slen, " aa"); 685266077Sdes if(LDNS_TC_WIRE(*d)) w += sldns_str_print(s, slen, " tc"); 686266077Sdes if(LDNS_RD_WIRE(*d)) w += sldns_str_print(s, slen, " rd"); 687266077Sdes if(LDNS_CD_WIRE(*d)) w += sldns_str_print(s, slen, " cd"); 688266077Sdes if(LDNS_RA_WIRE(*d)) w += sldns_str_print(s, slen, " ra"); 689266077Sdes if(LDNS_AD_WIRE(*d)) w += sldns_str_print(s, slen, " ad"); 690266077Sdes if(LDNS_Z_WIRE(*d)) w += sldns_str_print(s, slen, " z"); 691266077Sdes w += sldns_str_print(s, slen, " ; "); 692266077Sdes if(*dlen < LDNS_HEADER_SIZE) 693266077Sdes return w+print_remainder_hex("Error header too short 0x", d, dlen, s, slen); 694266077Sdes w += sldns_str_print(s, slen, "QUERY: %d, ", (int)LDNS_QDCOUNT(*d)); 695266077Sdes w += sldns_str_print(s, slen, "ANSWER: %d, ", (int)LDNS_ANCOUNT(*d)); 696266077Sdes w += sldns_str_print(s, slen, "AUTHORITY: %d, ", (int)LDNS_NSCOUNT(*d)); 697266077Sdes w += sldns_str_print(s, slen, "ADDITIONAL: %d ", (int)LDNS_ARCOUNT(*d)); 698266077Sdes *d += LDNS_HEADER_SIZE; 699266077Sdes *dlen -= LDNS_HEADER_SIZE; 700266077Sdes return w; 701266077Sdes} 702266077Sdes 703266077Sdesint sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s, 704356345Scy size_t* slen, uint16_t rrtype, uint8_t* pkt, size_t pktlen, 705356345Scy int* comprloop) 706266077Sdes{ 707266077Sdes /* try to prettyprint, but if that fails, use unknown format */ 708266077Sdes uint8_t* origd = *d; 709266077Sdes char* origs = *s; 710266077Sdes size_t origdlen = *dlen, origslen = *slen; 711356345Scy size_t r_cnt, r_max; 712266077Sdes sldns_rdf_type rdftype; 713266077Sdes int w = 0, n; 714266077Sdes 715266077Sdes const sldns_rr_descriptor *desc = sldns_rr_descript(rrtype); 716266077Sdes if(!desc) /* unknown format */ 717266077Sdes return sldns_wire2str_rdata_unknown_scan(d, dlen, s, slen); 718266077Sdes /* dlen equals the rdatalen for the rdata */ 719266077Sdes 720266077Sdes r_max = sldns_rr_descriptor_maximum(desc); 721266077Sdes for(r_cnt=0; r_cnt < r_max; r_cnt++) { 722266077Sdes if(*dlen == 0) { 723266077Sdes if(r_cnt < sldns_rr_descriptor_minimum(desc)) 724266077Sdes goto failed; 725266077Sdes break; /* nothing more to print */ 726266077Sdes } 727266077Sdes rdftype = sldns_rr_descriptor_field_type(desc, r_cnt); 728266077Sdes if(r_cnt != 0) 729266077Sdes w += sldns_str_print(s, slen, " "); 730266077Sdes n = sldns_wire2str_rdf_scan(d, dlen, s, slen, rdftype, 731356345Scy pkt, pktlen, comprloop); 732266077Sdes if(n == -1) { 733266077Sdes failed: 734266077Sdes /* failed, use unknown format */ 735266077Sdes *d = origd; *s = origs; 736266077Sdes *dlen = origdlen; *slen = origslen; 737266077Sdes return sldns_wire2str_rdata_unknown_scan(d, dlen, 738266077Sdes s, slen); 739266077Sdes } 740266077Sdes w += n; 741266077Sdes } 742292206Sdes if(*dlen != 0) { 743292206Sdes goto failed; 744292206Sdes } 745266077Sdes return w; 746266077Sdes} 747266077Sdes 748266077Sdesint sldns_wire2str_rdata_unknown_scan(uint8_t** d, size_t* dlen, char** s, 749266077Sdes size_t* slen) 750266077Sdes{ 751266077Sdes int w = 0; 752266077Sdes 753266077Sdes /* print length */ 754266077Sdes w += sldns_str_print(s, slen, "\\# %u", (unsigned)*dlen); 755266077Sdes 756266077Sdes /* print rdlen in hex */ 757266077Sdes if(*dlen != 0) 758266077Sdes w += sldns_str_print(s, slen, " "); 759266077Sdes w += print_hex_buf(s, slen, *d, *dlen); 760266077Sdes (*d) += *dlen; 761266077Sdes (*dlen) = 0; 762266077Sdes return w; 763266077Sdes} 764266077Sdes 765266077Sdes/** print and escape one character for a domain dname */ 766266077Sdesstatic int dname_char_print(char** s, size_t* slen, uint8_t c) 767266077Sdes{ 768266077Sdes if(c == '.' || c == ';' || c == '(' || c == ')' || c == '\\') 769266077Sdes return sldns_str_print(s, slen, "\\%c", c); 770276541Sdes else if(!(isascii((unsigned char)c) && isgraph((unsigned char)c))) 771266077Sdes return sldns_str_print(s, slen, "\\%03u", (unsigned)c); 772266077Sdes /* plain printout */ 773266077Sdes if(*slen) { 774266077Sdes **s = (char)c; 775266077Sdes (*s)++; 776266077Sdes (*slen)--; 777266077Sdes } 778266077Sdes return 1; 779266077Sdes} 780266077Sdes 781266077Sdesint sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen, 782356345Scy uint8_t* pkt, size_t pktlen, int* comprloop) 783266077Sdes{ 784266077Sdes int w = 0; 785266077Sdes /* spool labels onto the string, use compression if its there */ 786266077Sdes uint8_t* pos = *d; 787266077Sdes unsigned i, counter=0; 788356345Scy unsigned maxcompr = MAX_COMPRESS_PTRS; /* loop detection, max compr ptrs */ 789266077Sdes int in_buf = 1; 790356345Scy if(comprloop) { 791356345Scy if(*comprloop != 0) 792356345Scy maxcompr = 30; /* for like ipv6 reverse name, per label */ 793356345Scy if(*comprloop > 4) 794356345Scy maxcompr = 4; /* just don't want to spend time, any more */ 795356345Scy } 796266077Sdes if(*dlen == 0) return sldns_str_print(s, slen, "ErrorMissingDname"); 797266077Sdes if(*pos == 0) { 798266077Sdes (*d)++; 799266077Sdes (*dlen)--; 800266077Sdes return sldns_str_print(s, slen, "."); 801266077Sdes } 802356345Scy while((!pkt || pos < pkt+pktlen) && *pos) { 803266077Sdes /* read label length */ 804266077Sdes uint8_t labellen = *pos++; 805266077Sdes if(in_buf) { (*d)++; (*dlen)--; } 806266077Sdes 807266077Sdes /* find out what sort of label we have */ 808266077Sdes if((labellen&0xc0) == 0xc0) { 809266077Sdes /* compressed */ 810266077Sdes uint16_t target = 0; 811266077Sdes if(in_buf && *dlen == 0) 812266077Sdes return w + sldns_str_print(s, slen, 813266077Sdes "ErrorPartialDname"); 814266077Sdes else if(!in_buf && pos+1 > pkt+pktlen) 815266077Sdes return w + sldns_str_print(s, slen, 816266077Sdes "ErrorPartialDname"); 817266077Sdes target = ((labellen&0x3f)<<8) | *pos; 818266077Sdes if(in_buf) { (*d)++; (*dlen)--; } 819266077Sdes /* move to target, if possible */ 820266077Sdes if(!pkt || target >= pktlen) 821266077Sdes return w + sldns_str_print(s, slen, 822266077Sdes "ErrorComprPtrOutOfBounds"); 823356345Scy if(counter++ > maxcompr) { 824356345Scy if(comprloop && *comprloop < 10) 825356345Scy (*comprloop)++; 826266077Sdes return w + sldns_str_print(s, slen, 827266077Sdes "ErrorComprPtrLooped"); 828356345Scy } 829266077Sdes in_buf = 0; 830266077Sdes pos = pkt+target; 831266077Sdes continue; 832266077Sdes } else if((labellen&0xc0)) { 833266077Sdes /* notimpl label type */ 834266077Sdes w += sldns_str_print(s, slen, 835266077Sdes "ErrorLABELTYPE%xIsUnknown", 836266077Sdes (int)(labellen&0xc0)); 837266077Sdes return w; 838266077Sdes } 839266077Sdes 840266077Sdes /* spool label characters, end with '.' */ 841356345Scy if(in_buf && *dlen < (size_t)labellen) 842356345Scy labellen = (uint8_t)*dlen; 843356345Scy else if(!in_buf && pos+(size_t)labellen > pkt+pktlen) 844266077Sdes labellen = (uint8_t)(pkt + pktlen - pos); 845266077Sdes for(i=0; i<(unsigned)labellen; i++) { 846266077Sdes w += dname_char_print(s, slen, *pos++); 847266077Sdes } 848266077Sdes if(in_buf) { 849266077Sdes (*d) += labellen; 850266077Sdes (*dlen) -= labellen; 851266077Sdes if(*dlen == 0) break; 852266077Sdes } 853266077Sdes w += sldns_str_print(s, slen, "."); 854266077Sdes } 855266077Sdes /* skip over final root label */ 856266077Sdes if(in_buf && *dlen > 0) { (*d)++; (*dlen)--; } 857266077Sdes /* in case we printed no labels, terminate dname */ 858266077Sdes if(w == 0) w += sldns_str_print(s, slen, "."); 859266077Sdes return w; 860266077Sdes} 861266077Sdes 862266077Sdesint sldns_wire2str_opcode_print(char** s, size_t* slen, int opcode) 863266077Sdes{ 864266077Sdes sldns_lookup_table *lt = sldns_lookup_by_id(sldns_opcodes, opcode); 865266077Sdes if (lt && lt->name) { 866266077Sdes return sldns_str_print(s, slen, "%s", lt->name); 867266077Sdes } 868266077Sdes return sldns_str_print(s, slen, "OPCODE%u", (unsigned)opcode); 869266077Sdes} 870266077Sdes 871266077Sdesint sldns_wire2str_rcode_print(char** s, size_t* slen, int rcode) 872266077Sdes{ 873266077Sdes sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rcodes, rcode); 874266077Sdes if (lt && lt->name) { 875266077Sdes return sldns_str_print(s, slen, "%s", lt->name); 876266077Sdes } 877266077Sdes return sldns_str_print(s, slen, "RCODE%u", (unsigned)rcode); 878266077Sdes} 879266077Sdes 880266077Sdesint sldns_wire2str_class_print(char** s, size_t* slen, uint16_t rrclass) 881266077Sdes{ 882266077Sdes sldns_lookup_table *lt = sldns_lookup_by_id(sldns_rr_classes, 883266077Sdes (int)rrclass); 884266077Sdes if (lt && lt->name) { 885266077Sdes return sldns_str_print(s, slen, "%s", lt->name); 886266077Sdes } 887266077Sdes return sldns_str_print(s, slen, "CLASS%u", (unsigned)rrclass); 888266077Sdes} 889266077Sdes 890266077Sdesint sldns_wire2str_type_print(char** s, size_t* slen, uint16_t rrtype) 891266077Sdes{ 892266077Sdes const sldns_rr_descriptor *descriptor = sldns_rr_descript(rrtype); 893266077Sdes if (descriptor && descriptor->_name) { 894266077Sdes return sldns_str_print(s, slen, "%s", descriptor->_name); 895266077Sdes } 896266077Sdes return sldns_str_print(s, slen, "TYPE%u", (unsigned)rrtype); 897266077Sdes} 898266077Sdes 899266077Sdesint sldns_wire2str_edns_option_code_print(char** s, size_t* slen, 900266077Sdes uint16_t opcode) 901266077Sdes{ 902266077Sdes sldns_lookup_table *lt = sldns_lookup_by_id(sldns_edns_options, 903266077Sdes (int)opcode); 904266077Sdes if (lt && lt->name) { 905266077Sdes return sldns_str_print(s, slen, "%s", lt->name); 906266077Sdes } 907266077Sdes return sldns_str_print(s, slen, "OPT%u", (unsigned)opcode); 908266077Sdes} 909266077Sdes 910266077Sdesint sldns_wire2str_class_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen) 911266077Sdes{ 912266077Sdes uint16_t c; 913266077Sdes if(*dlen == 0) return 0; 914266077Sdes if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen); 915266077Sdes c = sldns_read_uint16(*d); 916266077Sdes (*d)+=2; 917266077Sdes (*dlen)-=2; 918266077Sdes return sldns_wire2str_class_print(s, slen, c); 919266077Sdes} 920266077Sdes 921266077Sdesint sldns_wire2str_type_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen) 922266077Sdes{ 923266077Sdes uint16_t t; 924266077Sdes if(*dlen == 0) return 0; 925266077Sdes if(*dlen < 2) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen); 926266077Sdes t = sldns_read_uint16(*d); 927266077Sdes (*d)+=2; 928266077Sdes (*dlen)-=2; 929266077Sdes return sldns_wire2str_type_print(s, slen, t); 930266077Sdes} 931266077Sdes 932266077Sdesint sldns_wire2str_ttl_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen) 933266077Sdes{ 934266077Sdes uint32_t ttl; 935266077Sdes if(*dlen == 0) return 0; 936266077Sdes if(*dlen < 4) return print_remainder_hex("Error malformed 0x", d, dlen, s, slen); 937266077Sdes ttl = sldns_read_uint32(*d); 938266077Sdes (*d)+=4; 939266077Sdes (*dlen)-=4; 940266077Sdes return sldns_str_print(s, slen, "%u", (unsigned)ttl); 941266077Sdes} 942266077Sdes 943266077Sdesint sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen, 944356345Scy int rdftype, uint8_t* pkt, size_t pktlen, int* comprloop) 945266077Sdes{ 946266077Sdes if(*dlen == 0) return 0; 947266077Sdes switch(rdftype) { 948266077Sdes case LDNS_RDF_TYPE_NONE: 949266077Sdes return 0; 950266077Sdes case LDNS_RDF_TYPE_DNAME: 951356345Scy return sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop); 952266077Sdes case LDNS_RDF_TYPE_INT8: 953266077Sdes return sldns_wire2str_int8_scan(d, dlen, s, slen); 954266077Sdes case LDNS_RDF_TYPE_INT16: 955266077Sdes return sldns_wire2str_int16_scan(d, dlen, s, slen); 956266077Sdes case LDNS_RDF_TYPE_INT32: 957266077Sdes return sldns_wire2str_int32_scan(d, dlen, s, slen); 958266077Sdes case LDNS_RDF_TYPE_PERIOD: 959266077Sdes return sldns_wire2str_period_scan(d, dlen, s, slen); 960266077Sdes case LDNS_RDF_TYPE_TSIGTIME: 961266077Sdes return sldns_wire2str_tsigtime_scan(d, dlen, s, slen); 962266077Sdes case LDNS_RDF_TYPE_A: 963266077Sdes return sldns_wire2str_a_scan(d, dlen, s, slen); 964266077Sdes case LDNS_RDF_TYPE_AAAA: 965266077Sdes return sldns_wire2str_aaaa_scan(d, dlen, s, slen); 966266077Sdes case LDNS_RDF_TYPE_STR: 967266077Sdes return sldns_wire2str_str_scan(d, dlen, s, slen); 968266077Sdes case LDNS_RDF_TYPE_APL: 969266077Sdes return sldns_wire2str_apl_scan(d, dlen, s, slen); 970266077Sdes case LDNS_RDF_TYPE_B32_EXT: 971266077Sdes return sldns_wire2str_b32_ext_scan(d, dlen, s, slen); 972266077Sdes case LDNS_RDF_TYPE_B64: 973266077Sdes return sldns_wire2str_b64_scan(d, dlen, s, slen); 974266077Sdes case LDNS_RDF_TYPE_HEX: 975266077Sdes return sldns_wire2str_hex_scan(d, dlen, s, slen); 976266077Sdes case LDNS_RDF_TYPE_NSEC: 977266077Sdes return sldns_wire2str_nsec_scan(d, dlen, s, slen); 978266077Sdes case LDNS_RDF_TYPE_NSEC3_SALT: 979266077Sdes return sldns_wire2str_nsec3_salt_scan(d, dlen, s, slen); 980266077Sdes case LDNS_RDF_TYPE_TYPE: 981266077Sdes return sldns_wire2str_type_scan(d, dlen, s, slen); 982266077Sdes case LDNS_RDF_TYPE_CLASS: 983266077Sdes return sldns_wire2str_class_scan(d, dlen, s, slen); 984266077Sdes case LDNS_RDF_TYPE_CERT_ALG: 985266077Sdes return sldns_wire2str_cert_alg_scan(d, dlen, s, slen); 986266077Sdes case LDNS_RDF_TYPE_ALG: 987266077Sdes return sldns_wire2str_alg_scan(d, dlen, s, slen); 988266077Sdes case LDNS_RDF_TYPE_UNKNOWN: 989266077Sdes return sldns_wire2str_unknown_scan(d, dlen, s, slen); 990266077Sdes case LDNS_RDF_TYPE_TIME: 991266077Sdes return sldns_wire2str_time_scan(d, dlen, s, slen); 992266077Sdes case LDNS_RDF_TYPE_LOC: 993266077Sdes return sldns_wire2str_loc_scan(d, dlen, s, slen); 994266077Sdes case LDNS_RDF_TYPE_WKS: 995266077Sdes case LDNS_RDF_TYPE_SERVICE: 996266077Sdes return sldns_wire2str_wks_scan(d, dlen, s, slen); 997266077Sdes case LDNS_RDF_TYPE_NSAP: 998266077Sdes return sldns_wire2str_nsap_scan(d, dlen, s, slen); 999266077Sdes case LDNS_RDF_TYPE_ATMA: 1000266077Sdes return sldns_wire2str_atma_scan(d, dlen, s, slen); 1001266077Sdes case LDNS_RDF_TYPE_IPSECKEY: 1002266077Sdes return sldns_wire2str_ipseckey_scan(d, dlen, s, slen, pkt, 1003356345Scy pktlen, comprloop); 1004266077Sdes case LDNS_RDF_TYPE_HIP: 1005266077Sdes return sldns_wire2str_hip_scan(d, dlen, s, slen); 1006266077Sdes case LDNS_RDF_TYPE_INT16_DATA: 1007266077Sdes return sldns_wire2str_int16_data_scan(d, dlen, s, slen); 1008266077Sdes case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: 1009266077Sdes return sldns_wire2str_b32_ext_scan(d, dlen, s, slen); 1010266077Sdes case LDNS_RDF_TYPE_ILNP64: 1011266077Sdes return sldns_wire2str_ilnp64_scan(d, dlen, s, slen); 1012266077Sdes case LDNS_RDF_TYPE_EUI48: 1013266077Sdes return sldns_wire2str_eui48_scan(d, dlen, s, slen); 1014266077Sdes case LDNS_RDF_TYPE_EUI64: 1015266077Sdes return sldns_wire2str_eui64_scan(d, dlen, s, slen); 1016266077Sdes case LDNS_RDF_TYPE_TAG: 1017266077Sdes return sldns_wire2str_tag_scan(d, dlen, s, slen); 1018266077Sdes case LDNS_RDF_TYPE_LONG_STR: 1019266077Sdes return sldns_wire2str_long_str_scan(d, dlen, s, slen); 1020356345Scy case LDNS_RDF_TYPE_TSIGERROR: 1021356345Scy return sldns_wire2str_tsigerror_scan(d, dlen, s, slen); 1022266077Sdes } 1023266077Sdes /* unknown rdf type */ 1024266077Sdes return -1; 1025266077Sdes} 1026266077Sdes 1027266077Sdesint sldns_wire2str_int8_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1028266077Sdes{ 1029266077Sdes int w; 1030266077Sdes if(*dl < 1) return -1; 1031266077Sdes w = sldns_str_print(s, sl, "%u", (unsigned)**d); 1032266077Sdes (*d)++; 1033266077Sdes (*dl)--; 1034266077Sdes return w; 1035266077Sdes} 1036266077Sdes 1037266077Sdesint sldns_wire2str_int16_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1038266077Sdes{ 1039266077Sdes int w; 1040266077Sdes if(*dl < 2) return -1; 1041266077Sdes w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint16(*d)); 1042266077Sdes (*d)+=2; 1043266077Sdes (*dl)-=2; 1044266077Sdes return w; 1045266077Sdes} 1046266077Sdes 1047266077Sdesint sldns_wire2str_int32_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1048266077Sdes{ 1049266077Sdes int w; 1050266077Sdes if(*dl < 4) return -1; 1051266077Sdes w = sldns_str_print(s, sl, "%lu", (unsigned long)sldns_read_uint32(*d)); 1052266077Sdes (*d)+=4; 1053266077Sdes (*dl)-=4; 1054266077Sdes return w; 1055266077Sdes} 1056266077Sdes 1057266077Sdesint sldns_wire2str_period_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1058266077Sdes{ 1059266077Sdes int w; 1060266077Sdes if(*dl < 4) return -1; 1061266077Sdes w = sldns_str_print(s, sl, "%u", (unsigned)sldns_read_uint32(*d)); 1062266077Sdes (*d)+=4; 1063266077Sdes (*dl)-=4; 1064266077Sdes return w; 1065266077Sdes} 1066266077Sdes 1067266077Sdesint sldns_wire2str_tsigtime_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1068266077Sdes{ 1069266077Sdes /* tsigtime is 48 bits network order unsigned integer */ 1070266077Sdes int w; 1071266077Sdes uint64_t tsigtime = 0; 1072266077Sdes uint64_t d0, d1, d2, d3, d4, d5; 1073266077Sdes if(*dl < 6) return -1; 1074266077Sdes d0 = (*d)[0]; /* cast to uint64 for shift operations */ 1075266077Sdes d1 = (*d)[1]; 1076266077Sdes d2 = (*d)[2]; 1077266077Sdes d3 = (*d)[3]; 1078266077Sdes d4 = (*d)[4]; 1079266077Sdes d5 = (*d)[5]; 1080266077Sdes tsigtime = (d0<<40) | (d1<<32) | (d2<<24) | (d3<<16) | (d4<<8) | d5; 1081266077Sdes#ifndef USE_WINSOCK 1082266077Sdes w = sldns_str_print(s, sl, "%llu", (long long)tsigtime); 1083266077Sdes#else 1084266077Sdes w = sldns_str_print(s, sl, "%I64u", (long long)tsigtime); 1085266077Sdes#endif 1086266077Sdes (*d)+=6; 1087266077Sdes (*dl)-=6; 1088266077Sdes return w; 1089266077Sdes} 1090266077Sdes 1091266077Sdesint sldns_wire2str_a_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1092266077Sdes{ 1093266077Sdes char buf[32]; 1094266077Sdes int w; 1095266077Sdes if(*dl < 4) return -1; 1096266077Sdes if(!inet_ntop(AF_INET, *d, buf, (socklen_t)sizeof(buf))) 1097266077Sdes return -1; 1098266077Sdes w = sldns_str_print(s, sl, "%s", buf); 1099266077Sdes (*d)+=4; 1100266077Sdes (*dl)-=4; 1101266077Sdes return w; 1102266077Sdes} 1103266077Sdes 1104266077Sdesint sldns_wire2str_aaaa_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1105266077Sdes{ 1106266077Sdes#ifdef AF_INET6 1107266077Sdes char buf[64]; 1108266077Sdes int w; 1109266077Sdes if(*dl < 16) return -1; 1110266077Sdes if(!inet_ntop(AF_INET6, *d, buf, (socklen_t)sizeof(buf))) 1111266077Sdes return -1; 1112266077Sdes w = sldns_str_print(s, sl, "%s", buf); 1113266077Sdes (*d)+=16; 1114266077Sdes (*dl)-=16; 1115266077Sdes return w; 1116266077Sdes#else 1117266077Sdes return -1; 1118266077Sdes#endif 1119266077Sdes} 1120266077Sdes 1121266077Sdes/** printout escaped TYPE_STR character */ 1122266077Sdesstatic int str_char_print(char** s, size_t* sl, uint8_t c) 1123266077Sdes{ 1124276541Sdes if(isprint((unsigned char)c) || c == '\t') { 1125266077Sdes if(c == '\"' || c == '\\') 1126266077Sdes return sldns_str_print(s, sl, "\\%c", c); 1127266077Sdes if(*sl) { 1128266077Sdes **s = (char)c; 1129266077Sdes (*s)++; 1130266077Sdes (*sl)--; 1131266077Sdes } 1132266077Sdes return 1; 1133266077Sdes } 1134266077Sdes return sldns_str_print(s, sl, "\\%03u", (unsigned)c); 1135266077Sdes} 1136266077Sdes 1137266077Sdesint sldns_wire2str_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1138266077Sdes{ 1139266077Sdes int w = 0; 1140266077Sdes size_t i, len; 1141266077Sdes if(*dl < 1) return -1; 1142266077Sdes len = **d; 1143266077Sdes if(*dl < 1+len) return -1; 1144266077Sdes (*d)++; 1145266077Sdes (*dl)--; 1146266077Sdes w += sldns_str_print(s, sl, "\""); 1147266077Sdes for(i=0; i<len; i++) 1148266077Sdes w += str_char_print(s, sl, (*d)[i]); 1149266077Sdes w += sldns_str_print(s, sl, "\""); 1150266077Sdes (*d)+=len; 1151266077Sdes (*dl)-=len; 1152266077Sdes return w; 1153266077Sdes} 1154266077Sdes 1155266077Sdesint sldns_wire2str_apl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1156266077Sdes{ 1157266077Sdes int i, w = 0; 1158266077Sdes uint16_t family; 1159266077Sdes uint8_t negation, prefix, adflength; 1160266077Sdes if(*dl < 4) return -1; 1161266077Sdes family = sldns_read_uint16(*d); 1162266077Sdes prefix = (*d)[2]; 1163266077Sdes negation = ((*d)[3] & LDNS_APL_NEGATION); 1164266077Sdes adflength = ((*d)[3] & LDNS_APL_MASK); 1165266077Sdes if(*dl < 4+(size_t)adflength) return -1; 1166266077Sdes if(family != LDNS_APL_IP4 && family != LDNS_APL_IP6) 1167266077Sdes return -1; /* unknown address family */ 1168266077Sdes if(negation) 1169266077Sdes w += sldns_str_print(s, sl, "!"); 1170266077Sdes w += sldns_str_print(s, sl, "%u:", (unsigned)family); 1171266077Sdes if(family == LDNS_APL_IP4) { 1172266077Sdes /* check if prefix <32 ? */ 1173266077Sdes /* address is variable length 0 - 4 */ 1174266077Sdes for(i=0; i<4; i++) { 1175266077Sdes if(i > 0) 1176266077Sdes w += sldns_str_print(s, sl, "."); 1177266077Sdes if(i < (int)adflength) 1178266077Sdes w += sldns_str_print(s, sl, "%d", (*d)[4+i]); 1179266077Sdes else w += sldns_str_print(s, sl, "0"); 1180266077Sdes } 1181266077Sdes } else if(family == LDNS_APL_IP6) { 1182266077Sdes /* check if prefix <128 ? */ 1183266077Sdes /* address is variable length 0 - 16 */ 1184266077Sdes for(i=0; i<16; i++) { 1185266077Sdes if(i%2 == 0 && i>0) 1186266077Sdes w += sldns_str_print(s, sl, ":"); 1187266077Sdes if(i < (int)adflength) 1188266077Sdes w += sldns_str_print(s, sl, "%02x", (*d)[4+i]); 1189266077Sdes else w += sldns_str_print(s, sl, "00"); 1190266077Sdes } 1191266077Sdes } 1192266077Sdes w += sldns_str_print(s, sl, "/%u", (unsigned)prefix); 1193266077Sdes (*d) += 4+adflength; 1194266077Sdes (*dl) -= 4+adflength; 1195266077Sdes return w; 1196266077Sdes} 1197266077Sdes 1198266077Sdesint sldns_wire2str_b32_ext_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1199266077Sdes{ 1200266077Sdes size_t datalen; 1201266077Sdes size_t sz; 1202266077Sdes if(*dl < 1) return -1; 1203266077Sdes datalen = (*d)[0]; 1204266077Sdes if(*dl < 1+datalen) return -1; 1205266077Sdes sz = sldns_b32_ntop_calculate_size(datalen); 1206266077Sdes if(*sl < sz+1) { 1207266077Sdes (*d) += datalen+1; 1208266077Sdes (*dl) -= (datalen+1); 1209266077Sdes return (int)sz; /* out of space really, but would need buffer 1210266077Sdes in order to truncate the output */ 1211266077Sdes } 1212266077Sdes sldns_b32_ntop_extended_hex((*d)+1, datalen, *s, *sl); 1213266077Sdes (*d) += datalen+1; 1214266077Sdes (*dl) -= (datalen+1); 1215266077Sdes (*s) += sz; 1216266077Sdes (*sl) -= sz; 1217266077Sdes return (int)sz; 1218266077Sdes} 1219266077Sdes 1220266077Sdes/** scan number of bytes from wire into b64 presentation format */ 1221266077Sdesstatic int sldns_wire2str_b64_scan_num(uint8_t** d, size_t* dl, char** s, 1222266077Sdes size_t* sl, size_t num) 1223266077Sdes{ 1224266077Sdes /* b64_ntop_calculate size includes null at the end */ 1225266077Sdes size_t sz = sldns_b64_ntop_calculate_size(num)-1; 1226266077Sdes if(*sl < sz+1) { 1227266077Sdes (*d) += num; 1228266077Sdes (*dl) -= num; 1229266077Sdes return (int)sz; /* out of space really, but would need buffer 1230266077Sdes in order to truncate the output */ 1231266077Sdes } 1232266077Sdes sldns_b64_ntop(*d, num, *s, *sl); 1233266077Sdes (*d) += num; 1234266077Sdes (*dl) -= num; 1235266077Sdes (*s) += sz; 1236266077Sdes (*sl) -= sz; 1237266077Sdes return (int)sz; 1238266077Sdes} 1239266077Sdes 1240266077Sdesint sldns_wire2str_b64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1241266077Sdes{ 1242356345Scy if(*dl == 0) { 1243356345Scy return sldns_str_print(s, sl, "0"); 1244356345Scy } 1245266077Sdes return sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl); 1246266077Sdes} 1247266077Sdes 1248266077Sdesint sldns_wire2str_hex_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1249266077Sdes{ 1250356345Scy if(*dl == 0) { 1251356345Scy return sldns_str_print(s, sl, "0"); 1252356345Scy } 1253266077Sdes return print_remainder_hex("", d, dl, s, sl); 1254266077Sdes} 1255266077Sdes 1256266077Sdesint sldns_wire2str_nsec_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1257266077Sdes{ 1258266077Sdes uint8_t* p = *d; 1259266077Sdes size_t pl = *dl; 1260266077Sdes unsigned i, bit, window, block_len; 1261266077Sdes uint16_t t; 1262266077Sdes int w = 0; 1263266077Sdes 1264266077Sdes /* check for errors */ 1265266077Sdes while(pl) { 1266266077Sdes if(pl < 2) return -1; 1267266077Sdes block_len = (unsigned)p[1]; 1268266077Sdes if(pl < 2+block_len) return -1; 1269266077Sdes p += block_len+2; 1270266077Sdes pl -= block_len+2; 1271266077Sdes } 1272266077Sdes 1273266077Sdes /* do it */ 1274266077Sdes p = *d; 1275266077Sdes pl = *dl; 1276266077Sdes while(pl) { 1277266077Sdes if(pl < 2) return -1; /* cannot happen */ 1278266077Sdes window = (unsigned)p[0]; 1279266077Sdes block_len = (unsigned)p[1]; 1280266077Sdes if(pl < 2+block_len) return -1; /* cannot happen */ 1281266077Sdes p += 2; 1282266077Sdes for(i=0; i<block_len; i++) { 1283266077Sdes if(p[i] == 0) continue; 1284266077Sdes /* base type number for this octet */ 1285266077Sdes t = ((window)<<8) | (i << 3); 1286266077Sdes for(bit=0; bit<8; bit++) { 1287266077Sdes if((p[i]&(0x80>>bit))) { 1288266077Sdes if(w) w += sldns_str_print(s, sl, " "); 1289266077Sdes w += sldns_wire2str_type_print(s, sl, 1290266077Sdes t+bit); 1291266077Sdes } 1292266077Sdes } 1293266077Sdes } 1294266077Sdes p += block_len; 1295266077Sdes pl -= block_len+2; 1296266077Sdes } 1297266077Sdes (*d) += *dl; 1298266077Sdes (*dl) = 0; 1299266077Sdes return w; 1300266077Sdes} 1301266077Sdes 1302266077Sdesint sldns_wire2str_nsec3_salt_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1303266077Sdes{ 1304266077Sdes size_t salt_len; 1305266077Sdes int w; 1306266077Sdes if(*dl < 1) return -1; 1307266077Sdes salt_len = (size_t)(*d)[0]; 1308266077Sdes if(*dl < 1+salt_len) return -1; 1309266077Sdes (*d)++; 1310266077Sdes (*dl)--; 1311266077Sdes if(salt_len == 0) { 1312266077Sdes return sldns_str_print(s, sl, "-"); 1313266077Sdes } 1314266077Sdes w = print_hex_buf(s, sl, *d, salt_len); 1315266077Sdes (*dl)-=salt_len; 1316266077Sdes (*d)+=salt_len; 1317266077Sdes return w; 1318266077Sdes} 1319266077Sdes 1320266077Sdesint sldns_wire2str_cert_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1321266077Sdes{ 1322266077Sdes sldns_lookup_table *lt; 1323266077Sdes int data, w; 1324266077Sdes if(*dl < 2) return -1; 1325266077Sdes data = (int)sldns_read_uint16(*d); 1326266077Sdes lt = sldns_lookup_by_id(sldns_cert_algorithms, data); 1327266077Sdes if(lt && lt->name) 1328266077Sdes w = sldns_str_print(s, sl, "%s", lt->name); 1329266077Sdes else w = sldns_str_print(s, sl, "%d", data); 1330266077Sdes (*dl)-=2; 1331266077Sdes (*d)+=2; 1332266077Sdes return w; 1333266077Sdes} 1334266077Sdes 1335266077Sdesint sldns_wire2str_alg_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1336266077Sdes{ 1337266077Sdes /* don't use algorithm mnemonics in the presentation format 1338266077Sdes * this kind of got sneaked into the rfc's */ 1339266077Sdes return sldns_wire2str_int8_scan(d, dl, s, sl); 1340266077Sdes} 1341266077Sdes 1342266077Sdesint sldns_wire2str_unknown_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1343266077Sdes{ 1344266077Sdes return sldns_wire2str_rdata_unknown_scan(d, dl, s, sl); 1345266077Sdes} 1346266077Sdes 1347266077Sdesint sldns_wire2str_time_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1348266077Sdes{ 1349266077Sdes /* create a YYYYMMDDHHMMSS string if possible */ 1350266077Sdes struct tm tm; 1351266077Sdes char date_buf[16]; 1352266077Sdes uint32_t t; 1353266077Sdes memset(&tm, 0, sizeof(tm)); 1354266077Sdes if(*dl < 4) return -1; 1355266077Sdes t = sldns_read_uint32(*d); 1356266077Sdes date_buf[15]=0; 1357356345Scy if(sldns_serial_arithmetics_gmtime_r(t, time(NULL), &tm) && 1358266077Sdes strftime(date_buf, 15, "%Y%m%d%H%M%S", &tm)) { 1359266077Sdes (*d) += 4; 1360266077Sdes (*dl) -= 4; 1361266077Sdes return sldns_str_print(s, sl, "%s", date_buf); 1362266077Sdes } 1363266077Sdes return -1; 1364266077Sdes} 1365266077Sdes 1366266077Sdesstatic int 1367266077Sdesloc_cm_print(char** str, size_t* sl, uint8_t mantissa, uint8_t exponent) 1368266077Sdes{ 1369266077Sdes int w = 0; 1370266077Sdes uint8_t i; 1371266077Sdes /* is it 0.<two digits> ? */ 1372266077Sdes if(exponent < 2) { 1373266077Sdes if(exponent == 1) 1374266077Sdes mantissa *= 10; 1375266077Sdes return sldns_str_print(str, sl, "0.%02ld", (long)mantissa); 1376266077Sdes } 1377266077Sdes /* always <digit><string of zeros> */ 1378266077Sdes w += sldns_str_print(str, sl, "%d", (int)mantissa); 1379266077Sdes for(i=0; i<exponent-2; i++) 1380266077Sdes w += sldns_str_print(str, sl, "0"); 1381266077Sdes return w; 1382266077Sdes} 1383266077Sdes 1384266077Sdesint sldns_wire2str_loc_scan(uint8_t** d, size_t* dl, char** str, size_t* sl) 1385266077Sdes{ 1386266077Sdes /* we could do checking (ie degrees < 90 etc)? */ 1387266077Sdes uint8_t version; 1388266077Sdes uint8_t size; 1389266077Sdes uint8_t horizontal_precision; 1390266077Sdes uint8_t vertical_precision; 1391266077Sdes uint32_t longitude; 1392266077Sdes uint32_t latitude; 1393266077Sdes uint32_t altitude; 1394266077Sdes char northerness; 1395266077Sdes char easterness; 1396266077Sdes uint32_t h; 1397266077Sdes uint32_t m; 1398266077Sdes double s; 1399266077Sdes uint32_t equator = (uint32_t)1 << 31; /* 2**31 */ 1400266077Sdes int w = 0; 1401266077Sdes 1402266077Sdes if(*dl < 16) return -1; 1403266077Sdes version = (*d)[0]; 1404266077Sdes if(version != 0) 1405266077Sdes return sldns_wire2str_hex_scan(d, dl, str, sl); 1406266077Sdes size = (*d)[1]; 1407266077Sdes horizontal_precision = (*d)[2]; 1408266077Sdes vertical_precision = (*d)[3]; 1409266077Sdes 1410266077Sdes latitude = sldns_read_uint32((*d)+4); 1411266077Sdes longitude = sldns_read_uint32((*d)+8); 1412266077Sdes altitude = sldns_read_uint32((*d)+12); 1413266077Sdes 1414266077Sdes if (latitude > equator) { 1415266077Sdes northerness = 'N'; 1416266077Sdes latitude = latitude - equator; 1417266077Sdes } else { 1418266077Sdes northerness = 'S'; 1419266077Sdes latitude = equator - latitude; 1420266077Sdes } 1421266077Sdes h = latitude / (1000 * 60 * 60); 1422266077Sdes latitude = latitude % (1000 * 60 * 60); 1423266077Sdes m = latitude / (1000 * 60); 1424266077Sdes latitude = latitude % (1000 * 60); 1425266077Sdes s = (double) latitude / 1000.0; 1426266077Sdes w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ", 1427266077Sdes h, m, s, northerness); 1428266077Sdes 1429266077Sdes if (longitude > equator) { 1430266077Sdes easterness = 'E'; 1431266077Sdes longitude = longitude - equator; 1432266077Sdes } else { 1433266077Sdes easterness = 'W'; 1434266077Sdes longitude = equator - longitude; 1435266077Sdes } 1436266077Sdes h = longitude / (1000 * 60 * 60); 1437266077Sdes longitude = longitude % (1000 * 60 * 60); 1438266077Sdes m = longitude / (1000 * 60); 1439266077Sdes longitude = longitude % (1000 * 60); 1440266077Sdes s = (double) longitude / (1000.0); 1441266077Sdes w += sldns_str_print(str, sl, "%02u %02u %06.3f %c ", 1442266077Sdes h, m, s, easterness); 1443266077Sdes 1444266077Sdes s = ((double) altitude) / 100; 1445266077Sdes s -= 100000; 1446266077Sdes 1447266077Sdes if(altitude%100 != 0) 1448266077Sdes w += sldns_str_print(str, sl, "%.2f", s); 1449266077Sdes else 1450266077Sdes w += sldns_str_print(str, sl, "%.0f", s); 1451266077Sdes 1452266077Sdes w += sldns_str_print(str, sl, "m "); 1453266077Sdes 1454266077Sdes w += loc_cm_print(str, sl, (size & 0xf0) >> 4, size & 0x0f); 1455266077Sdes w += sldns_str_print(str, sl, "m "); 1456266077Sdes 1457266077Sdes w += loc_cm_print(str, sl, (horizontal_precision & 0xf0) >> 4, 1458266077Sdes horizontal_precision & 0x0f); 1459266077Sdes w += sldns_str_print(str, sl, "m "); 1460266077Sdes 1461266077Sdes w += loc_cm_print(str, sl, (vertical_precision & 0xf0) >> 4, 1462266077Sdes vertical_precision & 0x0f); 1463266077Sdes w += sldns_str_print(str, sl, "m"); 1464266077Sdes 1465266077Sdes (*d)+=16; 1466266077Sdes (*dl)-=16; 1467266077Sdes return w; 1468266077Sdes} 1469266077Sdes 1470266077Sdesint sldns_wire2str_wks_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1471266077Sdes{ 1472266077Sdes /* protocol, followed by bitmap of services */ 1473266077Sdes const char* proto_name = NULL; 1474266077Sdes struct protoent *protocol; 1475266077Sdes struct servent *service; 1476266077Sdes uint8_t protocol_nr; 1477266077Sdes int bit, port, w = 0; 1478266077Sdes size_t i; 1479266077Sdes /* we cannot print with strings because they 1480266077Sdes * are not portable, the presentation format may 1481266077Sdes * not be able to be read in on another computer. */ 1482266077Sdes int print_symbols = 0; 1483266077Sdes 1484266077Sdes /* protocol */ 1485266077Sdes if(*dl < 1) return -1; 1486266077Sdes protocol_nr = (*d)[0]; 1487266077Sdes (*d)++; 1488266077Sdes (*dl)--; 1489266077Sdes protocol = getprotobynumber((int)protocol_nr); 1490266077Sdes if(protocol && (protocol->p_name != NULL)) { 1491266077Sdes w += sldns_str_print(s, sl, "%s", protocol->p_name); 1492266077Sdes proto_name = protocol->p_name; 1493356345Scy } else if(protocol_nr == 6) { 1494356345Scy w += sldns_str_print(s, sl, "tcp"); 1495356345Scy } else if(protocol_nr == 17) { 1496356345Scy w += sldns_str_print(s, sl, "udp"); 1497266077Sdes } else { 1498266077Sdes w += sldns_str_print(s, sl, "%u", (unsigned)protocol_nr); 1499266077Sdes } 1500266077Sdes 1501266077Sdes for(i=0; i<*dl; i++) { 1502266077Sdes if((*d)[i] == 0) 1503266077Sdes continue; 1504266077Sdes for(bit=0; bit<8; bit++) { 1505266077Sdes if(!(((*d)[i])&(0x80>>bit))) 1506266077Sdes continue; 1507266077Sdes port = (int)i*8 + bit; 1508266077Sdes 1509266077Sdes if(!print_symbols) 1510266077Sdes service = NULL; 1511266077Sdes else 1512266077Sdes service = getservbyport( 1513266077Sdes (int)htons((uint16_t)port), proto_name); 1514266077Sdes if(service && service->s_name) 1515266077Sdes w += sldns_str_print(s, sl, " %s", 1516266077Sdes service->s_name); 1517266077Sdes else w += sldns_str_print(s, sl, " %u", 1518266077Sdes (unsigned)port); 1519266077Sdes } 1520266077Sdes } 1521266077Sdes 1522266077Sdes#ifdef HAVE_ENDSERVENT 1523266077Sdes endservent(); 1524266077Sdes#endif 1525266077Sdes#ifdef HAVE_ENDPROTOENT 1526266077Sdes endprotoent(); 1527266077Sdes#endif 1528266077Sdes (*d) += *dl; 1529266077Sdes (*dl) = 0; 1530266077Sdes return w; 1531266077Sdes} 1532266077Sdes 1533266077Sdesint sldns_wire2str_nsap_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1534266077Sdes{ 1535266077Sdes return print_remainder_hex("0x", d, dl, s, sl); 1536266077Sdes} 1537266077Sdes 1538266077Sdesint sldns_wire2str_atma_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1539266077Sdes{ 1540266077Sdes return print_remainder_hex("", d, dl, s, sl); 1541266077Sdes} 1542266077Sdes 1543266077Sdes/* internal scan routine that can modify arguments on failure */ 1544266077Sdesstatic int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl, 1545356345Scy char** s, size_t* sl, uint8_t* pkt, size_t pktlen, int* comprloop) 1546266077Sdes{ 1547266077Sdes /* http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt*/ 1548266077Sdes uint8_t precedence, gateway_type, algorithm; 1549266077Sdes int w = 0; 1550266077Sdes 1551266077Sdes if(*dl < 3) return -1; 1552266077Sdes precedence = (*d)[0]; 1553266077Sdes gateway_type = (*d)[1]; 1554266077Sdes algorithm = (*d)[2]; 1555266077Sdes if(gateway_type > 3) 1556266077Sdes return -1; /* unknown */ 1557266077Sdes (*d)+=3; 1558266077Sdes (*dl)-=3; 1559266077Sdes w += sldns_str_print(s, sl, "%d %d %d ", 1560266077Sdes (int)precedence, (int)gateway_type, (int)algorithm); 1561266077Sdes 1562266077Sdes switch(gateway_type) { 1563266077Sdes case 0: /* no gateway */ 1564266077Sdes w += sldns_str_print(s, sl, "."); 1565266077Sdes break; 1566266077Sdes case 1: /* ip4 */ 1567266077Sdes w += sldns_wire2str_a_scan(d, dl, s, sl); 1568266077Sdes break; 1569266077Sdes case 2: /* ip6 */ 1570266077Sdes w += sldns_wire2str_aaaa_scan(d, dl, s, sl); 1571266077Sdes break; 1572266077Sdes case 3: /* dname */ 1573356345Scy w += sldns_wire2str_dname_scan(d, dl, s, sl, pkt, pktlen, comprloop); 1574266077Sdes break; 1575266077Sdes default: /* unknown */ 1576266077Sdes return -1; 1577266077Sdes } 1578266077Sdes 1579266077Sdes if(*dl < 1) 1580266077Sdes return -1; 1581266077Sdes w += sldns_str_print(s, sl, " "); 1582266077Sdes w += sldns_wire2str_b64_scan_num(d, dl, s, sl, *dl); 1583266077Sdes return w; 1584266077Sdes} 1585266077Sdes 1586266077Sdesint sldns_wire2str_ipseckey_scan(uint8_t** d, size_t* dl, char** s, size_t* sl, 1587356345Scy uint8_t* pkt, size_t pktlen, int* comprloop) 1588266077Sdes{ 1589266077Sdes uint8_t* od = *d; 1590266077Sdes char* os = *s; 1591266077Sdes size_t odl = *dl, osl = *sl; 1592356345Scy int w=sldns_wire2str_ipseckey_scan_internal(d, dl, s, sl, pkt, pktlen, comprloop); 1593266077Sdes if(w == -1) { 1594266077Sdes *d = od; 1595266077Sdes *s = os; 1596266077Sdes *dl = odl; 1597266077Sdes *sl = osl; 1598266077Sdes return -1; 1599266077Sdes } 1600266077Sdes return w; 1601266077Sdes} 1602266077Sdes 1603266077Sdesint sldns_wire2str_hip_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1604266077Sdes{ 1605266077Sdes int w; 1606266077Sdes uint8_t algo, hitlen; 1607266077Sdes uint16_t pklen; 1608266077Sdes 1609266077Sdes /* read lengths */ 1610266077Sdes if(*dl < 4) 1611266077Sdes return -1; 1612266077Sdes hitlen = (*d)[0]; 1613266077Sdes algo = (*d)[1]; 1614266077Sdes pklen = sldns_read_uint16((*d)+2); 1615266077Sdes if(*dl < (size_t)4 + (size_t)hitlen + (size_t)pklen) 1616266077Sdes return -1; 1617266077Sdes 1618266077Sdes /* write: algo hit pubkey */ 1619266077Sdes w = sldns_str_print(s, sl, "%u ", (unsigned)algo); 1620266077Sdes w += print_hex_buf(s, sl, (*d)+4, hitlen); 1621266077Sdes w += sldns_str_print(s, sl, " "); 1622266077Sdes (*d)+=4+hitlen; 1623266077Sdes (*dl)-= (4+hitlen); 1624266077Sdes w += sldns_wire2str_b64_scan_num(d, dl, s, sl, pklen); 1625266077Sdes return w; 1626266077Sdes} 1627266077Sdes 1628266077Sdesint sldns_wire2str_int16_data_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1629266077Sdes{ 1630356345Scy int w; 1631266077Sdes uint16_t n; 1632266077Sdes if(*dl < 2) 1633266077Sdes return -1; 1634266077Sdes n = sldns_read_uint16(*d); 1635266077Sdes if(*dl < 2+(size_t)n) 1636266077Sdes return -1; 1637266077Sdes (*d)+=2; 1638266077Sdes (*dl)-=2; 1639356345Scy if(n == 0) { 1640356345Scy return sldns_str_print(s, sl, "0"); 1641356345Scy } 1642356345Scy w = sldns_str_print(s, sl, "%u ", (unsigned)n); 1643356345Scy w += sldns_wire2str_b64_scan_num(d, dl, s, sl, n); 1644356345Scy return w; 1645266077Sdes} 1646266077Sdes 1647266077Sdesint sldns_wire2str_nsec3_next_owner_scan(uint8_t** d, size_t* dl, char** s, 1648266077Sdes size_t* sl) 1649266077Sdes{ 1650266077Sdes return sldns_wire2str_b32_ext_scan(d, dl, s, sl); 1651266077Sdes} 1652266077Sdes 1653266077Sdesint sldns_wire2str_ilnp64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1654266077Sdes{ 1655266077Sdes int w; 1656266077Sdes if(*dl < 8) 1657266077Sdes return -1; 1658266077Sdes w = sldns_str_print(s, sl, "%.4x:%.4x:%.4x:%.4x", 1659266077Sdes sldns_read_uint16(*d), sldns_read_uint16((*d)+2), 1660266077Sdes sldns_read_uint16((*d)+4), sldns_read_uint16((*d)+6)); 1661266077Sdes (*d)+=8; 1662266077Sdes (*dl)-=8; 1663266077Sdes return w; 1664266077Sdes} 1665266077Sdes 1666266077Sdesint sldns_wire2str_eui48_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1667266077Sdes{ 1668266077Sdes int w; 1669266077Sdes if(*dl < 6) 1670266077Sdes return -1; 1671266077Sdes w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", 1672266077Sdes (*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5]); 1673266077Sdes (*d)+=6; 1674266077Sdes (*dl)-=6; 1675266077Sdes return w; 1676266077Sdes} 1677266077Sdes 1678266077Sdesint sldns_wire2str_eui64_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1679266077Sdes{ 1680266077Sdes int w; 1681266077Sdes if(*dl < 8) 1682266077Sdes return -1; 1683266077Sdes w = sldns_str_print(s, sl, "%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x-%.2x", 1684266077Sdes (*d)[0], (*d)[1], (*d)[2], (*d)[3], (*d)[4], (*d)[5], 1685266077Sdes (*d)[6], (*d)[7]); 1686266077Sdes (*d)+=8; 1687266077Sdes (*dl)-=8; 1688266077Sdes return w; 1689266077Sdes} 1690266077Sdes 1691266077Sdesint sldns_wire2str_tag_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1692266077Sdes{ 1693266077Sdes size_t i, n; 1694266077Sdes int w = 0; 1695266077Sdes if(*dl < 1) 1696266077Sdes return -1; 1697266077Sdes n = (size_t)((*d)[0]); 1698266077Sdes if(*dl < 1+n) 1699266077Sdes return -1; 1700266077Sdes for(i=0; i<n; i++) 1701356345Scy if(!isalnum((unsigned char)(*d)[i+1])) 1702266077Sdes return -1; 1703266077Sdes for(i=0; i<n; i++) 1704356345Scy w += sldns_str_print(s, sl, "%c", (char)(*d)[i+1]); 1705266077Sdes (*d)+=n+1; 1706266077Sdes (*dl)-=(n+1); 1707266077Sdes return w; 1708266077Sdes} 1709266077Sdes 1710266077Sdesint sldns_wire2str_long_str_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1711266077Sdes{ 1712266077Sdes size_t i; 1713266077Sdes int w = 0; 1714266077Sdes w += sldns_str_print(s, sl, "\""); 1715266077Sdes for(i=0; i<*dl; i++) 1716266077Sdes w += str_char_print(s, sl, (*d)[i]); 1717266077Sdes w += sldns_str_print(s, sl, "\""); 1718266077Sdes (*d)+=*dl; 1719266077Sdes (*dl)=0; 1720266077Sdes return w; 1721266077Sdes} 1722266077Sdes 1723356345Scyint sldns_wire2str_tsigerror_scan(uint8_t** d, size_t* dl, char** s, size_t* sl) 1724356345Scy{ 1725356345Scy sldns_lookup_table *lt; 1726356345Scy int data, w; 1727356345Scy if(*dl < 2) return -1; 1728356345Scy data = (int)sldns_read_uint16(*d); 1729356345Scy lt = sldns_lookup_by_id(sldns_tsig_errors, data); 1730356345Scy if(lt && lt->name) 1731356345Scy w = sldns_str_print(s, sl, "%s", lt->name); 1732356345Scy else w = sldns_str_print(s, sl, "%d", data); 1733356345Scy (*dl)-=2; 1734356345Scy (*d)+=2; 1735356345Scy return w; 1736356345Scy} 1737356345Scy 1738266077Sdesint sldns_wire2str_edns_llq_print(char** s, size_t* sl, uint8_t* data, 1739266077Sdes size_t len) 1740266077Sdes{ 1741266077Sdes /* LLQ constants */ 1742266077Sdes const char* llq_errors[] = {"NO-ERROR", "SERV-FULL", "STATIC", 1743266077Sdes "FORMAT-ERR", "NO-SUCH-LLQ", "BAD-VERS", "UNKNOWN_ERR"}; 1744266077Sdes const unsigned int llq_errors_num = 7; 1745266077Sdes const char* llq_opcodes[] = {"LLQ-SETUP", "LLQ-REFRESH", "LLQ-EVENT"}; 1746266077Sdes const unsigned int llq_opcodes_num = 3; 1747266077Sdes uint16_t version, llq_opcode, error_code; 1748266077Sdes uint64_t llq_id; 1749266077Sdes uint32_t lease_life; /* Requested or granted life of LLQ, in seconds */ 1750266077Sdes int w = 0; 1751266077Sdes 1752266077Sdes /* read the record */ 1753266077Sdes if(len != 18) { 1754266077Sdes w += sldns_str_print(s, sl, "malformed LLQ "); 1755266077Sdes w += print_hex_buf(s, sl, data, len); 1756266077Sdes return w; 1757266077Sdes } 1758266077Sdes version = sldns_read_uint16(data); 1759266077Sdes llq_opcode = sldns_read_uint16(data+2); 1760266077Sdes error_code = sldns_read_uint16(data+4); 1761266077Sdes memmove(&llq_id, data+6, sizeof(llq_id)); 1762266077Sdes lease_life = sldns_read_uint32(data+14); 1763266077Sdes 1764266077Sdes /* print it */ 1765266077Sdes w += sldns_str_print(s, sl, "v%d ", (int)version); 1766266077Sdes if(llq_opcode < llq_opcodes_num) 1767266077Sdes w += sldns_str_print(s, sl, "%s", llq_opcodes[llq_opcode]); 1768266077Sdes else w += sldns_str_print(s, sl, "opcode %d", (int)llq_opcode); 1769266077Sdes if(error_code < llq_errors_num) 1770266077Sdes w += sldns_str_print(s, sl, " %s", llq_errors[error_code]); 1771266077Sdes else w += sldns_str_print(s, sl, " error %d", (int)error_code); 1772266077Sdes#ifndef USE_WINSOCK 1773266077Sdes w += sldns_str_print(s, sl, " id %llx lease-life %lu", 1774266077Sdes (unsigned long long)llq_id, (unsigned long)lease_life); 1775266077Sdes#else 1776266077Sdes w += sldns_str_print(s, sl, " id %I64x lease-life %lu", 1777266077Sdes (unsigned long long)llq_id, (unsigned long)lease_life); 1778266077Sdes#endif 1779266077Sdes return w; 1780266077Sdes} 1781266077Sdes 1782266077Sdesint sldns_wire2str_edns_ul_print(char** s, size_t* sl, uint8_t* data, 1783266077Sdes size_t len) 1784266077Sdes{ 1785266077Sdes uint32_t lease; 1786266077Sdes int w = 0; 1787266077Sdes if(len != 4) { 1788266077Sdes w += sldns_str_print(s, sl, "malformed UL "); 1789266077Sdes w += print_hex_buf(s, sl, data, len); 1790266077Sdes return w; 1791266077Sdes } 1792266077Sdes lease = sldns_read_uint32(data); 1793266077Sdes w += sldns_str_print(s, sl, "lease %lu", (unsigned long)lease); 1794266077Sdes return w; 1795266077Sdes} 1796266077Sdes 1797266077Sdesint sldns_wire2str_edns_nsid_print(char** s, size_t* sl, uint8_t* data, 1798266077Sdes size_t len) 1799266077Sdes{ 1800266077Sdes int w = 0; 1801266077Sdes size_t i, printed=0; 1802266077Sdes w += print_hex_buf(s, sl, data, len); 1803266077Sdes for(i=0; i<len; i++) { 1804276541Sdes if(isprint((unsigned char)data[i]) || data[i] == '\t') { 1805266077Sdes if(!printed) { 1806266077Sdes w += sldns_str_print(s, sl, " ("); 1807266077Sdes printed = 1; 1808266077Sdes } 1809266077Sdes w += sldns_str_print(s, sl, "%c", (char)data[i]); 1810266077Sdes } 1811266077Sdes } 1812266077Sdes if(printed) 1813266077Sdes w += sldns_str_print(s, sl, ")"); 1814266077Sdes return w; 1815266077Sdes} 1816266077Sdes 1817266077Sdesint sldns_wire2str_edns_dau_print(char** s, size_t* sl, uint8_t* data, 1818266077Sdes size_t len) 1819266077Sdes{ 1820266077Sdes sldns_lookup_table *lt; 1821266077Sdes size_t i; 1822266077Sdes int w = 0; 1823266077Sdes for(i=0; i<len; i++) { 1824266077Sdes lt = sldns_lookup_by_id(sldns_algorithms, (int)data[i]); 1825266077Sdes if(lt && lt->name) 1826266077Sdes w += sldns_str_print(s, sl, " %s", lt->name); 1827266077Sdes else w += sldns_str_print(s, sl, " %d", (int)data[i]); 1828266077Sdes } 1829266077Sdes return w; 1830266077Sdes} 1831266077Sdes 1832266077Sdesint sldns_wire2str_edns_dhu_print(char** s, size_t* sl, uint8_t* data, 1833266077Sdes size_t len) 1834266077Sdes{ 1835266077Sdes sldns_lookup_table *lt; 1836266077Sdes size_t i; 1837266077Sdes int w = 0; 1838266077Sdes for(i=0; i<len; i++) { 1839266077Sdes lt = sldns_lookup_by_id(sldns_hashes, (int)data[i]); 1840266077Sdes if(lt && lt->name) 1841266077Sdes w += sldns_str_print(s, sl, " %s", lt->name); 1842266077Sdes else w += sldns_str_print(s, sl, " %d", (int)data[i]); 1843266077Sdes } 1844266077Sdes return w; 1845266077Sdes} 1846266077Sdes 1847266077Sdesint sldns_wire2str_edns_n3u_print(char** s, size_t* sl, uint8_t* data, 1848266077Sdes size_t len) 1849266077Sdes{ 1850266077Sdes size_t i; 1851266077Sdes int w = 0; 1852266077Sdes for(i=0; i<len; i++) { 1853266077Sdes if(data[i] == 1) 1854266077Sdes w += sldns_str_print(s, sl, " SHA1"); 1855266077Sdes else w += sldns_str_print(s, sl, " %d", (int)data[i]); 1856266077Sdes } 1857266077Sdes return w; 1858266077Sdes} 1859266077Sdes 1860266077Sdesint sldns_wire2str_edns_subnet_print(char** s, size_t* sl, uint8_t* data, 1861266077Sdes size_t len) 1862266077Sdes{ 1863266077Sdes int w = 0; 1864266077Sdes uint16_t family; 1865266077Sdes uint8_t source, scope; 1866266077Sdes if(len < 4) { 1867266077Sdes w += sldns_str_print(s, sl, "malformed subnet "); 1868266077Sdes w += print_hex_buf(s, sl, data, len); 1869266077Sdes return w; 1870266077Sdes } 1871266077Sdes family = sldns_read_uint16(data); 1872266077Sdes source = data[2]; 1873266077Sdes scope = data[3]; 1874266077Sdes if(family == 1) { 1875266077Sdes /* IP4 */ 1876266077Sdes char buf[64]; 1877266077Sdes uint8_t ip4[4]; 1878266077Sdes memset(ip4, 0, sizeof(ip4)); 1879266077Sdes if(len-4 > 4) { 1880266077Sdes w += sldns_str_print(s, sl, "trailingdata:"); 1881266077Sdes w += print_hex_buf(s, sl, data+4+4, len-4-4); 1882266077Sdes w += sldns_str_print(s, sl, " "); 1883266077Sdes len = 4+4; 1884266077Sdes } 1885266077Sdes memmove(ip4, data+4, len-4); 1886266077Sdes if(!inet_ntop(AF_INET, ip4, buf, (socklen_t)sizeof(buf))) { 1887266077Sdes w += sldns_str_print(s, sl, "ip4ntoperror "); 1888266077Sdes w += print_hex_buf(s, sl, data+4+4, len-4-4); 1889266077Sdes } else { 1890266077Sdes w += sldns_str_print(s, sl, "%s", buf); 1891266077Sdes } 1892266077Sdes } else if(family == 2) { 1893266077Sdes /* IP6 */ 1894266077Sdes char buf[64]; 1895266077Sdes uint8_t ip6[16]; 1896266077Sdes memset(ip6, 0, sizeof(ip6)); 1897266077Sdes if(len-4 > 16) { 1898266077Sdes w += sldns_str_print(s, sl, "trailingdata:"); 1899266077Sdes w += print_hex_buf(s, sl, data+4+16, len-4-16); 1900266077Sdes w += sldns_str_print(s, sl, " "); 1901266077Sdes len = 4+16; 1902266077Sdes } 1903266077Sdes memmove(ip6, data+4, len-4); 1904266077Sdes#ifdef AF_INET6 1905266077Sdes if(!inet_ntop(AF_INET6, ip6, buf, (socklen_t)sizeof(buf))) { 1906266077Sdes w += sldns_str_print(s, sl, "ip6ntoperror "); 1907266077Sdes w += print_hex_buf(s, sl, data+4+4, len-4-4); 1908266077Sdes } else { 1909266077Sdes w += sldns_str_print(s, sl, "%s", buf); 1910266077Sdes } 1911266077Sdes#else 1912266077Sdes w += print_hex_buf(s, sl, data+4+4, len-4-4); 1913266077Sdes#endif 1914266077Sdes } else { 1915266077Sdes /* unknown */ 1916266077Sdes w += sldns_str_print(s, sl, "family %d ", 1917266077Sdes (int)family); 1918266077Sdes w += print_hex_buf(s, sl, data, len); 1919266077Sdes } 1920266077Sdes w += sldns_str_print(s, sl, "/%d scope /%d", (int)source, (int)scope); 1921266077Sdes return w; 1922266077Sdes} 1923266077Sdes 1924356345Scystatic int sldns_wire2str_edns_keepalive_print(char** s, size_t* sl, 1925356345Scy uint8_t* data, size_t len) 1926356345Scy{ 1927356345Scy int w = 0; 1928356345Scy uint16_t timeout; 1929356345Scy if(!(len == 0 || len == 2)) { 1930356345Scy w += sldns_str_print(s, sl, "malformed keepalive "); 1931356345Scy w += print_hex_buf(s, sl, data, len); 1932356345Scy return w; 1933356345Scy } 1934356345Scy if(len == 0 ) { 1935356345Scy w += sldns_str_print(s, sl, "no timeout value (only valid for client option) "); 1936356345Scy } else { 1937356345Scy timeout = sldns_read_uint16(data); 1938356345Scy w += sldns_str_print(s, sl, "timeout value in units of 100ms %u", (int)timeout); 1939356345Scy } 1940356345Scy return w; 1941356345Scy} 1942356345Scy 1943266077Sdesint sldns_wire2str_edns_option_print(char** s, size_t* sl, 1944266077Sdes uint16_t option_code, uint8_t* optdata, size_t optlen) 1945266077Sdes{ 1946266077Sdes int w = 0; 1947266077Sdes w += sldns_wire2str_edns_option_code_print(s, sl, option_code); 1948266077Sdes w += sldns_str_print(s, sl, ": "); 1949266077Sdes switch(option_code) { 1950266077Sdes case LDNS_EDNS_LLQ: 1951266077Sdes w += sldns_wire2str_edns_llq_print(s, sl, optdata, optlen); 1952266077Sdes break; 1953266077Sdes case LDNS_EDNS_UL: 1954266077Sdes w += sldns_wire2str_edns_ul_print(s, sl, optdata, optlen); 1955266077Sdes break; 1956266077Sdes case LDNS_EDNS_NSID: 1957266077Sdes w += sldns_wire2str_edns_nsid_print(s, sl, optdata, optlen); 1958266077Sdes break; 1959266077Sdes case LDNS_EDNS_DAU: 1960266077Sdes w += sldns_wire2str_edns_dau_print(s, sl, optdata, optlen); 1961266077Sdes break; 1962266077Sdes case LDNS_EDNS_DHU: 1963266077Sdes w += sldns_wire2str_edns_dhu_print(s, sl, optdata, optlen); 1964266077Sdes break; 1965266077Sdes case LDNS_EDNS_N3U: 1966266077Sdes w += sldns_wire2str_edns_n3u_print(s, sl, optdata, optlen); 1967266077Sdes break; 1968266077Sdes case LDNS_EDNS_CLIENT_SUBNET: 1969266077Sdes w += sldns_wire2str_edns_subnet_print(s, sl, optdata, optlen); 1970266077Sdes break; 1971356345Scy case LDNS_EDNS_KEEPALIVE: 1972356345Scy w += sldns_wire2str_edns_keepalive_print(s, sl, optdata, optlen); 1973356345Scy break; 1974307729Sdes case LDNS_EDNS_PADDING: 1975307729Sdes w += print_hex_buf(s, sl, optdata, optlen); 1976307729Sdes break; 1977266077Sdes default: 1978266077Sdes /* unknown option code */ 1979266077Sdes w += print_hex_buf(s, sl, optdata, optlen); 1980266077Sdes break; 1981266077Sdes } 1982266077Sdes return w; 1983266077Sdes} 1984266077Sdes 1985266077Sdes/** print the edns options to string */ 1986266077Sdesstatic int 1987266077Sdesprint_edns_opts(char** s, size_t* sl, uint8_t* rdata, size_t rdatalen) 1988266077Sdes{ 1989266077Sdes uint16_t option_code, option_len; 1990266077Sdes int w = 0; 1991266077Sdes while(rdatalen > 0) { 1992266077Sdes /* option name */ 1993266077Sdes if(rdatalen < 4) { 1994266077Sdes w += sldns_str_print(s, sl, " ; malformed: "); 1995266077Sdes w += print_hex_buf(s, sl, rdata, rdatalen); 1996266077Sdes return w; 1997266077Sdes } 1998266077Sdes option_code = sldns_read_uint16(rdata); 1999266077Sdes option_len = sldns_read_uint16(rdata+2); 2000266077Sdes rdata += 4; 2001266077Sdes rdatalen -= 4; 2002266077Sdes 2003266077Sdes /* option value */ 2004266077Sdes if(rdatalen < (size_t)option_len) { 2005266077Sdes w += sldns_str_print(s, sl, " ; malformed "); 2006266077Sdes w += sldns_wire2str_edns_option_code_print(s, sl, 2007266077Sdes option_code); 2008266077Sdes w += sldns_str_print(s, sl, ": "); 2009266077Sdes w += print_hex_buf(s, sl, rdata, rdatalen); 2010266077Sdes return w; 2011266077Sdes } 2012266077Sdes w += sldns_str_print(s, sl, " ; "); 2013266077Sdes w += sldns_wire2str_edns_option_print(s, sl, option_code, 2014266077Sdes rdata, option_len); 2015266077Sdes rdata += option_len; 2016266077Sdes rdatalen -= option_len; 2017266077Sdes } 2018266077Sdes return w; 2019266077Sdes} 2020266077Sdes 2021266077Sdesint sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str, 2022266077Sdes size_t* str_len, uint8_t* pkt, size_t pktlen) 2023266077Sdes{ 2024266077Sdes int w = 0; 2025266077Sdes uint8_t ext_rcode, edns_version; 2026266077Sdes uint16_t udpsize, edns_bits, rdatalen; 2027266077Sdes w += sldns_str_print(str, str_len, "; EDNS:"); 2028266077Sdes 2029266077Sdes /* some input checks, domain name */ 2030266077Sdes if(*data_len < 1+10) 2031266077Sdes return w + print_remainder_hex("Error malformed 0x", 2032266077Sdes data, data_len, str, str_len); 2033266077Sdes if(*data[0] != 0) { 2034266077Sdes return w + print_remainder_hex("Error nonrootdname 0x", 2035266077Sdes data, data_len, str, str_len); 2036266077Sdes } 2037266077Sdes (*data)++; 2038266077Sdes (*data_len)--; 2039266077Sdes 2040266077Sdes /* check type and read fixed contents */ 2041266077Sdes if(sldns_read_uint16((*data)) != LDNS_RR_TYPE_OPT) { 2042266077Sdes return w + print_remainder_hex("Error nottypeOPT 0x", 2043266077Sdes data, data_len, str, str_len); 2044266077Sdes } 2045266077Sdes udpsize = sldns_read_uint16((*data)+2); 2046266077Sdes ext_rcode = (*data)[4]; 2047266077Sdes edns_version = (*data)[5]; 2048266077Sdes edns_bits = sldns_read_uint16((*data)+6); 2049266077Sdes rdatalen = sldns_read_uint16((*data)+8); 2050266077Sdes (*data)+=10; 2051266077Sdes (*data_len)-=10; 2052266077Sdes 2053266077Sdes w += sldns_str_print(str, str_len, " version: %u;", 2054266077Sdes (unsigned)edns_version); 2055266077Sdes w += sldns_str_print(str, str_len, " flags:"); 2056266077Sdes if((edns_bits & LDNS_EDNS_MASK_DO_BIT)) 2057266077Sdes w += sldns_str_print(str, str_len, " do"); 2058266077Sdes /* the extended rcode is the value set, shifted four bits, 2059266077Sdes * and or'd with the original rcode */ 2060266077Sdes if(ext_rcode) { 2061266077Sdes int rc = ((int)ext_rcode)<<4; 2062266077Sdes if(pkt && pktlen >= LDNS_HEADER_SIZE) 2063266077Sdes rc |= LDNS_RCODE_WIRE(pkt); 2064266077Sdes w += sldns_str_print(str, str_len, " ; ext-rcode: %d", rc); 2065266077Sdes } 2066266077Sdes w += sldns_str_print(str, str_len, " ; udp: %u", (unsigned)udpsize); 2067266077Sdes 2068266077Sdes if(rdatalen) { 2069356345Scy if((size_t)*data_len < rdatalen) { 2070266077Sdes w += sldns_str_print(str, str_len, 2071266077Sdes " ; Error EDNS rdata too short; "); 2072356345Scy rdatalen = (uint16_t)*data_len; 2073266077Sdes } 2074266077Sdes w += print_edns_opts(str, str_len, *data, rdatalen); 2075266077Sdes (*data) += rdatalen; 2076266077Sdes (*data_len) -= rdatalen; 2077266077Sdes } 2078266077Sdes w += sldns_str_print(str, str_len, "\n"); 2079266077Sdes return w; 2080266077Sdes} 2081