📄 dns_util.c.svn-base
字号:
if ((err = dns_decode_rcode(hdr)) != DNS_ERROR_OK)
return err;
/*
* Check the Question section.
*
* Make sure the name server claims to be answering the question we asked.
*/
if ((n = hdr->qdcount) > (int) n_rrs)
n = n_rrs;
for (i = 0; i < n; ++i)
{
if (rrs[0].class != rrs[i].class || rrs[0].type != rrs[i].type ||
dns_namcmp(rrs[0].name, 0, 0, rrs[i].name, msg, msg_len) != 0)
return DNS_ERROR_BAD_PROTOCOL;
}
/*
* Check the Answer section.
*
* Unless CNAME RRs are a legitimate answer to the query, check any
* leading CNAME RRs to be sure they form a valid chain from the
* QNAME to the name of the first non-CNAME RR. Check the names of
* any remaining RRs in the answer section to be sure that they
* match the canonnicalized QNAME. Also check the types and classes
* of all the RRs in the Answer section. If we find a valid chain
* of CNAMEs but no other Answer RRs, it's the same as if we'd gotten
* a completely empty answer section.
*/
cqname = rrs[0].name;
if ((n = hdr->qdcount + hdr->ancount) > (int) n_rrs)
n = n_rrs;
matched = FALSE;
for (i = hdr->qdcount; i < n; ++i)
{
if (!dns_c_match(rrs[0].class, rrs[i].class) ||
dns_namcmp(cqname, (cqname == rrs[0].name ? 0 : msg),
msg_len, rrs[i].name, msg, msg_len) != 0)
{
return DNS_ERROR_BAD_PROTOCOL;
}
else if (dns_t_match(rrs[0].type, rrs[i].type))
{
matched = TRUE;
}
else if (matched || rrs[i].type != DNS_T_CNAME)
{
return DNS_ERROR_BAD_PROTOCOL;
}
else
{
cqname = rrs[i].rdata;
}
}
if (!matched)
return DNS_ERROR_NO_RRS;
/*
* No sanity checks for Authority or Additional sections at present.
*/
/*
* If we made it here, the message is ok, so give it our blessing.
*/
return DNS_ERROR_OK;
}
/*
* Returns error code or number of RRs decoded.
*/
int dns_decode_rrs
(unsigned char *msg, /* Network message ("packet") */
unsigned msg_len, /* Length of message */
struct dns_header *hdr, /* DNS header */
struct dns_rr rr[], /* Where to put parsed RRs */
unsigned nrrs, /* How many there are */
UI32_T now) /* Current time */
{
UI32_T n = hdr->qdcount + hdr->ancount + hdr->nscount + hdr->arcount;
UI32_T i = 0;
unsigned char *p = msg + DNS_HDR_LENGTH;
int name_length;
UI16_T rdcount;
while (i < n && i < nrrs)
{
struct dns_rr *r = rr + (int) (i);
if ((name_length = dns_decode_name(0, 0, p, msg, msg_len)) < 0)
return name_length;
if (r != 0)
r->name = p;
p += name_length;
if (r != 0)
r->type = (UI16_T )dns_decode_bits16(p);
p += 2;
if (r != 0)
r->class = (UI16_T )dns_decode_bits16(p);
p += 2;
if (i < hdr->qdcount)
{
if (r != 0)
{
r->ttl = 0;
r->rdcount = 0;
r->rdata = 0;
}
}
else
{
if (r != 0)
r->ttl = dns_decode_bits32(p);
p += 4;
rdcount = (UI16_T )dns_decode_bits16(p);
if (r != 0)
r->rdcount = rdcount;
p += 2;
if (r != 0)
r->rdata = p;
p += rdcount;
}
if (r != 0)
{
r->next = 0;
r->birthdate = now;
r->negative = FALSE;
r->answer = i < (unsigned)hdr->qdcount + hdr->ancount;
r->authoritative = r->answer && hdr->aa && hdr->qdcount != 0
&& dns_namcmp(msg + DNS_HDR_LENGTH, msg, msg_len, r->name, msg, msg_len) == 0;
r->errcode = DNS_ERROR_OK;
}
if (p > msg + msg_len)
return (int) i;
++i;
} /* while */
return (i);
}
enum dns_error dns_decode_rcode
(struct dns_header *hdr)
{
switch (hdr->rcode)
{
case DNS_RCODE_OK:
return DNS_ERROR_OK;
case DNS_RCODE_FORMAT:
return DNS_ERROR_FORMAT;
case DNS_RCODE_SERVER:
return DNS_ERROR_SERVER_FAILURE;
case DNS_RCODE_NAME:
return DNS_ERROR_NONEXISTANT_NAME;
case DNS_RCODE_NIY:
return DNS_ERROR_NIY;
case DNS_RCODE_REFUSED:
return DNS_ERROR_REFUSED;
default:
return DNS_ERROR_BAD_PROTOCOL;
}
}
/*
* Compare two DNS names (internal format).
*
* Returns an integer value. NB: The value returned is -not- like the
* value returned by the normal C library strcmp() function, because
* dns_namcmp() has to be able to return error codes as well. Sorry.
*
* Return value will either be an error code (DNS_ERROR_xxx value) or one
* of the following:
* DNS_NAMCMP_LESS: first argument is "less" than second argument
* DNS_NAMCMP_EQUAL: first argument is "equal" to second argument
* DNS_NAMCMP_GREATER: first argument is "greater" than second argument.
* These correspond to the three return cases of the C strcmp() routine.
*
* For the peace of mind of application authors who only want to
* compare two names for equality, the numeric value of
* DNS_NAMCMP_EQUAL is hereby and henceforth defined to be zero.
*
* The msg and msg_len parameters for either name are ignored if that
* name doesn't contain any compression pointers.
*/
int dns_namcmp
(unsigned char *name1,
unsigned char *msg1,
unsigned msg1_len,
unsigned char *name2,
unsigned char *msg2,
unsigned msg2_len)
{
if (name1 == 0 || name2 == 0)
return (int) DNS_ERROR_BAD_ARGS;
for (;;)
{
unsigned i = *name1, j = *name2;
/*
* Step one: find the length of the next label in each name.
* This may involve following multiple compression pointers.
*/
while ((i & DNS_COMPRESSION_MASK) != 0)
{
if ((i & DNS_COMPRESSION_MASK) != DNS_COMPRESSION_MASK)
return (int) DNS_ERROR_BAD_NAME;
if (msg1 == 0)
return (int) DNS_ERROR_BAD_ARGS;
name1 = msg1 + ((name1[0] & ~DNS_COMPRESSION_MASK) << 8) + name1[1];
if (name1 >= msg1 + msg1_len)
return (int) DNS_ERROR_BAD_NAME;
i = *name1;
}
while ((j & DNS_COMPRESSION_MASK) != 0)
{
if ((j & DNS_COMPRESSION_MASK) != DNS_COMPRESSION_MASK)
return (int) DNS_ERROR_BAD_NAME;
if (msg2 == 0)
return (int) DNS_ERROR_BAD_ARGS;
name2 = msg2 + ((name2[0] & ~DNS_COMPRESSION_MASK) << 8) + name2[1];
if (name2 >= msg2 + msg2_len)
return (int) DNS_ERROR_BAD_NAME;
j = *name2;
}
/*
* Step two: compare the lengths, returning the comparision if not equal.
* This is also where we catch identical names.
*/
if (i != j)
return (i < j ? DNS_NAMCMP_LESS : DNS_NAMCMP_GREATER);
if (i == 0)
return DNS_NAMCMP_EQUAL;
/*
* Step three: compare the labels, converting case as necessary.
*/
for (j = 1; j <= i; ++j)
{
unsigned c1 = name1[j], c2 = name2[j];
if (GLUE_ISUPPER(c1))
c1 = GLUE_LOWER(c1);
if (GLUE_ISUPPER(c2))
c2 = GLUE_LOWER(c2);
if (c1 != c2)
return (c1 < c2 ? DNS_NAMCMP_LESS : DNS_NAMCMP_GREATER);
}
/*
* Step four: advance pointers, loop for next labels.
*/
name1 += i + 1;
name2 += i + 1;
} /* for loop */
/*
* Never get here.
*/
}
/*
* Type and class matching.
*/
int dns_t_match
(unsigned wild,
unsigned tame)
{
return (wild == tame || wild == DNS_T_ANY ||
(wild == DNS_T_MAILA && tame == DNS_T_MX) ||
(wild == DNS_T_MAILB &&
(tame == DNS_T_MB || tame == DNS_T_MR ||
tame == DNS_T_MG || tame == DNS_T_MINFO)));
}
int dns_c_match
(unsigned wild,
unsigned tame)
{
return (wild == tame || wild == DNS_C_ANY);
}
/*
* TTL comparision.
*
* We check for TTL == 0 explicitly because dns_gc_mark() uses this to
* indicate a dead RR. This allows calls to dns_gc_sweep() to be put
* off as long as necessary without any cost to the application other
* than increased memory usage.
*/
int dns_ttl_valid
(struct dns_rr *r,
UI32_T now)
{
#if 0
return (!r->expired && r->birthdate + r->ttl * 1000 - now < 0x80000000L);
#else
return (!r->expired && r->birthdate + r->ttl * 1000 - now < MAX_DNS_CACHE_TTL*1000);
#endif
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -