void dns_compress_setmethods(dns_compress_t *cctx, unsigned int allowed) { REQUIRE(VALID_CCTX(cctx)); cctx->allowed &= ~DNS_COMPRESS_ALL; cctx->allowed |= (allowed & DNS_COMPRESS_ALL); }
void dns_compress_rollback(dns_compress_t *cctx, isc_uint16_t offset) { unsigned int i; dns_compressnode_t *node; REQUIRE(VALID_CCTX(cctx)); if (ISC_UNLIKELY((cctx->allowed & DNS_COMPRESS_ENABLED) == 0)) return; for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) { node = cctx->table[i]; /* * This relies on nodes with greater offsets being * closer to the beginning of the list, and the * items with the greatest offsets being at the end * of the initialnodes[] array. */ while (node != NULL && (node->offset & 0x7fff) >= offset) { cctx->table[i] = node->next; if ((node->offset & 0x8000) != 0) isc_mem_put(cctx->mctx, node->r.base, node->r.length); if (node->count >= DNS_COMPRESS_INITIALNODES) isc_mem_put(cctx->mctx, node, sizeof(*node)); cctx->count--; node = cctx->table[i]; } } }
void dns_compress_setsensitive(dns_compress_t *cctx, isc_boolean_t sensitive) { REQUIRE(VALID_CCTX(cctx)); if (sensitive) cctx->allowed |= DNS_COMPRESS_CASESENSITIVE; else cctx->allowed &= ~DNS_COMPRESS_CASESENSITIVE; }
void dns_compress_add(dns_compress_t *cctx, const dns_name_t *name, const dns_name_t *prefix, isc_uint16_t offset) { dns_name_t tname; unsigned int start; unsigned int n; unsigned int count; unsigned int hash; dns_compressnode_t *node; unsigned int length; unsigned int tlength; isc_uint16_t toffset; REQUIRE(VALID_CCTX(cctx)); REQUIRE(dns_name_isabsolute(name)); dns_name_init(&tname, NULL); n = dns_name_countlabels(name); count = dns_name_countlabels(prefix); if (dns_name_isabsolute(prefix)) count--; start = 0; length = name_length(name); while (count > 0) { if (offset >= 0x4000) break; dns_name_getlabelsequence(name, start, n, &tname); hash = dns_name_hash(&tname, ISC_FALSE) % DNS_COMPRESS_TABLESIZE; tlength = name_length(&tname); toffset = (isc_uint16_t)(offset + (length - tlength)); /* * Create a new node and add it. */ if (cctx->count < DNS_COMPRESS_INITIALNODES) node = &cctx->initialnodes[cctx->count]; else { node = isc_mem_get(cctx->mctx, sizeof(dns_compressnode_t)); if (node == NULL) return; } node->count = cctx->count++; node->offset = toffset; dns_name_toregion(&tname, &node->r); node->labels = (isc_uint8_t)dns_name_countlabels(&tname); node->next = cctx->table[hash]; cctx->table[hash] = node; start++; n--; count--; } }
/* * Find the longest match of name in the table. * If match is found return ISC_TRUE. prefix, suffix and offset are updated. * If no match is found return ISC_FALSE. */ isc_boolean_t dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name, dns_name_t *prefix, isc_uint16_t *offset) { dns_name_t tname, nname; dns_compressnode_t *node = NULL; unsigned int labels, hash, n; REQUIRE(VALID_CCTX(cctx)); REQUIRE(dns_name_isabsolute(name) == ISC_TRUE); REQUIRE(offset != NULL); if (cctx->count == 0) return (ISC_FALSE); labels = dns_name_countlabels(name); INSIST(labels > 0); dns_name_init(&tname, NULL); dns_name_init(&nname, NULL); for (n = 0; n < labels - 1; n++) { dns_name_getlabelsequence(name, n, labels - n, &tname); hash = dns_name_hash(&tname, ISC_FALSE) % DNS_COMPRESS_TABLESIZE; for (node = cctx->table[hash]; node != NULL; node = node->next) { NODENAME(node, &nname); if ((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0) { if (dns_name_caseequal(&nname, &tname)) break; } else { if (dns_name_equal(&nname, &tname)) break; } } if (node != NULL) break; } /* * If node == NULL, we found no match at all. */ if (node == NULL) return (ISC_FALSE); if (n == 0) dns_name_reset(prefix); else dns_name_getlabelsequence(name, 0, n, prefix); *offset = node->offset; return (ISC_TRUE); }
void dns_compress_invalidate(dns_compress_t *cctx) { dns_compressnode_t *node; unsigned int i; REQUIRE(VALID_CCTX(cctx)); cctx->magic = 0; for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) { while (cctx->table[i] != NULL) { node = cctx->table[i]; cctx->table[i] = cctx->table[i]->next; if (node->count < DNS_COMPRESS_INITIALNODES) continue; isc_mem_put(cctx->mctx, node, sizeof(*node)); } } cctx->allowed = 0; cctx->edns = -1; }
unsigned int dns_compress_getmethods(dns_compress_t *cctx) { REQUIRE(VALID_CCTX(cctx)); return (cctx->allowed & DNS_COMPRESS_ALL); }
int dns_compress_getedns(dns_compress_t *cctx) { REQUIRE(VALID_CCTX(cctx)); return (cctx->edns); }
isc_boolean_t dns_compress_getsensitive(dns_compress_t *cctx) { REQUIRE(VALID_CCTX(cctx)); return (ISC_TF((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0)); }
void dns_compress_add(dns_compress_t *cctx, const dns_name_t *name, const dns_name_t *prefix, isc_uint16_t offset) { dns_name_t tname, xname; unsigned int start; unsigned int n; unsigned int count; unsigned int i; dns_compressnode_t *node; unsigned int length; unsigned int tlength; isc_uint16_t toffset; unsigned char *tmp; isc_region_t r; REQUIRE(VALID_CCTX(cctx)); REQUIRE(dns_name_isabsolute(name)); if (ISC_UNLIKELY((cctx->allowed & DNS_COMPRESS_ENABLED) == 0)) return; if (offset >= 0x4000) return; dns_name_init(&tname, NULL); dns_name_init(&xname, NULL); n = dns_name_countlabels(name); count = dns_name_countlabels(prefix); if (dns_name_isabsolute(prefix)) count--; if (count == 0) return; start = 0; dns_name_toregion(name, &r); length = r.length; tmp = isc_mem_get(cctx->mctx, length); if (tmp == NULL) return; /* * Copy name data to 'tmp' and make 'r' use 'tmp'. */ memmove(tmp, r.base, r.length); r.base = tmp; dns_name_fromregion(&xname, &r); if (count > 2U) count = 2U; while (count > 0) { unsigned char ch; dns_name_getlabelsequence(&xname, start, n, &tname); /* * We calculate the table index using the first * character in the first label of tname. */ ch = tname.ndata[1]; i = tableindex[ch]; tlength = name_length(&tname); toffset = (isc_uint16_t)(offset + (length - tlength)); if (toffset >= 0x4000) break; /* * Create a new node and add it. */ if (cctx->count < DNS_COMPRESS_INITIALNODES) node = &cctx->initialnodes[cctx->count]; else { node = isc_mem_get(cctx->mctx, sizeof(dns_compressnode_t)); if (node == NULL) break; } node->count = cctx->count++; /* * 'node->r.base' becomes 'tmp' when start == 0. * Record this by setting 0x8000 so it can be freed later. */ if (start == 0) toffset |= 0x8000; node->offset = toffset; dns_name_toregion(&tname, &node->r); dns_name_init(&node->name, NULL); node->name.length = node->r.length; node->name.ndata = node->r.base; node->name.labels = tname.labels; node->name.attributes = DNS_NAMEATTR_ABSOLUTE; node->next = cctx->table[i]; cctx->table[i] = node; start++; n--; count--; } if (start == 0) isc_mem_put(cctx->mctx, tmp, length); }
/* * Find the longest match of name in the table. * If match is found return ISC_TRUE. prefix, suffix and offset are updated. * If no match is found return ISC_FALSE. */ isc_boolean_t dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name, dns_name_t *prefix, isc_uint16_t *offset) { dns_name_t tname; dns_compressnode_t *node = NULL; unsigned int labels, i, n; unsigned int numlabels; unsigned char *p; REQUIRE(VALID_CCTX(cctx)); REQUIRE(dns_name_isabsolute(name) == ISC_TRUE); REQUIRE(offset != NULL); if (ISC_UNLIKELY((cctx->allowed & DNS_COMPRESS_ENABLED) == 0)) return (ISC_FALSE); if (cctx->count == 0) return (ISC_FALSE); labels = dns_name_countlabels(name); INSIST(labels > 0); dns_name_init(&tname, NULL); numlabels = labels > 3U ? 3U : labels; p = name->ndata; for (n = 0; n < numlabels - 1; n++) { unsigned char ch, llen; unsigned int firstoffset, length; firstoffset = (unsigned int)(p - name->ndata); length = name->length - firstoffset; /* * We calculate the table index using the first * character in the first label of the suffix name. */ ch = p[1]; i = tableindex[ch]; if (ISC_LIKELY((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0)) { for (node = cctx->table[i]; node != NULL; node = node->next) { if (ISC_UNLIKELY(node->name.length != length)) continue; if (ISC_LIKELY(memcmp(node->name.ndata, p, length) == 0)) goto found; } } else { for (node = cctx->table[i]; node != NULL; node = node->next) { unsigned int l, count; unsigned char c; unsigned char *label1, *label2; if (ISC_UNLIKELY(node->name.length != length)) continue; l = labels - n; if (ISC_UNLIKELY(node->name.labels != l)) continue; label1 = node->name.ndata; label2 = p; while (ISC_LIKELY(l-- > 0)) { count = *label1++; if (count != *label2++) goto cont1; /* no bitstring support */ INSIST(count <= 63); /* Loop unrolled for performance */ while (ISC_LIKELY(count > 3)) { c = maptolower[label1[0]]; if (c != maptolower[label2[0]]) goto cont1; c = maptolower[label1[1]]; if (c != maptolower[label2[1]]) goto cont1; c = maptolower[label1[2]]; if (c != maptolower[label2[2]]) goto cont1; c = maptolower[label1[3]]; if (c != maptolower[label2[3]]) goto cont1; count -= 4; label1 += 4; label2 += 4; } while (ISC_LIKELY(count-- > 0)) { c = maptolower[*label1++]; if (c != maptolower[*label2++]) goto cont1; } } break; cont1: continue; } } if (node != NULL) break; llen = *p; p += llen + 1; } found: /* * If node == NULL, we found no match at all. */ if (node == NULL) return (ISC_FALSE); if (n == 0) dns_name_reset(prefix); else dns_name_getlabelsequence(name, 0, n, prefix); *offset = (node->offset & 0x7fff); return (ISC_TRUE); }
void dns_compress_disable(dns_compress_t *cctx) { REQUIRE(VALID_CCTX(cctx)); cctx->allowed &= ~DNS_COMPRESS_ENABLED; }