int label_compare(const uint8_t *left, const uint8_t *right) { int left_length; int right_length; size_t size; int result; assert(left); assert(right); assert(label_is_normal(left)); assert(label_is_normal(right)); left_length = label_length(left); right_length = label_length(right); size = left_length < right_length ? left_length : right_length; result = memcmp(label_data(left), label_data(right), size); if (result) { return result; } else { return (int) left_length - (int) right_length; } }
static void encode_dname(query_type *q, domain_type *domain) { while (domain->parent && query_get_dname_offset(q, domain) == 0) { query_put_dname_offset(q, domain, buffer_position(q->packet)); DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "dname: %s, number: %lu, offset: %u\n", dname_to_string(domain_dname(domain), NULL), (unsigned long) domain->number, query_get_dname_offset(q, domain))); buffer_write(q->packet, dname_name(domain_dname(domain)), label_length(dname_name(domain_dname(domain))) + 1U); domain = domain->parent; } if (domain->parent) { DEBUG(DEBUG_NAME_COMPRESSION, 2, (LOG_INFO, "dname: %s, number: %lu, pointer: %u\n", dname_to_string(domain_dname(domain), NULL), (unsigned long) domain->number, query_get_dname_offset(q, domain))); assert(query_get_dname_offset(q, domain) <= MAX_COMPRESSION_OFFSET); buffer_write_u16(q->packet, 0xc000 | query_get_dname_offset(q, domain)); } else { buffer_write_u8(q->packet, 0); } }
/** * Get the next label. * */ const uint8_t* label_next(const uint8_t* label) { assert(label); assert(label_is_normal(label)); assert(!label_is_root(label)); return label + label_length(label) + 1; }
const char * dname_to_string_r(const dname_type *dname, const dname_type *origin, char* buf) { size_t i; size_t labels_to_convert = 0; int absolute = 1; char *dst; const uint8_t *src; if (!dname) { *buf = '\0'; return buf; } if (dname->label_count == 1) { strlcpy(buf, ".", sizeof(buf)); return buf; } labels_to_convert = dname->label_count - 1; if (origin && dname_is_subdomain(dname, origin)) { int common_labels = dname_label_match_count(dname, origin); labels_to_convert = dname->label_count - common_labels; absolute = 0; } dst = buf; src = dname_name(dname); for (i = 0; i < labels_to_convert; ++i) { size_t len = label_length(src); size_t j; ++src; for (j = 0; j < len; ++j) { uint8_t ch = *src++; if (isalnum(ch) || ch == '-' || ch == '_') { *dst++ = ch; } else if (ch == '.' || ch == '\\') { *dst++ = '\\'; *dst++ = ch; } else { snprintf(dst, 5, "\\%03u", (unsigned int)ch); dst += 4; } } *dst++ = '.'; } if (absolute) { *dst = '\0'; } else { *--dst = '\0'; } return buf; }
/** * Create new domain name. * */ dname_type* dname_create(region_type* r, const char* str) { uint8_t wire[DNAME_MAXLEN]; uint8_t label_offsets[DNAME_MAXLEN]; uint8_t label_count = 0; size_t size = 0; const uint8_t* label = wire; dname_type *dname; ssize_t i; assert(r); assert(str); if (!dname_str2wire(wire, str)) { fprintf(stderr, "[%s] error: parse dname %s failed", logstr, str); return NULL; } while (1) { if (label_is_pointer(label)) { return NULL; } label_offsets[label_count] = (uint8_t) (label - wire); ++label_count; size += label_length(label) + 1; if (label_is_root(label)) { break; } label = label_next(label); } if (size > DNAME_MAXLEN) { return NULL; } assert(label_count <= DNAME_MAXLEN / 2 + 1); /* reverse label offsets. */ /* reverse label offsets. */ for (i = 0; i < label_count / 2; ++i) { uint8_t tmp = label_offsets[i]; label_offsets[i] = label_offsets[label_count - i - 1]; label_offsets[label_count - i - 1] = tmp; } dname = (dname_type *) region_alloc(r, (sizeof(dname_type) + (label_count + size) * sizeof(uint8_t))); dname->size = size; dname->label_count = label_count; memcpy((uint8_t *) dname_label_offsets(dname), label_offsets, label_count * sizeof(uint8_t)); memcpy((uint8_t *) dname_name(dname), wire, size * sizeof(uint8_t)); return dname; }
/** * Print domain name. * */ void dname_print(FILE* fd, dname_type* dname) { static char buf[DNAME_MAXLEN*5]; size_t i; size_t labels_to_convert; char* dst; const uint8_t* src; if (!dname || !fd) { return; } assert(dname->label_count > 0); if (dname->label_count == 1) { fprintf(fd, "."); return; } labels_to_convert = dname->label_count - 1; dst = buf; src = dname_name(dname); for (i = 0; i < labels_to_convert; ++i) { size_t len = label_length(src); size_t j; ++src; for (j = 0; j < len; ++j) { uint8_t ch = *src++; if (isalnum(ch) || ch == '-' || ch == '_') { *dst++ = ch; } else if (ch == '.' || ch == '\\' || ch == '(' || ch == ')' || ch == ';') { *dst++ = '\\'; *dst++ = ch; } else { snprintf(dst, 5, "\\%03u", (unsigned int)ch); dst += 4; } } *dst++ = '.'; } *dst = '\0'; fprintf(fd, "%s", buf); return; }
const dname_type * dname_make(region_type *region, const uint8_t *name, int normalize) { size_t name_size = 0; uint8_t label_offsets[MAXDOMAINLEN]; uint8_t label_count = 0; const uint8_t *label = name; dname_type *result; ssize_t i; assert(name); while (1) { if (label_is_pointer(label)) return NULL; label_offsets[label_count] = (uint8_t) (label - name); ++label_count; name_size += label_length(label) + 1; if (label_is_root(label)) break; label = label_next(label); } if (name_size > MAXDOMAINLEN) return NULL; assert(label_count <= MAXDOMAINLEN / 2 + 1); /* Reverse label offsets. */ for (i = 0; i < label_count / 2; ++i) { uint8_t tmp = label_offsets[i]; label_offsets[i] = label_offsets[label_count - i - 1]; label_offsets[label_count - i - 1] = tmp; } result = (dname_type *) region_alloc( region, (sizeof(dname_type) + (label_count + name_size) * sizeof(uint8_t))); result->name_size = name_size; result->label_count = label_count; memcpy((uint8_t *) dname_label_offsets(result), label_offsets, label_count * sizeof(uint8_t)); if (normalize) { uint8_t *dst = (uint8_t *) dname_name(result); const uint8_t *src = name; while (!label_is_root(src)) { ssize_t len = label_length(src); *dst++ = *src++; for (i = 0; i < len; ++i) { *dst++ = DNAME_NORMALIZE(*src++); } } *dst = *src; } else { memcpy((uint8_t *) dname_name(result), name, name_size * sizeof(uint8_t)); } return result; }
int dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, int allow_pointers) { int done = 0; uint8_t visited[(MAX_PACKET_SIZE+7)/8]; size_t dname_length = 0; const uint8_t *label; ssize_t mark = -1; memset(visited, 0, (buffer_limit(packet)+7)/8); while (!done) { if (!buffer_available(packet, 1)) { /* error("dname out of bounds"); */ return 0; } if (get_bit(visited, buffer_position(packet))) { /* error("dname loops"); */ return 0; } set_bit(visited, buffer_position(packet)); label = buffer_current(packet); if (label_is_pointer(label)) { size_t pointer; if (!allow_pointers) { return 0; } if (!buffer_available(packet, 2)) { /* error("dname pointer out of bounds"); */ return 0; } pointer = label_pointer_location(label); if (pointer >= buffer_limit(packet)) { /* error("dname pointer points outside packet"); */ return 0; } buffer_skip(packet, 2); if (mark == -1) { mark = buffer_position(packet); } buffer_set_position(packet, pointer); } else if (label_is_normal(label)) { size_t length = label_length(label) + 1; done = label_is_root(label); if (!buffer_available(packet, length)) { /* error("dname label out of bounds"); */ return 0; } if (dname_length + length >= MAXDOMAINLEN+1) { /* error("dname too large"); */ return 0; } buffer_read(packet, buf + dname_length, length); dname_length += length; } else { /* error("bad label type"); */ return 0; } } if (mark != -1) { buffer_set_position(packet, mark); } return dname_length; }