1238104Sdes/* 2238104Sdes * dname.c 3238104Sdes * 4238104Sdes * dname specific rdata implementations 5238104Sdes * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME 6238104Sdes * It is not a /real/ type! All function must therefor check 7238104Sdes * for LDNS_RDF_TYPE_DNAME. 8238104Sdes * 9238104Sdes * a Net::DNS like library for C 10238104Sdes * 11238104Sdes * (c) NLnet Labs, 2004-2006 12238104Sdes * 13238104Sdes * See the file LICENSE for the license 14238104Sdes */ 15238104Sdes 16238104Sdes#include <ldns/config.h> 17238104Sdes 18238104Sdes#include <ldns/ldns.h> 19238104Sdes 20238104Sdes#ifdef HAVE_NETINET_IN_H 21238104Sdes#include <netinet/in.h> 22238104Sdes#endif 23238104Sdes#ifdef HAVE_SYS_SOCKET_H 24238104Sdes#include <sys/socket.h> 25238104Sdes#endif 26238104Sdes#ifdef HAVE_NETDB_H 27238104Sdes#include <netdb.h> 28238104Sdes#endif 29238104Sdes#ifdef HAVE_ARPA_INET_H 30238104Sdes#include <arpa/inet.h> 31238104Sdes#endif 32238104Sdes 33246854Sdes/* Returns whether the last label in the name is a root label (a empty label). 34246854Sdes * Note that it is not enough to just test the last character to be 0, 35246854Sdes * because it may be part of the last label itself. 36246854Sdes */ 37246854Sdesstatic bool 38246854Sdesldns_dname_last_label_is_root_label(const ldns_rdf* dname) 39246854Sdes{ 40246854Sdes size_t src_pos; 41246854Sdes size_t len = 0; 42246854Sdes 43246854Sdes for (src_pos = 0; src_pos < ldns_rdf_size(dname); src_pos += len + 1) { 44246854Sdes len = ldns_rdf_data(dname)[src_pos]; 45246854Sdes } 46246854Sdes assert(src_pos == ldns_rdf_size(dname)); 47246854Sdes 48246854Sdes return src_pos > 0 && len == 0; 49246854Sdes} 50246854Sdes 51238104Sdesldns_rdf * 52238104Sdesldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) 53238104Sdes{ 54238104Sdes ldns_rdf *new; 55238104Sdes uint16_t new_size; 56238104Sdes uint8_t *buf; 57238104Sdes uint16_t left_size; 58238104Sdes 59238104Sdes if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME || 60238104Sdes ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) { 61238104Sdes return NULL; 62238104Sdes } 63238104Sdes 64238104Sdes /* remove root label if it is present at the end of the left 65238104Sdes * rd, by reducing the size with 1 66238104Sdes */ 67238104Sdes left_size = ldns_rdf_size(rd1); 68246854Sdes if (ldns_dname_last_label_is_root_label(rd1)) { 69238104Sdes left_size--; 70238104Sdes } 71238104Sdes 72238104Sdes /* we overwrite the nullbyte of rd1 */ 73238104Sdes new_size = left_size + ldns_rdf_size(rd2); 74238104Sdes buf = LDNS_XMALLOC(uint8_t, new_size); 75238104Sdes if (!buf) { 76238104Sdes return NULL; 77238104Sdes } 78238104Sdes 79238104Sdes /* put the two dname's after each other */ 80238104Sdes memcpy(buf, ldns_rdf_data(rd1), left_size); 81238104Sdes memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2)); 82238104Sdes 83238104Sdes new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf); 84238104Sdes 85238104Sdes LDNS_FREE(buf); 86238104Sdes return new; 87238104Sdes} 88238104Sdes 89238104Sdesldns_status 90238104Sdesldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2) 91238104Sdes{ 92238104Sdes uint16_t left_size; 93238104Sdes uint16_t size; 94238104Sdes uint8_t* newd; 95238104Sdes 96238104Sdes if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME || 97238104Sdes ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) { 98238104Sdes return LDNS_STATUS_ERR; 99238104Sdes } 100238104Sdes 101238104Sdes /* remove root label if it is present at the end of the left 102238104Sdes * rd, by reducing the size with 1 103238104Sdes */ 104238104Sdes left_size = ldns_rdf_size(rd1); 105246854Sdes if (ldns_dname_last_label_is_root_label(rd1)) { 106238104Sdes left_size--; 107238104Sdes } 108238104Sdes 109238104Sdes size = left_size + ldns_rdf_size(rd2); 110238104Sdes newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size); 111238104Sdes if(!newd) { 112238104Sdes return LDNS_STATUS_MEM_ERR; 113238104Sdes } 114238104Sdes 115238104Sdes ldns_rdf_set_data(rd1, newd); 116238104Sdes memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2), 117238104Sdes ldns_rdf_size(rd2)); 118238104Sdes ldns_rdf_set_size(rd1, size); 119238104Sdes 120238104Sdes return LDNS_STATUS_OK; 121238104Sdes} 122238104Sdes 123246854Sdesldns_rdf* 124246854Sdesldns_dname_reverse(const ldns_rdf *dname) 125238104Sdes{ 126246854Sdes size_t rd_size; 127246854Sdes uint8_t* buf; 128246854Sdes ldns_rdf* new; 129246854Sdes size_t src_pos; 130246854Sdes size_t len ; 131238104Sdes 132246854Sdes assert(ldns_rdf_get_type(dname) == LDNS_RDF_TYPE_DNAME); 133246854Sdes 134246854Sdes rd_size = ldns_rdf_size(dname); 135246854Sdes buf = LDNS_XMALLOC(uint8_t, rd_size); 136246854Sdes if (! buf) { 137246854Sdes return NULL; 138238104Sdes } 139246854Sdes new = ldns_rdf_new(LDNS_RDF_TYPE_DNAME, rd_size, buf); 140246854Sdes if (! new) { 141246854Sdes LDNS_FREE(buf); 142246854Sdes return NULL; 143246854Sdes } 144246854Sdes 145246854Sdes /* If dname ends in a root label, the reverse should too. 146246854Sdes */ 147246854Sdes if (ldns_dname_last_label_is_root_label(dname)) { 148246854Sdes buf[rd_size - 1] = 0; 149246854Sdes rd_size -= 1; 150246854Sdes } 151246854Sdes for (src_pos = 0; src_pos < rd_size; src_pos += len + 1) { 152246854Sdes len = ldns_rdf_data(dname)[src_pos]; 153246854Sdes memcpy(&buf[rd_size - src_pos - len - 1], 154246854Sdes &ldns_rdf_data(dname)[src_pos], len + 1); 155246854Sdes } 156238104Sdes return new; 157238104Sdes} 158238104Sdes 159238104Sdesldns_rdf * 160238104Sdesldns_dname_clone_from(const ldns_rdf *d, uint16_t n) 161238104Sdes{ 162238104Sdes uint8_t *data; 163238104Sdes uint8_t label_size; 164238104Sdes size_t data_size; 165238104Sdes 166238104Sdes if (!d || 167238104Sdes ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME || 168238104Sdes ldns_dname_label_count(d) < n) { 169238104Sdes return NULL; 170238104Sdes } 171238104Sdes 172238104Sdes data = ldns_rdf_data(d); 173238104Sdes data_size = ldns_rdf_size(d); 174238104Sdes while (n > 0) { 175238104Sdes label_size = data[0] + 1; 176238104Sdes data += label_size; 177238104Sdes if (data_size < label_size) { 178238104Sdes /* this label is very broken */ 179238104Sdes return NULL; 180238104Sdes } 181238104Sdes data_size -= label_size; 182238104Sdes n--; 183238104Sdes } 184238104Sdes 185238104Sdes return ldns_dname_new_frm_data(data_size, data); 186238104Sdes} 187238104Sdes 188238104Sdesldns_rdf * 189238104Sdesldns_dname_left_chop(const ldns_rdf *d) 190238104Sdes{ 191238104Sdes uint8_t label_pos; 192238104Sdes ldns_rdf *chop; 193238104Sdes 194238104Sdes if (!d) { 195238104Sdes return NULL; 196238104Sdes } 197238104Sdes 198238104Sdes if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) { 199238104Sdes return NULL; 200238104Sdes } 201238104Sdes if (ldns_dname_label_count(d) == 0) { 202238104Sdes /* root label */ 203238104Sdes return NULL; 204238104Sdes } 205238104Sdes /* 05blaat02nl00 */ 206238104Sdes label_pos = ldns_rdf_data(d)[0]; 207238104Sdes 208238104Sdes chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1, 209238104Sdes ldns_rdf_data(d) + label_pos + 1); 210238104Sdes return chop; 211238104Sdes} 212238104Sdes 213238104Sdesuint8_t 214238104Sdesldns_dname_label_count(const ldns_rdf *r) 215238104Sdes{ 216238104Sdes uint16_t src_pos; 217238104Sdes uint16_t len; 218238104Sdes uint8_t i; 219238104Sdes size_t r_size; 220238104Sdes 221238104Sdes if (!r) { 222238104Sdes return 0; 223238104Sdes } 224238104Sdes 225238104Sdes i = 0; 226238104Sdes src_pos = 0; 227238104Sdes r_size = ldns_rdf_size(r); 228238104Sdes 229238104Sdes if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) { 230238104Sdes return 0; 231238104Sdes } else { 232238104Sdes len = ldns_rdf_data(r)[src_pos]; /* start of the label */ 233238104Sdes 234238104Sdes /* single root label */ 235238104Sdes if (1 == r_size) { 236238104Sdes return 0; 237238104Sdes } else { 238238104Sdes while ((len > 0) && src_pos < r_size) { 239238104Sdes src_pos++; 240238104Sdes src_pos += len; 241238104Sdes len = ldns_rdf_data(r)[src_pos]; 242238104Sdes i++; 243238104Sdes } 244238104Sdes } 245238104Sdes } 246238104Sdes return i; 247238104Sdes} 248238104Sdes 249238104Sdesldns_rdf * 250238104Sdesldns_dname_new(uint16_t s, void *d) 251238104Sdes{ 252238104Sdes ldns_rdf *rd; 253238104Sdes 254238104Sdes rd = LDNS_MALLOC(ldns_rdf); 255238104Sdes if (!rd) { 256238104Sdes return NULL; 257238104Sdes } 258238104Sdes ldns_rdf_set_size(rd, s); 259238104Sdes ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME); 260238104Sdes ldns_rdf_set_data(rd, d); 261238104Sdes return rd; 262238104Sdes} 263238104Sdes 264238104Sdesldns_rdf * 265238104Sdesldns_dname_new_frm_str(const char *str) 266238104Sdes{ 267238104Sdes return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str); 268238104Sdes} 269238104Sdes 270238104Sdesldns_rdf * 271238104Sdesldns_dname_new_frm_data(uint16_t size, const void *data) 272238104Sdes{ 273238104Sdes return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data); 274238104Sdes} 275238104Sdes 276238104Sdesvoid 277238104Sdesldns_dname2canonical(const ldns_rdf *rd) 278238104Sdes{ 279238104Sdes uint8_t *rdd; 280238104Sdes uint16_t i; 281238104Sdes 282238104Sdes if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) { 283238104Sdes return; 284238104Sdes } 285238104Sdes 286238104Sdes rdd = (uint8_t*)ldns_rdf_data(rd); 287238104Sdes for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) { 288238104Sdes *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd); 289238104Sdes } 290238104Sdes} 291238104Sdes 292238104Sdesbool 293238104Sdesldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent) 294238104Sdes{ 295238104Sdes uint8_t sub_lab; 296238104Sdes uint8_t par_lab; 297238104Sdes int8_t i, j; 298238104Sdes ldns_rdf *tmp_sub = NULL; 299238104Sdes ldns_rdf *tmp_par = NULL; 300238104Sdes ldns_rdf *sub_clone; 301238104Sdes ldns_rdf *parent_clone; 302238104Sdes bool result = true; 303238104Sdes 304238104Sdes if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME || 305238104Sdes ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME || 306238104Sdes ldns_rdf_compare(sub, parent) == 0) { 307238104Sdes return false; 308238104Sdes } 309238104Sdes 310238104Sdes /* would be nicer if we do not have to clone... */ 311238104Sdes sub_clone = ldns_dname_clone_from(sub, 0); 312238104Sdes parent_clone = ldns_dname_clone_from(parent, 0); 313238104Sdes ldns_dname2canonical(sub_clone); 314238104Sdes ldns_dname2canonical(parent_clone); 315238104Sdes 316238104Sdes sub_lab = ldns_dname_label_count(sub_clone); 317238104Sdes par_lab = ldns_dname_label_count(parent_clone); 318238104Sdes 319238104Sdes /* if sub sits above parent, it cannot be a child/sub domain */ 320238104Sdes if (sub_lab < par_lab) { 321238104Sdes result = false; 322238104Sdes } else { 323238104Sdes /* check all labels the from the parent labels, from right to left. 324238104Sdes * When they /all/ match we have found a subdomain 325238104Sdes */ 326238104Sdes j = sub_lab - 1; /* we count from zero, thank you */ 327238104Sdes for (i = par_lab -1; i >= 0; i--) { 328238104Sdes tmp_sub = ldns_dname_label(sub_clone, j); 329238104Sdes tmp_par = ldns_dname_label(parent_clone, i); 330238104Sdes if (!tmp_sub || !tmp_par) { 331238104Sdes /* deep free does null check */ 332238104Sdes ldns_rdf_deep_free(tmp_sub); 333238104Sdes ldns_rdf_deep_free(tmp_par); 334238104Sdes result = false; 335238104Sdes break; 336238104Sdes } 337238104Sdes 338238104Sdes if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) { 339238104Sdes /* they are not equal */ 340238104Sdes ldns_rdf_deep_free(tmp_sub); 341238104Sdes ldns_rdf_deep_free(tmp_par); 342238104Sdes result = false; 343238104Sdes break; 344238104Sdes } 345238104Sdes ldns_rdf_deep_free(tmp_sub); 346238104Sdes ldns_rdf_deep_free(tmp_par); 347238104Sdes j--; 348238104Sdes } 349238104Sdes } 350238104Sdes ldns_rdf_deep_free(sub_clone); 351238104Sdes ldns_rdf_deep_free(parent_clone); 352238104Sdes return result; 353238104Sdes} 354238104Sdes 355238104Sdesint 356238104Sdesldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2) 357238104Sdes{ 358238104Sdes size_t lc1, lc2, lc1f, lc2f; 359238104Sdes size_t i; 360238104Sdes int result = 0; 361238104Sdes uint8_t *lp1, *lp2; 362238104Sdes 363238104Sdes /* see RFC4034 for this algorithm */ 364238104Sdes /* this algorithm assumes the names are normalized to case */ 365238104Sdes 366238104Sdes /* only when both are not NULL we can say anything about them */ 367238104Sdes if (!dname1 && !dname2) { 368238104Sdes return 0; 369238104Sdes } 370238104Sdes if (!dname1 || !dname2) { 371238104Sdes return -1; 372238104Sdes } 373238104Sdes /* asserts must happen later as we are looking in the 374238104Sdes * dname, which could be NULL. But this case is handled 375238104Sdes * above 376238104Sdes */ 377238104Sdes assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME); 378238104Sdes assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME); 379238104Sdes 380238104Sdes lc1 = ldns_dname_label_count(dname1); 381238104Sdes lc2 = ldns_dname_label_count(dname2); 382238104Sdes 383238104Sdes if (lc1 == 0 && lc2 == 0) { 384238104Sdes return 0; 385238104Sdes } 386238104Sdes if (lc1 == 0) { 387238104Sdes return -1; 388238104Sdes } 389238104Sdes if (lc2 == 0) { 390238104Sdes return 1; 391238104Sdes } 392238104Sdes lc1--; 393238104Sdes lc2--; 394238104Sdes /* we start at the last label */ 395238104Sdes while (true) { 396238104Sdes /* find the label first */ 397238104Sdes lc1f = lc1; 398238104Sdes lp1 = ldns_rdf_data(dname1); 399238104Sdes while (lc1f > 0) { 400238104Sdes lp1 += *lp1 + 1; 401238104Sdes lc1f--; 402238104Sdes } 403238104Sdes 404238104Sdes /* and find the other one */ 405238104Sdes lc2f = lc2; 406238104Sdes lp2 = ldns_rdf_data(dname2); 407238104Sdes while (lc2f > 0) { 408238104Sdes lp2 += *lp2 + 1; 409238104Sdes lc2f--; 410238104Sdes } 411238104Sdes 412238104Sdes /* now check the label character for character. */ 413238104Sdes for (i = 1; i < (size_t)(*lp1 + 1); i++) { 414238104Sdes if (i > *lp2) { 415238104Sdes /* apparently label 1 is larger */ 416238104Sdes result = 1; 417238104Sdes goto done; 418238104Sdes } 419238104Sdes if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) < 420238104Sdes LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) { 421238104Sdes result = -1; 422238104Sdes goto done; 423238104Sdes } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) > 424238104Sdes LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) { 425238104Sdes result = 1; 426238104Sdes goto done; 427238104Sdes } 428238104Sdes } 429238104Sdes if (*lp1 < *lp2) { 430238104Sdes /* apparently label 2 is larger */ 431238104Sdes result = -1; 432238104Sdes goto done; 433238104Sdes } 434238104Sdes if (lc1 == 0 && lc2 > 0) { 435238104Sdes result = -1; 436238104Sdes goto done; 437238104Sdes } else if (lc1 > 0 && lc2 == 0) { 438238104Sdes result = 1; 439238104Sdes goto done; 440238104Sdes } else if (lc1 == 0 && lc2 == 0) { 441238104Sdes result = 0; 442238104Sdes goto done; 443238104Sdes } 444238104Sdes lc1--; 445238104Sdes lc2--; 446238104Sdes } 447238104Sdes 448238104Sdes done: 449238104Sdes return result; 450238104Sdes} 451238104Sdes 452238104Sdesint 453238104Sdesldns_dname_is_wildcard(const ldns_rdf* dname) 454238104Sdes{ 455238104Sdes return ( ldns_dname_label_count(dname) > 0 && 456238104Sdes ldns_rdf_data(dname)[0] == 1 && 457238104Sdes ldns_rdf_data(dname)[1] == '*'); 458238104Sdes} 459238104Sdes 460238104Sdesint 461238104Sdesldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard) 462238104Sdes{ 463238104Sdes ldns_rdf *wc_chopped; 464238104Sdes int result; 465238104Sdes /* check whether it really is a wildcard */ 466238104Sdes if (ldns_dname_is_wildcard(wildcard)) { 467238104Sdes /* ok, so the dname needs to be a subdomain of the wildcard 468238104Sdes * without the * 469238104Sdes */ 470238104Sdes wc_chopped = ldns_dname_left_chop(wildcard); 471238104Sdes result = (int) ldns_dname_is_subdomain(dname, wc_chopped); 472238104Sdes ldns_rdf_deep_free(wc_chopped); 473238104Sdes } else { 474238104Sdes result = (ldns_dname_compare(dname, wildcard) == 0); 475238104Sdes } 476238104Sdes return result; 477238104Sdes} 478238104Sdes 479238104Sdes/* nsec test: does prev <= middle < next 480238104Sdes * -1 = yes 481238104Sdes * 0 = error/can't tell 482238104Sdes * 1 = no 483238104Sdes */ 484238104Sdesint 485238104Sdesldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle, 486238104Sdes const ldns_rdf *next) 487238104Sdes{ 488238104Sdes int prev_check, next_check; 489238104Sdes 490238104Sdes assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME); 491238104Sdes assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME); 492238104Sdes assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME); 493238104Sdes 494238104Sdes prev_check = ldns_dname_compare(prev, middle); 495238104Sdes next_check = ldns_dname_compare(middle, next); 496238104Sdes /* <= next. This cannot be the case for nsec, because then we would 497238104Sdes * have gotten the nsec of next... 498238104Sdes */ 499238104Sdes if (next_check == 0) { 500238104Sdes return 0; 501238104Sdes } 502238104Sdes 503238104Sdes /* <= */ 504238104Sdes if ((prev_check == -1 || prev_check == 0) && 505238104Sdes /* < */ 506238104Sdes next_check == -1) { 507238104Sdes return -1; 508238104Sdes } else { 509238104Sdes return 1; 510238104Sdes } 511238104Sdes} 512238104Sdes 513238104Sdes 514238104Sdesbool 515238104Sdesldns_dname_str_absolute(const char *dname_str) 516238104Sdes{ 517238104Sdes const char* s; 518238104Sdes if(dname_str && strcmp(dname_str, ".") == 0) 519238104Sdes return 1; 520238104Sdes if(!dname_str || strlen(dname_str) < 2) 521238104Sdes return 0; 522238104Sdes if(dname_str[strlen(dname_str) - 1] != '.') 523238104Sdes return 0; 524238104Sdes if(dname_str[strlen(dname_str) - 2] != '\\') 525238104Sdes return 1; /* ends in . and no \ before it */ 526238104Sdes /* so we have the case of ends in . and there is \ before it */ 527238104Sdes for(s=dname_str; *s; s++) { 528238104Sdes if(*s == '\\') { 529238104Sdes if(s[1] && s[2] && s[3] /* check length */ 530238104Sdes && isdigit(s[1]) && isdigit(s[2]) && 531238104Sdes isdigit(s[3])) 532238104Sdes s += 3; 533238104Sdes else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */ 534238104Sdes return 0; /* parse error */ 535238104Sdes else s++; /* another character escaped */ 536238104Sdes } 537238104Sdes else if(!*(s+1) && *s == '.') 538238104Sdes return 1; /* trailing dot, unescaped */ 539238104Sdes } 540238104Sdes return 0; 541238104Sdes} 542238104Sdes 543246854Sdesbool 544246854Sdesldns_dname_absolute(const ldns_rdf *rdf) 545246854Sdes{ 546246854Sdes char *str = ldns_rdf2str(rdf); 547246854Sdes if (str) { 548246854Sdes bool r = ldns_dname_str_absolute(str); 549246854Sdes LDNS_FREE(str); 550246854Sdes return r; 551246854Sdes } 552246854Sdes return false; 553246854Sdes} 554246854Sdes 555238104Sdesldns_rdf * 556238104Sdesldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos) 557238104Sdes{ 558238104Sdes uint8_t labelcnt; 559238104Sdes uint16_t src_pos; 560238104Sdes uint16_t len; 561238104Sdes ldns_rdf *tmpnew; 562238104Sdes size_t s; 563238104Sdes uint8_t *data; 564238104Sdes 565238104Sdes if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) { 566238104Sdes return NULL; 567238104Sdes } 568238104Sdes 569238104Sdes labelcnt = 0; 570238104Sdes src_pos = 0; 571238104Sdes s = ldns_rdf_size(rdf); 572238104Sdes 573238104Sdes len = ldns_rdf_data(rdf)[src_pos]; /* label start */ 574238104Sdes while ((len > 0) && src_pos < s) { 575238104Sdes if (labelcnt == labelpos) { 576238104Sdes /* found our label */ 577238104Sdes data = LDNS_XMALLOC(uint8_t, len + 2); 578238104Sdes if (!data) { 579238104Sdes return NULL; 580238104Sdes } 581238104Sdes memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1); 582238104Sdes data[len + 2 - 1] = 0; 583238104Sdes 584238104Sdes tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME 585238104Sdes , len + 2, data); 586238104Sdes if (!tmpnew) { 587238104Sdes LDNS_FREE(data); 588238104Sdes return NULL; 589238104Sdes } 590238104Sdes return tmpnew; 591238104Sdes } 592238104Sdes src_pos++; 593238104Sdes src_pos += len; 594238104Sdes len = ldns_rdf_data(rdf)[src_pos]; 595238104Sdes labelcnt++; 596238104Sdes } 597238104Sdes return NULL; 598238104Sdes} 599