📄 dnsclnt.c
字号:
* dnc_makeroom() - tries to make an empty entry (ready for re-use)
* in the cache.
*
*
* PARAM1: void
*
* RETURNS: void
*/
static void
dnc_makeroom(void)
{
/* if the DNS table is full... */
if (dnsc_active >= MAXDNSENTRY)
{
ulong min_expire_time = ~((ulong) 0L); /* all 1s in a long */
int min_expire_entry = -1; /* entry with earliest expiration time */
int entry;
/* find the one with the earliest expiration time */
for (entry = 0; entry < MAXDNSENTRY; entry++)
{
/* don't use entries that haven't resolved yet */
if (dns_qs[entry].ipaddr_list[0])
{
/* if this one is the earliest one seen so far */
if (dns_qs[entry].expire_time < min_expire_time)
{
/* remember it */
min_expire_time = dns_qs[entry].expire_time;
min_expire_entry = entry;
}
}
}
/* if we've identified an earliest expirable resolved entry,
* delete it
*/
if (min_expire_entry >= 0)
dnc_del(min_expire_entry);
}
}
/* FUNCTION: dns_check()
*
* dns_second() - poll once a second to drive DNS timeouts and
* retrys. Can be skipped when dnsc_active == 0
*
* PARAM1:
*
* RETURNS: void
*/
void
dns_check(void)
{
int entry; /* dns entry index */
int trysec; /* seconds to wait for next try */
for (entry = 0; entry < MAXDNSENTRY; entry++)
{
if (dns_qs[entry].id == 0) /* skip non-active request entrys */
continue;
if (dns_qs[entry].ipaddr_list[0] != 0) /* resolved request, check timeout */
{
if (dns_qs[entry].expire_time <= (cticks/TPS))
dnc_del(entry);
continue;
}
/* active request, see if it's time to retry */
trysec = dns_firsttry << dns_qs[entry].tries;
if ((dns_qs[entry].send_time + (TPS*(unsigned long)trysec)) < cticks)
{
if (dns_qs[entry].tries >= dns_trys) /* retried out */
{
dnc_del(entry);
dnsc_tmos++; /* count timeouts */
continue;
}
dnsc_retry++; /* count total retries */
dns_qs[entry].tries++; /* count entry retries */
dnc_sendreq(entry);
}
}
}
/* FUNCTION: badreply()
*
* dns_badreply() - per-port handler for less than ideal DNS replys.
*
*
* PARAM1: struct dns_hdr * dns
* PARAM2: char * text
*
* RETURNS: Returns ENP code if problem should kill transaction, else 0
*/
static int
badreply(struct dns_hdr * dns, char * text)
{
dnsc_errors++;
#ifdef NPDEBUG
dprintf("DNS error: %s; flags %x\n", text, htons(dns->flags));
#endif /* NPDEBUG */
/* don't kill request, let it retry with another server */
USE_ARG(dns);
USE_ARG(text);
return 0;
}
/* FUNCTION: dns_upcall()
*
* dns_upcall() - called from the UDP layer whenever we receive a DNS
* packet (one addressed to port 53). p_nb_prot points to UYDP data,
* which should be DNS header. Return 0 if OK, or ENP code.
*
*
* PARAM1: PACKET pkt
* PARAM2: unshort lport
*
* RETURNS:
*/
int
dns_upcall(PACKET pkt, unshort lport)
{
int entry; /* dns entry index */
struct dns_hdr * dns; /* incoming dns header */
char * cp; /* scratch pointer for building question field */
unshort flags; /* dns->flags in local endian */
unshort rcode; /* response code */
unshort answers; /* number of answer records in reply */
#ifdef DNS_CLIENT_UPDT
unshort addtnl; /* number of additional resource records */
unshort opcode; /* opcode of the response- 5=UPDATE,0=QUERY */
#endif /* DNS_CLIENT_UPDT */
unshort type; /* various fields from the reply */
unshort cls;
u_long ttl;
unshort rdlength;
unshort offset; /* offset to domain name text */
unshort i;
int ip_count = 0; /* count of IP addresses in response */
dnsc_replies++;
dns = (struct dns_hdr *)pkt->nb_prot;
for (entry = 0; entry <= MAXDNSENTRY; entry++)
{
if ((dns_qs[entry].id == dns->id) &&
(dns_qs[entry].lport == lport))
{
break;
}
}
/* make sure we found our entry in the table */
if (entry >= MAXDNSENTRY)
return ENP_NOT_MINE; /* do not free pkt here */
dns_qs[entry].replies++; /* count total replies */
flags = htons(dns->flags); /* extract data fromheader */
rcode = flags & DNSF_RCMASK; /* Response code */
answers = htons(dns->ancount); /* number of answers */
#ifdef DNS_CLIENT_UPDT
opcode = (flags & DNSF_OPMASK) >> 11; /* Op code */
addtnl = htons(dns->arcount); /* number of additional records */
#endif /* DNS_CLIENT_UPDT */
/* check DNS flags for good response value */
if (!(flags & DNSF_QR))
return(badreply(dns, "not reply"));
#ifdef DNS_CLIENT_UPDT
/* If UPDATE opcode, set the response code in dns query structure */
/* and set the ip address field to non zero and return */
if (opcode == DNS_UPDT)
{
dns_qs[entry].rcode = rcode;
dns_qs[entry].ipaddr_list[0] = 0xff;
return 0;
}
#endif /* DNS_CLIENT_UPDT */
if (rcode != DNSRC_OK)
return(badreply(dns, "bad response code"));
if (answers < 1)
return(badreply(dns, "no answers"));
/* looks like we got an answer to the query */
dns_qs[entry].rcode = rcode;
cp = (char*)(dns+1); /* start after DNS entry */
cp += dnc_copyin(dns_qs[entry].dns_name, cp, dns); /* get back name */
cp += 4; /* bump past two 16bit fields, point to answers */
for (i = 0; i < answers; i++)
{
/* bump past name field in answer, keeping offset to text */
if ((*cp & 0xC0) == 0xC0) /* is it an offset? */
{
offset = (unshort)(*cp++); /* get first byte of offset code */
offset &= 0x3f; /* mask our high two bits */
offset <<= 8; /* make it high byte of word */
offset += (unshort)(*cp++); /* add low byte of word */
}
else /* text for name is right here */
{
offset = (unshort)(cp - (char*)dns); /* save offset */
while (*cp++ != 0); /* scan past name */
}
/* get DNS vars from packet bytes */
type = (unshort)(*cp++ << 8);
type += (unshort)(*cp++);
cls = (unshort)(*cp++ << 8);
cls += (unshort)(*cp++);
if (cls != 1)
{
dtrap("dnsclnt 2\n");
return badreply(dns, "class not internet");
}
ttl = (ulong)(*cp++) << 24; /* 4 byte time to live field */
ttl += (ulong)(*cp++) << 16;
ttl += (ulong)(*cp++) << 8;
ttl += (*cp++);
rdlength = (unshort)(*cp++ << 8);
rdlength += (unshort)(*cp++);
if (type == 1) /* this is it */
{
if (rdlength != 4)
return(badreply(dns, "IPADDR len not 4"));
dnsc_good++;
/* save alias name */
dnc_copyin(dns_qs[entry].dns_alias, offset + (char*)(dns), dns);
/* save reply IP addresses in array of IP addresses so long
as there is room for them */
if (ip_count < MAXDNSADDRS)
{
MEMCPY(&dns_qs[entry].ipaddr_list[ip_count], cp, 4);
ip_count++;
}
if (dns_qs[entry].expire_time == 0)
dns_qs[entry].expire_time = (cticks/TPS) + (ttl);
}
else if (type == 5) /* alias */
{
/* use alias timeout for entry */
dns_qs[entry].expire_time = (cticks/TPS) + (ttl);
}
#ifdef DNS_CLIENT_UPDT
else if (type == DNS_TYPE_AUTHNS) /* authoritative name server */
{
dnc_copyin(dns_qs[entry].dns_soa, cp, dns);
}
#endif /* DNS_CLIENT_UPDT */
cp += rdlength; /* bump past trailing data */
}
#ifdef DNS_CLIENT_UPDT
/* Parse additional data only if original request was for authoritative */
/* name server */
if (dns_qs[entry].type == DNS_TYPE_AUTHNS)
{
for (i = 0; i < addtnl; i++)
{
/* bump past name field in answer, keeping offset to text */
if ((*cp & 0xC0) == 0xC0) /* is it an offset? */
{
offset = (unshort)(*cp++); /* get first byte of offset code */
offset &= 0x3f; /* mask our high two bits */
offset <<= 8; /* make it high byte of word */
offset += (unshort)(*cp++);/* add low byte of word */
}
else /* text for name is right here */
{
offset = (unshort)(cp - (char*)dns); /* save offset */
while (*cp++ != 0); /* scan past name */
}
/* get DNS vars from packet bytes */
type = (unshort)(*cp++ << 8);
type += (unshort)(*cp++);
cls = (unshort)(*cp++ << 8);
cls += (unshort)(*cp++);
if (cls != 1)
{
dtrap("dnsclnt 3\n");
return badreply(dns, "class not internet");
}
ttl = (ulong)(*cp++) << 24; /* 4 byte time to live field */
ttl += (ulong)(*cp++) << 16;
ttl += (ulong)(*cp++) << 8;
ttl += (*cp++);
rdlength = (unshort)(*cp++ << 8);
rdlength += (unshort)(*cp++);
if (type == 1) /* Get the ip addresses of authoritative srvrs */
{
if (rdlength != 4)
return(badreply(dns, "IPADDR len not 4"));
dnsc_good++;
/* save alias name */
dnc_copyin(dns_qs[entry].dns_alias, offset + (char*)(dns), dns);
/* save reply IP addresses in array of IP addresses so long
as there is room for them */
if (ip_count < MAXDNSADDRS)
{
MEMCPY(&dns_qs[entry].ipaddr_list[ip_count], cp, 4);
ip_count++;
}
if (dns_qs[entry].expire_time == 0)
dns_qs[entry].expire_time = (cticks/TPS) + (ttl);
}
else /* not expecting additional counts in other answers */
{
dtrap("dnsclnt 4\n");
return badreply(dns, "additional records not expected");
}
cp += rdlength; /* bump past trailing data */
}
}
#endif /* DNS_CLIENT_UPDT */
return 0;
}
/* FUNCTION: dnc_lookup()
*
* dnc_lookup() - check cache for a pending or completed DNS client
* request. Passed entry index is filled in if DNS query was resolved
* without error, else this returns non-zero ENP_ error code.
*
*
* PARAM1: char * name
* PARAM2: int * cacheindex
*
* RETURNS: ENP_SEND_PENDING if request is still on the net, or ENP_TIMEOUT
* id request timed out (or was never made), or 0 (SUCCESS) if passed
* name found in cache, or ENP_PARAM if
*/
static int
dnc_lookup(char * name, int * cacheindex)
{
int entry;
/* look through the cache for the passed name */
for (entry = 0; entry < MAXDNSENTRY; entry++)
if (strcmp(dns_qs[entry].dns_name, name) == 0)
break;
/* if not found, return error */
if (entry >= MAXDNSENTRY)
return ENP_PARAM;
/* else, prepare to return entry index */
if (cacheindex != NULL)
*cacheindex = entry;
/* if completed request, return success */
#ifdef DNS_CLIENT_UPDT
if (dns_qs[entry].ipaddr_list[0] || dns_qs[entry].dns_soa[0])
return 0;
#else
if (dns_qs[entry].ipaddr_list[0])
return 0;
#endif /* DNS_CLIENT_UPDT */
/* incomplete request -- return pending or timed-out status */
if (dns_qs[entry].tries < dns_trys) /* still trying? */
return ENP_SEND_PENDING;
else
return ENP_TIMEOUT;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -