summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '3rdParty/Ldns/src/src/dname.c')
-rw-r--r--3rdParty/Ldns/src/src/dname.c567
1 files changed, 567 insertions, 0 deletions
diff --git a/3rdParty/Ldns/src/src/dname.c b/3rdParty/Ldns/src/src/dname.c
new file mode 100644
index 0000000..0e63ef2
--- /dev/null
+++ b/3rdParty/Ldns/src/src/dname.c
@@ -0,0 +1,567 @@
+/*
+ * dname.c
+ *
+ * dname specific rdata implementations
+ * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME
+ * It is not a /real/ type! All function must therefor check
+ * for LDNS_RDF_TYPE_DNAME.
+ *
+ * a Net::DNS like library for C
+ *
+ * (c) NLnet Labs, 2004-2006
+ *
+ * See the file LICENSE for the license
+ */
+
+#include <ldns/config.h>
+
+#include <ldns/ldns.h>
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+ldns_rdf *
+ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2)
+{
+ ldns_rdf *new;
+ uint16_t new_size;
+ uint8_t *buf;
+ uint16_t left_size;
+
+ if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
+ return NULL;
+ }
+
+ /* remove root label if it is present at the end of the left
+ * rd, by reducing the size with 1
+ */
+ left_size = ldns_rdf_size(rd1);
+ if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
+ left_size--;
+ }
+
+ /* we overwrite the nullbyte of rd1 */
+ new_size = left_size + ldns_rdf_size(rd2);
+ buf = LDNS_XMALLOC(uint8_t, new_size);
+ if (!buf) {
+ return NULL;
+ }
+
+ /* put the two dname's after each other */
+ memcpy(buf, ldns_rdf_data(rd1), left_size);
+ memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2));
+
+ new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf);
+
+ LDNS_FREE(buf);
+ return new;
+}
+
+ldns_status
+ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2)
+{
+ uint16_t left_size;
+ uint16_t size;
+ uint8_t* newd;
+
+ if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) {
+ return LDNS_STATUS_ERR;
+ }
+
+ /* remove root label if it is present at the end of the left
+ * rd, by reducing the size with 1
+ */
+ left_size = ldns_rdf_size(rd1);
+ if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) {
+ left_size--;
+ }
+ if(left_size == 0) {
+ return LDNS_STATUS_OK;
+ }
+
+ size = left_size + ldns_rdf_size(rd2);
+ newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size);
+ if(!newd) {
+ return LDNS_STATUS_MEM_ERR;
+ }
+
+ ldns_rdf_set_data(rd1, newd);
+ memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2),
+ ldns_rdf_size(rd2));
+ ldns_rdf_set_size(rd1, size);
+
+ return LDNS_STATUS_OK;
+}
+
+ldns_rdf *
+ldns_dname_reverse(const ldns_rdf *d)
+{
+ ldns_rdf *new;
+ ldns_rdf *tmp;
+ ldns_rdf *d_tmp;
+ ldns_status status;
+
+ d_tmp = ldns_rdf_clone(d);
+
+ new = ldns_dname_new_frm_str(".");
+ if(!new)
+ return NULL;
+
+ while(ldns_dname_label_count(d_tmp) > 0) {
+ tmp = ldns_dname_label(d_tmp, 0);
+ status = ldns_dname_cat(tmp, new);
+ if(status != LDNS_STATUS_OK) {
+ ldns_rdf_deep_free(new);
+ ldns_rdf_deep_free(d_tmp);
+ return NULL;
+ }
+ ldns_rdf_deep_free(new);
+ new = tmp;
+ tmp = ldns_dname_left_chop(d_tmp);
+ ldns_rdf_deep_free(d_tmp);
+ d_tmp = tmp;
+ }
+ ldns_rdf_deep_free(d_tmp);
+
+ return new;
+}
+
+ldns_rdf *
+ldns_dname_clone_from(const ldns_rdf *d, uint16_t n)
+{
+ uint8_t *data;
+ uint8_t label_size;
+ size_t data_size;
+
+ if (!d ||
+ ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME ||
+ ldns_dname_label_count(d) < n) {
+ return NULL;
+ }
+
+ data = ldns_rdf_data(d);
+ data_size = ldns_rdf_size(d);
+ while (n > 0) {
+ label_size = data[0] + 1;
+ data += label_size;
+ if (data_size < label_size) {
+ /* this label is very broken */
+ return NULL;
+ }
+ data_size -= label_size;
+ n--;
+ }
+
+ return ldns_dname_new_frm_data(data_size, data);
+}
+
+ldns_rdf *
+ldns_dname_left_chop(const ldns_rdf *d)
+{
+ uint8_t label_pos;
+ ldns_rdf *chop;
+
+ if (!d) {
+ return NULL;
+ }
+
+ if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) {
+ return NULL;
+ }
+ if (ldns_dname_label_count(d) == 0) {
+ /* root label */
+ return NULL;
+ }
+ /* 05blaat02nl00 */
+ label_pos = ldns_rdf_data(d)[0];
+
+ chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1,
+ ldns_rdf_data(d) + label_pos + 1);
+ return chop;
+}
+
+uint8_t
+ldns_dname_label_count(const ldns_rdf *r)
+{
+ uint16_t src_pos;
+ uint16_t len;
+ uint8_t i;
+ size_t r_size;
+
+ if (!r) {
+ return 0;
+ }
+
+ i = 0;
+ src_pos = 0;
+ r_size = ldns_rdf_size(r);
+
+ if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) {
+ return 0;
+ } else {
+ len = ldns_rdf_data(r)[src_pos]; /* start of the label */
+
+ /* single root label */
+ if (1 == r_size) {
+ return 0;
+ } else {
+ while ((len > 0) && src_pos < r_size) {
+ src_pos++;
+ src_pos += len;
+ len = ldns_rdf_data(r)[src_pos];
+ i++;
+ }
+ }
+ }
+ return i;
+}
+
+ldns_rdf *
+ldns_dname_new(uint16_t s, void *d)
+{
+ ldns_rdf *rd;
+
+ rd = LDNS_MALLOC(ldns_rdf);
+ if (!rd) {
+ return NULL;
+ }
+ ldns_rdf_set_size(rd, s);
+ ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME);
+ ldns_rdf_set_data(rd, d);
+ return rd;
+}
+
+ldns_rdf *
+ldns_dname_new_frm_str(const char *str)
+{
+ return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str);
+}
+
+ldns_rdf *
+ldns_dname_new_frm_data(uint16_t size, const void *data)
+{
+ return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data);
+}
+
+void
+ldns_dname2canonical(const ldns_rdf *rd)
+{
+ uint8_t *rdd;
+ uint16_t i;
+
+ if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) {
+ return;
+ }
+
+ rdd = (uint8_t*)ldns_rdf_data(rd);
+ for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) {
+ *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd);
+ }
+}
+
+bool
+ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent)
+{
+ uint8_t sub_lab;
+ uint8_t par_lab;
+ int8_t i, j;
+ ldns_rdf *tmp_sub = NULL;
+ ldns_rdf *tmp_par = NULL;
+ ldns_rdf *sub_clone;
+ ldns_rdf *parent_clone;
+ bool result = true;
+
+ if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME ||
+ ldns_rdf_compare(sub, parent) == 0) {
+ return false;
+ }
+
+ /* would be nicer if we do not have to clone... */
+ sub_clone = ldns_dname_clone_from(sub, 0);
+ parent_clone = ldns_dname_clone_from(parent, 0);
+ ldns_dname2canonical(sub_clone);
+ ldns_dname2canonical(parent_clone);
+
+ sub_lab = ldns_dname_label_count(sub_clone);
+ par_lab = ldns_dname_label_count(parent_clone);
+
+ /* if sub sits above parent, it cannot be a child/sub domain */
+ if (sub_lab < par_lab) {
+ result = false;
+ } else {
+ /* check all labels the from the parent labels, from right to left.
+ * When they /all/ match we have found a subdomain
+ */
+ j = sub_lab - 1; /* we count from zero, thank you */
+ for (i = par_lab -1; i >= 0; i--) {
+ tmp_sub = ldns_dname_label(sub_clone, j);
+ tmp_par = ldns_dname_label(parent_clone, i);
+ if (!tmp_sub || !tmp_par) {
+ /* deep free does null check */
+ ldns_rdf_deep_free(tmp_sub);
+ ldns_rdf_deep_free(tmp_par);
+ result = false;
+ break;
+ }
+
+ if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) {
+ /* they are not equal */
+ ldns_rdf_deep_free(tmp_sub);
+ ldns_rdf_deep_free(tmp_par);
+ result = false;
+ break;
+ }
+ ldns_rdf_deep_free(tmp_sub);
+ ldns_rdf_deep_free(tmp_par);
+ j--;
+ }
+ }
+ ldns_rdf_deep_free(sub_clone);
+ ldns_rdf_deep_free(parent_clone);
+ return result;
+}
+
+int
+ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2)
+{
+ size_t lc1, lc2, lc1f, lc2f;
+ size_t i;
+ int result = 0;
+ uint8_t *lp1, *lp2;
+
+ /* see RFC4034 for this algorithm */
+ /* this algorithm assumes the names are normalized to case */
+
+ /* only when both are not NULL we can say anything about them */
+ if (!dname1 && !dname2) {
+ return 0;
+ }
+ if (!dname1 || !dname2) {
+ return -1;
+ }
+ /* asserts must happen later as we are looking in the
+ * dname, which could be NULL. But this case is handled
+ * above
+ */
+ assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME);
+ assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME);
+
+ lc1 = ldns_dname_label_count(dname1);
+ lc2 = ldns_dname_label_count(dname2);
+
+ if (lc1 == 0 && lc2 == 0) {
+ return 0;
+ }
+ if (lc1 == 0) {
+ return -1;
+ }
+ if (lc2 == 0) {
+ return 1;
+ }
+ lc1--;
+ lc2--;
+ /* we start at the last label */
+ while (true) {
+ /* find the label first */
+ lc1f = lc1;
+ lp1 = ldns_rdf_data(dname1);
+ while (lc1f > 0) {
+ lp1 += *lp1 + 1;
+ lc1f--;
+ }
+
+ /* and find the other one */
+ lc2f = lc2;
+ lp2 = ldns_rdf_data(dname2);
+ while (lc2f > 0) {
+ lp2 += *lp2 + 1;
+ lc2f--;
+ }
+
+ /* now check the label character for character. */
+ for (i = 1; i < (size_t)(*lp1 + 1); i++) {
+ if (i > *lp2) {
+ /* apparently label 1 is larger */
+ result = 1;
+ goto done;
+ }
+ if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) <
+ LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
+ result = -1;
+ goto done;
+ } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) >
+ LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) {
+ result = 1;
+ goto done;
+ }
+ }
+ if (*lp1 < *lp2) {
+ /* apparently label 2 is larger */
+ result = -1;
+ goto done;
+ }
+ if (lc1 == 0 && lc2 > 0) {
+ result = -1;
+ goto done;
+ } else if (lc1 > 0 && lc2 == 0) {
+ result = 1;
+ goto done;
+ } else if (lc1 == 0 && lc2 == 0) {
+ result = 0;
+ goto done;
+ }
+ lc1--;
+ lc2--;
+ }
+
+ done:
+ return result;
+}
+
+int
+ldns_dname_is_wildcard(const ldns_rdf* dname)
+{
+ return ( ldns_dname_label_count(dname) > 0 &&
+ ldns_rdf_data(dname)[0] == 1 &&
+ ldns_rdf_data(dname)[1] == '*');
+}
+
+int
+ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard)
+{
+ ldns_rdf *wc_chopped;
+ int result;
+ /* check whether it really is a wildcard */
+ if (ldns_dname_is_wildcard(wildcard)) {
+ /* ok, so the dname needs to be a subdomain of the wildcard
+ * without the *
+ */
+ wc_chopped = ldns_dname_left_chop(wildcard);
+ result = (int) ldns_dname_is_subdomain(dname, wc_chopped);
+ ldns_rdf_deep_free(wc_chopped);
+ } else {
+ result = (ldns_dname_compare(dname, wildcard) == 0);
+ }
+ return result;
+}
+
+/* nsec test: does prev <= middle < next
+ * -1 = yes
+ * 0 = error/can't tell
+ * 1 = no
+ */
+int
+ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle,
+ const ldns_rdf *next)
+{
+ int prev_check, next_check;
+
+ assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME);
+ assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME);
+ assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME);
+
+ prev_check = ldns_dname_compare(prev, middle);
+ next_check = ldns_dname_compare(middle, next);
+ /* <= next. This cannot be the case for nsec, because then we would
+ * have gotten the nsec of next...
+ */
+ if (next_check == 0) {
+ return 0;
+ }
+
+ /* <= */
+ if ((prev_check == -1 || prev_check == 0) &&
+ /* < */
+ next_check == -1) {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+
+bool
+ldns_dname_str_absolute(const char *dname_str)
+{
+ const char* s;
+ if(dname_str && strcmp(dname_str, ".") == 0)
+ return 1;
+ if(!dname_str || strlen(dname_str) < 2)
+ return 0;
+ if(dname_str[strlen(dname_str) - 1] != '.')
+ return 0;
+ if(dname_str[strlen(dname_str) - 2] != '\\')
+ return 1; /* ends in . and no \ before it */
+ /* so we have the case of ends in . and there is \ before it */
+ for(s=dname_str; *s; s++) {
+ if(*s == '\\') {
+ if(s[1] && s[2] && s[3] /* check length */
+ && isdigit(s[1]) && isdigit(s[2]) &&
+ isdigit(s[3]))
+ s += 3;
+ else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */
+ return 0; /* parse error */
+ else s++; /* another character escaped */
+ }
+ else if(!*(s+1) && *s == '.')
+ return 1; /* trailing dot, unescaped */
+ }
+ return 0;
+}
+
+ldns_rdf *
+ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos)
+{
+ uint8_t labelcnt;
+ uint16_t src_pos;
+ uint16_t len;
+ ldns_rdf *tmpnew;
+ size_t s;
+
+ if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) {
+ return NULL;
+ }
+
+ labelcnt = 0;
+ src_pos = 0;
+ s = ldns_rdf_size(rdf);
+
+ len = ldns_rdf_data(rdf)[src_pos]; /* label start */
+ while ((len > 0) && src_pos < s) {
+ if (labelcnt == labelpos) {
+ /* found our label */
+ tmpnew = LDNS_MALLOC(ldns_rdf);
+ if (!tmpnew) {
+ return NULL;
+ }
+ tmpnew->_type = LDNS_RDF_TYPE_DNAME;
+ tmpnew->_data = LDNS_XMALLOC(uint8_t, len + 2);
+ if (!tmpnew->_data) {
+ LDNS_FREE(tmpnew);
+ return NULL;
+ }
+ memset(tmpnew->_data, 0, len + 2);
+ memcpy(tmpnew->_data, ldns_rdf_data(rdf) + src_pos, len + 1);
+ tmpnew->_size = len + 2;
+ return tmpnew;
+ }
+ src_pos++;
+ src_pos += len;
+ len = ldns_rdf_data(rdf)[src_pos];
+ labelcnt++;
+ }
+ return NULL;
+}