📄 dns.c
字号:
*
* This function takes a domain name and converts it to a format a DNS
* server expects.
*
* INPUTS
*
* dst The converted name.
* src The original name.
*
* OUTPUTS
*
* INT:
* > 0 The size of the new name.
* NU_INVALID_PARM
* < 0 Failure
*
******************************************************************************/
INT DNS_Pack_Domain_Name (CHAR *dst, CHAR *src)
{
CHAR *p;
CHAR *original_dest;
INT n;
/* If this is a null string return an error. */
if (!*src)
return (NU_INVALID_PARM);
p = original_dest = dst;
do
{
/* Move past the byte where the length will be saved. */
dst++;
/* Assume all labels have been copied until proven otherwise. */
*p = 0;
/* Copy the label. */
for ( n = 0;
*src && (*src != '.') && (n <= DNS_MAX_LABEL_SIZE);
*dst++ = *src++, ++n );
/* Check to see if the label exceded the maximum length. */
if ( n > DNS_MAX_LABEL_SIZE)
return (NU_INVALID_LABEL);
/* Store the length of the label. */
*p = (UINT8)(dst - p - 1);
/* Point to where the next length value will be stored. */
p = dst;
if (*src)
src++;
} while (*src);
/* The end of the name is marked with a 0 length label. */
*p = 0;
dst++;
return (INT)(dst - original_dest);
} /* DNS_Pack_Domain_Name */
/****************************************************************************
* FUNCTION
*
* DNS_Unpack_Domain_Name
*
* DESCRIPTION
*
* This function packed name and converts it to a character string.
*
* INPUTS
*
* dst The new name.
* src The original name.
* buf_begin Pointer to start od response packet.
*
* OUTPUTS
*
* INT The size of the new name.
*
******************************************************************************/
INT DNS_Unpack_Domain_Name(CHAR *dst, CHAR *src, CHAR *buf_begin)
{
INT16 size;
INT i, retval = 0;
CHAR *savesrc;
savesrc = src;
/* The end of the name is marked by a 0 length label. */
while (*src)
{
/* Get the size of the label. */
size = *src;
/* Check to see if this is a pointer instead of a label size. */
while ((size & 0xC0) == 0xC0)
{
/* If we have not encountered a pointer yet compute the size of the
name so far. */
if (!retval)
{
retval = (INT)(src - savesrc + 2);
}
src++;
/* Point to the new location. */
src = &buf_begin[(size & 0x3f) * 256 + *src];
size = *src;
}
/* Move the pointer past the label size. */
src++;
/* Copy the label. */
for (i = 0; i < (size & 0x3f); i++)
{
*dst++ = *src++;
}
/* Insert the period between labels. */
*dst++ = '.';
}
/* Add the terminator. */
*(--dst) = 0;
/* Account for the terminator on src. */
src++;
/* If the name included a pointer then the return value has already been
computed. */
if (!retval)
{
retval = (INT)(src - savesrc);
}
return (retval);
} /* DNS_Unpack_Domain_Name */
/****************************************************************************
* FUNCTION
*
* DNS_Extract_Data
*
* DESCRIPTION
*
* This function takes a DNS response and extracts either an IP address or
* a domain name, which ever the case may be.
*
* INPUTS
*
* pkt A pointer to the DNS response.
* data Put the address or name here.
* ttl Put the Time To Live here.
* type The type of query.
*
* OUTPUTS
*
* NU_SUCCESS Indicates success.
* NU_DNS_ERROR
* NU_MEM_ALLOC
* < 0 Indicates failure.
*
******************************************************************************/
STATUS DNS_Extract_Data (DNS_PKT_HEADER *pkt, CHAR *data, UNSIGNED *ttl,
INT type)
{
DNS_RR *rr_ptr;
INT name_size, n_answers, rcode;
UINT16 length;
CHAR *p_ptr, *name;
CHAR answer_received = 0;
/* Get the number of answers in this message. */
n_answers = GET16(pkt, DNS_ANCOUNT_OFFSET);
/* Extract the return code. */
rcode = DNS_RCODE_MASK & GET16(pkt, DNS_FLAGS_OFFSET);
/* Was an error returned? */
if (rcode)
return (NU_DNS_ERROR);
/* If there is at least one answer and this is a response, process it. */
if ((n_answers > 0) && (GET16(pkt, DNS_FLAGS_OFFSET) & DNS_QR))
{
/* Point to where the question starts. */
p_ptr = (CHAR *)(pkt + 1);
/* Allocate a block of memory to put the name in. */
if (NU_Allocate_Memory (&System_Memory, (VOID **)&name,
DNS_MAX_NAME_SIZE,
NU_NO_SUSPEND) != NU_SUCCESS)
{
return (NU_NO_MEMORY);
}
/* Extract the name. */
name_size = DNS_Unpack_Domain_Name (name, p_ptr, (CHAR *)pkt);
/* Move the pointer past the name QTYPE and QCLASS to point at the
answer section of the response. */
p_ptr += name_size + 4;
/*
* At this point, there may be several answers. We will take the first
* one which has an IP number. There may be other types of answers that
* we want to support later.
*/
while ((n_answers--) > 0)
{
/* Extract the name from the answer. */
name_size = DNS_Unpack_Domain_Name (name, p_ptr, (CHAR *)pkt);
/* Move the pointer past the name. */
p_ptr += name_size;
/* Point to the resource record. */
rr_ptr = (DNS_RR *)p_ptr;
/* Verify the type and class. */
if ((GET16(p_ptr, DNS_TYPE_OFFSET) == type) &&
(GET16(p_ptr, DNS_CLASS_OFFSET) == DNS_CLASS_IN))
{
switch (type)
{
case DNS_TYPE_A :
/* The answer has the correct type and class. Copy
the IP addr. */
GET_STRING (rr_ptr, DNS_RDATA_OFFSET, data, 4);
break;
case DNS_TYPE_PTR :
/* The answer has the correct type and class. Get the name. */
DNS_Unpack_Domain_Name (data, rr_ptr->dns_rdata,
(CHAR *)pkt);
break;
default :
return -1;
}
/* Get the time to live for this RR. */
*ttl = GET32(rr_ptr, DNS_TTL_OFFSET);
/* Indicate an answer was found. */
answer_received = 1;
break;
}
/* Copy the length of this answer. */
length = GET16(rr_ptr, DNS_RDLENGTH_OFFSET);
/* Point to the next answer, if any. The rdlength field is the
length of the data section of the RR. Add 10 for the sizes of
the type, class, ttl, and rdlength.
*/
p_ptr += (10 + length);
}
NU_Deallocate_Memory(name);
}
if (answer_received)
return (NU_SUCCESS);
else
return (-1);
} /* DNS_Extract_Data */
/****************************************************************************
* FUNCTION
*
* DNS_Add_Host
*
* DESCRIPTION
*
* This function adds a new host to the "hosts file".
* A block of memory is alocated each time we want to add a new host.
* This can be wasteful of memory because Nucleus PLUS has a minimum
* allocation size of 50 bytes. The alternative would have been to
* allocate enough memory for several of these at one time. The problem
* with that is the RFC defines the maximum size of a name at 255 bytes.
* We would have to assume that a maximum sized name would have to be
* stored and allocate memory accordingly. Since most names are nowhere
* close to 255 bytes this method would have been even more wasteful.
*
* INPUTS
*
* name The name of the host to add.
* ip_addr The IP address of the host to add.
* ttl The Time To Live for this entry.
*
* OUTPUTS
*
* DNS_HOST* A host pointer, or NULL if the host can
* not be added.
*
******************************************************************************/
DNS_HOST *DNS_Add_Host(CHAR *name, CHAR *ip_addr, UNSIGNED ttl)
{
INT size;
DNS_HOST *dns_host;
UNSIGNED time;
/* Get the size of the name. */
size = strlen(name) + 1;
/* Retrieve the current time. */
time = NU_Retrieve_Clock();
/* Before allocating memory for a new entry, check to see if the TTL of an
old entry has expired. If so re-use that entry. */
for ( dns_host = DNS_Hosts.dns_head;
dns_host;
dns_host = dns_host->dns_next )
{
/* First check to see if this entry has a ttl. A ttl of 0 is used to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -