1266077Sdes/** 2266077Sdes * str2wire.c - read txt presentation of RRs 3266077Sdes * 4266077Sdes * (c) NLnet Labs, 2005-2006 5266077Sdes * 6266077Sdes * See the file LICENSE for the license 7266077Sdes */ 8266077Sdes 9266077Sdes/** 10266077Sdes * \file 11266077Sdes * 12266077Sdes * Parses text to wireformat. 13266077Sdes */ 14266077Sdes#include "config.h" 15287915Sdes#include "sldns/str2wire.h" 16287915Sdes#include "sldns/wire2str.h" 17287915Sdes#include "sldns/sbuffer.h" 18287915Sdes#include "sldns/parse.h" 19287915Sdes#include "sldns/parseutil.h" 20266077Sdes#include <ctype.h> 21266077Sdes#ifdef HAVE_TIME_H 22266077Sdes#include <time.h> 23266077Sdes#endif 24266077Sdes#ifdef HAVE_NETDB_H 25266077Sdes#include <netdb.h> 26266077Sdes#endif 27266077Sdes 28266077Sdes/** return an error */ 29266077Sdes#define RET_ERR(e, off) ((int)((e)|((off)<<LDNS_WIREPARSE_SHIFT))) 30266077Sdes/** Move parse error but keep its ID */ 31266077Sdes#define RET_ERR_SHIFT(e, move) RET_ERR(LDNS_WIREPARSE_ERROR(e), LDNS_WIREPARSE_OFFSET(e)+(move)); 32266077Sdes#define LDNS_IP6ADDRLEN (128/8) 33266077Sdes 34266077Sdes/* 35266077Sdes * No special care is taken, all dots are translated into 36266077Sdes * label separators. 37266077Sdes * @param rel: true if the domain is not absolute (not terminated in .). 38266077Sdes * The output is then still terminated with a '0' rootlabel. 39266077Sdes */ 40266077Sdesstatic int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf, 41266077Sdes size_t* olen, int* rel) 42266077Sdes{ 43266077Sdes size_t len; 44266077Sdes 45266077Sdes const char *s; 46266077Sdes uint8_t *q, *pq, label_len; 47266077Sdes 48266077Sdes if(rel) *rel = 0; 49266077Sdes len = strlen((char*)str); 50266077Sdes /* octet representation can make strings a lot longer than actual length */ 51266077Sdes if (len > LDNS_MAX_DOMAINLEN * 4) { 52266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, 0); 53266077Sdes } 54266077Sdes if (0 == len) { 55266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_UNDERFLOW, 0); 56266077Sdes } 57266077Sdes 58266077Sdes /* root label */ 59266077Sdes if (1 == len && *str == '.') { 60266077Sdes if(*olen < 1) 61266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0); 62266077Sdes buf[0] = 0; 63266077Sdes *olen = 1; 64266077Sdes return LDNS_WIREPARSE_ERR_OK; 65266077Sdes } 66266077Sdes 67266077Sdes /* get on with the rest */ 68266077Sdes 69266077Sdes /* s is on the current character in the string 70266077Sdes * pq points to where the labellength is going to go 71266077Sdes * label_len keeps track of the current label's length 72266077Sdes * q builds the dname inside the buf array 73266077Sdes */ 74266077Sdes len = 0; 75266077Sdes if(*olen < 1) 76266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 0); 77266077Sdes q = buf+1; 78266077Sdes pq = buf; 79266077Sdes label_len = 0; 80266077Sdes for (s = str; *s; s++, q++) { 81266077Sdes if (q >= buf + *olen) 82266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf); 83361435Scy if (q >= buf + LDNS_MAX_DOMAINLEN) 84266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf); 85266077Sdes switch (*s) { 86266077Sdes case '.': 87266077Sdes if (label_len > LDNS_MAX_LABELLEN) { 88266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf); 89266077Sdes } 90266077Sdes if (label_len == 0) { 91266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf); 92266077Sdes } 93266077Sdes len += label_len + 1; 94266077Sdes *q = 0; 95266077Sdes *pq = label_len; 96266077Sdes label_len = 0; 97266077Sdes pq = q; 98266077Sdes break; 99266077Sdes case '\\': 100266077Sdes /* octet value or literal char */ 101266077Sdes s += 1; 102266077Sdes if (!sldns_parse_escape(q, &s)) { 103266077Sdes *q = 0; 104266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE, q-buf); 105266077Sdes } 106266077Sdes s -= 1; 107266077Sdes label_len++; 108266077Sdes break; 109266077Sdes default: 110266077Sdes *q = (uint8_t)*s; 111266077Sdes label_len++; 112266077Sdes } 113266077Sdes } 114266077Sdes 115266077Sdes /* add root label if last char was not '.' */ 116266077Sdes if(label_len != 0) { 117266077Sdes if(rel) *rel = 1; 118266077Sdes if (q >= buf + *olen) 119266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf); 120361435Scy if (q >= buf + LDNS_MAX_DOMAINLEN) { 121266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf); 122266077Sdes } 123266077Sdes if (label_len > LDNS_MAX_LABELLEN) { 124266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, q-buf); 125266077Sdes } 126266077Sdes if (label_len == 0) { /* label_len 0 but not . at end? */ 127266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_EMPTY_LABEL, q-buf); 128266077Sdes } 129266077Sdes len += label_len + 1; 130266077Sdes *pq = label_len; 131266077Sdes *q = 0; 132266077Sdes } 133266077Sdes len++; 134266077Sdes *olen = len; 135266077Sdes 136266077Sdes return LDNS_WIREPARSE_ERR_OK; 137266077Sdes} 138266077Sdes 139266077Sdesint sldns_str2wire_dname_buf(const char* str, uint8_t* buf, size_t* len) 140266077Sdes{ 141266077Sdes return sldns_str2wire_dname_buf_rel(str, buf, len, NULL); 142266077Sdes} 143266077Sdes 144266077Sdesint sldns_str2wire_dname_buf_origin(const char* str, uint8_t* buf, size_t* len, 145266077Sdes uint8_t* origin, size_t origin_len) 146266077Sdes{ 147266077Sdes size_t dlen = *len; 148266077Sdes int rel = 0; 149266077Sdes int s = sldns_str2wire_dname_buf_rel(str, buf, &dlen, &rel); 150266077Sdes if(s) return s; 151266077Sdes 152266077Sdes if(rel && origin && dlen > 0) { 153356345Scy if((unsigned)dlen >= 0x00ffffffU || 154356345Scy (unsigned)origin_len >= 0x00ffffffU) 155356345Scy /* guard against integer overflow in addition */ 156356345Scy return RET_ERR(LDNS_WIREPARSE_ERR_GENERAL, *len); 157266077Sdes if(dlen + origin_len - 1 > LDNS_MAX_DOMAINLEN) 158266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, 159266077Sdes LDNS_MAX_DOMAINLEN); 160266077Sdes if(dlen + origin_len - 1 > *len) 161266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 162266077Sdes *len); 163266077Sdes memmove(buf+dlen-1, origin, origin_len); 164266077Sdes *len = dlen + origin_len - 1; 165266077Sdes } else 166266077Sdes *len = dlen; 167266077Sdes return LDNS_WIREPARSE_ERR_OK; 168266077Sdes} 169266077Sdes 170266077Sdesuint8_t* sldns_str2wire_dname(const char* str, size_t* len) 171266077Sdes{ 172266077Sdes uint8_t dname[LDNS_MAX_DOMAINLEN+1]; 173266077Sdes *len = sizeof(dname); 174266077Sdes if(sldns_str2wire_dname_buf(str, dname, len) == 0) { 175356345Scy uint8_t* r; 176356345Scy if(*len > sizeof(dname)) return NULL; 177356345Scy r = (uint8_t*)malloc(*len); 178266077Sdes if(r) return memcpy(r, dname, *len); 179266077Sdes } 180266077Sdes *len = 0; 181266077Sdes return NULL; 182266077Sdes} 183266077Sdes 184266077Sdes/** read owner name */ 185266077Sdesstatic int 186266077Sdesrrinternal_get_owner(sldns_buffer* strbuf, uint8_t* rr, size_t* len, 187266077Sdes size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev, 188266077Sdes size_t prev_len, char* token, size_t token_len) 189266077Sdes{ 190266077Sdes /* split the rr in its parts -1 signals trouble */ 191266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 192266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, 193266077Sdes sldns_buffer_position(strbuf)); 194266077Sdes } 195266077Sdes 196356345Scy if(token_len < 2) /* make sure there is space to read "@" or "" */ 197356345Scy return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 198356345Scy sldns_buffer_position(strbuf)); 199356345Scy if(token[0]=='@' && token[1]=='\0') { 200266077Sdes uint8_t* tocopy; 201266077Sdes if (origin) { 202266077Sdes *dname_len = origin_len; 203266077Sdes tocopy = origin; 204266077Sdes } else if (prev) { 205266077Sdes *dname_len = prev_len; 206266077Sdes tocopy = prev; 207266077Sdes } else { 208266077Sdes /* default to root */ 209266077Sdes *dname_len = 1; 210266077Sdes tocopy = (uint8_t*)"\0"; 211266077Sdes } 212266077Sdes if(*len < *dname_len) 213266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 214266077Sdes sldns_buffer_position(strbuf)); 215266077Sdes memmove(rr, tocopy, *dname_len); 216296415Sdes } else if(*token == '\0') { 217266077Sdes /* no ownername was given, try prev, if that fails 218266077Sdes * origin, else default to root */ 219266077Sdes uint8_t* tocopy; 220266077Sdes if(prev) { 221266077Sdes *dname_len = prev_len; 222266077Sdes tocopy = prev; 223266077Sdes } else if(origin) { 224266077Sdes *dname_len = origin_len; 225266077Sdes tocopy = origin; 226266077Sdes } else { 227266077Sdes *dname_len = 1; 228266077Sdes tocopy = (uint8_t*)"\0"; 229266077Sdes } 230266077Sdes if(*len < *dname_len) 231266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 232266077Sdes sldns_buffer_position(strbuf)); 233266077Sdes memmove(rr, tocopy, *dname_len); 234266077Sdes } else { 235266077Sdes size_t dlen = *len; 236266077Sdes int s = sldns_str2wire_dname_buf_origin(token, rr, &dlen, 237266077Sdes origin, origin_len); 238266077Sdes if(s) return RET_ERR_SHIFT(s, 239266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 240266077Sdes *dname_len = dlen; 241266077Sdes } 242266077Sdes return LDNS_WIREPARSE_ERR_OK; 243266077Sdes} 244266077Sdes 245266077Sdes/** read ttl */ 246266077Sdesstatic int 247266077Sdesrrinternal_get_ttl(sldns_buffer* strbuf, char* token, size_t token_len, 248266077Sdes int* not_there, uint32_t* ttl, uint32_t default_ttl) 249266077Sdes{ 250266077Sdes const char* endptr; 251266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 252266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TTL, 253266077Sdes sldns_buffer_position(strbuf)); 254266077Sdes } 255266077Sdes *ttl = (uint32_t) sldns_str2period(token, &endptr); 256266077Sdes 257276541Sdes if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) { 258266077Sdes *not_there = 1; 259266077Sdes /* ah, it's not there or something */ 260266077Sdes if (default_ttl == 0) { 261266077Sdes *ttl = LDNS_DEFAULT_TTL; 262266077Sdes } else { 263266077Sdes *ttl = default_ttl; 264266077Sdes } 265266077Sdes } 266266077Sdes return LDNS_WIREPARSE_ERR_OK; 267266077Sdes} 268266077Sdes 269266077Sdes/** read class */ 270266077Sdesstatic int 271266077Sdesrrinternal_get_class(sldns_buffer* strbuf, char* token, size_t token_len, 272266077Sdes int* not_there, uint16_t* cl) 273266077Sdes{ 274266077Sdes /* if 'not_there' then we got token from previous parse routine */ 275266077Sdes if(!*not_there) { 276266077Sdes /* parse new token for class */ 277266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 278266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_CLASS, 279266077Sdes sldns_buffer_position(strbuf)); 280266077Sdes } 281266077Sdes } else *not_there = 0; 282266077Sdes *cl = sldns_get_rr_class_by_name(token); 283266077Sdes /* class can be left out too, assume IN, current token must be type */ 284266077Sdes if(*cl == 0 && strcmp(token, "CLASS0") != 0) { 285266077Sdes *not_there = 1; 286266077Sdes *cl = LDNS_RR_CLASS_IN; 287266077Sdes } 288266077Sdes return LDNS_WIREPARSE_ERR_OK; 289266077Sdes} 290266077Sdes 291266077Sdes/** read type */ 292266077Sdesstatic int 293266077Sdesrrinternal_get_type(sldns_buffer* strbuf, char* token, size_t token_len, 294266077Sdes int* not_there, uint16_t* tp) 295266077Sdes{ 296266077Sdes /* if 'not_there' then we got token from previous parse routine */ 297266077Sdes if(!*not_there) { 298266077Sdes /* parse new token for type */ 299266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 300266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE, 301266077Sdes sldns_buffer_position(strbuf)); 302266077Sdes } 303266077Sdes } 304266077Sdes *tp = sldns_get_rr_type_by_name(token); 305266077Sdes if(*tp == 0 && strcmp(token, "TYPE0") != 0) { 306266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE, 307266077Sdes sldns_buffer_position(strbuf)); 308266077Sdes } 309266077Sdes return LDNS_WIREPARSE_ERR_OK; 310266077Sdes} 311266077Sdes 312266077Sdes/** put type, class, ttl into rr buffer */ 313266077Sdesstatic int 314266077Sdesrrinternal_write_typeclassttl(sldns_buffer* strbuf, uint8_t* rr, size_t len, 315266077Sdes size_t dname_len, uint16_t tp, uint16_t cl, uint32_t ttl, int question) 316266077Sdes{ 317266077Sdes if(question) { 318266077Sdes /* question is : name, type, class */ 319266077Sdes if(dname_len + 4 > len) 320266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 321266077Sdes sldns_buffer_position(strbuf)); 322266077Sdes sldns_write_uint16(rr+dname_len, tp); 323266077Sdes sldns_write_uint16(rr+dname_len+2, cl); 324266077Sdes return LDNS_WIREPARSE_ERR_OK; 325266077Sdes } 326266077Sdes 327266077Sdes /* type(2), class(2), ttl(4), rdatalen(2 (later)) = 10 */ 328266077Sdes if(dname_len + 10 > len) 329266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 330266077Sdes sldns_buffer_position(strbuf)); 331266077Sdes sldns_write_uint16(rr+dname_len, tp); 332266077Sdes sldns_write_uint16(rr+dname_len+2, cl); 333266077Sdes sldns_write_uint32(rr+dname_len+4, ttl); 334266077Sdes sldns_write_uint16(rr+dname_len+8, 0); /* rdatalen placeholder */ 335266077Sdes return LDNS_WIREPARSE_ERR_OK; 336266077Sdes} 337266077Sdes 338266077Sdes/** find delimiters for type */ 339266077Sdesstatic const char* 340356345Scyrrinternal_get_delims(sldns_rdf_type rdftype, size_t r_cnt, size_t r_max) 341266077Sdes{ 342266077Sdes switch(rdftype) { 343266077Sdes case LDNS_RDF_TYPE_B64 : 344266077Sdes case LDNS_RDF_TYPE_HEX : /* These rdf types may con- */ 345266077Sdes case LDNS_RDF_TYPE_LOC : /* tain whitespace, only if */ 346266077Sdes case LDNS_RDF_TYPE_WKS : /* it is the last rd field. */ 347266077Sdes case LDNS_RDF_TYPE_IPSECKEY : 348266077Sdes case LDNS_RDF_TYPE_NSEC : if (r_cnt == r_max - 1) { 349276541Sdes return "\n"; 350266077Sdes } 351266077Sdes break; 352266077Sdes default : break; 353266077Sdes } 354266077Sdes return "\n\t "; 355266077Sdes} 356266077Sdes 357266077Sdes/* Syntactic sugar for sldns_rr_new_frm_str_internal */ 358266077Sdesstatic int 359266077Sdessldns_rdf_type_maybe_quoted(sldns_rdf_type rdf_type) 360266077Sdes{ 361266077Sdes return rdf_type == LDNS_RDF_TYPE_STR || 362266077Sdes rdf_type == LDNS_RDF_TYPE_LONG_STR; 363266077Sdes} 364266077Sdes 365266077Sdes/** see if rdata is quoted */ 366266077Sdesstatic int 367266077Sdesrrinternal_get_quoted(sldns_buffer* strbuf, const char** delimiters, 368266077Sdes sldns_rdf_type rdftype) 369266077Sdes{ 370266077Sdes if(sldns_rdf_type_maybe_quoted(rdftype) && 371266077Sdes sldns_buffer_remaining(strbuf) > 0) { 372266077Sdes 373266077Sdes /* skip spaces */ 374266077Sdes while(sldns_buffer_remaining(strbuf) > 0 && 375266077Sdes *(sldns_buffer_current(strbuf)) == ' ') { 376266077Sdes sldns_buffer_skip(strbuf, 1); 377266077Sdes } 378266077Sdes 379266077Sdes if(sldns_buffer_remaining(strbuf) > 0 && 380266077Sdes *(sldns_buffer_current(strbuf)) == '\"') { 381266077Sdes *delimiters = "\"\0"; 382266077Sdes sldns_buffer_skip(strbuf, 1); 383266077Sdes return 1; 384266077Sdes } 385266077Sdes } 386266077Sdes return 0; 387266077Sdes} 388266077Sdes 389266077Sdes/** spool hex data into rdata */ 390266077Sdesstatic int 391266077Sdesrrinternal_spool_hex(char* token, uint8_t* rr, size_t rr_len, 392266077Sdes size_t rr_cur_len, size_t* cur_hex_data_size, size_t hex_data_size) 393266077Sdes{ 394266077Sdes char* p = token; 395266077Sdes while(*p) { 396276541Sdes if(isspace((unsigned char)*p)) { 397266077Sdes p++; 398266077Sdes continue; 399266077Sdes } 400276541Sdes if(!isxdigit((unsigned char)*p)) 401266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 402266077Sdes p-token); 403266077Sdes if(*cur_hex_data_size >= hex_data_size) 404266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 405266077Sdes p-token); 406266077Sdes /* extra robust check */ 407266077Sdes if(rr_cur_len+(*cur_hex_data_size)/2 >= rr_len) 408266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 409266077Sdes p-token); 410266077Sdes /* see if 16s or 1s */ 411266077Sdes if( ((*cur_hex_data_size)&1) == 0) { 412266077Sdes rr[rr_cur_len+(*cur_hex_data_size)/2] = 413266077Sdes (uint8_t)sldns_hexdigit_to_int(*p)*16; 414266077Sdes } else { 415266077Sdes rr[rr_cur_len+(*cur_hex_data_size)/2] += 416266077Sdes (uint8_t)sldns_hexdigit_to_int(*p); 417266077Sdes } 418266077Sdes p++; 419266077Sdes (*cur_hex_data_size)++; 420266077Sdes } 421266077Sdes return LDNS_WIREPARSE_ERR_OK; 422266077Sdes} 423266077Sdes 424266077Sdes/** read unknown rr type format */ 425266077Sdesstatic int 426266077Sdesrrinternal_parse_unknown(sldns_buffer* strbuf, char* token, size_t token_len, 427266077Sdes uint8_t* rr, size_t* rr_len, size_t* rr_cur_len, size_t pre_data_pos) 428266077Sdes{ 429266077Sdes const char* delim = "\n\t "; 430266077Sdes size_t hex_data_size, cur_hex_data_size; 431266077Sdes /* go back to before \# 432266077Sdes * and skip it while setting delimiters better 433266077Sdes */ 434266077Sdes sldns_buffer_set_position(strbuf, pre_data_pos); 435266077Sdes if(sldns_bget_token(strbuf, token, delim, token_len) == -1) 436266077Sdes return LDNS_WIREPARSE_ERR_GENERAL; /* should not fail */ 437266077Sdes /* read rdata octet length */ 438266077Sdes if(sldns_bget_token(strbuf, token, delim, token_len) == -1) { 439266077Sdes /* something goes very wrong here */ 440266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 441266077Sdes sldns_buffer_position(strbuf)); 442266077Sdes } 443266077Sdes hex_data_size = (size_t)atoi(token); 444266077Sdes if(hex_data_size > LDNS_MAX_RDFLEN || 445266077Sdes *rr_cur_len + hex_data_size > *rr_len) { 446266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 447266077Sdes sldns_buffer_position(strbuf)); 448266077Sdes } 449266077Sdes /* copy hex chars into hex str (2 chars per byte) */ 450266077Sdes hex_data_size *= 2; 451266077Sdes cur_hex_data_size = 0; 452266077Sdes while(cur_hex_data_size < hex_data_size) { 453266077Sdes int status; 454266077Sdes ssize_t c = sldns_bget_token(strbuf, token, delim, token_len); 455266077Sdes if((status = rrinternal_spool_hex(token, rr, *rr_len, 456266077Sdes *rr_cur_len, &cur_hex_data_size, hex_data_size)) != 0) 457266077Sdes return RET_ERR_SHIFT(status, 458266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 459266077Sdes if(c == -1) { 460266077Sdes if(cur_hex_data_size != hex_data_size) 461266077Sdes return RET_ERR( 462266077Sdes LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 463266077Sdes sldns_buffer_position(strbuf)); 464266077Sdes break; 465266077Sdes } 466266077Sdes } 467266077Sdes *rr_cur_len += hex_data_size/2; 468266077Sdes return LDNS_WIREPARSE_ERR_OK; 469266077Sdes} 470266077Sdes 471266077Sdes/** parse normal RR rdata element */ 472266077Sdesstatic int 473266077Sdesrrinternal_parse_rdf(sldns_buffer* strbuf, char* token, size_t token_len, 474266077Sdes uint8_t* rr, size_t rr_len, size_t* rr_cur_len, sldns_rdf_type rdftype, 475356345Scy uint16_t rr_type, size_t r_cnt, size_t r_max, size_t dname_len, 476266077Sdes uint8_t* origin, size_t origin_len) 477266077Sdes{ 478266077Sdes size_t len; 479266077Sdes int status; 480266077Sdes 481266077Sdes switch(rdftype) { 482266077Sdes case LDNS_RDF_TYPE_DNAME: 483266077Sdes /* check if the origin should be used or concatenated */ 484266077Sdes if(strcmp(token, "@") == 0) { 485266077Sdes uint8_t* tocopy; 486266077Sdes size_t copylen; 487266077Sdes if(origin) { 488266077Sdes copylen = origin_len; 489266077Sdes tocopy = origin; 490266077Sdes } else if(rr_type == LDNS_RR_TYPE_SOA) { 491266077Sdes copylen = dname_len; 492266077Sdes tocopy = rr; /* copy rr owner name */ 493266077Sdes } else { 494266077Sdes copylen = 1; 495266077Sdes tocopy = (uint8_t*)"\0"; 496266077Sdes } 497266077Sdes if((*rr_cur_len) + copylen > rr_len) 498266077Sdes return RET_ERR( 499266077Sdes LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 500266077Sdes sldns_buffer_position(strbuf)); 501266077Sdes memmove(rr+*rr_cur_len, tocopy, copylen); 502266077Sdes (*rr_cur_len) += copylen; 503266077Sdes } else { 504266077Sdes size_t dlen = rr_len - (*rr_cur_len); 505266077Sdes int s = sldns_str2wire_dname_buf_origin(token, 506266077Sdes rr+*rr_cur_len, &dlen, origin, origin_len); 507266077Sdes if(s) return RET_ERR_SHIFT(s, 508266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 509266077Sdes (*rr_cur_len) += dlen; 510266077Sdes } 511266077Sdes return LDNS_WIREPARSE_ERR_OK; 512266077Sdes 513266077Sdes case LDNS_RDF_TYPE_HEX: 514266077Sdes case LDNS_RDF_TYPE_B64: 515266077Sdes /* When this is the last rdata field, then the 516266077Sdes * rest should be read in (cause then these 517266077Sdes * rdf types may contain spaces). */ 518266077Sdes if(r_cnt == r_max - 1) { 519266077Sdes size_t tlen = strlen(token); 520266077Sdes (void)sldns_bget_token(strbuf, token+tlen, "\n", 521266077Sdes token_len - tlen); 522266077Sdes } 523266077Sdes break; 524266077Sdes default: 525266077Sdes break; 526266077Sdes } 527266077Sdes 528266077Sdes len = rr_len - (*rr_cur_len); 529266077Sdes if((status=sldns_str2wire_rdf_buf(token, rr+(*rr_cur_len), &len, 530266077Sdes rdftype)) != 0) 531266077Sdes return RET_ERR_SHIFT(status, 532266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 533266077Sdes *rr_cur_len += len; 534266077Sdes return LDNS_WIREPARSE_ERR_OK; 535266077Sdes} 536266077Sdes 537266077Sdes/** 538266077Sdes * Parse one rdf token. Takes care of quotes and parenthesis. 539266077Sdes */ 540266077Sdesstatic int 541266077Sdessldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len, 542266077Sdes int* quoted, int* parens, size_t* pre_data_pos, 543266077Sdes const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen) 544266077Sdes{ 545266077Sdes size_t slen; 546266077Sdes 547266077Sdes /* skip spaces */ 548266077Sdes while(sldns_buffer_remaining(strbuf) > 0 && !*quoted && 549266077Sdes *(sldns_buffer_current(strbuf)) == ' ') { 550266077Sdes sldns_buffer_skip(strbuf, 1); 551266077Sdes } 552266077Sdes 553266077Sdes *pre_data_pos = sldns_buffer_position(strbuf); 554266077Sdes if(sldns_bget_token_par(strbuf, token, (*quoted)?"\"":delimiters, 555266077Sdes token_len, parens, (*quoted)?NULL:" \t") == -1) { 556266077Sdes return 0; 557266077Sdes } 558266077Sdes slen = strlen(token); 559266077Sdes /* check if not quoted yet, and we have encountered quotes */ 560266077Sdes if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) && 561266077Sdes slen >= 2 && 562266077Sdes (token[0] == '"' || token[0] == '\'') && 563266077Sdes (token[slen-1] == '"' || token[slen-1] == '\'')) { 564266077Sdes /* move token two smaller (quotes) with endnull */ 565266077Sdes memmove(token, token+1, slen-2); 566266077Sdes token[slen-2] = 0; 567266077Sdes slen -= 2; 568266077Sdes *quoted = 1; 569266077Sdes } else if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) && 570266077Sdes slen >= 2 && 571266077Sdes (token[0] == '"' || token[0] == '\'')) { 572266077Sdes /* got the start quote (remove it) but read remainder 573266077Sdes * of quoted string as well into remainder of token */ 574266077Sdes memmove(token, token+1, slen-1); 575266077Sdes token[slen-1] = 0; 576266077Sdes slen -= 1; 577266077Sdes *quoted = 1; 578266077Sdes /* rewind buffer over skipped whitespace */ 579266077Sdes while(sldns_buffer_position(strbuf) > 0 && 580266077Sdes (sldns_buffer_current(strbuf)[-1] == ' ' || 581266077Sdes sldns_buffer_current(strbuf)[-1] == '\t')) { 582266077Sdes sldns_buffer_skip(strbuf, -1); 583266077Sdes } 584266077Sdes if(sldns_bget_token_par(strbuf, token+slen, 585266077Sdes "\"", token_len-slen, 586266077Sdes parens, NULL) == -1) { 587266077Sdes return 0; 588266077Sdes } 589266077Sdes slen = strlen(token); 590266077Sdes } 591266077Sdes *token_strlen = slen; 592266077Sdes return 1; 593266077Sdes} 594266077Sdes 595266077Sdes/** Add space and one more rdf token onto the existing token string. */ 596266077Sdesstatic int 597266077Sdessldns_affix_token(sldns_buffer* strbuf, char* token, size_t* token_len, 598266077Sdes int* quoted, int* parens, size_t* pre_data_pos, 599266077Sdes const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen) 600266077Sdes{ 601266077Sdes size_t addlen = *token_len - *token_strlen; 602266077Sdes size_t addstrlen = 0; 603266077Sdes 604266077Sdes /* add space */ 605266077Sdes if(addlen < 1) return 0; 606266077Sdes token[*token_strlen] = ' '; 607266077Sdes token[++(*token_strlen)] = 0; 608266077Sdes 609266077Sdes /* read another token */ 610266077Sdes addlen = *token_len - *token_strlen; 611266077Sdes if(!sldns_parse_rdf_token(strbuf, token+*token_strlen, addlen, quoted, 612266077Sdes parens, pre_data_pos, delimiters, rdftype, &addstrlen)) 613266077Sdes return 0; 614266077Sdes (*token_strlen) += addstrlen; 615266077Sdes return 1; 616266077Sdes} 617266077Sdes 618266077Sdes/** parse rdata from string into rr buffer(-remainder after dname). */ 619266077Sdesstatic int 620266077Sdesrrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, 621266077Sdes uint8_t* rr, size_t* rr_len, size_t dname_len, uint16_t rr_type, 622266077Sdes uint8_t* origin, size_t origin_len) 623266077Sdes{ 624266077Sdes const sldns_rr_descriptor *desc = sldns_rr_descript((uint16_t)rr_type); 625356345Scy size_t r_cnt, r_min, r_max; 626266077Sdes size_t rr_cur_len = dname_len + 10, pre_data_pos, token_strlen; 627266077Sdes int was_unknown_rr_format = 0, parens = 0, status, quoted; 628266077Sdes const char* delimiters; 629266077Sdes sldns_rdf_type rdftype; 630266077Sdes /* a desc is always returned */ 631266077Sdes if(!desc) return LDNS_WIREPARSE_ERR_GENERAL; 632266077Sdes r_max = sldns_rr_descriptor_maximum(desc); 633266077Sdes r_min = sldns_rr_descriptor_minimum(desc); 634266077Sdes /* robust check */ 635266077Sdes if(rr_cur_len > *rr_len) 636266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 637266077Sdes sldns_buffer_position(strbuf)); 638266077Sdes 639266077Sdes /* because number of fields can be variable, we can't rely on 640266077Sdes * _maximum() only */ 641266077Sdes for(r_cnt=0; r_cnt < r_max; r_cnt++) { 642266077Sdes rdftype = sldns_rr_descriptor_field_type(desc, r_cnt); 643266077Sdes delimiters = rrinternal_get_delims(rdftype, r_cnt, r_max); 644266077Sdes quoted = rrinternal_get_quoted(strbuf, &delimiters, rdftype); 645266077Sdes 646266077Sdes if(!sldns_parse_rdf_token(strbuf, token, token_len, "ed, 647266077Sdes &parens, &pre_data_pos, delimiters, rdftype, 648266077Sdes &token_strlen)) 649266077Sdes break; 650266077Sdes 651266077Sdes /* rfc3597 specifies that any type can be represented 652266077Sdes * with \# method, which can contain spaces... 653266077Sdes * it does specify size though... */ 654266077Sdes 655266077Sdes /* unknown RR data */ 656266077Sdes if(token_strlen>=2 && strncmp(token, "\\#", 2) == 0 && 657266077Sdes !quoted && (token_strlen == 2 || token[2]==' ')) { 658266077Sdes was_unknown_rr_format = 1; 659266077Sdes if((status=rrinternal_parse_unknown(strbuf, token, 660266077Sdes token_len, rr, rr_len, &rr_cur_len, 661266077Sdes pre_data_pos)) != 0) 662266077Sdes return status; 663266077Sdes } else if(token_strlen > 0 || quoted) { 664266077Sdes if(rdftype == LDNS_RDF_TYPE_HIP) { 665266077Sdes /* affix the HIT and PK fields, with a space */ 666266077Sdes if(!sldns_affix_token(strbuf, token, 667266077Sdes &token_len, "ed, &parens, 668266077Sdes &pre_data_pos, delimiters, 669266077Sdes rdftype, &token_strlen)) 670266077Sdes break; 671266077Sdes if(!sldns_affix_token(strbuf, token, 672266077Sdes &token_len, "ed, &parens, 673266077Sdes &pre_data_pos, delimiters, 674266077Sdes rdftype, &token_strlen)) 675266077Sdes break; 676356345Scy } else if(rdftype == LDNS_RDF_TYPE_INT16_DATA && 677356345Scy strcmp(token, "0")!=0) { 678356345Scy /* affix len and b64 fields */ 679356345Scy if(!sldns_affix_token(strbuf, token, 680356345Scy &token_len, "ed, &parens, 681356345Scy &pre_data_pos, delimiters, 682356345Scy rdftype, &token_strlen)) 683356345Scy break; 684266077Sdes } 685266077Sdes 686266077Sdes /* normal RR */ 687266077Sdes if((status=rrinternal_parse_rdf(strbuf, token, 688266077Sdes token_len, rr, *rr_len, &rr_cur_len, rdftype, 689266077Sdes rr_type, r_cnt, r_max, dname_len, origin, 690266077Sdes origin_len)) != 0) { 691266077Sdes return status; 692266077Sdes } 693266077Sdes } 694266077Sdes } 695266077Sdes if(!was_unknown_rr_format && r_cnt+1 < r_min) { 696266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE, 697266077Sdes sldns_buffer_position(strbuf)); 698266077Sdes } 699266077Sdes while(parens != 0) { 700266077Sdes /* read remainder, must be "" */ 701266077Sdes if(sldns_bget_token_par(strbuf, token, "\n", token_len, 702266077Sdes &parens, " \t") == -1) { 703266077Sdes if(parens != 0) 704266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS, 705266077Sdes sldns_buffer_position(strbuf)); 706266077Sdes break; 707266077Sdes } 708266077Sdes if(strcmp(token, "") != 0) 709266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS, 710266077Sdes sldns_buffer_position(strbuf)); 711266077Sdes } 712266077Sdes /* write rdata length */ 713356345Scy sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10)); 714266077Sdes *rr_len = rr_cur_len; 715266077Sdes return LDNS_WIREPARSE_ERR_OK; 716266077Sdes} 717266077Sdes 718266077Sdes/* 719266077Sdes * trailing spaces are allowed 720266077Sdes * leading spaces are not allowed 721266077Sdes * allow ttl to be optional 722266077Sdes * class is optional too 723266077Sdes * if ttl is missing, and default_ttl is 0, use DEF_TTL 724266077Sdes * allow ttl to be written as 1d3h 725266077Sdes * So the RR should look like. e.g. 726266077Sdes * miek.nl. 3600 IN MX 10 elektron.atoom.net 727266077Sdes * or 728266077Sdes * miek.nl. 1h IN MX 10 elektron.atoom.net 729266077Sdes * or 730266077Sdes * miek.nl. IN MX 10 elektron.atoom.net 731266077Sdes */ 732266077Sdesstatic int 733266077Sdessldns_str2wire_rr_buf_internal(const char* str, uint8_t* rr, size_t* len, 734266077Sdes size_t* dname_len, uint32_t default_ttl, uint8_t* origin, 735266077Sdes size_t origin_len, uint8_t* prev, size_t prev_len, int question) 736266077Sdes{ 737266077Sdes int status; 738266077Sdes int not_there = 0; 739266077Sdes char token[LDNS_MAX_RDFLEN+1]; 740266077Sdes uint32_t ttl = 0; 741266077Sdes uint16_t tp = 0, cl = 0; 742266077Sdes size_t ddlen = 0; 743266077Sdes 744266077Sdes /* string in buffer */ 745266077Sdes sldns_buffer strbuf; 746266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 747266077Sdes if(!dname_len) dname_len = &ddlen; 748266077Sdes 749266077Sdes /* parse the owner */ 750266077Sdes if((status=rrinternal_get_owner(&strbuf, rr, len, dname_len, origin, 751266077Sdes origin_len, prev, prev_len, token, sizeof(token))) != 0) 752266077Sdes return status; 753266077Sdes 754266077Sdes /* parse the [ttl] [class] <type> */ 755266077Sdes if((status=rrinternal_get_ttl(&strbuf, token, sizeof(token), 756266077Sdes ¬_there, &ttl, default_ttl)) != 0) 757266077Sdes return status; 758266077Sdes if((status=rrinternal_get_class(&strbuf, token, sizeof(token), 759266077Sdes ¬_there, &cl)) != 0) 760266077Sdes return status; 761266077Sdes if((status=rrinternal_get_type(&strbuf, token, sizeof(token), 762266077Sdes ¬_there, &tp)) != 0) 763266077Sdes return status; 764266077Sdes /* put ttl, class, type into the rr result */ 765266077Sdes if((status=rrinternal_write_typeclassttl(&strbuf, rr, *len, *dname_len, tp, cl, 766266077Sdes ttl, question)) != 0) 767266077Sdes return status; 768266077Sdes /* for a question-RR we are done, no rdata */ 769266077Sdes if(question) { 770266077Sdes *len = *dname_len + 4; 771266077Sdes return LDNS_WIREPARSE_ERR_OK; 772266077Sdes } 773266077Sdes 774266077Sdes /* rdata */ 775266077Sdes if((status=rrinternal_parse_rdata(&strbuf, token, sizeof(token), 776266077Sdes rr, len, *dname_len, tp, origin, origin_len)) != 0) 777266077Sdes return status; 778266077Sdes 779266077Sdes return LDNS_WIREPARSE_ERR_OK; 780266077Sdes} 781266077Sdes 782266077Sdesint sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len, 783266077Sdes size_t* dname_len, uint32_t default_ttl, uint8_t* origin, 784266077Sdes size_t origin_len, uint8_t* prev, size_t prev_len) 785266077Sdes{ 786266077Sdes return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len, 787266077Sdes default_ttl, origin, origin_len, prev, prev_len, 0); 788266077Sdes} 789266077Sdes 790266077Sdesint sldns_str2wire_rr_question_buf(const char* str, uint8_t* rr, size_t* len, 791266077Sdes size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev, 792266077Sdes size_t prev_len) 793266077Sdes{ 794266077Sdes return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len, 795266077Sdes 0, origin, origin_len, prev, prev_len, 1); 796266077Sdes} 797266077Sdes 798266077Sdesuint16_t sldns_wirerr_get_type(uint8_t* rr, size_t len, size_t dname_len) 799266077Sdes{ 800266077Sdes if(len < dname_len+2) 801266077Sdes return 0; 802266077Sdes return sldns_read_uint16(rr+dname_len); 803266077Sdes} 804266077Sdes 805266077Sdesuint16_t sldns_wirerr_get_class(uint8_t* rr, size_t len, size_t dname_len) 806266077Sdes{ 807266077Sdes if(len < dname_len+4) 808266077Sdes return 0; 809266077Sdes return sldns_read_uint16(rr+dname_len+2); 810266077Sdes} 811266077Sdes 812266077Sdesuint32_t sldns_wirerr_get_ttl(uint8_t* rr, size_t len, size_t dname_len) 813266077Sdes{ 814266077Sdes if(len < dname_len+8) 815266077Sdes return 0; 816266077Sdes return sldns_read_uint32(rr+dname_len+4); 817266077Sdes} 818266077Sdes 819266077Sdesuint16_t sldns_wirerr_get_rdatalen(uint8_t* rr, size_t len, size_t dname_len) 820266077Sdes{ 821266077Sdes if(len < dname_len+10) 822266077Sdes return 0; 823266077Sdes return sldns_read_uint16(rr+dname_len+8); 824266077Sdes} 825266077Sdes 826266077Sdesuint8_t* sldns_wirerr_get_rdata(uint8_t* rr, size_t len, size_t dname_len) 827266077Sdes{ 828266077Sdes if(len < dname_len+10) 829266077Sdes return NULL; 830266077Sdes return rr+dname_len+10; 831266077Sdes} 832266077Sdes 833266077Sdesuint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len) 834266077Sdes{ 835266077Sdes if(len < dname_len+10) 836266077Sdes return NULL; 837266077Sdes return rr+dname_len+8; 838266077Sdes} 839266077Sdes 840266077Sdesconst char* sldns_get_errorstr_parse(int e) 841266077Sdes{ 842266077Sdes sldns_lookup_table *lt; 843266077Sdes lt = sldns_lookup_by_id(sldns_wireparse_errors, LDNS_WIREPARSE_ERROR(e)); 844266077Sdes return lt?lt->name:"unknown error"; 845266077Sdes} 846266077Sdes 847276541Sdes/* Strip whitespace from the start and the end of <line>. */ 848356345Scychar * 849276541Sdessldns_strip_ws(char *line) 850276541Sdes{ 851276541Sdes char *s = line, *e; 852276541Sdes 853276541Sdes for (s = line; *s && isspace((unsigned char)*s); s++) 854276541Sdes ; 855276541Sdes for (e = strchr(s, 0); e > s+2 && isspace((unsigned char)e[-1]) && e[-2] != '\\'; e--) 856276541Sdes ; 857276541Sdes *e = 0; 858276541Sdes return s; 859276541Sdes} 860276541Sdes 861266077Sdesint sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len, 862266077Sdes struct sldns_file_parse_state* parse_state) 863266077Sdes{ 864266077Sdes char line[LDNS_RR_BUF_SIZE+1]; 865266077Sdes ssize_t size; 866266077Sdes 867266077Sdes /* read an entire line in from the file */ 868266077Sdes if((size = sldns_fget_token_l(in, line, LDNS_PARSE_SKIP_SPACE, 869266077Sdes LDNS_RR_BUF_SIZE, parse_state?&parse_state->lineno:NULL)) 870266077Sdes == -1) { 871266077Sdes /* if last line was empty, we are now at feof, which is not 872266077Sdes * always a parse error (happens when for instance last line 873266077Sdes * was a comment) 874266077Sdes */ 875266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX; 876266077Sdes } 877266077Sdes 878266077Sdes /* we can have the situation, where we've read ok, but still got 879266077Sdes * no bytes to play with, in this case size is 0 */ 880266077Sdes if(size == 0) { 881356345Scy if(*len > 0) 882356345Scy rr[0] = 0; 883266077Sdes *len = 0; 884266077Sdes *dname_len = 0; 885266077Sdes return LDNS_WIREPARSE_ERR_OK; 886266077Sdes } 887266077Sdes 888276541Sdes if(strncmp(line, "$ORIGIN", 7) == 0 && isspace((unsigned char)line[7])) { 889266077Sdes int s; 890356345Scy strlcpy((char*)rr, line, *len); 891266077Sdes *len = 0; 892266077Sdes *dname_len = 0; 893266077Sdes if(!parse_state) return LDNS_WIREPARSE_ERR_OK; 894266077Sdes parse_state->origin_len = sizeof(parse_state->origin); 895276541Sdes s = sldns_str2wire_dname_buf(sldns_strip_ws(line+8), 896276541Sdes parse_state->origin, &parse_state->origin_len); 897266077Sdes if(s) parse_state->origin_len = 0; 898266077Sdes return s; 899276541Sdes } else if(strncmp(line, "$TTL", 4) == 0 && isspace((unsigned char)line[4])) { 900266077Sdes const char* end = NULL; 901356345Scy strlcpy((char*)rr, line, *len); 902266077Sdes *len = 0; 903266077Sdes *dname_len = 0; 904266077Sdes if(!parse_state) return LDNS_WIREPARSE_ERR_OK; 905276541Sdes parse_state->default_ttl = sldns_str2period( 906276541Sdes sldns_strip_ws(line+5), &end); 907266077Sdes } else if (strncmp(line, "$INCLUDE", 8) == 0) { 908356345Scy strlcpy((char*)rr, line, *len); 909266077Sdes *len = 0; 910266077Sdes *dname_len = 0; 911266077Sdes return LDNS_WIREPARSE_ERR_INCLUDE; 912356345Scy } else if (strncmp(line, "$", 1) == 0) { 913356345Scy strlcpy((char*)rr, line, *len); 914356345Scy *len = 0; 915356345Scy *dname_len = 0; 916356345Scy return LDNS_WIREPARSE_ERR_INCLUDE; 917266077Sdes } else { 918356345Scy int r = sldns_str2wire_rr_buf(line, rr, len, dname_len, 919266077Sdes parse_state?parse_state->default_ttl:0, 920266077Sdes (parse_state&&parse_state->origin_len)? 921266077Sdes parse_state->origin:NULL, 922307729Sdes parse_state?parse_state->origin_len:0, 923266077Sdes (parse_state&&parse_state->prev_rr_len)? 924266077Sdes parse_state->prev_rr:NULL, 925307729Sdes parse_state?parse_state->prev_rr_len:0); 926356345Scy if(r == LDNS_WIREPARSE_ERR_OK && (*dname_len) != 0 && 927356345Scy parse_state && 928356345Scy (*dname_len) <= sizeof(parse_state->prev_rr)) { 929356345Scy memmove(parse_state->prev_rr, rr, *dname_len); 930356345Scy parse_state->prev_rr_len = (*dname_len); 931356345Scy } 932356345Scy return r; 933266077Sdes } 934266077Sdes return LDNS_WIREPARSE_ERR_OK; 935266077Sdes} 936266077Sdes 937266077Sdesint sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len, 938266077Sdes sldns_rdf_type rdftype) 939266077Sdes{ 940266077Sdes switch (rdftype) { 941266077Sdes case LDNS_RDF_TYPE_DNAME: 942266077Sdes return sldns_str2wire_dname_buf(str, rd, len); 943266077Sdes case LDNS_RDF_TYPE_INT8: 944266077Sdes return sldns_str2wire_int8_buf(str, rd, len); 945266077Sdes case LDNS_RDF_TYPE_INT16: 946266077Sdes return sldns_str2wire_int16_buf(str, rd, len); 947266077Sdes case LDNS_RDF_TYPE_INT32: 948266077Sdes return sldns_str2wire_int32_buf(str, rd, len); 949266077Sdes case LDNS_RDF_TYPE_A: 950266077Sdes return sldns_str2wire_a_buf(str, rd, len); 951266077Sdes case LDNS_RDF_TYPE_AAAA: 952266077Sdes return sldns_str2wire_aaaa_buf(str, rd, len); 953266077Sdes case LDNS_RDF_TYPE_STR: 954266077Sdes return sldns_str2wire_str_buf(str, rd, len); 955266077Sdes case LDNS_RDF_TYPE_APL: 956266077Sdes return sldns_str2wire_apl_buf(str, rd, len); 957266077Sdes case LDNS_RDF_TYPE_B64: 958266077Sdes return sldns_str2wire_b64_buf(str, rd, len); 959266077Sdes case LDNS_RDF_TYPE_B32_EXT: 960266077Sdes return sldns_str2wire_b32_ext_buf(str, rd, len); 961266077Sdes case LDNS_RDF_TYPE_HEX: 962266077Sdes return sldns_str2wire_hex_buf(str, rd, len); 963266077Sdes case LDNS_RDF_TYPE_NSEC: 964266077Sdes return sldns_str2wire_nsec_buf(str, rd, len); 965266077Sdes case LDNS_RDF_TYPE_TYPE: 966266077Sdes return sldns_str2wire_type_buf(str, rd, len); 967266077Sdes case LDNS_RDF_TYPE_CLASS: 968266077Sdes return sldns_str2wire_class_buf(str, rd, len); 969266077Sdes case LDNS_RDF_TYPE_CERT_ALG: 970266077Sdes return sldns_str2wire_cert_alg_buf(str, rd, len); 971266077Sdes case LDNS_RDF_TYPE_ALG: 972266077Sdes return sldns_str2wire_alg_buf(str, rd, len); 973266077Sdes case LDNS_RDF_TYPE_TIME: 974266077Sdes return sldns_str2wire_time_buf(str, rd, len); 975266077Sdes case LDNS_RDF_TYPE_PERIOD: 976266077Sdes return sldns_str2wire_period_buf(str, rd, len); 977356345Scy case LDNS_RDF_TYPE_TSIGTIME: 978356345Scy return sldns_str2wire_tsigtime_buf(str, rd, len); 979266077Sdes case LDNS_RDF_TYPE_LOC: 980266077Sdes return sldns_str2wire_loc_buf(str, rd, len); 981266077Sdes case LDNS_RDF_TYPE_WKS: 982266077Sdes return sldns_str2wire_wks_buf(str, rd, len); 983266077Sdes case LDNS_RDF_TYPE_NSAP: 984266077Sdes return sldns_str2wire_nsap_buf(str, rd, len); 985266077Sdes case LDNS_RDF_TYPE_ATMA: 986266077Sdes return sldns_str2wire_atma_buf(str, rd, len); 987266077Sdes case LDNS_RDF_TYPE_IPSECKEY: 988266077Sdes return sldns_str2wire_ipseckey_buf(str, rd, len); 989266077Sdes case LDNS_RDF_TYPE_NSEC3_SALT: 990266077Sdes return sldns_str2wire_nsec3_salt_buf(str, rd, len); 991266077Sdes case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: 992266077Sdes return sldns_str2wire_b32_ext_buf(str, rd, len); 993266077Sdes case LDNS_RDF_TYPE_ILNP64: 994266077Sdes return sldns_str2wire_ilnp64_buf(str, rd, len); 995266077Sdes case LDNS_RDF_TYPE_EUI48: 996266077Sdes return sldns_str2wire_eui48_buf(str, rd, len); 997266077Sdes case LDNS_RDF_TYPE_EUI64: 998266077Sdes return sldns_str2wire_eui64_buf(str, rd, len); 999266077Sdes case LDNS_RDF_TYPE_TAG: 1000266077Sdes return sldns_str2wire_tag_buf(str, rd, len); 1001266077Sdes case LDNS_RDF_TYPE_LONG_STR: 1002266077Sdes return sldns_str2wire_long_str_buf(str, rd, len); 1003356345Scy case LDNS_RDF_TYPE_TSIGERROR: 1004356345Scy return sldns_str2wire_tsigerror_buf(str, rd, len); 1005266077Sdes case LDNS_RDF_TYPE_HIP: 1006266077Sdes return sldns_str2wire_hip_buf(str, rd, len); 1007266077Sdes case LDNS_RDF_TYPE_INT16_DATA: 1008266077Sdes return sldns_str2wire_int16_data_buf(str, rd, len); 1009266077Sdes case LDNS_RDF_TYPE_UNKNOWN: 1010266077Sdes case LDNS_RDF_TYPE_SERVICE: 1011266077Sdes return LDNS_WIREPARSE_ERR_NOT_IMPL; 1012266077Sdes case LDNS_RDF_TYPE_NONE: 1013266077Sdes default: 1014266077Sdes break; 1015266077Sdes } 1016266077Sdes return LDNS_WIREPARSE_ERR_GENERAL; 1017266077Sdes} 1018266077Sdes 1019266077Sdesint sldns_str2wire_int8_buf(const char* str, uint8_t* rd, size_t* len) 1020266077Sdes{ 1021266077Sdes char* end; 1022266077Sdes uint8_t r = (uint8_t)strtol((char*)str, &end, 10); 1023266077Sdes if(*end != 0) 1024266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str); 1025266077Sdes if(*len < 1) 1026266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1027266077Sdes rd[0] = r; 1028266077Sdes *len = 1; 1029266077Sdes return LDNS_WIREPARSE_ERR_OK; 1030266077Sdes} 1031266077Sdes 1032266077Sdesint sldns_str2wire_int16_buf(const char* str, uint8_t* rd, size_t* len) 1033266077Sdes{ 1034266077Sdes char* end; 1035266077Sdes uint16_t r = (uint16_t)strtol((char*)str, &end, 10); 1036266077Sdes if(*end != 0) 1037266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str); 1038266077Sdes if(*len < 2) 1039266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1040266077Sdes sldns_write_uint16(rd, r); 1041266077Sdes *len = 2; 1042266077Sdes return LDNS_WIREPARSE_ERR_OK; 1043266077Sdes} 1044266077Sdes 1045266077Sdesint sldns_str2wire_int32_buf(const char* str, uint8_t* rd, size_t* len) 1046266077Sdes{ 1047266077Sdes char* end; 1048266077Sdes uint32_t r; 1049266077Sdes errno = 0; /* must set to zero before call, 1050266077Sdes note race condition on errno */ 1051266077Sdes if(*str == '-') 1052266077Sdes r = (uint32_t)strtol((char*)str, &end, 10); 1053266077Sdes else r = (uint32_t)strtoul((char*)str, &end, 10); 1054266077Sdes if(*end != 0) 1055266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str); 1056266077Sdes if(errno == ERANGE) 1057266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW; 1058266077Sdes if(*len < 4) 1059266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1060266077Sdes sldns_write_uint32(rd, r); 1061266077Sdes *len = 4; 1062266077Sdes return LDNS_WIREPARSE_ERR_OK; 1063266077Sdes} 1064266077Sdes 1065266077Sdesint sldns_str2wire_a_buf(const char* str, uint8_t* rd, size_t* len) 1066266077Sdes{ 1067266077Sdes struct in_addr address; 1068266077Sdes if(inet_pton(AF_INET, (char*)str, &address) != 1) 1069266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_IP4; 1070266077Sdes if(*len < sizeof(address)) 1071266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1072266077Sdes memmove(rd, &address, sizeof(address)); 1073266077Sdes *len = sizeof(address); 1074266077Sdes return LDNS_WIREPARSE_ERR_OK; 1075266077Sdes} 1076266077Sdes 1077266077Sdesint sldns_str2wire_aaaa_buf(const char* str, uint8_t* rd, size_t* len) 1078266077Sdes{ 1079266077Sdes#ifdef AF_INET6 1080266077Sdes uint8_t address[LDNS_IP6ADDRLEN + 1]; 1081266077Sdes if(inet_pton(AF_INET6, (char*)str, address) != 1) 1082266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_IP6; 1083266077Sdes if(*len < LDNS_IP6ADDRLEN) 1084266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1085266077Sdes memmove(rd, address, LDNS_IP6ADDRLEN); 1086266077Sdes *len = LDNS_IP6ADDRLEN; 1087266077Sdes return LDNS_WIREPARSE_ERR_OK; 1088266077Sdes#else 1089266077Sdes return LDNS_WIREPARSE_ERR_NOT_IMPL; 1090266077Sdes#endif 1091266077Sdes} 1092266077Sdes 1093266077Sdesint sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len) 1094266077Sdes{ 1095266077Sdes uint8_t ch = 0; 1096266077Sdes size_t sl = 0; 1097266077Sdes const char* s = str; 1098266077Sdes /* skip length byte */ 1099266077Sdes if(*len < 1) 1100266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1101266077Sdes 1102266077Sdes /* read characters */ 1103266077Sdes while(sldns_parse_char(&ch, &s)) { 1104266077Sdes if(sl >= 255) 1105266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, s-str); 1106356345Scy if(*len < sl+2) 1107266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1108266077Sdes s-str); 1109266077Sdes rd[++sl] = ch; 1110266077Sdes } 1111266077Sdes if(!s) 1112266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE; 1113266077Sdes rd[0] = (uint8_t)sl; 1114266077Sdes *len = sl+1; 1115266077Sdes return LDNS_WIREPARSE_ERR_OK; 1116266077Sdes} 1117266077Sdes 1118266077Sdesint sldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len) 1119266077Sdes{ 1120266077Sdes const char *my_str = str; 1121266077Sdes 1122266077Sdes char my_ip_str[64]; 1123266077Sdes size_t ip_str_len; 1124266077Sdes 1125266077Sdes uint16_t family; 1126266077Sdes int negation; 1127266077Sdes size_t adflength = 0; 1128266077Sdes uint8_t data[16+4]; 1129266077Sdes uint8_t prefix; 1130266077Sdes size_t i; 1131266077Sdes 1132296415Sdes if(*my_str == '\0') { 1133266077Sdes /* empty APL element, no data, no string */ 1134266077Sdes *len = 0; 1135266077Sdes return LDNS_WIREPARSE_ERR_OK; 1136266077Sdes } 1137266077Sdes 1138266077Sdes /* [!]afi:address/prefix */ 1139266077Sdes if (strlen(my_str) < 2 1140266077Sdes || strchr(my_str, ':') == NULL 1141266077Sdes || strchr(my_str, '/') == NULL 1142266077Sdes || strchr(my_str, ':') > strchr(my_str, '/')) { 1143266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1144266077Sdes } 1145266077Sdes 1146266077Sdes if (my_str[0] == '!') { 1147266077Sdes negation = 1; 1148266077Sdes my_str += 1; 1149266077Sdes } else { 1150266077Sdes negation = 0; 1151266077Sdes } 1152266077Sdes 1153266077Sdes family = (uint16_t) atoi(my_str); 1154266077Sdes 1155266077Sdes my_str = strchr(my_str, ':') + 1; 1156266077Sdes 1157266077Sdes /* need ip addr and only ip addr for inet_pton */ 1158266077Sdes ip_str_len = (size_t) (strchr(my_str, '/') - my_str); 1159266077Sdes if(ip_str_len+1 > sizeof(my_ip_str)) 1160266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1161266077Sdes (void)strlcpy(my_ip_str, my_str, sizeof(my_ip_str)); 1162266077Sdes my_ip_str[ip_str_len] = 0; 1163266077Sdes 1164266077Sdes if (family == 1) { 1165266077Sdes /* ipv4 */ 1166266077Sdes if(inet_pton(AF_INET, my_ip_str, data+4) == 0) 1167266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1168266077Sdes for (i = 0; i < 4; i++) { 1169266077Sdes if (data[i+4] != 0) { 1170266077Sdes adflength = i + 1; 1171266077Sdes } 1172266077Sdes } 1173266077Sdes } else if (family == 2) { 1174266077Sdes /* ipv6 */ 1175266077Sdes if (inet_pton(AF_INET6, my_ip_str, data+4) == 0) 1176266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1177266077Sdes for (i = 0; i < 16; i++) { 1178266077Sdes if (data[i+4] != 0) { 1179266077Sdes adflength = i + 1; 1180266077Sdes } 1181266077Sdes } 1182266077Sdes } else { 1183266077Sdes /* unknown family */ 1184266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1185266077Sdes } 1186266077Sdes 1187266077Sdes my_str = strchr(my_str, '/') + 1; 1188266077Sdes prefix = (uint8_t) atoi(my_str); 1189266077Sdes 1190266077Sdes sldns_write_uint16(data, family); 1191266077Sdes data[2] = prefix; 1192266077Sdes data[3] = (uint8_t)adflength; 1193266077Sdes if (negation) { 1194266077Sdes /* set bit 1 of byte 3 */ 1195266077Sdes data[3] = data[3] | 0x80; 1196266077Sdes } 1197266077Sdes 1198266077Sdes if(*len < 4+adflength) 1199266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1200266077Sdes memmove(rd, data, 4+adflength); 1201266077Sdes *len = 4+adflength; 1202266077Sdes return LDNS_WIREPARSE_ERR_OK; 1203266077Sdes} 1204266077Sdes 1205266077Sdesint sldns_str2wire_b64_buf(const char* str, uint8_t* rd, size_t* len) 1206266077Sdes{ 1207266077Sdes size_t sz = sldns_b64_pton_calculate_size(strlen(str)); 1208266077Sdes int n; 1209356345Scy if(strcmp(str, "0") == 0) { 1210356345Scy *len = 0; 1211356345Scy return LDNS_WIREPARSE_ERR_OK; 1212356345Scy } 1213266077Sdes if(*len < sz) 1214266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1215266077Sdes n = sldns_b64_pton(str, rd, *len); 1216266077Sdes if(n < 0) 1217266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_B64; 1218266077Sdes *len = (size_t)n; 1219266077Sdes return LDNS_WIREPARSE_ERR_OK; 1220266077Sdes} 1221266077Sdes 1222266077Sdesint sldns_str2wire_b32_ext_buf(const char* str, uint8_t* rd, size_t* len) 1223266077Sdes{ 1224266077Sdes size_t slen = strlen(str); 1225266077Sdes size_t sz = sldns_b32_pton_calculate_size(slen); 1226266077Sdes int n; 1227266077Sdes if(*len < 1+sz) 1228266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1229266077Sdes rd[0] = (uint8_t)sz; 1230266077Sdes n = sldns_b32_pton_extended_hex(str, slen, rd+1, *len-1); 1231266077Sdes if(n < 0) 1232266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT; 1233266077Sdes *len = (size_t)n+1; 1234266077Sdes return LDNS_WIREPARSE_ERR_OK; 1235266077Sdes} 1236266077Sdes 1237356345Scy/** see if the string ends, or ends in whitespace */ 1238356345Scystatic int 1239356345Scysldns_is_last_of_string(const char* str) 1240356345Scy{ 1241356345Scy if(*str == 0) return 1; 1242356345Scy while(isspace((unsigned char)*str)) 1243356345Scy str++; 1244356345Scy if(*str == 0) return 1; 1245356345Scy return 0; 1246356345Scy} 1247356345Scy 1248266077Sdesint sldns_str2wire_hex_buf(const char* str, uint8_t* rd, size_t* len) 1249266077Sdes{ 1250266077Sdes const char* s = str; 1251266077Sdes size_t dlen = 0; /* number of hexdigits parsed */ 1252266077Sdes while(*s) { 1253276541Sdes if(isspace((unsigned char)*s)) { 1254266077Sdes s++; 1255266077Sdes continue; 1256266077Sdes } 1257356345Scy if(dlen == 0 && *s == '0' && sldns_is_last_of_string(s+1)) { 1258356345Scy *len = 0; 1259356345Scy return LDNS_WIREPARSE_ERR_OK; 1260356345Scy } 1261276541Sdes if(!isxdigit((unsigned char)*s)) 1262266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1263266077Sdes if(*len < dlen/2 + 1) 1264266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1265266077Sdes s-str); 1266266077Sdes if((dlen&1)==0) 1267266077Sdes rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16; 1268266077Sdes else rd[dlen/2] += (uint8_t)sldns_hexdigit_to_int(*s++); 1269266077Sdes dlen++; 1270266077Sdes } 1271266077Sdes if((dlen&1)!=0) 1272266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1273266077Sdes *len = dlen/2; 1274266077Sdes return LDNS_WIREPARSE_ERR_OK; 1275266077Sdes} 1276266077Sdes 1277266077Sdesint sldns_str2wire_nsec_buf(const char* str, uint8_t* rd, size_t* len) 1278266077Sdes{ 1279266077Sdes const char *delim = "\n\t "; 1280266077Sdes char token[64]; /* for a type name */ 1281266077Sdes size_t type_count = 0; 1282266077Sdes int block; 1283266077Sdes size_t used = 0; 1284266077Sdes uint16_t maxtype = 0; 1285266077Sdes uint8_t typebits[8192]; /* 65536 bits */ 1286266077Sdes uint8_t window_in_use[256]; 1287266077Sdes 1288266077Sdes /* string in buffer */ 1289266077Sdes sldns_buffer strbuf; 1290266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 1291266077Sdes 1292266077Sdes /* parse the types */ 1293266077Sdes memset(typebits, 0, sizeof(typebits)); 1294266077Sdes memset(window_in_use, 0, sizeof(window_in_use)); 1295266077Sdes while(sldns_buffer_remaining(&strbuf) > 0 && 1296266077Sdes sldns_bget_token(&strbuf, token, delim, sizeof(token)) != -1) { 1297266077Sdes uint16_t t = sldns_get_rr_type_by_name(token); 1298266077Sdes if(token[0] == 0) 1299266077Sdes continue; 1300266077Sdes if(t == 0 && strcmp(token, "TYPE0") != 0) 1301266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE, 1302266077Sdes sldns_buffer_position(&strbuf)); 1303266077Sdes typebits[t/8] |= (0x80>>(t%8)); 1304266077Sdes window_in_use[t/256] = 1; 1305266077Sdes type_count++; 1306266077Sdes if(t > maxtype) maxtype = t; 1307266077Sdes } 1308266077Sdes 1309266077Sdes /* empty NSEC bitmap */ 1310266077Sdes if(type_count == 0) { 1311266077Sdes *len = 0; 1312266077Sdes return LDNS_WIREPARSE_ERR_OK; 1313266077Sdes } 1314266077Sdes 1315266077Sdes /* encode windows {u8 windowblock, u8 bitmaplength, 0-32u8 bitmap}, 1316266077Sdes * block is 0-255 upper octet of types, length if 0-32. */ 1317266077Sdes for(block = 0; block <= (int)maxtype/256; block++) { 1318266077Sdes int i, blocklen = 0; 1319266077Sdes if(!window_in_use[block]) 1320266077Sdes continue; 1321266077Sdes for(i=0; i<32; i++) { 1322266077Sdes if(typebits[block*32+i] != 0) 1323266077Sdes blocklen = i+1; 1324266077Sdes } 1325266077Sdes if(blocklen == 0) 1326266077Sdes continue; /* empty window should have been !in_use */ 1327266077Sdes if(used+blocklen+2 > *len) 1328266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1329266077Sdes rd[used+0] = (uint8_t)block; 1330266077Sdes rd[used+1] = (uint8_t)blocklen; 1331266077Sdes for(i=0; i<blocklen; i++) { 1332266077Sdes rd[used+2+i] = typebits[block*32+i]; 1333266077Sdes } 1334266077Sdes used += blocklen+2; 1335266077Sdes } 1336266077Sdes *len = used; 1337266077Sdes return LDNS_WIREPARSE_ERR_OK; 1338266077Sdes} 1339266077Sdes 1340266077Sdesint sldns_str2wire_type_buf(const char* str, uint8_t* rd, size_t* len) 1341266077Sdes{ 1342266077Sdes uint16_t t = sldns_get_rr_type_by_name(str); 1343266077Sdes if(t == 0 && strcmp(str, "TYPE0") != 0) 1344266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TYPE; 1345266077Sdes if(*len < 2) 1346266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1347266077Sdes sldns_write_uint16(rd, t); 1348266077Sdes *len = 2; 1349266077Sdes return LDNS_WIREPARSE_ERR_OK; 1350266077Sdes} 1351266077Sdes 1352266077Sdesint sldns_str2wire_class_buf(const char* str, uint8_t* rd, size_t* len) 1353266077Sdes{ 1354266077Sdes uint16_t c = sldns_get_rr_class_by_name(str); 1355266077Sdes if(c == 0 && strcmp(str, "CLASS0") != 0) 1356266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_CLASS; 1357266077Sdes if(*len < 2) 1358266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1359266077Sdes sldns_write_uint16(rd, c); 1360266077Sdes *len = 2; 1361266077Sdes return LDNS_WIREPARSE_ERR_OK; 1362266077Sdes} 1363266077Sdes 1364266077Sdes/* An certificate alg field can either be specified as a 8 bits number 1365266077Sdes * or by its symbolic name. Handle both */ 1366266077Sdesint sldns_str2wire_cert_alg_buf(const char* str, uint8_t* rd, size_t* len) 1367266077Sdes{ 1368266077Sdes sldns_lookup_table *lt = sldns_lookup_by_name(sldns_cert_algorithms, 1369266077Sdes str); 1370266077Sdes if(*len < 2) 1371266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1372266077Sdes if(lt) { 1373266077Sdes sldns_write_uint16(rd, (uint16_t)lt->id); 1374266077Sdes } else { 1375266077Sdes int s = sldns_str2wire_int16_buf(str, rd, len); 1376266077Sdes if(s) return s; 1377266077Sdes if(sldns_read_uint16(rd) == 0) 1378266077Sdes return LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM; 1379266077Sdes } 1380266077Sdes *len = 2; 1381266077Sdes return LDNS_WIREPARSE_ERR_OK; 1382266077Sdes} 1383266077Sdes 1384266077Sdes/* An alg field can either be specified as a 8 bits number 1385266077Sdes * or by its symbolic name. Handle both */ 1386266077Sdesint sldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len) 1387266077Sdes{ 1388266077Sdes sldns_lookup_table *lt = sldns_lookup_by_name(sldns_algorithms, str); 1389266077Sdes if(*len < 1) 1390266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1391266077Sdes if(lt) { 1392266077Sdes rd[0] = (uint8_t)lt->id; 1393266077Sdes *len = 1; 1394266077Sdes } else { 1395266077Sdes /* try as-is (a number) */ 1396266077Sdes return sldns_str2wire_int8_buf(str, rd, len); 1397266077Sdes } 1398266077Sdes return LDNS_WIREPARSE_ERR_OK; 1399266077Sdes} 1400266077Sdes 1401356345Scyint sldns_str2wire_tsigerror_buf(const char* str, uint8_t* rd, size_t* len) 1402356345Scy{ 1403356345Scy sldns_lookup_table *lt = sldns_lookup_by_name(sldns_tsig_errors, str); 1404356345Scy if(*len < 2) 1405356345Scy return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1406356345Scy if(lt) { 1407356345Scy sldns_write_uint16(rd, (uint16_t)lt->id); 1408356345Scy *len = 2; 1409356345Scy } else { 1410356345Scy /* try as-is (a number) */ 1411356345Scy return sldns_str2wire_int16_buf(str, rd, len); 1412356345Scy } 1413356345Scy return LDNS_WIREPARSE_ERR_OK; 1414356345Scy} 1415356345Scy 1416266077Sdesint sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len) 1417266077Sdes{ 1418266077Sdes /* convert a time YYYYDDMMHHMMSS to wireformat */ 1419266077Sdes struct tm tm; 1420266077Sdes if(*len < 4) 1421266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1422266077Sdes 1423266077Sdes /* Try to scan the time... */ 1424266077Sdes memset(&tm, 0, sizeof(tm)); 1425266077Sdes if (strlen(str) == 14 && sscanf(str, "%4d%2d%2d%2d%2d%2d", 1426266077Sdes &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, 1427266077Sdes &tm.tm_min, &tm.tm_sec) == 6) { 1428266077Sdes tm.tm_year -= 1900; 1429266077Sdes tm.tm_mon--; 1430266077Sdes /* Check values */ 1431266077Sdes if (tm.tm_year < 70) 1432266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1433266077Sdes if (tm.tm_mon < 0 || tm.tm_mon > 11) 1434266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1435266077Sdes if (tm.tm_mday < 1 || tm.tm_mday > 31) 1436266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1437266077Sdes if (tm.tm_hour < 0 || tm.tm_hour > 23) 1438266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1439266077Sdes if (tm.tm_min < 0 || tm.tm_min > 59) 1440266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1441266077Sdes if (tm.tm_sec < 0 || tm.tm_sec > 59) 1442266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1443266077Sdes 1444356345Scy sldns_write_uint32(rd, (uint32_t)sldns_mktime_from_utc(&tm)); 1445266077Sdes } else { 1446266077Sdes /* handle it as 32 bits timestamp */ 1447266077Sdes char *end; 1448266077Sdes uint32_t l = (uint32_t)strtol((char*)str, &end, 10); 1449266077Sdes if(*end != 0) 1450266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TIME, 1451266077Sdes end-(char*)str); 1452266077Sdes sldns_write_uint32(rd, l); 1453266077Sdes } 1454266077Sdes *len = 4; 1455266077Sdes return LDNS_WIREPARSE_ERR_OK; 1456266077Sdes} 1457266077Sdes 1458356345Scyint sldns_str2wire_tsigtime_buf(const char* str, uint8_t* rd, size_t* len) 1459356345Scy{ 1460356345Scy char* end; 1461356345Scy uint64_t t = (uint64_t)strtol((char*)str, &end, 10); 1462356345Scy uint16_t high; 1463356345Scy uint32_t low; 1464356345Scy if(*end != 0) 1465356345Scy return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TIME, end-str); 1466356345Scy if(*len < 6) 1467356345Scy return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1468356345Scy high = (uint16_t)(t>>32); 1469356345Scy low = (uint32_t)(t); 1470356345Scy sldns_write_uint16(rd, high); 1471356345Scy sldns_write_uint32(rd+2, low); 1472356345Scy *len = 6; 1473356345Scy return LDNS_WIREPARSE_ERR_OK; 1474356345Scy} 1475356345Scy 1476266077Sdesint sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len) 1477266077Sdes{ 1478266077Sdes const char* end; 1479266077Sdes uint32_t p = sldns_str2period(str, &end); 1480266077Sdes if(*end != 0) 1481266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, end-str); 1482266077Sdes if(*len < 4) 1483266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1484266077Sdes sldns_write_uint32(rd, p); 1485266077Sdes *len = 4; 1486266077Sdes return LDNS_WIREPARSE_ERR_OK; 1487266077Sdes} 1488266077Sdes 1489266077Sdes/** read "<digits>[.<digits>][mM]" into mantissa exponent format for LOC type */ 1490266077Sdesstatic int 1491266077Sdesloc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e) 1492266077Sdes{ 1493266077Sdes uint32_t meters = 0, cm = 0, val; 1494276541Sdes while (isblank((unsigned char)*my_str)) { 1495266077Sdes my_str++; 1496266077Sdes } 1497266077Sdes meters = (uint32_t)strtol(my_str, &my_str, 10); 1498266077Sdes if (*my_str == '.') { 1499266077Sdes my_str++; 1500266077Sdes cm = (uint32_t)strtol(my_str, &my_str, 10); 1501266077Sdes } 1502266077Sdes if (meters >= 1) { 1503266077Sdes *e = 2; 1504266077Sdes val = meters; 1505266077Sdes } else { 1506266077Sdes *e = 0; 1507266077Sdes val = cm; 1508266077Sdes } 1509266077Sdes while(val >= 10) { 1510266077Sdes (*e)++; 1511266077Sdes val /= 10; 1512266077Sdes } 1513266077Sdes *m = (uint8_t)val; 1514266077Sdes 1515266077Sdes if (*e > 9) 1516266077Sdes return 0; 1517266077Sdes if (*my_str == 'm' || *my_str == 'M') { 1518266077Sdes my_str++; 1519266077Sdes } 1520266077Sdes *endstr = my_str; 1521266077Sdes return 1; 1522266077Sdes} 1523266077Sdes 1524266077Sdesint sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len) 1525266077Sdes{ 1526266077Sdes uint32_t latitude = 0; 1527266077Sdes uint32_t longitude = 0; 1528266077Sdes uint32_t altitude = 0; 1529266077Sdes 1530266077Sdes uint32_t equator = (uint32_t)1<<31; /* 2**31 */ 1531266077Sdes 1532266077Sdes /* only support version 0 */ 1533266077Sdes uint32_t h = 0; 1534266077Sdes uint32_t m = 0; 1535266077Sdes uint8_t size_b = 1, size_e = 2; 1536266077Sdes uint8_t horiz_pre_b = 1, horiz_pre_e = 6; 1537266077Sdes uint8_t vert_pre_b = 1, vert_pre_e = 3; 1538266077Sdes 1539266077Sdes double s = 0.0; 1540266077Sdes int northerness; 1541266077Sdes int easterness; 1542266077Sdes 1543266077Sdes char *my_str = (char *) str; 1544266077Sdes 1545276541Sdes if (isdigit((unsigned char) *my_str)) { 1546266077Sdes h = (uint32_t) strtol(my_str, &my_str, 10); 1547266077Sdes } else { 1548266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1549266077Sdes } 1550266077Sdes 1551276541Sdes while (isblank((unsigned char) *my_str)) { 1552266077Sdes my_str++; 1553266077Sdes } 1554266077Sdes 1555276541Sdes if (isdigit((unsigned char) *my_str)) { 1556266077Sdes m = (uint32_t) strtol(my_str, &my_str, 10); 1557266077Sdes } else if (*my_str == 'N' || *my_str == 'S') { 1558266077Sdes goto north; 1559266077Sdes } else { 1560266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1561266077Sdes } 1562266077Sdes 1563276541Sdes while (isblank((unsigned char) *my_str)) { 1564266077Sdes my_str++; 1565266077Sdes } 1566266077Sdes 1567276541Sdes if (isdigit((unsigned char) *my_str)) { 1568266077Sdes s = strtod(my_str, &my_str); 1569266077Sdes } 1570266077Sdes 1571356345Scy /* skip blanks before northerness */ 1572276541Sdes while (isblank((unsigned char) *my_str)) { 1573266077Sdes my_str++; 1574266077Sdes } 1575266077Sdes 1576266077Sdesnorth: 1577266077Sdes if (*my_str == 'N') { 1578266077Sdes northerness = 1; 1579266077Sdes } else if (*my_str == 'S') { 1580266077Sdes northerness = 0; 1581266077Sdes } else { 1582266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1583266077Sdes } 1584266077Sdes 1585266077Sdes my_str++; 1586266077Sdes 1587266077Sdes /* store number */ 1588266077Sdes s = 1000.0 * s; 1589266077Sdes /* add a little to make floor in conversion a round */ 1590266077Sdes s += 0.0005; 1591266077Sdes latitude = (uint32_t) s; 1592266077Sdes latitude += 1000 * 60 * m; 1593266077Sdes latitude += 1000 * 60 * 60 * h; 1594266077Sdes if (northerness) { 1595266077Sdes latitude = equator + latitude; 1596266077Sdes } else { 1597266077Sdes latitude = equator - latitude; 1598266077Sdes } 1599276541Sdes while (isblank((unsigned char)*my_str)) { 1600266077Sdes my_str++; 1601266077Sdes } 1602266077Sdes 1603276541Sdes if (isdigit((unsigned char) *my_str)) { 1604266077Sdes h = (uint32_t) strtol(my_str, &my_str, 10); 1605266077Sdes } else { 1606266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1607266077Sdes } 1608266077Sdes 1609276541Sdes while (isblank((unsigned char) *my_str)) { 1610266077Sdes my_str++; 1611266077Sdes } 1612266077Sdes 1613276541Sdes if (isdigit((unsigned char) *my_str)) { 1614266077Sdes m = (uint32_t) strtol(my_str, &my_str, 10); 1615266077Sdes } else if (*my_str == 'E' || *my_str == 'W') { 1616266077Sdes goto east; 1617266077Sdes } else { 1618266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1619266077Sdes } 1620266077Sdes 1621276541Sdes while (isblank((unsigned char)*my_str)) { 1622266077Sdes my_str++; 1623266077Sdes } 1624266077Sdes 1625276541Sdes if (isdigit((unsigned char) *my_str)) { 1626266077Sdes s = strtod(my_str, &my_str); 1627266077Sdes } 1628266077Sdes 1629266077Sdes /* skip blanks before easterness */ 1630276541Sdes while (isblank((unsigned char)*my_str)) { 1631266077Sdes my_str++; 1632266077Sdes } 1633266077Sdes 1634266077Sdeseast: 1635266077Sdes if (*my_str == 'E') { 1636266077Sdes easterness = 1; 1637266077Sdes } else if (*my_str == 'W') { 1638266077Sdes easterness = 0; 1639266077Sdes } else { 1640266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1641266077Sdes } 1642266077Sdes 1643266077Sdes my_str++; 1644266077Sdes 1645266077Sdes /* store number */ 1646266077Sdes s *= 1000.0; 1647266077Sdes /* add a little to make floor in conversion a round */ 1648266077Sdes s += 0.0005; 1649266077Sdes longitude = (uint32_t) s; 1650266077Sdes longitude += 1000 * 60 * m; 1651266077Sdes longitude += 1000 * 60 * 60 * h; 1652266077Sdes 1653266077Sdes if (easterness) { 1654266077Sdes longitude += equator; 1655266077Sdes } else { 1656266077Sdes longitude = equator - longitude; 1657266077Sdes } 1658266077Sdes 1659266077Sdes altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 + 1660266077Sdes 10000000.0 + 0.5); 1661266077Sdes if (*my_str == 'm' || *my_str == 'M') { 1662266077Sdes my_str++; 1663266077Sdes } 1664266077Sdes 1665266077Sdes if (strlen(my_str) > 0) { 1666266077Sdes if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e)) 1667266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1668266077Sdes } 1669266077Sdes 1670266077Sdes if (strlen(my_str) > 0) { 1671266077Sdes if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e)) 1672266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1673266077Sdes } 1674266077Sdes 1675266077Sdes if (strlen(my_str) > 0) { 1676266077Sdes if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e)) 1677266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1678266077Sdes } 1679266077Sdes 1680266077Sdes if(*len < 16) 1681266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1682266077Sdes rd[0] = 0; 1683266077Sdes rd[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f); 1684266077Sdes rd[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f); 1685266077Sdes rd[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f); 1686266077Sdes sldns_write_uint32(rd + 4, latitude); 1687266077Sdes sldns_write_uint32(rd + 8, longitude); 1688266077Sdes sldns_write_uint32(rd + 12, altitude); 1689266077Sdes *len = 16; 1690266077Sdes return LDNS_WIREPARSE_ERR_OK; 1691266077Sdes} 1692266077Sdes 1693276541Sdesstatic void 1694276541Sdesldns_tolower_str(char* s) 1695276541Sdes{ 1696276541Sdes if(s) { 1697276541Sdes while(*s) { 1698276541Sdes *s = (char)tolower((unsigned char)*s); 1699276541Sdes s++; 1700276541Sdes } 1701276541Sdes } 1702276541Sdes} 1703276541Sdes 1704266077Sdesint sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len) 1705266077Sdes{ 1706266077Sdes int rd_len = 1; 1707266077Sdes int have_proto = 0; 1708266077Sdes char token[50], proto_str[50]; 1709266077Sdes sldns_buffer strbuf; 1710266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 1711266077Sdes proto_str[0]=0; 1712266077Sdes 1713266077Sdes /* check we have one byte for proto */ 1714266077Sdes if(*len < 1) 1715266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1716266077Sdes 1717266077Sdes while(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) > 0) { 1718276541Sdes ldns_tolower_str(token); 1719266077Sdes if(!have_proto) { 1720266077Sdes struct protoent *p = getprotobyname(token); 1721266077Sdes have_proto = 1; 1722266077Sdes if(p) rd[0] = (uint8_t)p->p_proto; 1723356345Scy else if(strcasecmp(token, "tcp")==0) rd[0]=6; 1724356345Scy else if(strcasecmp(token, "udp")==0) rd[0]=17; 1725266077Sdes else rd[0] = (uint8_t)atoi(token); 1726266077Sdes (void)strlcpy(proto_str, token, sizeof(proto_str)); 1727266077Sdes } else { 1728266077Sdes int serv_port; 1729266077Sdes struct servent *serv = getservbyname(token, proto_str); 1730266077Sdes if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port); 1731356345Scy else if(strcasecmp(token, "domain")==0) serv_port=53; 1732266077Sdes else { 1733266077Sdes serv_port = atoi(token); 1734266077Sdes if(serv_port == 0 && strcmp(token, "0") != 0) { 1735266077Sdes#ifdef HAVE_ENDSERVENT 1736266077Sdes endservent(); 1737266077Sdes#endif 1738266077Sdes#ifdef HAVE_ENDPROTOENT 1739266077Sdes endprotoent(); 1740266077Sdes#endif 1741266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, 1742266077Sdes sldns_buffer_position(&strbuf)); 1743266077Sdes } 1744266077Sdes if(serv_port < 0 || serv_port > 65535) { 1745266077Sdes#ifdef HAVE_ENDSERVENT 1746266077Sdes endservent(); 1747266077Sdes#endif 1748266077Sdes#ifdef HAVE_ENDPROTOENT 1749266077Sdes endprotoent(); 1750266077Sdes#endif 1751266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, 1752266077Sdes sldns_buffer_position(&strbuf)); 1753266077Sdes } 1754266077Sdes } 1755266077Sdes if(rd_len < 1+serv_port/8+1) { 1756266077Sdes /* bitmap is larger, init new bytes at 0 */ 1757266077Sdes if(*len < 1+(size_t)serv_port/8+1) { 1758266077Sdes#ifdef HAVE_ENDSERVENT 1759266077Sdes endservent(); 1760266077Sdes#endif 1761266077Sdes#ifdef HAVE_ENDPROTOENT 1762266077Sdes endprotoent(); 1763266077Sdes#endif 1764266077Sdes return RET_ERR( 1765266077Sdes LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1766266077Sdes sldns_buffer_position(&strbuf)); 1767266077Sdes } 1768266077Sdes memset(rd+rd_len, 0, 1+(size_t)serv_port/8+1-rd_len); 1769266077Sdes rd_len = 1+serv_port/8+1; 1770266077Sdes } 1771266077Sdes rd[1+ serv_port/8] |= (1 << (7 - serv_port % 8)); 1772266077Sdes } 1773266077Sdes } 1774266077Sdes *len = (size_t)rd_len; 1775266077Sdes 1776266077Sdes#ifdef HAVE_ENDSERVENT 1777266077Sdes endservent(); 1778266077Sdes#endif 1779266077Sdes#ifdef HAVE_ENDPROTOENT 1780266077Sdes endprotoent(); 1781266077Sdes#endif 1782266077Sdes return LDNS_WIREPARSE_ERR_OK; 1783266077Sdes} 1784266077Sdes 1785266077Sdesint sldns_str2wire_nsap_buf(const char* str, uint8_t* rd, size_t* len) 1786266077Sdes{ 1787266077Sdes const char* s = str; 1788266077Sdes size_t slen; 1789266077Sdes size_t dlen = 0; /* number of hexdigits parsed */ 1790266077Sdes 1791266077Sdes /* just a hex string with optional dots? */ 1792266077Sdes if (s[0] != '0' || s[1] != 'x') 1793266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1794266077Sdes s += 2; 1795266077Sdes slen = strlen(s); 1796266077Sdes if(slen > LDNS_MAX_RDFLEN*2) 1797266077Sdes return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW; 1798266077Sdes while(*s) { 1799276541Sdes if(isspace((unsigned char)*s) || *s == '.') { 1800266077Sdes s++; 1801266077Sdes continue; 1802266077Sdes } 1803276541Sdes if(!isxdigit((unsigned char)*s)) 1804266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1805266077Sdes if(*len < dlen/2 + 1) 1806266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1807266077Sdes s-str); 1808266077Sdes if((dlen&1)==0) 1809266077Sdes rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16; 1810266077Sdes else rd[dlen/2] += sldns_hexdigit_to_int(*s++); 1811266077Sdes dlen++; 1812266077Sdes } 1813266077Sdes if((dlen&1)!=0) 1814266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1815266077Sdes *len = dlen/2; 1816266077Sdes return LDNS_WIREPARSE_ERR_OK; 1817266077Sdes} 1818266077Sdes 1819266077Sdesint sldns_str2wire_atma_buf(const char* str, uint8_t* rd, size_t* len) 1820266077Sdes{ 1821266077Sdes const char* s = str; 1822266077Sdes size_t slen = strlen(str); 1823266077Sdes size_t dlen = 0; /* number of hexdigits parsed */ 1824266077Sdes 1825266077Sdes /* just a hex string with optional dots? */ 1826266077Sdes /* notimpl e.164 format */ 1827266077Sdes if(slen > LDNS_MAX_RDFLEN*2) 1828266077Sdes return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW; 1829266077Sdes while(*s) { 1830276541Sdes if(isspace((unsigned char)*s) || *s == '.') { 1831266077Sdes s++; 1832266077Sdes continue; 1833266077Sdes } 1834276541Sdes if(!isxdigit((unsigned char)*s)) 1835266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1836266077Sdes if(*len < dlen/2 + 1) 1837266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1838266077Sdes s-str); 1839266077Sdes if((dlen&1)==0) 1840266077Sdes rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16; 1841266077Sdes else rd[dlen/2] += sldns_hexdigit_to_int(*s++); 1842266077Sdes dlen++; 1843266077Sdes } 1844266077Sdes if((dlen&1)!=0) 1845266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1846266077Sdes *len = dlen/2; 1847266077Sdes return LDNS_WIREPARSE_ERR_OK; 1848266077Sdes} 1849266077Sdes 1850266077Sdesint sldns_str2wire_ipseckey_buf(const char* str, uint8_t* rd, size_t* len) 1851266077Sdes{ 1852266077Sdes size_t gwlen = 0, keylen = 0; 1853266077Sdes int s; 1854266077Sdes uint8_t gwtype; 1855266077Sdes char token[512]; 1856266077Sdes sldns_buffer strbuf; 1857266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 1858266077Sdes 1859266077Sdes if(*len < 3) 1860266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1861266077Sdes /* precedence */ 1862266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1863266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1864266077Sdes sldns_buffer_position(&strbuf)); 1865266077Sdes rd[0] = (uint8_t)atoi(token); 1866266077Sdes /* gateway_type */ 1867266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1868266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1869266077Sdes sldns_buffer_position(&strbuf)); 1870266077Sdes rd[1] = (uint8_t)atoi(token); 1871266077Sdes gwtype = rd[1]; 1872266077Sdes /* algorithm */ 1873266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1874266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1875266077Sdes sldns_buffer_position(&strbuf)); 1876266077Sdes rd[2] = (uint8_t)atoi(token); 1877266077Sdes 1878266077Sdes /* gateway */ 1879266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1880266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1881266077Sdes sldns_buffer_position(&strbuf)); 1882266077Sdes if(gwtype == 0) { 1883266077Sdes /* NOGATEWAY */ 1884266077Sdes if(strcmp(token, ".") != 0) 1885266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1886266077Sdes sldns_buffer_position(&strbuf)); 1887266077Sdes gwlen = 0; 1888266077Sdes } else if(gwtype == 1) { 1889266077Sdes /* IP4 */ 1890266077Sdes gwlen = *len - 3; 1891266077Sdes s = sldns_str2wire_a_buf(token, rd+3, &gwlen); 1892266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1893266077Sdes } else if(gwtype == 2) { 1894266077Sdes /* IP6 */ 1895266077Sdes gwlen = *len - 3; 1896266077Sdes s = sldns_str2wire_aaaa_buf(token, rd+3, &gwlen); 1897266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1898266077Sdes } else if(gwtype == 3) { 1899266077Sdes /* DNAME */ 1900266077Sdes gwlen = *len - 3; 1901266077Sdes s = sldns_str2wire_dname_buf(token, rd+3, &gwlen); 1902266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1903266077Sdes } else { 1904266077Sdes /* unknown gateway type */ 1905266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1906266077Sdes sldns_buffer_position(&strbuf)); 1907266077Sdes } 1908266077Sdes /* double check for size */ 1909266077Sdes if(*len < 3 + gwlen) 1910266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1911266077Sdes sldns_buffer_position(&strbuf)); 1912266077Sdes 1913266077Sdes /* publickey in remainder of strbuf */ 1914266077Sdes keylen = *len - 3 - gwlen; 1915266077Sdes s = sldns_str2wire_b64_buf((const char*)sldns_buffer_current(&strbuf), 1916266077Sdes rd+3+gwlen, &keylen); 1917266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1918266077Sdes 1919266077Sdes *len = 3 + gwlen + keylen; 1920266077Sdes return LDNS_WIREPARSE_ERR_OK; 1921266077Sdes} 1922266077Sdes 1923266077Sdesint sldns_str2wire_nsec3_salt_buf(const char* str, uint8_t* rd, size_t* len) 1924266077Sdes{ 1925266077Sdes int i, salt_length_str = (int)strlen(str); 1926266077Sdes if (salt_length_str == 1 && str[0] == '-') { 1927266077Sdes salt_length_str = 0; 1928266077Sdes } else if (salt_length_str % 2 != 0) { 1929266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_HEX; 1930266077Sdes } 1931266077Sdes if (salt_length_str > 512) 1932266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_HEX; 1933266077Sdes if(*len < 1+(size_t)salt_length_str / 2) 1934266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1935266077Sdes rd[0] = (uint8_t) (salt_length_str / 2); 1936266077Sdes for (i = 0; i < salt_length_str; i += 2) { 1937276541Sdes if (isxdigit((unsigned char)str[i]) && 1938276541Sdes isxdigit((unsigned char)str[i+1])) { 1939266077Sdes rd[1+i/2] = (uint8_t)(sldns_hexdigit_to_int(str[i])*16 1940266077Sdes + sldns_hexdigit_to_int(str[i+1])); 1941266077Sdes } else { 1942266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, i); 1943266077Sdes } 1944266077Sdes } 1945266077Sdes *len = 1 + (size_t)rd[0]; 1946266077Sdes return LDNS_WIREPARSE_ERR_OK; 1947266077Sdes} 1948266077Sdes 1949266077Sdesint sldns_str2wire_ilnp64_buf(const char* str, uint8_t* rd, size_t* len) 1950266077Sdes{ 1951266077Sdes unsigned int a, b, c, d; 1952266077Sdes uint16_t shorts[4]; 1953266077Sdes int l; 1954266077Sdes if(*len < sizeof(shorts)) 1955266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1956266077Sdes 1957266077Sdes if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 || 1958266077Sdes l != (int)strlen(str) || /* more data to read */ 1959266077Sdes strpbrk(str, "+-") /* signed hexes */ 1960266077Sdes ) 1961266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_ILNP64; 1962266077Sdes shorts[0] = htons(a); 1963266077Sdes shorts[1] = htons(b); 1964266077Sdes shorts[2] = htons(c); 1965266077Sdes shorts[3] = htons(d); 1966266077Sdes memmove(rd, &shorts, sizeof(shorts)); 1967266077Sdes *len = sizeof(shorts); 1968266077Sdes return LDNS_WIREPARSE_ERR_OK; 1969266077Sdes} 1970266077Sdes 1971266077Sdesint sldns_str2wire_eui48_buf(const char* str, uint8_t* rd, size_t* len) 1972266077Sdes{ 1973266077Sdes unsigned int a, b, c, d, e, f; 1974266077Sdes int l; 1975266077Sdes 1976266077Sdes if(*len < 6) 1977266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1978266077Sdes if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n", 1979266077Sdes &a, &b, &c, &d, &e, &f, &l) != 6 || 1980266077Sdes l != (int)strlen(str)) 1981266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_EUI48; 1982266077Sdes rd[0] = a; 1983266077Sdes rd[1] = b; 1984266077Sdes rd[2] = c; 1985266077Sdes rd[3] = d; 1986266077Sdes rd[4] = e; 1987266077Sdes rd[5] = f; 1988266077Sdes *len = 6; 1989266077Sdes return LDNS_WIREPARSE_ERR_OK; 1990266077Sdes} 1991266077Sdes 1992266077Sdesint sldns_str2wire_eui64_buf(const char* str, uint8_t* rd, size_t* len) 1993266077Sdes{ 1994266077Sdes unsigned int a, b, c, d, e, f, g, h; 1995266077Sdes int l; 1996266077Sdes 1997266077Sdes if(*len < 8) 1998266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1999266077Sdes if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n", 2000266077Sdes &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 || 2001266077Sdes l != (int)strlen(str)) 2002266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_EUI64; 2003266077Sdes rd[0] = a; 2004266077Sdes rd[1] = b; 2005266077Sdes rd[2] = c; 2006266077Sdes rd[3] = d; 2007266077Sdes rd[4] = e; 2008266077Sdes rd[5] = f; 2009266077Sdes rd[6] = g; 2010266077Sdes rd[7] = h; 2011266077Sdes *len = 8; 2012266077Sdes return LDNS_WIREPARSE_ERR_OK; 2013266077Sdes} 2014266077Sdes 2015266077Sdesint sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len) 2016266077Sdes{ 2017266077Sdes size_t slen = strlen(str); 2018266077Sdes const char* ptr; 2019266077Sdes 2020266077Sdes if (slen > 255) 2021266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TAG; 2022266077Sdes if(*len < slen+1) 2023266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 2024266077Sdes for (ptr = str; *ptr; ptr++) { 2025276541Sdes if(!isalnum((unsigned char)*ptr)) 2026266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TAG, ptr-str); 2027266077Sdes } 2028356345Scy rd[0] = (uint8_t)slen; 2029266077Sdes memmove(rd+1, str, slen); 2030266077Sdes *len = slen+1; 2031266077Sdes return LDNS_WIREPARSE_ERR_OK; 2032266077Sdes} 2033266077Sdes 2034266077Sdesint sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len) 2035266077Sdes{ 2036266077Sdes uint8_t ch = 0; 2037266077Sdes const char* pstr = str; 2038266077Sdes size_t length = 0; 2039266077Sdes 2040266077Sdes /* Fill data with parsed bytes */ 2041266077Sdes while (sldns_parse_char(&ch, &pstr)) { 2042266077Sdes if(*len < length+1) 2043266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 2044266077Sdes rd[length++] = ch; 2045266077Sdes } 2046266077Sdes if(!pstr) 2047266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE; 2048266077Sdes *len = length; 2049266077Sdes return LDNS_WIREPARSE_ERR_OK; 2050266077Sdes} 2051266077Sdes 2052266077Sdesint sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len) 2053266077Sdes{ 2054266077Sdes char* s, *end; 2055266077Sdes int e; 2056266077Sdes size_t hitlen, pklen = 0; 2057266077Sdes /* presentation format: 2058266077Sdes * pk-algo HIThex pubkeybase64 2059266077Sdes * wireformat: 2060266077Sdes * hitlen[1byte] pkalgo[1byte] pubkeylen[2byte] [hit] [pubkey] */ 2061266077Sdes if(*len < 4) 2062266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 2063266077Sdes 2064266077Sdes /* read PK algorithm */ 2065266077Sdes rd[1] = (uint8_t)strtol((char*)str, &s, 10); 2066266077Sdes if(*s != ' ') 2067266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str); 2068266077Sdes s++; 2069266077Sdes while(*s == ' ') 2070266077Sdes s++; 2071266077Sdes 2072266077Sdes /* read HIT hex tag */ 2073266077Sdes /* zero terminate the tag (replace later) */ 2074266077Sdes end = strchr(s, ' '); 2075266077Sdes if(!end) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, s-(char*)str); 2076266077Sdes *end = 0; 2077266077Sdes hitlen = *len - 4; 2078266077Sdes if((e = sldns_str2wire_hex_buf(s, rd+4, &hitlen)) != 0) { 2079266077Sdes *end = ' '; 2080266077Sdes return RET_ERR_SHIFT(e, s-(char*)str); 2081266077Sdes } 2082266077Sdes if(hitlen > 255) { 2083266077Sdes *end = ' '; 2084266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+255*2); 2085266077Sdes } 2086266077Sdes rd[0] = (uint8_t)hitlen; 2087266077Sdes *end = ' '; 2088266077Sdes s = end+1; 2089266077Sdes 2090266077Sdes /* read pubkey base64 sequence */ 2091266077Sdes pklen = *len - 4 - hitlen; 2092266077Sdes if((e = sldns_str2wire_b64_buf(s, rd+4+hitlen, &pklen)) != 0) 2093266077Sdes return RET_ERR_SHIFT(e, s-(char*)str); 2094266077Sdes if(pklen > 65535) 2095266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+65535); 2096356345Scy sldns_write_uint16(rd+2, (uint16_t)pklen); 2097266077Sdes 2098266077Sdes *len = 4 + hitlen + pklen; 2099266077Sdes return LDNS_WIREPARSE_ERR_OK; 2100266077Sdes} 2101266077Sdes 2102266077Sdesint sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len) 2103266077Sdes{ 2104356345Scy char* s; 2105266077Sdes int n; 2106356345Scy n = strtol(str, &s, 10); 2107356345Scy if(n < 0) /* negative number not allowed */ 2108356345Scy return LDNS_WIREPARSE_ERR_SYNTAX; 2109356345Scy if(*len < ((size_t)n)+2) 2110266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 2111356345Scy if(n > 65535) 2112266077Sdes return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW; 2113356345Scy 2114356345Scy if(n == 0) { 2115356345Scy sldns_write_uint16(rd, 0); 2116356345Scy *len = 2; 2117356345Scy return LDNS_WIREPARSE_ERR_OK; 2118356345Scy } 2119356345Scy if(*s != ' ') 2120356345Scy return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str); 2121356345Scy s++; 2122356345Scy while(*s == ' ') 2123356345Scy s++; 2124356345Scy 2125356345Scy n = sldns_b64_pton(s, rd+2, (*len)-2); 2126266077Sdes if(n < 0) 2127266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_B64; 2128266077Sdes sldns_write_uint16(rd, (uint16_t)n); 2129356345Scy *len = ((size_t)n)+2; 2130266077Sdes return LDNS_WIREPARSE_ERR_OK; 2131266077Sdes} 2132