Dname compare routines with compression pointers.

git-svn-id: file:///svn/unbound/trunk@239 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-04-12 14:54:34 +00:00
parent eb51f48214
commit dc1513899f
3 changed files with 106 additions and 8 deletions

View file

@ -185,3 +185,44 @@ pkt_dname_len(ldns_buffer* pkt)
return len; return len;
} }
int
dname_pkt_compare(ldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
{
uint8_t len1, len2;
log_assert(pkt && d1 && d2);
len1 = *d1++;
len2 = *d2++;
while( len1 != 0 || len2 != 0 ) {
/* resolve ptrs */
if( (len1 & 0xc0) == 0xc0) {
d1 = ldns_buffer_at(pkt, (len1&0x3f)<<8 | *d1);
len1 = *d1++;
continue;
}
if( (len2 & 0xc0) == 0xc0) {
d2 = ldns_buffer_at(pkt, (len2&0x3f)<<8 | *d2);
len2 = *d2++;
continue;
}
/* check label length */
log_assert(len1 <= LDNS_MAX_LABELLEN);
log_assert(len2 <= LDNS_MAX_LABELLEN);
if(len1 != len2) {
if(len1 < len2) return -1;
return 1;
}
log_assert(len1 == len2 && len1 != 0);
/* compare labels */
while(len1--) {
if(tolower((int)*d1++) != tolower((int)*d2++)) {
if(tolower((int)d1[-1]) < tolower((int)d2[-1]))
return -1;
return 1;
}
}
len1 = *d1++;
len2 = *d2++;
}
return 0;
}

View file

@ -78,4 +78,15 @@ int query_dname_compare(uint8_t* d1, uint8_t* d2);
*/ */
size_t pkt_dname_len(ldns_buffer* pkt); size_t pkt_dname_len(ldns_buffer* pkt);
/**
* Compare dnames in packet (compressed). Dnames must be valid.
* routine performs lowercasing, so the packet casing is preserved.
* @param pkt: packet, used to resolve compression pointers.
* @param d1: dname to compare
* @param d2: dname to compare
* @return: -1, 0, or +1 depending on comparison results.
* Sort order is first difference found. not the canonical ordering.
*/
int dname_pkt_compare(ldns_buffer* pkt, uint8_t* d1, uint8_t* d2);
#endif /* UTIL_DATA_DNAME_H */ #endif /* UTIL_DATA_DNAME_H */

View file

@ -143,14 +143,51 @@ struct rr_parse {
struct rr_parse* next; struct rr_parse* next;
}; };
/** smart comparison of (compressed, valid) dnames from packet. */
static int
smart_compare(ldns_buffer* pkt, uint8_t* dnow,
uint8_t *dprfirst, uint8_t* dprlast)
{
uint8_t* p;
if( (*dnow & 0xc0) == 0xc0) {
/* prev dname is also a ptr, both ptrs are the same. */
if( (*dprfirst & 0xc0) == 0xc0 &&
dprfirst[0] == dnow[0] && dprfirst[1] == dnow[1])
return 0;
if( (*dprlast & 0xc0) == 0xc0 &&
dprlast[0] == dnow[0] && dprlast[1] == dnow[1])
return 0;
/* ptr points to a previous dname */
p = ldns_buffer_at(pkt, (dnow[0]&0x3f)<<8 | dnow[1]);
if( p == dprfirst || p == dprlast )
return 0;
/* checks for prev dnames pointing forwards in the packet
} else {
if( (*dprfirst & 0xc0) == 0xc0 ) {
if(ldns_buffer_at(pkt, (dprfirst[0]&0x3f)<<8 |
dprfirst[1]) == dnow)
return 0;
}
if( (*dprlast & 0xc0) == 0xc0 ) {
if(ldns_buffer_at(pkt, (dprlast[0]&0x3f)<<8 |
dprlast[1]) == dnow)
return 0;
}
*/
}
return dname_pkt_compare(pkt, dnow, dprlast);
}
/** Find rrset. If equal to previous it is fast. hash if not so. /** Find rrset. If equal to previous it is fast. hash if not so.
* @param msg: the message with hash table. * @param msg: the message with hash table.
* @param pkt: the packet in wireformat (needed for compression ptrs).
* @param dname: pointer to start of dname (compressed) in packet. * @param dname: pointer to start of dname (compressed) in packet.
* @param dnamelen: uncompressed wirefmt length of dname. * @param dnamelen: uncompressed wirefmt length of dname.
* @param type: type of current rr. * @param type: type of current rr.
* @param dclass: class of current rr. * @param dclass: class of current rr.
* @param hash: hash value is returned if the rrset could not be found. * @param hash: hash value is returned if the rrset could not be found.
* @param prev_dname: dname of last seen RR. * @param prev_dname_first: dname of last seen RR. First seen dname.
* @param prev_dname_last: dname of last seen RR. Last seen dname.
* @param prev_dnamelen: dname len of last seen RR. * @param prev_dnamelen: dname len of last seen RR.
* @param prev_type: type of last seen RR. * @param prev_type: type of last seen RR.
* @param prev_dclass: class of last seen RR. * @param prev_dclass: class of last seen RR.
@ -158,13 +195,22 @@ struct rr_parse {
* @return the rrset if found, or null if no matching rrset exists. * @return the rrset if found, or null if no matching rrset exists.
*/ */
static struct rrset_parse* static struct rrset_parse*
find_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen, find_rrset(struct msg_parse* msg, ldns_buffer* pkt, uint8_t* dname,
uint16_t type, uint16_t dclass, hashvalue_t* hash, size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_t* hash,
uint8_t** prev_dname, size_t* prev_dnamelen, uint16_t* prev_type, uint8_t** prev_dname_first, uint8_t** prev_dname_last,
size_t* prev_dnamelen, uint16_t* prev_type,
uint16_t* prev_dclass, struct rrset_parse** rrset_prev) uint16_t* prev_dclass, struct rrset_parse** rrset_prev)
{ {
if(rrset_prev) { if(rrset_prev) {
/* check if equal to previous item */ /* check if equal to previous item */
if(type == *prev_type && dclass == *prev_dclass &&
dnamelen == *prev_dnamelen &&
smart_compare(pkt, dname, *prev_dname_first,
*prev_dname_last) == 0) {
/* same as previous */
*prev_dname_last = dname;
return *rrset_prev;
}
} }
/* find by hashing and lookup in hashtable */ /* find by hashing and lookup in hashtable */
@ -214,7 +260,7 @@ parse_section(ldns_buffer* pkt, struct msg_parse* msg, region_type* region,
ldns_pkt_section section, uint16_t num_rrs, size_t* num_rrsets) ldns_pkt_section section, uint16_t num_rrs, size_t* num_rrsets)
{ {
uint16_t i; uint16_t i;
uint8_t* dname, *prev_dname = NULL; uint8_t* dname, *prev_dname_f = NULL, *prev_dname_l = NULL;
size_t dnamelen, prev_dnamelen = 0; size_t dnamelen, prev_dnamelen = 0;
uint16_t type, prev_type = 0; uint16_t type, prev_type = 0;
uint16_t dclass, prev_dclass = 0; uint16_t dclass, prev_dclass = 0;
@ -236,9 +282,9 @@ parse_section(ldns_buffer* pkt, struct msg_parse* msg, region_type* region,
ldns_buffer_read(pkt, &dclass, sizeof(dclass)); ldns_buffer_read(pkt, &dclass, sizeof(dclass));
/* see if it is part of an existing RR set */ /* see if it is part of an existing RR set */
if((rrset = find_rrset(msg, dname, dnamelen, type, dclass, if((rrset = find_rrset(msg, pkt, dname, dnamelen, type, dclass,
&hash, &prev_dname, &prev_dnamelen, &prev_type, &hash, &prev_dname_f, &prev_dname_l, &prev_dnamelen,
&prev_dclass, &rrset_prev)) != 0) { &prev_type, &prev_dclass, &rrset_prev)) != 0) {
/* check if it fits the existing rrset */ /* check if it fits the existing rrset */
/* add to rrset. */ /* add to rrset. */
} else { } else {