str2wire.c revision 276541
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" 15266077Sdes#include "ldns/str2wire.h" 16266077Sdes#include "ldns/wire2str.h" 17266077Sdes#include "ldns/sbuffer.h" 18266077Sdes#include "ldns/parse.h" 19266077Sdes#include "ldns/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); 83266077Sdes 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); 120266077Sdes 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) { 153266077Sdes if(dlen + origin_len - 1 > LDNS_MAX_DOMAINLEN) 154266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, 155266077Sdes LDNS_MAX_DOMAINLEN); 156266077Sdes if(dlen + origin_len - 1 > *len) 157266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 158266077Sdes *len); 159266077Sdes memmove(buf+dlen-1, origin, origin_len); 160266077Sdes *len = dlen + origin_len - 1; 161266077Sdes } else 162266077Sdes *len = dlen; 163266077Sdes return LDNS_WIREPARSE_ERR_OK; 164266077Sdes} 165266077Sdes 166266077Sdesuint8_t* sldns_str2wire_dname(const char* str, size_t* len) 167266077Sdes{ 168266077Sdes uint8_t dname[LDNS_MAX_DOMAINLEN+1]; 169266077Sdes *len = sizeof(dname); 170266077Sdes if(sldns_str2wire_dname_buf(str, dname, len) == 0) { 171266077Sdes uint8_t* r = (uint8_t*)malloc(*len); 172266077Sdes if(r) return memcpy(r, dname, *len); 173266077Sdes } 174266077Sdes *len = 0; 175266077Sdes return NULL; 176266077Sdes} 177266077Sdes 178266077Sdes/** read owner name */ 179266077Sdesstatic int 180266077Sdesrrinternal_get_owner(sldns_buffer* strbuf, uint8_t* rr, size_t* len, 181266077Sdes size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev, 182266077Sdes size_t prev_len, char* token, size_t token_len) 183266077Sdes{ 184266077Sdes /* split the rr in its parts -1 signals trouble */ 185266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 186266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, 187266077Sdes sldns_buffer_position(strbuf)); 188266077Sdes } 189266077Sdes 190266077Sdes if(strcmp(token, "@") == 0) { 191266077Sdes uint8_t* tocopy; 192266077Sdes if (origin) { 193266077Sdes *dname_len = origin_len; 194266077Sdes tocopy = origin; 195266077Sdes } else if (prev) { 196266077Sdes *dname_len = prev_len; 197266077Sdes tocopy = prev; 198266077Sdes } else { 199266077Sdes /* default to root */ 200266077Sdes *dname_len = 1; 201266077Sdes tocopy = (uint8_t*)"\0"; 202266077Sdes } 203266077Sdes if(*len < *dname_len) 204266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 205266077Sdes sldns_buffer_position(strbuf)); 206266077Sdes memmove(rr, tocopy, *dname_len); 207266077Sdes } else if(strlen(token) == 0) { 208266077Sdes /* no ownername was given, try prev, if that fails 209266077Sdes * origin, else default to root */ 210266077Sdes uint8_t* tocopy; 211266077Sdes if(prev) { 212266077Sdes *dname_len = prev_len; 213266077Sdes tocopy = prev; 214266077Sdes } else if(origin) { 215266077Sdes *dname_len = origin_len; 216266077Sdes tocopy = origin; 217266077Sdes } else { 218266077Sdes *dname_len = 1; 219266077Sdes tocopy = (uint8_t*)"\0"; 220266077Sdes } 221266077Sdes if(*len < *dname_len) 222266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 223266077Sdes sldns_buffer_position(strbuf)); 224266077Sdes memmove(rr, tocopy, *dname_len); 225266077Sdes } else { 226266077Sdes size_t dlen = *len; 227266077Sdes int s = sldns_str2wire_dname_buf_origin(token, rr, &dlen, 228266077Sdes origin, origin_len); 229266077Sdes if(s) return RET_ERR_SHIFT(s, 230266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 231266077Sdes *dname_len = dlen; 232266077Sdes } 233266077Sdes return LDNS_WIREPARSE_ERR_OK; 234266077Sdes} 235266077Sdes 236266077Sdes/** read ttl */ 237266077Sdesstatic int 238266077Sdesrrinternal_get_ttl(sldns_buffer* strbuf, char* token, size_t token_len, 239266077Sdes int* not_there, uint32_t* ttl, uint32_t default_ttl) 240266077Sdes{ 241266077Sdes const char* endptr; 242266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 243266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TTL, 244266077Sdes sldns_buffer_position(strbuf)); 245266077Sdes } 246266077Sdes *ttl = (uint32_t) sldns_str2period(token, &endptr); 247266077Sdes 248276541Sdes if (strlen(token) > 0 && !isdigit((unsigned char)token[0])) { 249266077Sdes *not_there = 1; 250266077Sdes /* ah, it's not there or something */ 251266077Sdes if (default_ttl == 0) { 252266077Sdes *ttl = LDNS_DEFAULT_TTL; 253266077Sdes } else { 254266077Sdes *ttl = default_ttl; 255266077Sdes } 256266077Sdes } 257266077Sdes return LDNS_WIREPARSE_ERR_OK; 258266077Sdes} 259266077Sdes 260266077Sdes/** read class */ 261266077Sdesstatic int 262266077Sdesrrinternal_get_class(sldns_buffer* strbuf, char* token, size_t token_len, 263266077Sdes int* not_there, uint16_t* cl) 264266077Sdes{ 265266077Sdes /* if 'not_there' then we got token from previous parse routine */ 266266077Sdes if(!*not_there) { 267266077Sdes /* parse new token for class */ 268266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 269266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_CLASS, 270266077Sdes sldns_buffer_position(strbuf)); 271266077Sdes } 272266077Sdes } else *not_there = 0; 273266077Sdes *cl = sldns_get_rr_class_by_name(token); 274266077Sdes /* class can be left out too, assume IN, current token must be type */ 275266077Sdes if(*cl == 0 && strcmp(token, "CLASS0") != 0) { 276266077Sdes *not_there = 1; 277266077Sdes *cl = LDNS_RR_CLASS_IN; 278266077Sdes } 279266077Sdes return LDNS_WIREPARSE_ERR_OK; 280266077Sdes} 281266077Sdes 282266077Sdes/** read type */ 283266077Sdesstatic int 284266077Sdesrrinternal_get_type(sldns_buffer* strbuf, char* token, size_t token_len, 285266077Sdes int* not_there, uint16_t* tp) 286266077Sdes{ 287266077Sdes /* if 'not_there' then we got token from previous parse routine */ 288266077Sdes if(!*not_there) { 289266077Sdes /* parse new token for type */ 290266077Sdes if(sldns_bget_token(strbuf, token, "\t\n ", token_len) == -1) { 291266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE, 292266077Sdes sldns_buffer_position(strbuf)); 293266077Sdes } 294266077Sdes } 295266077Sdes *tp = sldns_get_rr_type_by_name(token); 296266077Sdes if(*tp == 0 && strcmp(token, "TYPE0") != 0) { 297266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE, 298266077Sdes sldns_buffer_position(strbuf)); 299266077Sdes } 300266077Sdes return LDNS_WIREPARSE_ERR_OK; 301266077Sdes} 302266077Sdes 303266077Sdes/** put type, class, ttl into rr buffer */ 304266077Sdesstatic int 305266077Sdesrrinternal_write_typeclassttl(sldns_buffer* strbuf, uint8_t* rr, size_t len, 306266077Sdes size_t dname_len, uint16_t tp, uint16_t cl, uint32_t ttl, int question) 307266077Sdes{ 308266077Sdes if(question) { 309266077Sdes /* question is : name, type, class */ 310266077Sdes if(dname_len + 4 > len) 311266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 312266077Sdes sldns_buffer_position(strbuf)); 313266077Sdes sldns_write_uint16(rr+dname_len, tp); 314266077Sdes sldns_write_uint16(rr+dname_len+2, cl); 315266077Sdes return LDNS_WIREPARSE_ERR_OK; 316266077Sdes } 317266077Sdes 318266077Sdes /* type(2), class(2), ttl(4), rdatalen(2 (later)) = 10 */ 319266077Sdes if(dname_len + 10 > 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 sldns_write_uint32(rr+dname_len+4, ttl); 325266077Sdes sldns_write_uint16(rr+dname_len+8, 0); /* rdatalen placeholder */ 326266077Sdes return LDNS_WIREPARSE_ERR_OK; 327266077Sdes} 328266077Sdes 329266077Sdes/** find delimiters for type */ 330266077Sdesstatic const char* 331266077Sdesrrinternal_get_delims(sldns_rdf_type rdftype, uint16_t r_cnt, uint16_t r_max) 332266077Sdes{ 333266077Sdes switch(rdftype) { 334266077Sdes case LDNS_RDF_TYPE_B64 : 335266077Sdes case LDNS_RDF_TYPE_HEX : /* These rdf types may con- */ 336266077Sdes case LDNS_RDF_TYPE_LOC : /* tain whitespace, only if */ 337266077Sdes case LDNS_RDF_TYPE_WKS : /* it is the last rd field. */ 338266077Sdes case LDNS_RDF_TYPE_IPSECKEY : 339266077Sdes case LDNS_RDF_TYPE_NSEC : if (r_cnt == r_max - 1) { 340276541Sdes return "\n"; 341266077Sdes } 342266077Sdes break; 343266077Sdes default : break; 344266077Sdes } 345266077Sdes return "\n\t "; 346266077Sdes} 347266077Sdes 348266077Sdes/* Syntactic sugar for sldns_rr_new_frm_str_internal */ 349266077Sdesstatic int 350266077Sdessldns_rdf_type_maybe_quoted(sldns_rdf_type rdf_type) 351266077Sdes{ 352266077Sdes return rdf_type == LDNS_RDF_TYPE_STR || 353266077Sdes rdf_type == LDNS_RDF_TYPE_LONG_STR; 354266077Sdes} 355266077Sdes 356266077Sdes/** see if rdata is quoted */ 357266077Sdesstatic int 358266077Sdesrrinternal_get_quoted(sldns_buffer* strbuf, const char** delimiters, 359266077Sdes sldns_rdf_type rdftype) 360266077Sdes{ 361266077Sdes if(sldns_rdf_type_maybe_quoted(rdftype) && 362266077Sdes sldns_buffer_remaining(strbuf) > 0) { 363266077Sdes 364266077Sdes /* skip spaces */ 365266077Sdes while(sldns_buffer_remaining(strbuf) > 0 && 366266077Sdes *(sldns_buffer_current(strbuf)) == ' ') { 367266077Sdes sldns_buffer_skip(strbuf, 1); 368266077Sdes } 369266077Sdes 370266077Sdes if(sldns_buffer_remaining(strbuf) > 0 && 371266077Sdes *(sldns_buffer_current(strbuf)) == '\"') { 372266077Sdes *delimiters = "\"\0"; 373266077Sdes sldns_buffer_skip(strbuf, 1); 374266077Sdes return 1; 375266077Sdes } 376266077Sdes } 377266077Sdes return 0; 378266077Sdes} 379266077Sdes 380266077Sdes/** spool hex data into rdata */ 381266077Sdesstatic int 382266077Sdesrrinternal_spool_hex(char* token, uint8_t* rr, size_t rr_len, 383266077Sdes size_t rr_cur_len, size_t* cur_hex_data_size, size_t hex_data_size) 384266077Sdes{ 385266077Sdes char* p = token; 386266077Sdes while(*p) { 387276541Sdes if(isspace((unsigned char)*p)) { 388266077Sdes p++; 389266077Sdes continue; 390266077Sdes } 391276541Sdes if(!isxdigit((unsigned char)*p)) 392266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 393266077Sdes p-token); 394266077Sdes if(*cur_hex_data_size >= hex_data_size) 395266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 396266077Sdes p-token); 397266077Sdes /* extra robust check */ 398266077Sdes if(rr_cur_len+(*cur_hex_data_size)/2 >= rr_len) 399266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 400266077Sdes p-token); 401266077Sdes /* see if 16s or 1s */ 402266077Sdes if( ((*cur_hex_data_size)&1) == 0) { 403266077Sdes rr[rr_cur_len+(*cur_hex_data_size)/2] = 404266077Sdes (uint8_t)sldns_hexdigit_to_int(*p)*16; 405266077Sdes } else { 406266077Sdes rr[rr_cur_len+(*cur_hex_data_size)/2] += 407266077Sdes (uint8_t)sldns_hexdigit_to_int(*p); 408266077Sdes } 409266077Sdes p++; 410266077Sdes (*cur_hex_data_size)++; 411266077Sdes } 412266077Sdes return LDNS_WIREPARSE_ERR_OK; 413266077Sdes} 414266077Sdes 415266077Sdes/** read unknown rr type format */ 416266077Sdesstatic int 417266077Sdesrrinternal_parse_unknown(sldns_buffer* strbuf, char* token, size_t token_len, 418266077Sdes uint8_t* rr, size_t* rr_len, size_t* rr_cur_len, size_t pre_data_pos) 419266077Sdes{ 420266077Sdes const char* delim = "\n\t "; 421266077Sdes size_t hex_data_size, cur_hex_data_size; 422266077Sdes /* go back to before \# 423266077Sdes * and skip it while setting delimiters better 424266077Sdes */ 425266077Sdes sldns_buffer_set_position(strbuf, pre_data_pos); 426266077Sdes if(sldns_bget_token(strbuf, token, delim, token_len) == -1) 427266077Sdes return LDNS_WIREPARSE_ERR_GENERAL; /* should not fail */ 428266077Sdes /* read rdata octet length */ 429266077Sdes if(sldns_bget_token(strbuf, token, delim, token_len) == -1) { 430266077Sdes /* something goes very wrong here */ 431266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 432266077Sdes sldns_buffer_position(strbuf)); 433266077Sdes } 434266077Sdes hex_data_size = (size_t)atoi(token); 435266077Sdes if(hex_data_size > LDNS_MAX_RDFLEN || 436266077Sdes *rr_cur_len + hex_data_size > *rr_len) { 437266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 438266077Sdes sldns_buffer_position(strbuf)); 439266077Sdes } 440266077Sdes /* copy hex chars into hex str (2 chars per byte) */ 441266077Sdes hex_data_size *= 2; 442266077Sdes cur_hex_data_size = 0; 443266077Sdes while(cur_hex_data_size < hex_data_size) { 444266077Sdes int status; 445266077Sdes ssize_t c = sldns_bget_token(strbuf, token, delim, token_len); 446266077Sdes if((status = rrinternal_spool_hex(token, rr, *rr_len, 447266077Sdes *rr_cur_len, &cur_hex_data_size, hex_data_size)) != 0) 448266077Sdes return RET_ERR_SHIFT(status, 449266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 450266077Sdes if(c == -1) { 451266077Sdes if(cur_hex_data_size != hex_data_size) 452266077Sdes return RET_ERR( 453266077Sdes LDNS_WIREPARSE_ERR_SYNTAX_RDATA, 454266077Sdes sldns_buffer_position(strbuf)); 455266077Sdes break; 456266077Sdes } 457266077Sdes } 458266077Sdes *rr_cur_len += hex_data_size/2; 459266077Sdes return LDNS_WIREPARSE_ERR_OK; 460266077Sdes} 461266077Sdes 462266077Sdes/** parse normal RR rdata element */ 463266077Sdesstatic int 464266077Sdesrrinternal_parse_rdf(sldns_buffer* strbuf, char* token, size_t token_len, 465266077Sdes uint8_t* rr, size_t rr_len, size_t* rr_cur_len, sldns_rdf_type rdftype, 466266077Sdes uint16_t rr_type, uint16_t r_cnt, uint16_t r_max, size_t dname_len, 467266077Sdes uint8_t* origin, size_t origin_len) 468266077Sdes{ 469266077Sdes size_t len; 470266077Sdes int status; 471266077Sdes 472266077Sdes switch(rdftype) { 473266077Sdes case LDNS_RDF_TYPE_DNAME: 474266077Sdes /* check if the origin should be used or concatenated */ 475266077Sdes if(strcmp(token, "@") == 0) { 476266077Sdes uint8_t* tocopy; 477266077Sdes size_t copylen; 478266077Sdes if(origin) { 479266077Sdes copylen = origin_len; 480266077Sdes tocopy = origin; 481266077Sdes } else if(rr_type == LDNS_RR_TYPE_SOA) { 482266077Sdes copylen = dname_len; 483266077Sdes tocopy = rr; /* copy rr owner name */ 484266077Sdes } else { 485266077Sdes copylen = 1; 486266077Sdes tocopy = (uint8_t*)"\0"; 487266077Sdes } 488266077Sdes if((*rr_cur_len) + copylen > rr_len) 489266077Sdes return RET_ERR( 490266077Sdes LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 491266077Sdes sldns_buffer_position(strbuf)); 492266077Sdes memmove(rr+*rr_cur_len, tocopy, copylen); 493266077Sdes (*rr_cur_len) += copylen; 494266077Sdes } else { 495266077Sdes size_t dlen = rr_len - (*rr_cur_len); 496266077Sdes int s = sldns_str2wire_dname_buf_origin(token, 497266077Sdes rr+*rr_cur_len, &dlen, origin, origin_len); 498266077Sdes if(s) return RET_ERR_SHIFT(s, 499266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 500266077Sdes (*rr_cur_len) += dlen; 501266077Sdes } 502266077Sdes return LDNS_WIREPARSE_ERR_OK; 503266077Sdes 504266077Sdes case LDNS_RDF_TYPE_HEX: 505266077Sdes case LDNS_RDF_TYPE_B64: 506266077Sdes /* When this is the last rdata field, then the 507266077Sdes * rest should be read in (cause then these 508266077Sdes * rdf types may contain spaces). */ 509266077Sdes if(r_cnt == r_max - 1) { 510266077Sdes size_t tlen = strlen(token); 511266077Sdes (void)sldns_bget_token(strbuf, token+tlen, "\n", 512266077Sdes token_len - tlen); 513266077Sdes } 514266077Sdes break; 515266077Sdes default: 516266077Sdes break; 517266077Sdes } 518266077Sdes 519266077Sdes len = rr_len - (*rr_cur_len); 520266077Sdes if((status=sldns_str2wire_rdf_buf(token, rr+(*rr_cur_len), &len, 521266077Sdes rdftype)) != 0) 522266077Sdes return RET_ERR_SHIFT(status, 523266077Sdes sldns_buffer_position(strbuf)-strlen(token)); 524266077Sdes *rr_cur_len += len; 525266077Sdes return LDNS_WIREPARSE_ERR_OK; 526266077Sdes} 527266077Sdes 528266077Sdes/** 529266077Sdes * Parse one rdf token. Takes care of quotes and parenthesis. 530266077Sdes */ 531266077Sdesstatic int 532266077Sdessldns_parse_rdf_token(sldns_buffer* strbuf, char* token, size_t token_len, 533266077Sdes int* quoted, int* parens, size_t* pre_data_pos, 534266077Sdes const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen) 535266077Sdes{ 536266077Sdes size_t slen; 537266077Sdes 538266077Sdes /* skip spaces */ 539266077Sdes while(sldns_buffer_remaining(strbuf) > 0 && !*quoted && 540266077Sdes *(sldns_buffer_current(strbuf)) == ' ') { 541266077Sdes sldns_buffer_skip(strbuf, 1); 542266077Sdes } 543266077Sdes 544266077Sdes *pre_data_pos = sldns_buffer_position(strbuf); 545266077Sdes if(sldns_bget_token_par(strbuf, token, (*quoted)?"\"":delimiters, 546266077Sdes token_len, parens, (*quoted)?NULL:" \t") == -1) { 547266077Sdes return 0; 548266077Sdes } 549266077Sdes slen = strlen(token); 550266077Sdes /* check if not quoted yet, and we have encountered quotes */ 551266077Sdes if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) && 552266077Sdes slen >= 2 && 553266077Sdes (token[0] == '"' || token[0] == '\'') && 554266077Sdes (token[slen-1] == '"' || token[slen-1] == '\'')) { 555266077Sdes /* move token two smaller (quotes) with endnull */ 556266077Sdes memmove(token, token+1, slen-2); 557266077Sdes token[slen-2] = 0; 558266077Sdes slen -= 2; 559266077Sdes *quoted = 1; 560266077Sdes } else if(!*quoted && sldns_rdf_type_maybe_quoted(rdftype) && 561266077Sdes slen >= 2 && 562266077Sdes (token[0] == '"' || token[0] == '\'')) { 563266077Sdes /* got the start quote (remove it) but read remainder 564266077Sdes * of quoted string as well into remainder of token */ 565266077Sdes memmove(token, token+1, slen-1); 566266077Sdes token[slen-1] = 0; 567266077Sdes slen -= 1; 568266077Sdes *quoted = 1; 569266077Sdes /* rewind buffer over skipped whitespace */ 570266077Sdes while(sldns_buffer_position(strbuf) > 0 && 571266077Sdes (sldns_buffer_current(strbuf)[-1] == ' ' || 572266077Sdes sldns_buffer_current(strbuf)[-1] == '\t')) { 573266077Sdes sldns_buffer_skip(strbuf, -1); 574266077Sdes } 575266077Sdes if(sldns_bget_token_par(strbuf, token+slen, 576266077Sdes "\"", token_len-slen, 577266077Sdes parens, NULL) == -1) { 578266077Sdes return 0; 579266077Sdes } 580266077Sdes slen = strlen(token); 581266077Sdes } 582266077Sdes *token_strlen = slen; 583266077Sdes return 1; 584266077Sdes} 585266077Sdes 586266077Sdes/** Add space and one more rdf token onto the existing token string. */ 587266077Sdesstatic int 588266077Sdessldns_affix_token(sldns_buffer* strbuf, char* token, size_t* token_len, 589266077Sdes int* quoted, int* parens, size_t* pre_data_pos, 590266077Sdes const char* delimiters, sldns_rdf_type rdftype, size_t* token_strlen) 591266077Sdes{ 592266077Sdes size_t addlen = *token_len - *token_strlen; 593266077Sdes size_t addstrlen = 0; 594266077Sdes 595266077Sdes /* add space */ 596266077Sdes if(addlen < 1) return 0; 597266077Sdes token[*token_strlen] = ' '; 598266077Sdes token[++(*token_strlen)] = 0; 599266077Sdes 600266077Sdes /* read another token */ 601266077Sdes addlen = *token_len - *token_strlen; 602266077Sdes if(!sldns_parse_rdf_token(strbuf, token+*token_strlen, addlen, quoted, 603266077Sdes parens, pre_data_pos, delimiters, rdftype, &addstrlen)) 604266077Sdes return 0; 605266077Sdes (*token_strlen) += addstrlen; 606266077Sdes return 1; 607266077Sdes} 608266077Sdes 609266077Sdes/** parse rdata from string into rr buffer(-remainder after dname). */ 610266077Sdesstatic int 611266077Sdesrrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len, 612266077Sdes uint8_t* rr, size_t* rr_len, size_t dname_len, uint16_t rr_type, 613266077Sdes uint8_t* origin, size_t origin_len) 614266077Sdes{ 615266077Sdes const sldns_rr_descriptor *desc = sldns_rr_descript((uint16_t)rr_type); 616266077Sdes uint16_t r_cnt, r_min, r_max; 617266077Sdes size_t rr_cur_len = dname_len + 10, pre_data_pos, token_strlen; 618266077Sdes int was_unknown_rr_format = 0, parens = 0, status, quoted; 619266077Sdes const char* delimiters; 620266077Sdes sldns_rdf_type rdftype; 621266077Sdes /* a desc is always returned */ 622266077Sdes if(!desc) return LDNS_WIREPARSE_ERR_GENERAL; 623266077Sdes r_max = sldns_rr_descriptor_maximum(desc); 624266077Sdes r_min = sldns_rr_descriptor_minimum(desc); 625266077Sdes /* robust check */ 626266077Sdes if(rr_cur_len > *rr_len) 627266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 628266077Sdes sldns_buffer_position(strbuf)); 629266077Sdes 630266077Sdes /* because number of fields can be variable, we can't rely on 631266077Sdes * _maximum() only */ 632266077Sdes for(r_cnt=0; r_cnt < r_max; r_cnt++) { 633266077Sdes rdftype = sldns_rr_descriptor_field_type(desc, r_cnt); 634266077Sdes delimiters = rrinternal_get_delims(rdftype, r_cnt, r_max); 635266077Sdes quoted = rrinternal_get_quoted(strbuf, &delimiters, rdftype); 636266077Sdes 637266077Sdes if(!sldns_parse_rdf_token(strbuf, token, token_len, "ed, 638266077Sdes &parens, &pre_data_pos, delimiters, rdftype, 639266077Sdes &token_strlen)) 640266077Sdes break; 641266077Sdes 642266077Sdes /* rfc3597 specifies that any type can be represented 643266077Sdes * with \# method, which can contain spaces... 644266077Sdes * it does specify size though... */ 645266077Sdes 646266077Sdes /* unknown RR data */ 647266077Sdes if(token_strlen>=2 && strncmp(token, "\\#", 2) == 0 && 648266077Sdes !quoted && (token_strlen == 2 || token[2]==' ')) { 649266077Sdes was_unknown_rr_format = 1; 650266077Sdes if((status=rrinternal_parse_unknown(strbuf, token, 651266077Sdes token_len, rr, rr_len, &rr_cur_len, 652266077Sdes pre_data_pos)) != 0) 653266077Sdes return status; 654266077Sdes } else if(token_strlen > 0 || quoted) { 655266077Sdes if(rdftype == LDNS_RDF_TYPE_HIP) { 656266077Sdes /* affix the HIT and PK fields, with a space */ 657266077Sdes if(!sldns_affix_token(strbuf, token, 658266077Sdes &token_len, "ed, &parens, 659266077Sdes &pre_data_pos, delimiters, 660266077Sdes rdftype, &token_strlen)) 661266077Sdes break; 662266077Sdes if(!sldns_affix_token(strbuf, token, 663266077Sdes &token_len, "ed, &parens, 664266077Sdes &pre_data_pos, delimiters, 665266077Sdes rdftype, &token_strlen)) 666266077Sdes break; 667266077Sdes } 668266077Sdes 669266077Sdes /* normal RR */ 670266077Sdes if((status=rrinternal_parse_rdf(strbuf, token, 671266077Sdes token_len, rr, *rr_len, &rr_cur_len, rdftype, 672266077Sdes rr_type, r_cnt, r_max, dname_len, origin, 673266077Sdes origin_len)) != 0) { 674266077Sdes return status; 675266077Sdes } 676266077Sdes } 677266077Sdes } 678266077Sdes if(!was_unknown_rr_format && r_cnt+1 < r_min) { 679266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_MISSING_VALUE, 680266077Sdes sldns_buffer_position(strbuf)); 681266077Sdes } 682266077Sdes while(parens != 0) { 683266077Sdes /* read remainder, must be "" */ 684266077Sdes if(sldns_bget_token_par(strbuf, token, "\n", token_len, 685266077Sdes &parens, " \t") == -1) { 686266077Sdes if(parens != 0) 687266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS, 688266077Sdes sldns_buffer_position(strbuf)); 689266077Sdes break; 690266077Sdes } 691266077Sdes if(strcmp(token, "") != 0) 692266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_PARENTHESIS, 693266077Sdes sldns_buffer_position(strbuf)); 694266077Sdes } 695266077Sdes /* write rdata length */ 696266077Sdes sldns_write_uint16(rr+dname_len+8, rr_cur_len-dname_len-10); 697266077Sdes *rr_len = rr_cur_len; 698266077Sdes return LDNS_WIREPARSE_ERR_OK; 699266077Sdes} 700266077Sdes 701266077Sdes/* 702266077Sdes * trailing spaces are allowed 703266077Sdes * leading spaces are not allowed 704266077Sdes * allow ttl to be optional 705266077Sdes * class is optional too 706266077Sdes * if ttl is missing, and default_ttl is 0, use DEF_TTL 707266077Sdes * allow ttl to be written as 1d3h 708266077Sdes * So the RR should look like. e.g. 709266077Sdes * miek.nl. 3600 IN MX 10 elektron.atoom.net 710266077Sdes * or 711266077Sdes * miek.nl. 1h IN MX 10 elektron.atoom.net 712266077Sdes * or 713266077Sdes * miek.nl. IN MX 10 elektron.atoom.net 714266077Sdes */ 715266077Sdesstatic int 716266077Sdessldns_str2wire_rr_buf_internal(const char* str, uint8_t* rr, size_t* len, 717266077Sdes size_t* dname_len, uint32_t default_ttl, uint8_t* origin, 718266077Sdes size_t origin_len, uint8_t* prev, size_t prev_len, int question) 719266077Sdes{ 720266077Sdes int status; 721266077Sdes int not_there = 0; 722266077Sdes char token[LDNS_MAX_RDFLEN+1]; 723266077Sdes uint32_t ttl = 0; 724266077Sdes uint16_t tp = 0, cl = 0; 725266077Sdes size_t ddlen = 0; 726266077Sdes 727266077Sdes /* string in buffer */ 728266077Sdes sldns_buffer strbuf; 729266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 730266077Sdes if(!dname_len) dname_len = &ddlen; 731266077Sdes 732266077Sdes /* parse the owner */ 733266077Sdes if((status=rrinternal_get_owner(&strbuf, rr, len, dname_len, origin, 734266077Sdes origin_len, prev, prev_len, token, sizeof(token))) != 0) 735266077Sdes return status; 736266077Sdes 737266077Sdes /* parse the [ttl] [class] <type> */ 738266077Sdes if((status=rrinternal_get_ttl(&strbuf, token, sizeof(token), 739266077Sdes ¬_there, &ttl, default_ttl)) != 0) 740266077Sdes return status; 741266077Sdes if((status=rrinternal_get_class(&strbuf, token, sizeof(token), 742266077Sdes ¬_there, &cl)) != 0) 743266077Sdes return status; 744266077Sdes if((status=rrinternal_get_type(&strbuf, token, sizeof(token), 745266077Sdes ¬_there, &tp)) != 0) 746266077Sdes return status; 747266077Sdes /* put ttl, class, type into the rr result */ 748266077Sdes if((status=rrinternal_write_typeclassttl(&strbuf, rr, *len, *dname_len, tp, cl, 749266077Sdes ttl, question)) != 0) 750266077Sdes return status; 751266077Sdes /* for a question-RR we are done, no rdata */ 752266077Sdes if(question) { 753266077Sdes *len = *dname_len + 4; 754266077Sdes return LDNS_WIREPARSE_ERR_OK; 755266077Sdes } 756266077Sdes 757266077Sdes /* rdata */ 758266077Sdes if((status=rrinternal_parse_rdata(&strbuf, token, sizeof(token), 759266077Sdes rr, len, *dname_len, tp, origin, origin_len)) != 0) 760266077Sdes return status; 761266077Sdes 762266077Sdes return LDNS_WIREPARSE_ERR_OK; 763266077Sdes} 764266077Sdes 765266077Sdesint sldns_str2wire_rr_buf(const char* str, uint8_t* rr, size_t* len, 766266077Sdes size_t* dname_len, uint32_t default_ttl, uint8_t* origin, 767266077Sdes size_t origin_len, uint8_t* prev, size_t prev_len) 768266077Sdes{ 769266077Sdes return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len, 770266077Sdes default_ttl, origin, origin_len, prev, prev_len, 0); 771266077Sdes} 772266077Sdes 773266077Sdesint sldns_str2wire_rr_question_buf(const char* str, uint8_t* rr, size_t* len, 774266077Sdes size_t* dname_len, uint8_t* origin, size_t origin_len, uint8_t* prev, 775266077Sdes size_t prev_len) 776266077Sdes{ 777266077Sdes return sldns_str2wire_rr_buf_internal(str, rr, len, dname_len, 778266077Sdes 0, origin, origin_len, prev, prev_len, 1); 779266077Sdes} 780266077Sdes 781266077Sdesuint16_t sldns_wirerr_get_type(uint8_t* rr, size_t len, size_t dname_len) 782266077Sdes{ 783266077Sdes if(len < dname_len+2) 784266077Sdes return 0; 785266077Sdes return sldns_read_uint16(rr+dname_len); 786266077Sdes} 787266077Sdes 788266077Sdesuint16_t sldns_wirerr_get_class(uint8_t* rr, size_t len, size_t dname_len) 789266077Sdes{ 790266077Sdes if(len < dname_len+4) 791266077Sdes return 0; 792266077Sdes return sldns_read_uint16(rr+dname_len+2); 793266077Sdes} 794266077Sdes 795266077Sdesuint32_t sldns_wirerr_get_ttl(uint8_t* rr, size_t len, size_t dname_len) 796266077Sdes{ 797266077Sdes if(len < dname_len+8) 798266077Sdes return 0; 799266077Sdes return sldns_read_uint32(rr+dname_len+4); 800266077Sdes} 801266077Sdes 802266077Sdesuint16_t sldns_wirerr_get_rdatalen(uint8_t* rr, size_t len, size_t dname_len) 803266077Sdes{ 804266077Sdes if(len < dname_len+10) 805266077Sdes return 0; 806266077Sdes return sldns_read_uint16(rr+dname_len+8); 807266077Sdes} 808266077Sdes 809266077Sdesuint8_t* sldns_wirerr_get_rdata(uint8_t* rr, size_t len, size_t dname_len) 810266077Sdes{ 811266077Sdes if(len < dname_len+10) 812266077Sdes return NULL; 813266077Sdes return rr+dname_len+10; 814266077Sdes} 815266077Sdes 816266077Sdesuint8_t* sldns_wirerr_get_rdatawl(uint8_t* rr, size_t len, size_t dname_len) 817266077Sdes{ 818266077Sdes if(len < dname_len+10) 819266077Sdes return NULL; 820266077Sdes return rr+dname_len+8; 821266077Sdes} 822266077Sdes 823266077Sdesconst char* sldns_get_errorstr_parse(int e) 824266077Sdes{ 825266077Sdes sldns_lookup_table *lt; 826266077Sdes lt = sldns_lookup_by_id(sldns_wireparse_errors, LDNS_WIREPARSE_ERROR(e)); 827266077Sdes return lt?lt->name:"unknown error"; 828266077Sdes} 829266077Sdes 830276541Sdes/* Strip whitespace from the start and the end of <line>. */ 831276541Sdesstatic char * 832276541Sdessldns_strip_ws(char *line) 833276541Sdes{ 834276541Sdes char *s = line, *e; 835276541Sdes 836276541Sdes for (s = line; *s && isspace((unsigned char)*s); s++) 837276541Sdes ; 838276541Sdes for (e = strchr(s, 0); e > s+2 && isspace((unsigned char)e[-1]) && e[-2] != '\\'; e--) 839276541Sdes ; 840276541Sdes *e = 0; 841276541Sdes return s; 842276541Sdes} 843276541Sdes 844266077Sdesint sldns_fp2wire_rr_buf(FILE* in, uint8_t* rr, size_t* len, size_t* dname_len, 845266077Sdes struct sldns_file_parse_state* parse_state) 846266077Sdes{ 847266077Sdes char line[LDNS_RR_BUF_SIZE+1]; 848266077Sdes ssize_t size; 849266077Sdes 850266077Sdes /* read an entire line in from the file */ 851266077Sdes if((size = sldns_fget_token_l(in, line, LDNS_PARSE_SKIP_SPACE, 852266077Sdes LDNS_RR_BUF_SIZE, parse_state?&parse_state->lineno:NULL)) 853266077Sdes == -1) { 854266077Sdes /* if last line was empty, we are now at feof, which is not 855266077Sdes * always a parse error (happens when for instance last line 856266077Sdes * was a comment) 857266077Sdes */ 858266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX; 859266077Sdes } 860266077Sdes 861266077Sdes /* we can have the situation, where we've read ok, but still got 862266077Sdes * no bytes to play with, in this case size is 0 */ 863266077Sdes if(size == 0) { 864266077Sdes *len = 0; 865266077Sdes *dname_len = 0; 866266077Sdes return LDNS_WIREPARSE_ERR_OK; 867266077Sdes } 868266077Sdes 869276541Sdes if(strncmp(line, "$ORIGIN", 7) == 0 && isspace((unsigned char)line[7])) { 870266077Sdes int s; 871266077Sdes *len = 0; 872266077Sdes *dname_len = 0; 873266077Sdes if(!parse_state) return LDNS_WIREPARSE_ERR_OK; 874266077Sdes parse_state->origin_len = sizeof(parse_state->origin); 875276541Sdes s = sldns_str2wire_dname_buf(sldns_strip_ws(line+8), 876276541Sdes parse_state->origin, &parse_state->origin_len); 877266077Sdes if(s) parse_state->origin_len = 0; 878266077Sdes return s; 879276541Sdes } else if(strncmp(line, "$TTL", 4) == 0 && isspace((unsigned char)line[4])) { 880266077Sdes const char* end = NULL; 881266077Sdes *len = 0; 882266077Sdes *dname_len = 0; 883266077Sdes if(!parse_state) return LDNS_WIREPARSE_ERR_OK; 884276541Sdes parse_state->default_ttl = sldns_str2period( 885276541Sdes sldns_strip_ws(line+5), &end); 886266077Sdes } else if (strncmp(line, "$INCLUDE", 8) == 0) { 887266077Sdes *len = 0; 888266077Sdes *dname_len = 0; 889266077Sdes return LDNS_WIREPARSE_ERR_INCLUDE; 890266077Sdes } else { 891266077Sdes return sldns_str2wire_rr_buf(line, rr, len, dname_len, 892266077Sdes parse_state?parse_state->default_ttl:0, 893266077Sdes (parse_state&&parse_state->origin_len)? 894266077Sdes parse_state->origin:NULL, 895266077Sdes parse_state->origin_len, 896266077Sdes (parse_state&&parse_state->prev_rr_len)? 897266077Sdes parse_state->prev_rr:NULL, 898266077Sdes parse_state->prev_rr_len); 899266077Sdes } 900266077Sdes return LDNS_WIREPARSE_ERR_OK; 901266077Sdes} 902266077Sdes 903266077Sdesint sldns_str2wire_rdf_buf(const char* str, uint8_t* rd, size_t* len, 904266077Sdes sldns_rdf_type rdftype) 905266077Sdes{ 906266077Sdes switch (rdftype) { 907266077Sdes case LDNS_RDF_TYPE_DNAME: 908266077Sdes return sldns_str2wire_dname_buf(str, rd, len); 909266077Sdes case LDNS_RDF_TYPE_INT8: 910266077Sdes return sldns_str2wire_int8_buf(str, rd, len); 911266077Sdes case LDNS_RDF_TYPE_INT16: 912266077Sdes return sldns_str2wire_int16_buf(str, rd, len); 913266077Sdes case LDNS_RDF_TYPE_INT32: 914266077Sdes return sldns_str2wire_int32_buf(str, rd, len); 915266077Sdes case LDNS_RDF_TYPE_A: 916266077Sdes return sldns_str2wire_a_buf(str, rd, len); 917266077Sdes case LDNS_RDF_TYPE_AAAA: 918266077Sdes return sldns_str2wire_aaaa_buf(str, rd, len); 919266077Sdes case LDNS_RDF_TYPE_STR: 920266077Sdes return sldns_str2wire_str_buf(str, rd, len); 921266077Sdes case LDNS_RDF_TYPE_APL: 922266077Sdes return sldns_str2wire_apl_buf(str, rd, len); 923266077Sdes case LDNS_RDF_TYPE_B64: 924266077Sdes return sldns_str2wire_b64_buf(str, rd, len); 925266077Sdes case LDNS_RDF_TYPE_B32_EXT: 926266077Sdes return sldns_str2wire_b32_ext_buf(str, rd, len); 927266077Sdes case LDNS_RDF_TYPE_HEX: 928266077Sdes return sldns_str2wire_hex_buf(str, rd, len); 929266077Sdes case LDNS_RDF_TYPE_NSEC: 930266077Sdes return sldns_str2wire_nsec_buf(str, rd, len); 931266077Sdes case LDNS_RDF_TYPE_TYPE: 932266077Sdes return sldns_str2wire_type_buf(str, rd, len); 933266077Sdes case LDNS_RDF_TYPE_CLASS: 934266077Sdes return sldns_str2wire_class_buf(str, rd, len); 935266077Sdes case LDNS_RDF_TYPE_CERT_ALG: 936266077Sdes return sldns_str2wire_cert_alg_buf(str, rd, len); 937266077Sdes case LDNS_RDF_TYPE_ALG: 938266077Sdes return sldns_str2wire_alg_buf(str, rd, len); 939266077Sdes case LDNS_RDF_TYPE_TIME: 940266077Sdes return sldns_str2wire_time_buf(str, rd, len); 941266077Sdes case LDNS_RDF_TYPE_PERIOD: 942266077Sdes return sldns_str2wire_period_buf(str, rd, len); 943266077Sdes case LDNS_RDF_TYPE_LOC: 944266077Sdes return sldns_str2wire_loc_buf(str, rd, len); 945266077Sdes case LDNS_RDF_TYPE_WKS: 946266077Sdes return sldns_str2wire_wks_buf(str, rd, len); 947266077Sdes case LDNS_RDF_TYPE_NSAP: 948266077Sdes return sldns_str2wire_nsap_buf(str, rd, len); 949266077Sdes case LDNS_RDF_TYPE_ATMA: 950266077Sdes return sldns_str2wire_atma_buf(str, rd, len); 951266077Sdes case LDNS_RDF_TYPE_IPSECKEY: 952266077Sdes return sldns_str2wire_ipseckey_buf(str, rd, len); 953266077Sdes case LDNS_RDF_TYPE_NSEC3_SALT: 954266077Sdes return sldns_str2wire_nsec3_salt_buf(str, rd, len); 955266077Sdes case LDNS_RDF_TYPE_NSEC3_NEXT_OWNER: 956266077Sdes return sldns_str2wire_b32_ext_buf(str, rd, len); 957266077Sdes case LDNS_RDF_TYPE_ILNP64: 958266077Sdes return sldns_str2wire_ilnp64_buf(str, rd, len); 959266077Sdes case LDNS_RDF_TYPE_EUI48: 960266077Sdes return sldns_str2wire_eui48_buf(str, rd, len); 961266077Sdes case LDNS_RDF_TYPE_EUI64: 962266077Sdes return sldns_str2wire_eui64_buf(str, rd, len); 963266077Sdes case LDNS_RDF_TYPE_TAG: 964266077Sdes return sldns_str2wire_tag_buf(str, rd, len); 965266077Sdes case LDNS_RDF_TYPE_LONG_STR: 966266077Sdes return sldns_str2wire_long_str_buf(str, rd, len); 967266077Sdes case LDNS_RDF_TYPE_HIP: 968266077Sdes return sldns_str2wire_hip_buf(str, rd, len); 969266077Sdes case LDNS_RDF_TYPE_INT16_DATA: 970266077Sdes return sldns_str2wire_int16_data_buf(str, rd, len); 971266077Sdes case LDNS_RDF_TYPE_UNKNOWN: 972266077Sdes case LDNS_RDF_TYPE_SERVICE: 973266077Sdes return LDNS_WIREPARSE_ERR_NOT_IMPL; 974266077Sdes case LDNS_RDF_TYPE_NONE: 975266077Sdes default: 976266077Sdes break; 977266077Sdes } 978266077Sdes return LDNS_WIREPARSE_ERR_GENERAL; 979266077Sdes} 980266077Sdes 981266077Sdesint sldns_str2wire_int8_buf(const char* str, uint8_t* rd, size_t* len) 982266077Sdes{ 983266077Sdes char* end; 984266077Sdes uint8_t r = (uint8_t)strtol((char*)str, &end, 10); 985266077Sdes if(*end != 0) 986266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str); 987266077Sdes if(*len < 1) 988266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 989266077Sdes rd[0] = r; 990266077Sdes *len = 1; 991266077Sdes return LDNS_WIREPARSE_ERR_OK; 992266077Sdes} 993266077Sdes 994266077Sdesint sldns_str2wire_int16_buf(const char* str, uint8_t* rd, size_t* len) 995266077Sdes{ 996266077Sdes char* end; 997266077Sdes uint16_t r = (uint16_t)strtol((char*)str, &end, 10); 998266077Sdes if(*end != 0) 999266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str); 1000266077Sdes if(*len < 2) 1001266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1002266077Sdes sldns_write_uint16(rd, r); 1003266077Sdes *len = 2; 1004266077Sdes return LDNS_WIREPARSE_ERR_OK; 1005266077Sdes} 1006266077Sdes 1007266077Sdesint sldns_str2wire_int32_buf(const char* str, uint8_t* rd, size_t* len) 1008266077Sdes{ 1009266077Sdes char* end; 1010266077Sdes uint32_t r; 1011266077Sdes errno = 0; /* must set to zero before call, 1012266077Sdes note race condition on errno */ 1013266077Sdes if(*str == '-') 1014266077Sdes r = (uint32_t)strtol((char*)str, &end, 10); 1015266077Sdes else r = (uint32_t)strtoul((char*)str, &end, 10); 1016266077Sdes if(*end != 0) 1017266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, end-(char*)str); 1018266077Sdes if(errno == ERANGE) 1019266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_INTEGER_OVERFLOW; 1020266077Sdes if(*len < 4) 1021266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1022266077Sdes sldns_write_uint32(rd, r); 1023266077Sdes *len = 4; 1024266077Sdes return LDNS_WIREPARSE_ERR_OK; 1025266077Sdes} 1026266077Sdes 1027266077Sdesint sldns_str2wire_a_buf(const char* str, uint8_t* rd, size_t* len) 1028266077Sdes{ 1029266077Sdes struct in_addr address; 1030266077Sdes if(inet_pton(AF_INET, (char*)str, &address) != 1) 1031266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_IP4; 1032266077Sdes if(*len < sizeof(address)) 1033266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1034266077Sdes memmove(rd, &address, sizeof(address)); 1035266077Sdes *len = sizeof(address); 1036266077Sdes return LDNS_WIREPARSE_ERR_OK; 1037266077Sdes} 1038266077Sdes 1039266077Sdesint sldns_str2wire_aaaa_buf(const char* str, uint8_t* rd, size_t* len) 1040266077Sdes{ 1041266077Sdes#ifdef AF_INET6 1042266077Sdes uint8_t address[LDNS_IP6ADDRLEN + 1]; 1043266077Sdes if(inet_pton(AF_INET6, (char*)str, address) != 1) 1044266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_IP6; 1045266077Sdes if(*len < LDNS_IP6ADDRLEN) 1046266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1047266077Sdes memmove(rd, address, LDNS_IP6ADDRLEN); 1048266077Sdes *len = LDNS_IP6ADDRLEN; 1049266077Sdes return LDNS_WIREPARSE_ERR_OK; 1050266077Sdes#else 1051266077Sdes return LDNS_WIREPARSE_ERR_NOT_IMPL; 1052266077Sdes#endif 1053266077Sdes} 1054266077Sdes 1055266077Sdesint sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len) 1056266077Sdes{ 1057266077Sdes uint8_t ch = 0; 1058266077Sdes size_t sl = 0; 1059266077Sdes const char* s = str; 1060266077Sdes /* skip length byte */ 1061266077Sdes if(*len < 1) 1062266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1063266077Sdes 1064266077Sdes /* read characters */ 1065266077Sdes while(sldns_parse_char(&ch, &s)) { 1066266077Sdes if(sl >= 255) 1067266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, s-str); 1068266077Sdes if(*len < sl+1) 1069266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1070266077Sdes s-str); 1071266077Sdes rd[++sl] = ch; 1072266077Sdes } 1073266077Sdes if(!s) 1074266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE; 1075266077Sdes rd[0] = (uint8_t)sl; 1076266077Sdes *len = sl+1; 1077266077Sdes return LDNS_WIREPARSE_ERR_OK; 1078266077Sdes} 1079266077Sdes 1080266077Sdesint sldns_str2wire_apl_buf(const char* str, uint8_t* rd, size_t* len) 1081266077Sdes{ 1082266077Sdes const char *my_str = str; 1083266077Sdes 1084266077Sdes char my_ip_str[64]; 1085266077Sdes size_t ip_str_len; 1086266077Sdes 1087266077Sdes uint16_t family; 1088266077Sdes int negation; 1089266077Sdes size_t adflength = 0; 1090266077Sdes uint8_t data[16+4]; 1091266077Sdes uint8_t prefix; 1092266077Sdes size_t i; 1093266077Sdes 1094266077Sdes if(strlen(my_str) == 0) { 1095266077Sdes /* empty APL element, no data, no string */ 1096266077Sdes *len = 0; 1097266077Sdes return LDNS_WIREPARSE_ERR_OK; 1098266077Sdes } 1099266077Sdes 1100266077Sdes /* [!]afi:address/prefix */ 1101266077Sdes if (strlen(my_str) < 2 1102266077Sdes || strchr(my_str, ':') == NULL 1103266077Sdes || strchr(my_str, '/') == NULL 1104266077Sdes || strchr(my_str, ':') > strchr(my_str, '/')) { 1105266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1106266077Sdes } 1107266077Sdes 1108266077Sdes if (my_str[0] == '!') { 1109266077Sdes negation = 1; 1110266077Sdes my_str += 1; 1111266077Sdes } else { 1112266077Sdes negation = 0; 1113266077Sdes } 1114266077Sdes 1115266077Sdes family = (uint16_t) atoi(my_str); 1116266077Sdes 1117266077Sdes my_str = strchr(my_str, ':') + 1; 1118266077Sdes 1119266077Sdes /* need ip addr and only ip addr for inet_pton */ 1120266077Sdes ip_str_len = (size_t) (strchr(my_str, '/') - my_str); 1121266077Sdes if(ip_str_len+1 > sizeof(my_ip_str)) 1122266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1123266077Sdes (void)strlcpy(my_ip_str, my_str, sizeof(my_ip_str)); 1124266077Sdes my_ip_str[ip_str_len] = 0; 1125266077Sdes 1126266077Sdes if (family == 1) { 1127266077Sdes /* ipv4 */ 1128266077Sdes if(inet_pton(AF_INET, my_ip_str, data+4) == 0) 1129266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1130266077Sdes for (i = 0; i < 4; i++) { 1131266077Sdes if (data[i+4] != 0) { 1132266077Sdes adflength = i + 1; 1133266077Sdes } 1134266077Sdes } 1135266077Sdes } else if (family == 2) { 1136266077Sdes /* ipv6 */ 1137266077Sdes if (inet_pton(AF_INET6, my_ip_str, data+4) == 0) 1138266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1139266077Sdes for (i = 0; i < 16; i++) { 1140266077Sdes if (data[i+4] != 0) { 1141266077Sdes adflength = i + 1; 1142266077Sdes } 1143266077Sdes } 1144266077Sdes } else { 1145266077Sdes /* unknown family */ 1146266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1147266077Sdes } 1148266077Sdes 1149266077Sdes my_str = strchr(my_str, '/') + 1; 1150266077Sdes prefix = (uint8_t) atoi(my_str); 1151266077Sdes 1152266077Sdes sldns_write_uint16(data, family); 1153266077Sdes data[2] = prefix; 1154266077Sdes data[3] = (uint8_t)adflength; 1155266077Sdes if (negation) { 1156266077Sdes /* set bit 1 of byte 3 */ 1157266077Sdes data[3] = data[3] | 0x80; 1158266077Sdes } 1159266077Sdes 1160266077Sdes if(*len < 4+adflength) 1161266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1162266077Sdes memmove(rd, data, 4+adflength); 1163266077Sdes *len = 4+adflength; 1164266077Sdes return LDNS_WIREPARSE_ERR_OK; 1165266077Sdes} 1166266077Sdes 1167266077Sdesint sldns_str2wire_b64_buf(const char* str, uint8_t* rd, size_t* len) 1168266077Sdes{ 1169266077Sdes size_t sz = sldns_b64_pton_calculate_size(strlen(str)); 1170266077Sdes int n; 1171266077Sdes if(*len < sz) 1172266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1173266077Sdes n = sldns_b64_pton(str, rd, *len); 1174266077Sdes if(n < 0) 1175266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_B64; 1176266077Sdes *len = (size_t)n; 1177266077Sdes return LDNS_WIREPARSE_ERR_OK; 1178266077Sdes} 1179266077Sdes 1180266077Sdesint sldns_str2wire_b32_ext_buf(const char* str, uint8_t* rd, size_t* len) 1181266077Sdes{ 1182266077Sdes size_t slen = strlen(str); 1183266077Sdes size_t sz = sldns_b32_pton_calculate_size(slen); 1184266077Sdes int n; 1185266077Sdes if(*len < 1+sz) 1186266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1187266077Sdes rd[0] = (uint8_t)sz; 1188266077Sdes n = sldns_b32_pton_extended_hex(str, slen, rd+1, *len-1); 1189266077Sdes if(n < 0) 1190266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_B32_EXT; 1191266077Sdes *len = (size_t)n+1; 1192266077Sdes return LDNS_WIREPARSE_ERR_OK; 1193266077Sdes} 1194266077Sdes 1195266077Sdesint sldns_str2wire_hex_buf(const char* str, uint8_t* rd, size_t* len) 1196266077Sdes{ 1197266077Sdes const char* s = str; 1198266077Sdes size_t dlen = 0; /* number of hexdigits parsed */ 1199266077Sdes while(*s) { 1200276541Sdes if(isspace((unsigned char)*s)) { 1201266077Sdes s++; 1202266077Sdes continue; 1203266077Sdes } 1204276541Sdes if(!isxdigit((unsigned char)*s)) 1205266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1206266077Sdes if(*len < dlen/2 + 1) 1207266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1208266077Sdes s-str); 1209266077Sdes if((dlen&1)==0) 1210266077Sdes rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16; 1211266077Sdes else rd[dlen/2] += (uint8_t)sldns_hexdigit_to_int(*s++); 1212266077Sdes dlen++; 1213266077Sdes } 1214266077Sdes if((dlen&1)!=0) 1215266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1216266077Sdes *len = dlen/2; 1217266077Sdes return LDNS_WIREPARSE_ERR_OK; 1218266077Sdes} 1219266077Sdes 1220266077Sdesint sldns_str2wire_nsec_buf(const char* str, uint8_t* rd, size_t* len) 1221266077Sdes{ 1222266077Sdes const char *delim = "\n\t "; 1223266077Sdes char token[64]; /* for a type name */ 1224266077Sdes size_t type_count = 0; 1225266077Sdes int block; 1226266077Sdes size_t used = 0; 1227266077Sdes uint16_t maxtype = 0; 1228266077Sdes uint8_t typebits[8192]; /* 65536 bits */ 1229266077Sdes uint8_t window_in_use[256]; 1230266077Sdes 1231266077Sdes /* string in buffer */ 1232266077Sdes sldns_buffer strbuf; 1233266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 1234266077Sdes 1235266077Sdes /* parse the types */ 1236266077Sdes memset(typebits, 0, sizeof(typebits)); 1237266077Sdes memset(window_in_use, 0, sizeof(window_in_use)); 1238266077Sdes while(sldns_buffer_remaining(&strbuf) > 0 && 1239266077Sdes sldns_bget_token(&strbuf, token, delim, sizeof(token)) != -1) { 1240266077Sdes uint16_t t = sldns_get_rr_type_by_name(token); 1241266077Sdes if(token[0] == 0) 1242266077Sdes continue; 1243266077Sdes if(t == 0 && strcmp(token, "TYPE0") != 0) 1244266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TYPE, 1245266077Sdes sldns_buffer_position(&strbuf)); 1246266077Sdes typebits[t/8] |= (0x80>>(t%8)); 1247266077Sdes window_in_use[t/256] = 1; 1248266077Sdes type_count++; 1249266077Sdes if(t > maxtype) maxtype = t; 1250266077Sdes } 1251266077Sdes 1252266077Sdes /* empty NSEC bitmap */ 1253266077Sdes if(type_count == 0) { 1254266077Sdes *len = 0; 1255266077Sdes return LDNS_WIREPARSE_ERR_OK; 1256266077Sdes } 1257266077Sdes 1258266077Sdes /* encode windows {u8 windowblock, u8 bitmaplength, 0-32u8 bitmap}, 1259266077Sdes * block is 0-255 upper octet of types, length if 0-32. */ 1260266077Sdes for(block = 0; block <= (int)maxtype/256; block++) { 1261266077Sdes int i, blocklen = 0; 1262266077Sdes if(!window_in_use[block]) 1263266077Sdes continue; 1264266077Sdes for(i=0; i<32; i++) { 1265266077Sdes if(typebits[block*32+i] != 0) 1266266077Sdes blocklen = i+1; 1267266077Sdes } 1268266077Sdes if(blocklen == 0) 1269266077Sdes continue; /* empty window should have been !in_use */ 1270266077Sdes if(used+blocklen+2 > *len) 1271266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1272266077Sdes rd[used+0] = (uint8_t)block; 1273266077Sdes rd[used+1] = (uint8_t)blocklen; 1274266077Sdes for(i=0; i<blocklen; i++) { 1275266077Sdes rd[used+2+i] = typebits[block*32+i]; 1276266077Sdes } 1277266077Sdes used += blocklen+2; 1278266077Sdes } 1279266077Sdes *len = used; 1280266077Sdes return LDNS_WIREPARSE_ERR_OK; 1281266077Sdes} 1282266077Sdes 1283266077Sdesint sldns_str2wire_type_buf(const char* str, uint8_t* rd, size_t* len) 1284266077Sdes{ 1285266077Sdes uint16_t t = sldns_get_rr_type_by_name(str); 1286266077Sdes if(t == 0 && strcmp(str, "TYPE0") != 0) 1287266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TYPE; 1288266077Sdes if(*len < 2) 1289266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1290266077Sdes sldns_write_uint16(rd, t); 1291266077Sdes *len = 2; 1292266077Sdes return LDNS_WIREPARSE_ERR_OK; 1293266077Sdes} 1294266077Sdes 1295266077Sdesint sldns_str2wire_class_buf(const char* str, uint8_t* rd, size_t* len) 1296266077Sdes{ 1297266077Sdes uint16_t c = sldns_get_rr_class_by_name(str); 1298266077Sdes if(c == 0 && strcmp(str, "CLASS0") != 0) 1299266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_CLASS; 1300266077Sdes if(*len < 2) 1301266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1302266077Sdes sldns_write_uint16(rd, c); 1303266077Sdes *len = 2; 1304266077Sdes return LDNS_WIREPARSE_ERR_OK; 1305266077Sdes} 1306266077Sdes 1307266077Sdes/* An certificate alg field can either be specified as a 8 bits number 1308266077Sdes * or by its symbolic name. Handle both */ 1309266077Sdesint sldns_str2wire_cert_alg_buf(const char* str, uint8_t* rd, size_t* len) 1310266077Sdes{ 1311266077Sdes sldns_lookup_table *lt = sldns_lookup_by_name(sldns_cert_algorithms, 1312266077Sdes str); 1313266077Sdes if(*len < 2) 1314266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1315266077Sdes if(lt) { 1316266077Sdes sldns_write_uint16(rd, (uint16_t)lt->id); 1317266077Sdes } else { 1318266077Sdes int s = sldns_str2wire_int16_buf(str, rd, len); 1319266077Sdes if(s) return s; 1320266077Sdes if(sldns_read_uint16(rd) == 0) 1321266077Sdes return LDNS_WIREPARSE_ERR_CERT_BAD_ALGORITHM; 1322266077Sdes } 1323266077Sdes *len = 2; 1324266077Sdes return LDNS_WIREPARSE_ERR_OK; 1325266077Sdes} 1326266077Sdes 1327266077Sdes/* An alg field can either be specified as a 8 bits number 1328266077Sdes * or by its symbolic name. Handle both */ 1329266077Sdesint sldns_str2wire_alg_buf(const char* str, uint8_t* rd, size_t* len) 1330266077Sdes{ 1331266077Sdes sldns_lookup_table *lt = sldns_lookup_by_name(sldns_algorithms, str); 1332266077Sdes if(*len < 1) 1333266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1334266077Sdes if(lt) { 1335266077Sdes rd[0] = (uint8_t)lt->id; 1336266077Sdes *len = 1; 1337266077Sdes } else { 1338266077Sdes /* try as-is (a number) */ 1339266077Sdes return sldns_str2wire_int8_buf(str, rd, len); 1340266077Sdes } 1341266077Sdes return LDNS_WIREPARSE_ERR_OK; 1342266077Sdes} 1343266077Sdes 1344266077Sdesint sldns_str2wire_time_buf(const char* str, uint8_t* rd, size_t* len) 1345266077Sdes{ 1346266077Sdes /* convert a time YYYYDDMMHHMMSS to wireformat */ 1347266077Sdes struct tm tm; 1348266077Sdes if(*len < 4) 1349266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1350266077Sdes 1351266077Sdes /* Try to scan the time... */ 1352266077Sdes memset(&tm, 0, sizeof(tm)); 1353266077Sdes if (strlen(str) == 14 && sscanf(str, "%4d%2d%2d%2d%2d%2d", 1354266077Sdes &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, 1355266077Sdes &tm.tm_min, &tm.tm_sec) == 6) { 1356266077Sdes tm.tm_year -= 1900; 1357266077Sdes tm.tm_mon--; 1358266077Sdes /* Check values */ 1359266077Sdes if (tm.tm_year < 70) 1360266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1361266077Sdes if (tm.tm_mon < 0 || tm.tm_mon > 11) 1362266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1363266077Sdes if (tm.tm_mday < 1 || tm.tm_mday > 31) 1364266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1365266077Sdes if (tm.tm_hour < 0 || tm.tm_hour > 23) 1366266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1367266077Sdes if (tm.tm_min < 0 || tm.tm_min > 59) 1368266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1369266077Sdes if (tm.tm_sec < 0 || tm.tm_sec > 59) 1370266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TIME; 1371266077Sdes 1372266077Sdes sldns_write_uint32(rd, sldns_mktime_from_utc(&tm)); 1373266077Sdes } else { 1374266077Sdes /* handle it as 32 bits timestamp */ 1375266077Sdes char *end; 1376266077Sdes uint32_t l = (uint32_t)strtol((char*)str, &end, 10); 1377266077Sdes if(*end != 0) 1378266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TIME, 1379266077Sdes end-(char*)str); 1380266077Sdes sldns_write_uint32(rd, l); 1381266077Sdes } 1382266077Sdes *len = 4; 1383266077Sdes return LDNS_WIREPARSE_ERR_OK; 1384266077Sdes} 1385266077Sdes 1386266077Sdesint sldns_str2wire_period_buf(const char* str, uint8_t* rd, size_t* len) 1387266077Sdes{ 1388266077Sdes const char* end; 1389266077Sdes uint32_t p = sldns_str2period(str, &end); 1390266077Sdes if(*end != 0) 1391266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_PERIOD, end-str); 1392266077Sdes if(*len < 4) 1393266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1394266077Sdes sldns_write_uint32(rd, p); 1395266077Sdes *len = 4; 1396266077Sdes return LDNS_WIREPARSE_ERR_OK; 1397266077Sdes} 1398266077Sdes 1399266077Sdes/** read "<digits>[.<digits>][mM]" into mantissa exponent format for LOC type */ 1400266077Sdesstatic int 1401266077Sdesloc_parse_cm(char* my_str, char** endstr, uint8_t* m, uint8_t* e) 1402266077Sdes{ 1403266077Sdes uint32_t meters = 0, cm = 0, val; 1404276541Sdes while (isblank((unsigned char)*my_str)) { 1405266077Sdes my_str++; 1406266077Sdes } 1407266077Sdes meters = (uint32_t)strtol(my_str, &my_str, 10); 1408266077Sdes if (*my_str == '.') { 1409266077Sdes my_str++; 1410266077Sdes cm = (uint32_t)strtol(my_str, &my_str, 10); 1411266077Sdes } 1412266077Sdes if (meters >= 1) { 1413266077Sdes *e = 2; 1414266077Sdes val = meters; 1415266077Sdes } else { 1416266077Sdes *e = 0; 1417266077Sdes val = cm; 1418266077Sdes } 1419266077Sdes while(val >= 10) { 1420266077Sdes (*e)++; 1421266077Sdes val /= 10; 1422266077Sdes } 1423266077Sdes *m = (uint8_t)val; 1424266077Sdes 1425266077Sdes if (*e > 9) 1426266077Sdes return 0; 1427266077Sdes if (*my_str == 'm' || *my_str == 'M') { 1428266077Sdes my_str++; 1429266077Sdes } 1430266077Sdes *endstr = my_str; 1431266077Sdes return 1; 1432266077Sdes} 1433266077Sdes 1434266077Sdesint sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len) 1435266077Sdes{ 1436266077Sdes uint32_t latitude = 0; 1437266077Sdes uint32_t longitude = 0; 1438266077Sdes uint32_t altitude = 0; 1439266077Sdes 1440266077Sdes uint32_t equator = (uint32_t)1<<31; /* 2**31 */ 1441266077Sdes 1442266077Sdes /* only support version 0 */ 1443266077Sdes uint32_t h = 0; 1444266077Sdes uint32_t m = 0; 1445266077Sdes uint8_t size_b = 1, size_e = 2; 1446266077Sdes uint8_t horiz_pre_b = 1, horiz_pre_e = 6; 1447266077Sdes uint8_t vert_pre_b = 1, vert_pre_e = 3; 1448266077Sdes 1449266077Sdes double s = 0.0; 1450266077Sdes int northerness; 1451266077Sdes int easterness; 1452266077Sdes 1453266077Sdes char *my_str = (char *) str; 1454266077Sdes 1455276541Sdes if (isdigit((unsigned char) *my_str)) { 1456266077Sdes h = (uint32_t) strtol(my_str, &my_str, 10); 1457266077Sdes } else { 1458266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1459266077Sdes } 1460266077Sdes 1461276541Sdes while (isblank((unsigned char) *my_str)) { 1462266077Sdes my_str++; 1463266077Sdes } 1464266077Sdes 1465276541Sdes if (isdigit((unsigned char) *my_str)) { 1466266077Sdes m = (uint32_t) strtol(my_str, &my_str, 10); 1467266077Sdes } else if (*my_str == 'N' || *my_str == 'S') { 1468266077Sdes goto north; 1469266077Sdes } else { 1470266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1471266077Sdes } 1472266077Sdes 1473276541Sdes while (isblank((unsigned char) *my_str)) { 1474266077Sdes my_str++; 1475266077Sdes } 1476266077Sdes 1477276541Sdes if (isdigit((unsigned char) *my_str)) { 1478266077Sdes s = strtod(my_str, &my_str); 1479266077Sdes } 1480266077Sdes 1481266077Sdes /* skip blanks before norterness */ 1482276541Sdes while (isblank((unsigned char) *my_str)) { 1483266077Sdes my_str++; 1484266077Sdes } 1485266077Sdes 1486266077Sdesnorth: 1487266077Sdes if (*my_str == 'N') { 1488266077Sdes northerness = 1; 1489266077Sdes } else if (*my_str == 'S') { 1490266077Sdes northerness = 0; 1491266077Sdes } else { 1492266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1493266077Sdes } 1494266077Sdes 1495266077Sdes my_str++; 1496266077Sdes 1497266077Sdes /* store number */ 1498266077Sdes s = 1000.0 * s; 1499266077Sdes /* add a little to make floor in conversion a round */ 1500266077Sdes s += 0.0005; 1501266077Sdes latitude = (uint32_t) s; 1502266077Sdes latitude += 1000 * 60 * m; 1503266077Sdes latitude += 1000 * 60 * 60 * h; 1504266077Sdes if (northerness) { 1505266077Sdes latitude = equator + latitude; 1506266077Sdes } else { 1507266077Sdes latitude = equator - latitude; 1508266077Sdes } 1509276541Sdes while (isblank((unsigned char)*my_str)) { 1510266077Sdes my_str++; 1511266077Sdes } 1512266077Sdes 1513276541Sdes if (isdigit((unsigned char) *my_str)) { 1514266077Sdes h = (uint32_t) strtol(my_str, &my_str, 10); 1515266077Sdes } else { 1516266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1517266077Sdes } 1518266077Sdes 1519276541Sdes while (isblank((unsigned char) *my_str)) { 1520266077Sdes my_str++; 1521266077Sdes } 1522266077Sdes 1523276541Sdes if (isdigit((unsigned char) *my_str)) { 1524266077Sdes m = (uint32_t) strtol(my_str, &my_str, 10); 1525266077Sdes } else if (*my_str == 'E' || *my_str == 'W') { 1526266077Sdes goto east; 1527266077Sdes } else { 1528266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1529266077Sdes } 1530266077Sdes 1531276541Sdes while (isblank((unsigned char)*my_str)) { 1532266077Sdes my_str++; 1533266077Sdes } 1534266077Sdes 1535276541Sdes if (isdigit((unsigned char) *my_str)) { 1536266077Sdes s = strtod(my_str, &my_str); 1537266077Sdes } 1538266077Sdes 1539266077Sdes /* skip blanks before easterness */ 1540276541Sdes while (isblank((unsigned char)*my_str)) { 1541266077Sdes my_str++; 1542266077Sdes } 1543266077Sdes 1544266077Sdeseast: 1545266077Sdes if (*my_str == 'E') { 1546266077Sdes easterness = 1; 1547266077Sdes } else if (*my_str == 'W') { 1548266077Sdes easterness = 0; 1549266077Sdes } else { 1550266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1551266077Sdes } 1552266077Sdes 1553266077Sdes my_str++; 1554266077Sdes 1555266077Sdes /* store number */ 1556266077Sdes s *= 1000.0; 1557266077Sdes /* add a little to make floor in conversion a round */ 1558266077Sdes s += 0.0005; 1559266077Sdes longitude = (uint32_t) s; 1560266077Sdes longitude += 1000 * 60 * m; 1561266077Sdes longitude += 1000 * 60 * 60 * h; 1562266077Sdes 1563266077Sdes if (easterness) { 1564266077Sdes longitude += equator; 1565266077Sdes } else { 1566266077Sdes longitude = equator - longitude; 1567266077Sdes } 1568266077Sdes 1569266077Sdes altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 + 1570266077Sdes 10000000.0 + 0.5); 1571266077Sdes if (*my_str == 'm' || *my_str == 'M') { 1572266077Sdes my_str++; 1573266077Sdes } 1574266077Sdes 1575266077Sdes if (strlen(my_str) > 0) { 1576266077Sdes if(!loc_parse_cm(my_str, &my_str, &size_b, &size_e)) 1577266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1578266077Sdes } 1579266077Sdes 1580266077Sdes if (strlen(my_str) > 0) { 1581266077Sdes if(!loc_parse_cm(my_str, &my_str, &horiz_pre_b, &horiz_pre_e)) 1582266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1583266077Sdes } 1584266077Sdes 1585266077Sdes if (strlen(my_str) > 0) { 1586266077Sdes if(!loc_parse_cm(my_str, &my_str, &vert_pre_b, &vert_pre_e)) 1587266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1588266077Sdes } 1589266077Sdes 1590266077Sdes if(*len < 16) 1591266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1592266077Sdes rd[0] = 0; 1593266077Sdes rd[1] = ((size_b << 4) & 0xf0) | (size_e & 0x0f); 1594266077Sdes rd[2] = ((horiz_pre_b << 4) & 0xf0) | (horiz_pre_e & 0x0f); 1595266077Sdes rd[3] = ((vert_pre_b << 4) & 0xf0) | (vert_pre_e & 0x0f); 1596266077Sdes sldns_write_uint32(rd + 4, latitude); 1597266077Sdes sldns_write_uint32(rd + 8, longitude); 1598266077Sdes sldns_write_uint32(rd + 12, altitude); 1599266077Sdes *len = 16; 1600266077Sdes return LDNS_WIREPARSE_ERR_OK; 1601266077Sdes} 1602266077Sdes 1603276541Sdesstatic void 1604276541Sdesldns_tolower_str(char* s) 1605276541Sdes{ 1606276541Sdes if(s) { 1607276541Sdes while(*s) { 1608276541Sdes *s = (char)tolower((unsigned char)*s); 1609276541Sdes s++; 1610276541Sdes } 1611276541Sdes } 1612276541Sdes} 1613276541Sdes 1614266077Sdesint sldns_str2wire_wks_buf(const char* str, uint8_t* rd, size_t* len) 1615266077Sdes{ 1616266077Sdes int rd_len = 1; 1617266077Sdes int have_proto = 0; 1618266077Sdes char token[50], proto_str[50]; 1619266077Sdes sldns_buffer strbuf; 1620266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 1621266077Sdes proto_str[0]=0; 1622266077Sdes 1623266077Sdes /* check we have one byte for proto */ 1624266077Sdes if(*len < 1) 1625266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1626266077Sdes 1627266077Sdes while(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) > 0) { 1628276541Sdes ldns_tolower_str(token); 1629266077Sdes if(!have_proto) { 1630266077Sdes struct protoent *p = getprotobyname(token); 1631266077Sdes have_proto = 1; 1632266077Sdes if(p) rd[0] = (uint8_t)p->p_proto; 1633266077Sdes else rd[0] = (uint8_t)atoi(token); 1634266077Sdes (void)strlcpy(proto_str, token, sizeof(proto_str)); 1635266077Sdes } else { 1636266077Sdes int serv_port; 1637266077Sdes struct servent *serv = getservbyname(token, proto_str); 1638266077Sdes if(serv) serv_port=(int)ntohs((uint16_t)serv->s_port); 1639266077Sdes else { 1640266077Sdes serv_port = atoi(token); 1641266077Sdes if(serv_port == 0 && strcmp(token, "0") != 0) { 1642266077Sdes#ifdef HAVE_ENDSERVENT 1643266077Sdes endservent(); 1644266077Sdes#endif 1645266077Sdes#ifdef HAVE_ENDPROTOENT 1646266077Sdes endprotoent(); 1647266077Sdes#endif 1648266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, 1649266077Sdes sldns_buffer_position(&strbuf)); 1650266077Sdes } 1651266077Sdes if(serv_port < 0 || serv_port > 65535) { 1652266077Sdes#ifdef HAVE_ENDSERVENT 1653266077Sdes endservent(); 1654266077Sdes#endif 1655266077Sdes#ifdef HAVE_ENDPROTOENT 1656266077Sdes endprotoent(); 1657266077Sdes#endif 1658266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, 1659266077Sdes sldns_buffer_position(&strbuf)); 1660266077Sdes } 1661266077Sdes } 1662266077Sdes if(rd_len < 1+serv_port/8+1) { 1663266077Sdes /* bitmap is larger, init new bytes at 0 */ 1664266077Sdes if(*len < 1+(size_t)serv_port/8+1) { 1665266077Sdes#ifdef HAVE_ENDSERVENT 1666266077Sdes endservent(); 1667266077Sdes#endif 1668266077Sdes#ifdef HAVE_ENDPROTOENT 1669266077Sdes endprotoent(); 1670266077Sdes#endif 1671266077Sdes return RET_ERR( 1672266077Sdes LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1673266077Sdes sldns_buffer_position(&strbuf)); 1674266077Sdes } 1675266077Sdes memset(rd+rd_len, 0, 1+(size_t)serv_port/8+1-rd_len); 1676266077Sdes rd_len = 1+serv_port/8+1; 1677266077Sdes } 1678266077Sdes rd[1+ serv_port/8] |= (1 << (7 - serv_port % 8)); 1679266077Sdes } 1680266077Sdes } 1681266077Sdes *len = (size_t)rd_len; 1682266077Sdes 1683266077Sdes#ifdef HAVE_ENDSERVENT 1684266077Sdes endservent(); 1685266077Sdes#endif 1686266077Sdes#ifdef HAVE_ENDPROTOENT 1687266077Sdes endprotoent(); 1688266077Sdes#endif 1689266077Sdes return LDNS_WIREPARSE_ERR_OK; 1690266077Sdes} 1691266077Sdes 1692266077Sdesint sldns_str2wire_nsap_buf(const char* str, uint8_t* rd, size_t* len) 1693266077Sdes{ 1694266077Sdes const char* s = str; 1695266077Sdes size_t slen; 1696266077Sdes size_t dlen = 0; /* number of hexdigits parsed */ 1697266077Sdes 1698266077Sdes /* just a hex string with optional dots? */ 1699266077Sdes if (s[0] != '0' || s[1] != 'x') 1700266077Sdes return LDNS_WIREPARSE_ERR_INVALID_STR; 1701266077Sdes s += 2; 1702266077Sdes slen = strlen(s); 1703266077Sdes if(slen > LDNS_MAX_RDFLEN*2) 1704266077Sdes return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW; 1705266077Sdes while(*s) { 1706276541Sdes if(isspace((unsigned char)*s) || *s == '.') { 1707266077Sdes s++; 1708266077Sdes continue; 1709266077Sdes } 1710276541Sdes if(!isxdigit((unsigned char)*s)) 1711266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1712266077Sdes if(*len < dlen/2 + 1) 1713266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1714266077Sdes s-str); 1715266077Sdes if((dlen&1)==0) 1716266077Sdes rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16; 1717266077Sdes else rd[dlen/2] += sldns_hexdigit_to_int(*s++); 1718266077Sdes dlen++; 1719266077Sdes } 1720266077Sdes if((dlen&1)!=0) 1721266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1722266077Sdes *len = dlen/2; 1723266077Sdes return LDNS_WIREPARSE_ERR_OK; 1724266077Sdes} 1725266077Sdes 1726266077Sdesint sldns_str2wire_atma_buf(const char* str, uint8_t* rd, size_t* len) 1727266077Sdes{ 1728266077Sdes const char* s = str; 1729266077Sdes size_t slen = strlen(str); 1730266077Sdes size_t dlen = 0; /* number of hexdigits parsed */ 1731266077Sdes 1732266077Sdes /* just a hex string with optional dots? */ 1733266077Sdes /* notimpl e.164 format */ 1734266077Sdes if(slen > LDNS_MAX_RDFLEN*2) 1735266077Sdes return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW; 1736266077Sdes while(*s) { 1737276541Sdes if(isspace((unsigned char)*s) || *s == '.') { 1738266077Sdes s++; 1739266077Sdes continue; 1740266077Sdes } 1741276541Sdes if(!isxdigit((unsigned char)*s)) 1742266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1743266077Sdes if(*len < dlen/2 + 1) 1744266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1745266077Sdes s-str); 1746266077Sdes if((dlen&1)==0) 1747266077Sdes rd[dlen/2] = (uint8_t)sldns_hexdigit_to_int(*s++) * 16; 1748266077Sdes else rd[dlen/2] += sldns_hexdigit_to_int(*s++); 1749266077Sdes dlen++; 1750266077Sdes } 1751266077Sdes if((dlen&1)!=0) 1752266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, s-str); 1753266077Sdes *len = dlen/2; 1754266077Sdes return LDNS_WIREPARSE_ERR_OK; 1755266077Sdes} 1756266077Sdes 1757266077Sdesint sldns_str2wire_ipseckey_buf(const char* str, uint8_t* rd, size_t* len) 1758266077Sdes{ 1759266077Sdes size_t gwlen = 0, keylen = 0; 1760266077Sdes int s; 1761266077Sdes uint8_t gwtype; 1762266077Sdes char token[512]; 1763266077Sdes sldns_buffer strbuf; 1764266077Sdes sldns_buffer_init_frm_data(&strbuf, (uint8_t*)str, strlen(str)); 1765266077Sdes 1766266077Sdes if(*len < 3) 1767266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1768266077Sdes /* precedence */ 1769266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1770266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1771266077Sdes sldns_buffer_position(&strbuf)); 1772266077Sdes rd[0] = (uint8_t)atoi(token); 1773266077Sdes /* gateway_type */ 1774266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1775266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1776266077Sdes sldns_buffer_position(&strbuf)); 1777266077Sdes rd[1] = (uint8_t)atoi(token); 1778266077Sdes gwtype = rd[1]; 1779266077Sdes /* algorithm */ 1780266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1781266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1782266077Sdes sldns_buffer_position(&strbuf)); 1783266077Sdes rd[2] = (uint8_t)atoi(token); 1784266077Sdes 1785266077Sdes /* gateway */ 1786266077Sdes if(sldns_bget_token(&strbuf, token, "\t\n ", sizeof(token)) <= 0) 1787266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1788266077Sdes sldns_buffer_position(&strbuf)); 1789266077Sdes if(gwtype == 0) { 1790266077Sdes /* NOGATEWAY */ 1791266077Sdes if(strcmp(token, ".") != 0) 1792266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1793266077Sdes sldns_buffer_position(&strbuf)); 1794266077Sdes gwlen = 0; 1795266077Sdes } else if(gwtype == 1) { 1796266077Sdes /* IP4 */ 1797266077Sdes gwlen = *len - 3; 1798266077Sdes s = sldns_str2wire_a_buf(token, rd+3, &gwlen); 1799266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1800266077Sdes } else if(gwtype == 2) { 1801266077Sdes /* IP6 */ 1802266077Sdes gwlen = *len - 3; 1803266077Sdes s = sldns_str2wire_aaaa_buf(token, rd+3, &gwlen); 1804266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1805266077Sdes } else if(gwtype == 3) { 1806266077Sdes /* DNAME */ 1807266077Sdes gwlen = *len - 3; 1808266077Sdes s = sldns_str2wire_dname_buf(token, rd+3, &gwlen); 1809266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1810266077Sdes } else { 1811266077Sdes /* unknown gateway type */ 1812266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, 1813266077Sdes sldns_buffer_position(&strbuf)); 1814266077Sdes } 1815266077Sdes /* double check for size */ 1816266077Sdes if(*len < 3 + gwlen) 1817266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, 1818266077Sdes sldns_buffer_position(&strbuf)); 1819266077Sdes 1820266077Sdes /* publickey in remainder of strbuf */ 1821266077Sdes keylen = *len - 3 - gwlen; 1822266077Sdes s = sldns_str2wire_b64_buf((const char*)sldns_buffer_current(&strbuf), 1823266077Sdes rd+3+gwlen, &keylen); 1824266077Sdes if(s) return RET_ERR_SHIFT(s, sldns_buffer_position(&strbuf)); 1825266077Sdes 1826266077Sdes *len = 3 + gwlen + keylen; 1827266077Sdes return LDNS_WIREPARSE_ERR_OK; 1828266077Sdes} 1829266077Sdes 1830266077Sdesint sldns_str2wire_nsec3_salt_buf(const char* str, uint8_t* rd, size_t* len) 1831266077Sdes{ 1832266077Sdes int i, salt_length_str = (int)strlen(str); 1833266077Sdes if (salt_length_str == 1 && str[0] == '-') { 1834266077Sdes salt_length_str = 0; 1835266077Sdes } else if (salt_length_str % 2 != 0) { 1836266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_HEX; 1837266077Sdes } 1838266077Sdes if (salt_length_str > 512) 1839266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_HEX; 1840266077Sdes if(*len < 1+(size_t)salt_length_str / 2) 1841266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1842266077Sdes rd[0] = (uint8_t) (salt_length_str / 2); 1843266077Sdes for (i = 0; i < salt_length_str; i += 2) { 1844276541Sdes if (isxdigit((unsigned char)str[i]) && 1845276541Sdes isxdigit((unsigned char)str[i+1])) { 1846266077Sdes rd[1+i/2] = (uint8_t)(sldns_hexdigit_to_int(str[i])*16 1847266077Sdes + sldns_hexdigit_to_int(str[i+1])); 1848266077Sdes } else { 1849266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_HEX, i); 1850266077Sdes } 1851266077Sdes } 1852266077Sdes *len = 1 + (size_t)rd[0]; 1853266077Sdes return LDNS_WIREPARSE_ERR_OK; 1854266077Sdes} 1855266077Sdes 1856266077Sdesint sldns_str2wire_ilnp64_buf(const char* str, uint8_t* rd, size_t* len) 1857266077Sdes{ 1858266077Sdes unsigned int a, b, c, d; 1859266077Sdes uint16_t shorts[4]; 1860266077Sdes int l; 1861266077Sdes if(*len < sizeof(shorts)) 1862266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1863266077Sdes 1864266077Sdes if (sscanf(str, "%4x:%4x:%4x:%4x%n", &a, &b, &c, &d, &l) != 4 || 1865266077Sdes l != (int)strlen(str) || /* more data to read */ 1866266077Sdes strpbrk(str, "+-") /* signed hexes */ 1867266077Sdes ) 1868266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_ILNP64; 1869266077Sdes shorts[0] = htons(a); 1870266077Sdes shorts[1] = htons(b); 1871266077Sdes shorts[2] = htons(c); 1872266077Sdes shorts[3] = htons(d); 1873266077Sdes memmove(rd, &shorts, sizeof(shorts)); 1874266077Sdes *len = sizeof(shorts); 1875266077Sdes return LDNS_WIREPARSE_ERR_OK; 1876266077Sdes} 1877266077Sdes 1878266077Sdesint sldns_str2wire_eui48_buf(const char* str, uint8_t* rd, size_t* len) 1879266077Sdes{ 1880266077Sdes unsigned int a, b, c, d, e, f; 1881266077Sdes int l; 1882266077Sdes 1883266077Sdes if(*len < 6) 1884266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1885266077Sdes if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x%n", 1886266077Sdes &a, &b, &c, &d, &e, &f, &l) != 6 || 1887266077Sdes l != (int)strlen(str)) 1888266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_EUI48; 1889266077Sdes rd[0] = a; 1890266077Sdes rd[1] = b; 1891266077Sdes rd[2] = c; 1892266077Sdes rd[3] = d; 1893266077Sdes rd[4] = e; 1894266077Sdes rd[5] = f; 1895266077Sdes *len = 6; 1896266077Sdes return LDNS_WIREPARSE_ERR_OK; 1897266077Sdes} 1898266077Sdes 1899266077Sdesint sldns_str2wire_eui64_buf(const char* str, uint8_t* rd, size_t* len) 1900266077Sdes{ 1901266077Sdes unsigned int a, b, c, d, e, f, g, h; 1902266077Sdes int l; 1903266077Sdes 1904266077Sdes if(*len < 8) 1905266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1906266077Sdes if (sscanf(str, "%2x-%2x-%2x-%2x-%2x-%2x-%2x-%2x%n", 1907266077Sdes &a, &b, &c, &d, &e, &f, &g, &h, &l) != 8 || 1908266077Sdes l != (int)strlen(str)) 1909266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_EUI64; 1910266077Sdes rd[0] = a; 1911266077Sdes rd[1] = b; 1912266077Sdes rd[2] = c; 1913266077Sdes rd[3] = d; 1914266077Sdes rd[4] = e; 1915266077Sdes rd[5] = f; 1916266077Sdes rd[6] = g; 1917266077Sdes rd[7] = h; 1918266077Sdes *len = 8; 1919266077Sdes return LDNS_WIREPARSE_ERR_OK; 1920266077Sdes} 1921266077Sdes 1922266077Sdesint sldns_str2wire_tag_buf(const char* str, uint8_t* rd, size_t* len) 1923266077Sdes{ 1924266077Sdes size_t slen = strlen(str); 1925266077Sdes const char* ptr; 1926266077Sdes 1927266077Sdes if (slen > 255) 1928266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_TAG; 1929266077Sdes if(*len < slen+1) 1930266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1931266077Sdes for (ptr = str; *ptr; ptr++) { 1932276541Sdes if(!isalnum((unsigned char)*ptr)) 1933266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_TAG, ptr-str); 1934266077Sdes } 1935266077Sdes rd[0] = slen; 1936266077Sdes memmove(rd+1, str, slen); 1937266077Sdes *len = slen+1; 1938266077Sdes return LDNS_WIREPARSE_ERR_OK; 1939266077Sdes} 1940266077Sdes 1941266077Sdesint sldns_str2wire_long_str_buf(const char* str, uint8_t* rd, size_t* len) 1942266077Sdes{ 1943266077Sdes uint8_t ch = 0; 1944266077Sdes const char* pstr = str; 1945266077Sdes size_t length = 0; 1946266077Sdes 1947266077Sdes /* Fill data with parsed bytes */ 1948266077Sdes while (sldns_parse_char(&ch, &pstr)) { 1949266077Sdes if(*len < length+1) 1950266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1951266077Sdes rd[length++] = ch; 1952266077Sdes } 1953266077Sdes if(!pstr) 1954266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_BAD_ESCAPE; 1955266077Sdes *len = length; 1956266077Sdes return LDNS_WIREPARSE_ERR_OK; 1957266077Sdes} 1958266077Sdes 1959266077Sdesint sldns_str2wire_hip_buf(const char* str, uint8_t* rd, size_t* len) 1960266077Sdes{ 1961266077Sdes char* s, *end; 1962266077Sdes int e; 1963266077Sdes size_t hitlen, pklen = 0; 1964266077Sdes /* presentation format: 1965266077Sdes * pk-algo HIThex pubkeybase64 1966266077Sdes * wireformat: 1967266077Sdes * hitlen[1byte] pkalgo[1byte] pubkeylen[2byte] [hit] [pubkey] */ 1968266077Sdes if(*len < 4) 1969266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 1970266077Sdes 1971266077Sdes /* read PK algorithm */ 1972266077Sdes rd[1] = (uint8_t)strtol((char*)str, &s, 10); 1973266077Sdes if(*s != ' ') 1974266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX_INT, s-(char*)str); 1975266077Sdes s++; 1976266077Sdes while(*s == ' ') 1977266077Sdes s++; 1978266077Sdes 1979266077Sdes /* read HIT hex tag */ 1980266077Sdes /* zero terminate the tag (replace later) */ 1981266077Sdes end = strchr(s, ' '); 1982266077Sdes if(!end) return RET_ERR(LDNS_WIREPARSE_ERR_SYNTAX, s-(char*)str); 1983266077Sdes *end = 0; 1984266077Sdes hitlen = *len - 4; 1985266077Sdes if((e = sldns_str2wire_hex_buf(s, rd+4, &hitlen)) != 0) { 1986266077Sdes *end = ' '; 1987266077Sdes return RET_ERR_SHIFT(e, s-(char*)str); 1988266077Sdes } 1989266077Sdes if(hitlen > 255) { 1990266077Sdes *end = ' '; 1991266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+255*2); 1992266077Sdes } 1993266077Sdes rd[0] = (uint8_t)hitlen; 1994266077Sdes *end = ' '; 1995266077Sdes s = end+1; 1996266077Sdes 1997266077Sdes /* read pubkey base64 sequence */ 1998266077Sdes pklen = *len - 4 - hitlen; 1999266077Sdes if((e = sldns_str2wire_b64_buf(s, rd+4+hitlen, &pklen)) != 0) 2000266077Sdes return RET_ERR_SHIFT(e, s-(char*)str); 2001266077Sdes if(pklen > 65535) 2002266077Sdes return RET_ERR(LDNS_WIREPARSE_ERR_LABEL_OVERFLOW, s-(char*)str+65535); 2003266077Sdes sldns_write_uint16(rd+2, pklen); 2004266077Sdes 2005266077Sdes *len = 4 + hitlen + pklen; 2006266077Sdes return LDNS_WIREPARSE_ERR_OK; 2007266077Sdes} 2008266077Sdes 2009266077Sdesint sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len) 2010266077Sdes{ 2011266077Sdes size_t sz = sldns_b64_pton_calculate_size(strlen(str)); 2012266077Sdes int n; 2013266077Sdes if(*len < sz+2) 2014266077Sdes return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL; 2015266077Sdes if(sz > 65535) 2016266077Sdes return LDNS_WIREPARSE_ERR_LABEL_OVERFLOW; 2017266077Sdes n = sldns_b64_pton(str, rd+2, (*len)-2); 2018266077Sdes if(n < 0) 2019266077Sdes return LDNS_WIREPARSE_ERR_SYNTAX_B64; 2020266077Sdes sldns_write_uint16(rd, (uint16_t)n); 2021266077Sdes *len = (size_t)n; 2022266077Sdes return LDNS_WIREPARSE_ERR_OK; 2023266077Sdes} 2024