📄 dnsclnt.c
字号:
/*
* FILENAME: dnsclnt.c
*
* Copyright 1997- 2000 By InterNiche Technologies Inc. All rights reserved
*
* DNS Client code for NetPort IP stack
*
* MODULE: INET
*
* ROUTINES: dns_query(), dnc_sendreq(), dnc_copyout(),
* ROUTINES: dnc_copyin(), dnc_del(), dnc_makeroom(), dns_check(),
* ROUTINES: badreply(), dns_upcall(), dnc_lookup(), dns_lookup(),
* ROUTINES: t_gethostbyname(), *gethostbyname(), dns_state(),
*
* PORTABLE: yes
*/
#include "ipport.h"
#ifdef DNS_CLIENT /* ifdef out whole file */
#include "q.h"
#include "netbuf.h"
#include "net.h"
#include "ip.h"
#include "udp.h"
#include "dns.h"
/* static table for actual queries. Non-zero ipaddr means entry is active. */
struct dns_querys dns_qs[MAXDNSENTRY];
unshort dnsids = 0x1234; /* seed for unique request IDs */
/* DNS client statistics: */
ulong dnsc_errors = 0; /* protocol/implementation runtime errors */
ulong dnsc_requests = 0; /* requests sent */
ulong dnsc_replies = 0; /* replys received */
ulong dnsc_good = 0; /* usable replys received */
ulong dnsc_tmos = 0; /* timeouts */
ulong dnsc_retry = 0; /* total retries */
#ifdef DNS_CLIENT_UPDT
ulong dnsc_updates = 0; /* Dynamic DNS Updates sent */
#endif /* DNS_CLIENT_UPDT */
/* pending requests, can be used as a flag to spin dnsc_check() task */
unsigned dnsc_active = 0;
/* retry info, can be overwritten by application code */
unsigned dns_firsttry = 4; /* time to first retry, in seconds */
unsigned dns_trys = 5; /* max number of retrys */
ip_addr dns_servers[MAXDNSSERVERS]; /* need to be set from NV parameters */
#ifdef DNS_CLIENT_UPDT
char soa_mname[MAXDNSNAME];
/* internal routines */
static struct hostent* getsoa(char *);
#endif /* DNS_CLIENT_UPDT */
/* internal routines */
static int dnc_sendreq(int entry);
static int dnc_copyout(char * dest, char * src);
static int dnc_copyin(char * dest, char * src, struct dns_hdr * dns);
static void dnc_del(int entry);
static void dnc_makeroom(void);
static int badreply(struct dns_hdr * dns, char * text);
/* FUNCTION: dns_query()
*
* dns_query() - starts the process of sending out a DNS request for
* a domain name. This is hardwired for the basic question "what is
* the IP address of named host?". It creates the control structures
* and calls dnc_sendreq() to send the actual packet. Called should
* poll dns_lookup for results.
*
* PARAM1: char * name
* PARAM2: ip_addr * ip
*
* RETURNS: Returns 0 if IP address was filled in
* from cache, ENP_SEND_PENDING if query was launched OK, or one of
* the ENP error codes.
*/
int
dns_query(char * name, ip_addr * ip)
{
int entry; /* dns entry index */
int e;
/* see if we already have an entry for this name in the cache */
e = dns_lookup(ip, name);
if (e >= 0)
return e;
/* else find a free entry so we can start a query */
dnc_makeroom();
for (entry = 0; entry < MAXDNSENTRY; entry++)
{
if (dns_qs[entry].id == 0) /* found empty entry? */
break;
}
/* sanity check to make sure we really have a free entry */
if (entry >= MAXDNSENTRY)
{
dtrap("dnsclnt 0\n"); /* may need to increase DNS_MAXENTRY */
return ENP_RESOURCE;
}
/* prepare entry for use and copy in name */
MEMSET(&dns_qs[entry], 0, sizeof(dns_qs[entry])); /* clear entry */
strncpy(dns_qs[entry].dns_name, name, MAXDNSNAME-1); /* copy in name */
dns_qs[entry].tries = 0; /* no retries yet */
dns_qs[entry].id = dnsids++; /* set ID for this transaction */
dns_qs[entry].ipaddr_list[0] = 0L; /* non-zero when it succeeds */
if (dnsids == 0) /* don't allow ID of 0 */
dnsids++;
/* get UDP port for packet, keep for ID */
dns_qs[entry].lport = udp_socket();
dnsc_active++; /* maintain global dns pending count */
dnsc_requests++; /* count this request */
#ifdef DNS_CLIENT_UPDT
dns_qs[entry].type = 1; /* Set type to A */
#endif /* DNS_CLIENT_UPDT */
e = dnc_sendreq(entry);
if (e == 0) /* first packet sent OK */
return ENP_SEND_PENDING;
else /* some kind of error */
return e;
}
/* FUNCTION: dnc_sendreq()
*
* dnc_sendreq() - Sends out a DNS request packet based on the query
* info in dns_qs[entry]. This is intended to be called from
* dns_query() or dns_check().
*
*
* PARAM1: int entry
*
* RETURNS: Returns 0 if OK, or one of the ENP error codes.
*/
static int
dnc_sendreq(int entry)
{
PACKET pkt;
struct dns_hdr * dns; /* outgoing dns header */
char * cp; /* scratch pointer for building question field */
int server; /* index of server to use */
/* figure out which server to try */
for (server = 0; server < MAXDNSSERVERS; server++)
{
if (dns_servers[server] == 0L)
break;
}
if (server == 0) /* no servers set? */
{
dtrap("dnsclnt 1\n");
return ENP_LOGIC;
}
server = dns_qs[entry].tries % server;
/* allocate packet for DNS request */
if ((pkt = udp_alloc(MAXDNSUDP, 0)) == NULL)
return ENP_RESOURCE;
/* fill in DNS header. Most fields are cleared to 0s */
dns = (struct dns_hdr *)pkt->nb_prot;
MEMSET(dns, 0, sizeof(struct dns_hdr));
dns->id = dns_qs[entry].id;
#ifdef DNS_CLIENT_UPDT
/* If this is an UPDATE packet, format the DNS packet differently */
if (dns_qs[entry].type == DNS_UPDT)
{
dns->qdcount = htons(1); /* Set zone count to 1 */
dns->nscount = htons(1); /* Set update count to 1 */
dns->flags = htons(0x2800); /* Set opcode field to 5 */
/* format zone name into UPDATE packet */
cp = (char*)(dns+1); /* point at next byte past header */
cp += dnc_copyout(cp, dns_qs[entry].h_z_name);
/* finish off zone section. We write these two 16 bit words a
* byte at a time since cp may be on an odd address and some
* machines
*/
*cp++ = 0; /* high byte of type */
*cp++ = 6; /* type 6 = soa */
*cp++ = 0; /* high byte of class */
*cp++ = 1; /* class 1 == internet */
cp += dnc_copyout(cp, dns_qs[entry].dns_name);
/* Put in NAME and TYPE */
*cp++ = 0; /* high byte of type */
/* If ttl value is 0, this is a delete operation. Set type to ANY */
if (dns_qs[entry].h_ttl == 0)
*cp++ = (unsigned char)255;
else
*cp++ = 1; /* type 1 == host address, type 6 = soa */
*cp++ = 0; /* high byte of class */
*cp++ = 1; /* class 1 == internet */
/* Put in TTL value */
*cp++ = (unsigned char)(dns_qs[entry].h_ttl >> 24);
*cp++ = (unsigned char)(dns_qs[entry].h_ttl >> 16);
*cp++ = (unsigned char)(dns_qs[entry].h_ttl >> 8);
*cp++ = (unsigned char)dns_qs[entry].h_ttl;
/* Put in RDLENGTH which is length of ip address ie 4 */
*cp++ = 0; /* low byte of length */
/* If ttl value is 0, this is a delete operation. Set RDLENGTH to 0 */
if (dns_qs[entry].h_ttl == 0)
*cp++ = 0;
else
*cp++ = 4;
/* Put in IP address */
MEMCPY(cp,&dns_qs[entry].h_add_ipaddr,4);
cp += 4;
dnsc_updates++;
}
else
{
#endif /* DNS_CLIENT_UPDT */
dns->qdcount = htons(1); /* 1 question */
dns->flags = htons(DNSF_RD); /* Recursion Desired */
/* format name into question field after header */
cp = (char*)(dns + 1); /* point at next byte past header */
cp += dnc_copyout(cp, dns_qs[entry].dns_name);
/* finish off question field. We write these two 16 bit words a
* byte at a time since cp may be on an odd address and some
* machines
*/
*cp++ = 0; /* high byte of type */
#ifdef DNS_CLIENT_UPDT
*cp++ = dns_qs[entry].type; /* type 1 == host address, type 6 = soa */
#else
*cp++ = 1;
#endif /* DNS_CLIENT_UPDT */
*cp++ = 0; /* high byte of class */
*cp++ = 1; /* class 1 == internet */
#ifdef DNS_CLIENT_UPDT
}
#endif /* DNS_CLIENT_UPDT */
pkt->fhost = dns_servers[server];
pkt->nb_plen = cp - (char*)dns; /* length of packet */
dns_qs[entry].send_time = cticks; /* note time we send packet */
return(udp_send(DNS_PORT, dns_qs[entry].lport, pkt));
}
/* FUNCTION: dnc_copyout()
*
* dnc_copyout() - copy a domain name from user "dot" text format to
* DNS header format. dest buffer is assumed to be large enough,
* which means at least as big as src string.
*
* PARAM1: char * dest
* PARAM2: char * src
*
* RETURNS: Returns length of string copied.
*/
static int
dnc_copyout(char * dest, char * src)
{
int namelen; /* length of name segment */
char * cp; /* pointer to dest string we're building */
char * fld, * next; /* pointers into src */
cp = dest;
next = src; /* will be assigned to "this" on first pass */
while (next) /* 1 loop per field in dot-delimited string */
{
fld = next;
next = strchr(fld, '.'); /* find next dot in string */
if (next) /* if not last field... */
{
namelen = next - fld; /* length of this field */
next++; /* bump next pointer past dot */
}
else /* no dot means end of string */
namelen = strlen(fld);
*cp++ = (char)(namelen & 0xFF); /* put length in dest buffer */
MEMCPY(cp, fld, namelen); /* follow with string data */
cp += namelen; /* point past name to next length byte */
}
*cp++ = 0; /* null terminate string */
return(cp - dest);
}
/* FUNCTION: dnc_copyin()
*
* dnc_copyin() - the inverse of copyout above - it copies a dns
* format domain name to "dot" formatting.
*
*
* PARAM1: char * dest
* PARAM2: char * src
* PARAM3: struct dns_hdr * dns
*
* RETURNS: Returns length of string copied, 0 if error.
*/
int
dnc_copyin(char * dest, char * src, struct dns_hdr * dns)
{
unshort namelen; /* length of name segment */
char * cp; /* pointer to dest string we're building */
char * fld, * next; /* pointers into src */
int donelen; /* number of bytes moved */
unshort offset;
cp = dest;
next = src; /* will be assigned to "this" on first pass */
donelen = 0;
while (next) /* 1 loop per field in dot-delimited string */
{
fld = next;
namelen = *fld++;
if (namelen == 0)
break; /* done */
if ((namelen & 0xC0) == 0xC0)
{
fld--;
offset = (unshort)*fld; /* get first byte of offset code */
fld++;
offset &= 0x3f; /* mask our high two bits */
offset <<= 8; /* make it high byte of word */
offset += (unshort)*fld; /* add low byte of word */
fld = offset + (char *)dns; /* ptr into domain name */
namelen = *fld++;
}
if (namelen + donelen > MAXDNSNAME) /* check for overflow */
return 0; /* error */
MEMCPY(cp, fld, namelen);
donelen += (namelen+1); /* allow for dot/len byte */
cp += namelen;
*cp++ = '.';
next = fld + namelen;
}
*(cp-1) = 0; /* null terminate string (over last dot) */
return donelen + 1; /* include null in count */
}
/* FUNCTION: dnc_del()
*
* Delete a DNS entry
*
* PARAM1: int entry
*
* RETURNS: void
*/
static void
dnc_del(int entry)
{
MEMSET(&dns_qs[entry], 0, sizeof(struct dns_querys));
dnsc_active--; /* one less active entry */
}
/* FUNCTION: dnc_makeroom()
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -