You've already forked Frequency_Inverter
mirror of
https://github.com/Indemsys/Frequency_Inverter.git
synced 2026-06-10 03:09:07 +00:00
2958 lines
97 KiB
C
2958 lines
97 KiB
C
/**HEADER*******************************************************************
|
|
*
|
|
* Copyright (c) 2008 Freescale Semiconductor;
|
|
* All Rights Reserved
|
|
*
|
|
* Copyright (c) 2004-2008 Embedded Access Inc.;
|
|
* All Rights Reserved
|
|
*
|
|
* Copyright (c) 1989-2008 ARC International;
|
|
* All Rights Reserved
|
|
*
|
|
***************************************************************************
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
* THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
**************************************************************************
|
|
*
|
|
* $FileName: resolver.c$
|
|
* $Version : 3.8.28.0$
|
|
* $Date : Jun-14-2012$
|
|
*
|
|
* Comments:
|
|
*
|
|
* This file contains the Domain Name System resolver
|
|
* functions for RTCS.
|
|
*
|
|
*END************************************************************************/
|
|
|
|
#include <rtcs.h>
|
|
#include "rtcs_prv.h"
|
|
|
|
#if RTCSCFG_ENABLE_DNS | RTCSCFG_ENABLE_LWDNS
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include "dns.h"
|
|
|
|
#endif
|
|
|
|
#if RTCSCFG_ENABLE_DNS
|
|
|
|
/*
|
|
|
|
GCC compiler did not have ctype in libc.
|
|
Used these definitions to resolve the problem:
|
|
|
|
#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-'A'+'a' : (c))
|
|
#define isalpha(c) (((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
|
|
#define isdigit(c) ( (c) >= '0' && (c) <= '9' )
|
|
#define isalnum(c) (isalpha(c) || isdigit(c))
|
|
|
|
*/
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_get_query_id()
|
|
* Returned Value : uint_16.
|
|
* Comments : The function returns a unique value that
|
|
* is used by the resolver for queries and keeps track
|
|
* of the last query id used.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_16 DNS_get_query_id
|
|
(
|
|
void
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
static uint_16 current_query_id = 0;
|
|
|
|
/* The masking is required for TI machines to operate correctly */
|
|
if ( current_query_id == 0 ) {
|
|
current_query_id = RTCS_rand() & DNS_UINT_16_MASK;
|
|
if ( current_query_id == 0 ) {
|
|
current_query_id++;
|
|
} /* Endif */
|
|
} else {
|
|
current_query_id++;
|
|
current_query_id &= DNS_UINT_16_MASK;
|
|
if ( current_query_id == 0 ) {
|
|
current_query_id++;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
return( current_query_id );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_update_TTL()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static void DNS_update_TTL
|
|
(
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
TIME_STRUCT time;
|
|
int_32 difference;
|
|
|
|
_time_get( &time );
|
|
|
|
difference = time.SECONDS - query_ptr->LAST_TTL_CHECK;
|
|
|
|
if ( query_ptr->TTL <= difference ) {
|
|
query_ptr->TTL = 0;
|
|
} else {
|
|
query_ptr->TTL -= difference;
|
|
} /* Endif */
|
|
|
|
query_ptr->LAST_TTL_CHECK = time.SECONDS;
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_free_internal_query()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void DNS_free_internal_query
|
|
(
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_CNAME_STRUCT _PTR_ free_cname_ptr;
|
|
DNS_CNAME_STRUCT _PTR_ next_cname_ptr;
|
|
|
|
if ( query->QNAME_PTR != NULL ) {
|
|
_mem_free( query->QNAME_PTR );
|
|
} /* Endif */
|
|
|
|
free_cname_ptr = query->CNAME;
|
|
while ( free_cname_ptr != NULL ) {
|
|
next_cname_ptr = free_cname_ptr->NEXT;
|
|
_mem_free( free_cname_ptr->CNAME_PTR );
|
|
RTCS_part_free( free_cname_ptr );
|
|
free_cname_ptr = next_cname_ptr;
|
|
} /* Endwhile */
|
|
|
|
RTCS_part_free( query );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_Send_UDP_Query()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_Send_UDP_Query
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr,
|
|
boolean cname_retry
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
DNS_MESSAGE_TAIL_STRUCT _PTR_ message_tail_ptr;
|
|
DNS_CNAME_STRUCT _PTR_ cname_ptr;
|
|
sockaddr_in raddr;
|
|
int_32 error;
|
|
uint_32 buffer_size;
|
|
uint_32 name_size;
|
|
uchar _PTR_ name_ptr;
|
|
uchar _PTR_ temp_ptr;
|
|
|
|
/* Remote address, Name Servers use port 53 */
|
|
raddr.sin_family = AF_INET;
|
|
raddr.sin_port = DNS_NAMESERVER_PORT;
|
|
raddr.sin_addr.s_addr = query_ptr->SERVER_IPADDR;
|
|
|
|
/* set up buffer for sending query. */
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)control_ptr->RES_BUFFER;
|
|
|
|
htons(message_head_ptr->ID, query_ptr->QUERY_ID);
|
|
htons(message_head_ptr->CONTROL, query_ptr->CONTROL);
|
|
htons(message_head_ptr->QDCOUNT, DNS_SINGLE_QUERY);
|
|
htons(message_head_ptr->ANCOUNT, 0);
|
|
htons(message_head_ptr->NSCOUNT, 0);
|
|
htons(message_head_ptr->ARCOUNT, 0);
|
|
|
|
name_ptr = control_ptr->RES_BUFFER + sizeof(DNS_MESSAGE_HEADER_STRUCT);
|
|
if ( cname_retry == TRUE ) {
|
|
cname_ptr = query_ptr->CNAME;
|
|
while ( cname_ptr->NEXT != NULL ) {
|
|
cname_ptr = cname_ptr->NEXT;
|
|
} /* Endwhile */
|
|
name_size = strlen((char _PTR_)cname_ptr->CNAME_PTR );
|
|
temp_ptr = cname_ptr->CNAME_PTR;
|
|
} else {
|
|
name_size = strlen((char _PTR_)query_ptr->QNAME_PTR );
|
|
temp_ptr = query_ptr->QNAME_PTR;
|
|
} /* Endif */
|
|
|
|
/* To include the terminating NULL char */
|
|
name_size++;
|
|
buffer_size = sizeof(DNS_MESSAGE_HEADER_STRUCT) + name_size
|
|
+ sizeof(DNS_MESSAGE_TAIL_STRUCT);
|
|
|
|
while( name_size != 0 ) {
|
|
htonc(name_ptr, *temp_ptr);
|
|
name_ptr++;
|
|
temp_ptr++;
|
|
name_size--;
|
|
} /* Endwhile */
|
|
|
|
message_tail_ptr = (DNS_MESSAGE_TAIL_STRUCT _PTR_)name_ptr;
|
|
htons(message_tail_ptr->QTYPE, query_ptr->QTYPE);
|
|
htons(message_tail_ptr->QCLASS, query_ptr->QCLASS);
|
|
|
|
|
|
error = sendto(control_ptr->RES_SOCKET, control_ptr->RES_BUFFER, buffer_size, 0,
|
|
&raddr, sizeof(raddr));
|
|
if (error == RTCS_ERROR) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_SEND_QUERY, 1, 0, 0);
|
|
error = RTCSERR_DNS_UNABLE_TO_SEND_QUERY;
|
|
} else {
|
|
error = DNS_OK;
|
|
} /* Endif */
|
|
|
|
return( error );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_return_UDP_response_to_query()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_return_UDP_response_to_query
|
|
(
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ current_query_ptr,
|
|
uchar _PTR_ buffer_ptr,
|
|
uint_32 buffer_size,
|
|
uint_32 query_sock
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
int_32 error;
|
|
|
|
error = sendto(query_sock, buffer_ptr, buffer_size, 0,
|
|
¤t_query_ptr->CLIENT_SIN,
|
|
sizeof(current_query_ptr->CLIENT_SIN) );
|
|
if (error == RTCS_ERROR) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_SEND_QUERY, 2, 0, 0);
|
|
|
|
DNS_free_internal_query( current_query_ptr );
|
|
return( RTCSERR_DNS_UNABLE_TO_SEND_QUERY );
|
|
} /* Endif */
|
|
|
|
DNS_free_internal_query( current_query_ptr );
|
|
return( DNS_OK );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_free_resource_record()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static void DNS_free_resource_record
|
|
(
|
|
DNS_RR_HEADER_STRUCT _PTR_ list_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_ADDR_RECORD_STRUCT _PTR_ addr_rr_ptr;
|
|
DNS_NAME_RECORD_STRUCT _PTR_ name_rr_ptr;
|
|
|
|
switch ( list_ptr->TYPE ) {
|
|
case DNS_A:
|
|
addr_rr_ptr = (DNS_ADDR_RECORD_STRUCT _PTR_)((void _PTR_)list_ptr);
|
|
RTCS_part_free( addr_rr_ptr );
|
|
break;
|
|
|
|
case DNS_PTR:
|
|
case DNS_CNAME:
|
|
case DNS_NS:
|
|
name_rr_ptr = (DNS_NAME_RECORD_STRUCT _PTR_)((void _PTR_)list_ptr);
|
|
if ( name_rr_ptr->ANS_NAME_PTR ) {
|
|
_mem_free( name_rr_ptr->ANS_NAME_PTR );
|
|
}/* Endif */
|
|
RTCS_part_free( name_rr_ptr );
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
** If we reach here, there could be a potential memory leak.
|
|
** Depending upon the Resource Record type, it may not all
|
|
** be freed.
|
|
*/
|
|
RTCS_part_free( list_ptr );
|
|
} /* Endswitch */
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_free_slist_records()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static void DNS_free_slist_records
|
|
(
|
|
DNS_SLIST_STRUCT _PTR_ list_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
/* NOT IMPLEMENTED */
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_get_best_name_server_for_query()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
/* Start CR 2424
|
|
NOTE: This only works if DNS entries are added correctly into the linked
|
|
list, with the last entry's NEXT == NULL. This should be done using the
|
|
API for adding DNS entries (CR 2257):
|
|
{
|
|
DNS_SLIST_STRUCT tmp_slist_entry;
|
|
DNS_init_slist_entry(&tmp_slist_entry);
|
|
return( DNS_add_slist_entry(&tmp_slist_entry));
|
|
}
|
|
*/
|
|
#define PRIMARY_NAME_SERVER_TIMEOUT 300 // 5 minutes
|
|
|
|
static uint_32 DNS_get_best_name_server_for_query
|
|
(
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr,
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
static DNS_SLIST_STRUCT _PTR_ best_ptr = NULL;
|
|
TIME_STRUCT time;
|
|
static uint_32 last_time;
|
|
|
|
// Start with the Primary DNS Server
|
|
if (best_ptr == NULL) {
|
|
best_ptr = control_ptr->LOCAL_SLIST_PTR;
|
|
query_ptr->SERVER_IPADDR = best_ptr->IPADDR;
|
|
return( DNS_OK );
|
|
}
|
|
|
|
// Only change our notion of best server if this query has exhausted
|
|
// its QUERY_RETRIES on our current best server. If the query expired
|
|
// on some other server, we cannot use that info to change our current
|
|
// notion of best server, since our current best server may be fine.
|
|
if (query_ptr->SERVER_IPADDR == best_ptr->IPADDR) {
|
|
_time_get( &time );
|
|
|
|
// Go back to the Primary every so often to see if it has returned.
|
|
if (best_ptr != control_ptr->LOCAL_SLIST_PTR) {
|
|
if ((time.SECONDS - last_time) >= PRIMARY_NAME_SERVER_TIMEOUT) {
|
|
best_ptr = control_ptr->LOCAL_SLIST_PTR;
|
|
query_ptr->SERVER_IPADDR = best_ptr->IPADDR;
|
|
return( DNS_OK );
|
|
}
|
|
}
|
|
|
|
// If the query has exhausted its retries, change our notion of best.
|
|
// If that takes us back to the Primary, we can ignore the timeout.
|
|
if (query_ptr->QUERY_RETRIES <= 0) {
|
|
if (best_ptr->NEXT) {
|
|
best_ptr = best_ptr->NEXT;
|
|
last_time = time.SECONDS;
|
|
}
|
|
else {
|
|
best_ptr = control_ptr->LOCAL_SLIST_PTR;
|
|
}
|
|
}
|
|
}
|
|
query_ptr->SERVER_IPADDR = best_ptr->IPADDR;
|
|
return( DNS_OK );
|
|
|
|
} /* Endbody */
|
|
// End CR 2424
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_get_next_expired_query()
|
|
* Returned Value : DNS_QUERY_ID_STRUCT _PTR_
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static DNS_INTERNAL_QUERY_STRUCT _PTR_ DNS_get_next_expired_query
|
|
(
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ _PTR_ query_head_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ expired_query_ptr;
|
|
|
|
|
|
if ( *query_head_ptr == NULL ) {
|
|
return( NULL );
|
|
} /* Endif */
|
|
|
|
|
|
expired_query_ptr = *query_head_ptr;
|
|
|
|
DNS_update_TTL( expired_query_ptr );
|
|
|
|
if ( expired_query_ptr->TTL == 0 ) {
|
|
*query_head_ptr = expired_query_ptr->NEXT;
|
|
return( expired_query_ptr );
|
|
} /* Endif */
|
|
|
|
return( NULL );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_add_query_to_list()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_add_query_to_list
|
|
(
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ _PTR_ query_head_ptr,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ new_query_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ previous_ptr = NULL;
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ temp_ptr;
|
|
|
|
/*
|
|
** set the new_query_ptr->NEXT to be NULL, in case this is a query
|
|
** retry, the NEXT field may not be NULL. Just to be safe.
|
|
*/
|
|
new_query_ptr->NEXT = NULL;
|
|
|
|
/* first check to see if list is empty */
|
|
if ( *query_head_ptr == NULL) {
|
|
*query_head_ptr = new_query_ptr;
|
|
return( DNS_OK );
|
|
} /* Endif */
|
|
|
|
temp_ptr = *query_head_ptr;
|
|
|
|
while ( temp_ptr != NULL ) {
|
|
DNS_update_TTL( temp_ptr );
|
|
|
|
if ( new_query_ptr->TTL < temp_ptr->TTL ) {
|
|
if ( previous_ptr ) {
|
|
previous_ptr->NEXT = new_query_ptr;
|
|
new_query_ptr->NEXT = temp_ptr;
|
|
return( DNS_OK );
|
|
} else {
|
|
new_query_ptr->NEXT = temp_ptr;
|
|
*query_head_ptr = new_query_ptr;
|
|
return( DNS_OK );
|
|
} /* Endif */
|
|
} /* Endif */
|
|
previous_ptr = temp_ptr;
|
|
temp_ptr = temp_ptr->NEXT;
|
|
} /* Endwhile */
|
|
|
|
previous_ptr->NEXT = new_query_ptr;
|
|
return( DNS_OK );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_send_no_query_error_response()
|
|
* Returned Value : uint_32
|
|
* Comments : This function is only used if DNS is unable to allocate
|
|
* or fill a DNS_INTERNAL_QUERY_STRUCT
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void DNS_send_no_query_error_response
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
uint_16 error_code,
|
|
sockaddr_in _PTR_ client_sin_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
int_32 error;
|
|
uint_16 pack_variable;
|
|
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)control_ptr->RES_BUFFER;
|
|
pack_variable = ntohs(message_head_ptr->CONTROL);
|
|
htons(message_head_ptr->CONTROL,
|
|
(pack_variable | DNS_RESPONSE | error_code));
|
|
htons(message_head_ptr->ANCOUNT, DNS_NO_ANSWER);
|
|
htons(message_head_ptr->ARCOUNT, 0);
|
|
htons(message_head_ptr->NSCOUNT, 0);
|
|
|
|
error = sendto(control_ptr->RES_SOCKET, control_ptr->RES_BUFFER,
|
|
control_ptr->RES_BUFFER_SIZE, 0,
|
|
client_sin_ptr, sizeof(*client_sin_ptr));
|
|
if (error == RTCS_ERROR) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_SEND_QUERY, 3, 0, 0);
|
|
} /* Endif */
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_fill_generic_response_buffer()
|
|
* Returned Value : uint-32
|
|
* Comments : This function is used to fill the response buffer
|
|
* with information common to all queries
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_fill_generic_response_buffer
|
|
(
|
|
uchar _PTR_ buffer,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr,
|
|
uint_16 error_code
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
DNS_MESSAGE_TAIL_STRUCT _PTR_ message_tail_ptr;
|
|
uchar _PTR_ name_ptr;
|
|
uchar _PTR_ temp_ptr;
|
|
uint_32 name_size;
|
|
uint_32 buffer_size;
|
|
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)buffer;
|
|
|
|
name_size = strlen((char _PTR_)query_ptr->QNAME_PTR );
|
|
/* To include the terminating NULL char */
|
|
name_size++;
|
|
|
|
buffer_size = sizeof(DNS_MESSAGE_HEADER_STRUCT) + name_size
|
|
+ sizeof(DNS_MESSAGE_TAIL_STRUCT);
|
|
|
|
temp_ptr = buffer + sizeof(DNS_MESSAGE_HEADER_STRUCT)
|
|
+ name_size;
|
|
|
|
message_tail_ptr = (DNS_MESSAGE_TAIL_STRUCT _PTR_)temp_ptr;
|
|
|
|
name_ptr = buffer + sizeof(DNS_MESSAGE_HEADER_STRUCT);
|
|
temp_ptr = query_ptr->QNAME_PTR;
|
|
|
|
htons(message_head_ptr->ID, query_ptr->QUERY_ID);
|
|
htons(message_head_ptr->CONTROL,
|
|
(query_ptr->CONTROL | error_code | DNS_RESPONSE));
|
|
htons(message_head_ptr->ANCOUNT, DNS_NO_ANSWER);
|
|
htons(message_head_ptr->QDCOUNT, DNS_SINGLE_QUERY);
|
|
htons(message_head_ptr->NSCOUNT, DNS_NO_ANSWER);
|
|
htons(message_head_ptr->ARCOUNT, DNS_NO_ANSWER);
|
|
|
|
while ( name_size ) {
|
|
htonc(name_ptr, *temp_ptr);
|
|
name_ptr++;
|
|
temp_ptr++;
|
|
name_size--;
|
|
} /* Endwhile */
|
|
|
|
htons(message_tail_ptr->QTYPE, query_ptr->QTYPE);
|
|
htons(message_tail_ptr->QCLASS, query_ptr->QCLASS);
|
|
|
|
return( buffer_size );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_send_error_response()
|
|
* Returned Value : void
|
|
* Comments : This function is used if a DNS_INTERNAL_QUERY_STRUCT
|
|
* exists
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void DNS_send_error_response
|
|
(
|
|
uchar _PTR_ buffer,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr,
|
|
uint_16 error_code,
|
|
uint_32 query_sock,
|
|
int_32 actual_error
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
int_32 error;
|
|
uint_32 buffer_size;
|
|
|
|
if ( actual_error != DNS_OK ) {
|
|
RTCS_log_error(ERROR_DNS, actual_error, 0, 0, 0);
|
|
} /* Endif */
|
|
|
|
buffer_size = DNS_fill_generic_response_buffer( buffer, query_ptr,
|
|
error_code );
|
|
/* Send the response buffer to the client */
|
|
error = sendto(query_sock, buffer, buffer_size, 0,
|
|
&query_ptr->CLIENT_SIN,
|
|
sizeof(query_ptr->CLIENT_SIN));
|
|
if (error == RTCS_ERROR) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_SEND_QUERY, 4, 0, 0);
|
|
} /* Endif */
|
|
|
|
DNS_free_internal_query( query_ptr );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_check_outstanding_queries()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static void DNS_check_outstanding_queries
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ current_ptr;
|
|
int_32 error;
|
|
|
|
current_ptr = DNS_get_next_expired_query( &control_ptr->RES_QUERY_HEAD_PTR );
|
|
|
|
while ( current_ptr ) {
|
|
/*
|
|
** cycle through all queries and retry with different server, or
|
|
** return "name server error" response to client
|
|
*/
|
|
// Start CR 2424
|
|
current_ptr->QUERY_RETRIES--;
|
|
error = DNS_get_best_name_server_for_query( current_ptr, control_ptr );
|
|
// End CR 2424
|
|
|
|
if ( current_ptr->QUERY_RETRIES <= 0 ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER, current_ptr,
|
|
DNS_QUERY_REFUSED,
|
|
control_ptr->RES_SOCKET, DNS_OK );
|
|
current_ptr = DNS_get_next_expired_query(
|
|
&control_ptr->RES_QUERY_HEAD_PTR );
|
|
continue;
|
|
} /* Endif */
|
|
|
|
if ( error != DNS_OK ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER, current_ptr,
|
|
DNS_SERVER_FAILURE, control_ptr->RES_SOCKET,
|
|
error );
|
|
current_ptr = DNS_get_next_expired_query(
|
|
&control_ptr->RES_QUERY_HEAD_PTR );
|
|
continue;
|
|
} /* Endif */
|
|
|
|
current_ptr->TTL = DNS_QUERY_RETRY_TIME;
|
|
current_ptr->QUERY_ID = DNS_get_query_id();
|
|
|
|
error = DNS_Send_UDP_Query( control_ptr, current_ptr, FALSE );
|
|
if ( error == RTCS_ERROR ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER, current_ptr,
|
|
DNS_QUERY_REFUSED, control_ptr->RES_SOCKET,
|
|
error );
|
|
current_ptr = DNS_get_next_expired_query(
|
|
&control_ptr->RES_QUERY_HEAD_PTR );
|
|
continue;
|
|
} /* Endif */
|
|
|
|
DNS_add_query_to_list( &control_ptr->RES_QUERY_HEAD_PTR, current_ptr );
|
|
current_ptr = DNS_get_next_expired_query(
|
|
&control_ptr->RES_QUERY_HEAD_PTR );
|
|
} /* Endwhile */
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_update_cache()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void DNS_update_cache
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
DNS_RR_LIST_STRUCT _PTR_ _PTR_ local_cache_ptr = &control_ptr->CACHE_PTR;
|
|
DNS_RR_LIST_STRUCT _PTR_ previous_cache_ptr = NULL;
|
|
DNS_RR_LIST_STRUCT _PTR_ next_cache_ptr;
|
|
DNS_RR_LIST_STRUCT _PTR_ free_cache_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ previous_rr_head_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ next_rr_head_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ free_rr_head_ptr;
|
|
TIME_STRUCT time;
|
|
uint_32 difference;
|
|
|
|
_time_get( &time);
|
|
|
|
next_cache_ptr = *local_cache_ptr;
|
|
|
|
while ( next_cache_ptr != NULL ) {
|
|
next_rr_head_ptr = next_cache_ptr->RR_HEAD_PTR;
|
|
previous_rr_head_ptr = NULL;
|
|
while ( next_rr_head_ptr != NULL ) {
|
|
difference = time.SECONDS - next_rr_head_ptr->LAST_TTL_CHECK;
|
|
if ( next_rr_head_ptr->TTL <= difference ) {
|
|
if ( previous_rr_head_ptr ) {
|
|
previous_rr_head_ptr->NEXT = next_rr_head_ptr->NEXT;
|
|
free_rr_head_ptr = next_rr_head_ptr;
|
|
next_rr_head_ptr = next_rr_head_ptr->NEXT;
|
|
} else {
|
|
next_cache_ptr->RR_HEAD_PTR = next_rr_head_ptr->NEXT;
|
|
free_rr_head_ptr = next_rr_head_ptr;
|
|
next_rr_head_ptr = next_rr_head_ptr->NEXT;
|
|
} /* Endif */
|
|
|
|
DNS_free_resource_record( free_rr_head_ptr );
|
|
} else {
|
|
next_rr_head_ptr->LAST_TTL_CHECK = time.SECONDS;
|
|
next_rr_head_ptr->TTL = next_rr_head_ptr->TTL
|
|
- difference;
|
|
previous_rr_head_ptr = next_rr_head_ptr;
|
|
next_rr_head_ptr = next_rr_head_ptr->NEXT;
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
|
|
if ( next_cache_ptr->RR_HEAD_PTR == NULL ) {
|
|
if ( previous_cache_ptr ) {
|
|
previous_cache_ptr->NEXT = next_cache_ptr->NEXT;
|
|
free_cache_ptr = next_cache_ptr;
|
|
next_cache_ptr = next_cache_ptr->NEXT;
|
|
} else {
|
|
*local_cache_ptr = next_cache_ptr->NEXT;
|
|
free_cache_ptr = next_cache_ptr;
|
|
next_cache_ptr = next_cache_ptr->NEXT;
|
|
} /* Endif */
|
|
|
|
if (control_ptr->NUM_NAMES_CACHED > 0) {
|
|
control_ptr->NUM_NAMES_CACHED--;
|
|
}/* Endif */
|
|
_mem_free( free_cache_ptr->NAME_PTR );
|
|
RTCS_part_free( free_cache_ptr );
|
|
} else {
|
|
previous_cache_ptr = next_cache_ptr;
|
|
next_cache_ptr = next_cache_ptr->NEXT;
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_check_packet_for_name()
|
|
* Returned Value : uint_32
|
|
* Comments : Crude, but it will do for now.
|
|
* We should check every lable for compression, not
|
|
* just whole names -- could reduce packet size.
|
|
* (See DNS_assign_answer_middle_ptr() for a more
|
|
* elegant solution idea)
|
|
* However, this doesn't violate RFC 1035.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_16 DNS_check_packet_for_name
|
|
(
|
|
uchar _PTR_ buffer_ptr,
|
|
uint_32 buffer_size,
|
|
uchar _PTR_ name_ptr
|
|
)
|
|
{ /* Body */
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head =
|
|
(DNS_MESSAGE_HEADER_STRUCT _PTR_)buffer_ptr;
|
|
uchar _PTR_ temp_ptr = buffer_ptr + sizeof(DNS_MESSAGE_HEADER_STRUCT);
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ response_ptr;
|
|
uint_16 i, num_queries = ntohs(message_head->QDCOUNT);
|
|
|
|
/* First, need to check the original queries. */
|
|
for (i = 0; i < num_queries; i++) {
|
|
if (strcmp((char _PTR_)temp_ptr, (char _PTR_)name_ptr) == 0) {
|
|
return((uint_16)(temp_ptr - buffer_ptr));
|
|
} /* Endif */
|
|
if(ntohc(temp_ptr) & DNS_COMPRESSED_NAME_MASK) {
|
|
temp_ptr += sizeof(uint_16);
|
|
} else {
|
|
temp_ptr += strlen((char _PTR_)temp_ptr) + 1;
|
|
} /* Endif */
|
|
temp_ptr += sizeof(DNS_MESSAGE_TAIL_STRUCT);
|
|
} /* Endfor */
|
|
|
|
/* Now check the answer sections. */
|
|
while (temp_ptr < buffer_ptr + buffer_size) {
|
|
if (strcmp((char _PTR_)temp_ptr, (char _PTR_)name_ptr) == 0) {
|
|
return((uint_16)(temp_ptr - buffer_ptr));
|
|
} /* Endif */
|
|
if(ntohc(temp_ptr) & DNS_COMPRESSED_NAME_MASK) {
|
|
temp_ptr += sizeof(uint_16);
|
|
} else {
|
|
temp_ptr += strlen((char _PTR_)temp_ptr) + 1;
|
|
} /* Endif */
|
|
response_ptr = (DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_)temp_ptr;
|
|
temp_ptr += sizeof(DNS_RESPONSE_RR_MIDDLE_STRUCT);
|
|
/* Checking the answer section for name as well. */
|
|
if ((ntohs(response_ptr->TYPE) == DNS_PTR ||
|
|
ntohs(response_ptr->TYPE) == DNS_CNAME ||
|
|
ntohs(response_ptr->TYPE) == DNS_NS) &&
|
|
(strcmp((char _PTR_)temp_ptr, (char _PTR_)name_ptr) == 0))
|
|
{
|
|
return((uint_16)(temp_ptr - buffer_ptr));
|
|
} /* Endif */
|
|
temp_ptr += ntohs(response_ptr->RDLENGTH);
|
|
} /* Endwhile */
|
|
return(0);
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_fill_answer_section_of_buffer()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_fill_answer_section_of_buffer
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
DNS_RR_HEADER_STRUCT _PTR_ rr_ptr,
|
|
uchar _PTR_ buffer_ptr,
|
|
int_32 _PTR_ buffer_size_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ response_ptr;
|
|
uchar _PTR_ answer_ptr;
|
|
uchar _PTR_ temp_ptr;
|
|
uint_32 new_buffer_size = *buffer_size_ptr;
|
|
uint_32 name_size;
|
|
uint_16 pack_variable, name_location;
|
|
|
|
answer_ptr = buffer_ptr + *buffer_size_ptr;
|
|
|
|
name_location = DNS_check_packet_for_name(buffer_ptr, *buffer_size_ptr,
|
|
rr_ptr->DOMAIN_NAME_PTR);
|
|
if(name_location) {
|
|
/* Name is already in packet, use offset */
|
|
pack_variable = (DNS_COMPRESSED_NAME_MASK << 8) | name_location;
|
|
htons(answer_ptr, pack_variable);
|
|
new_buffer_size += sizeof( uint_16 );
|
|
answer_ptr += sizeof( uint_16 );
|
|
} else {
|
|
/* Name doesn't exist in packet yet */
|
|
temp_ptr = rr_ptr->DOMAIN_NAME_PTR;
|
|
name_size = strlen((char _PTR_)rr_ptr->DOMAIN_NAME_PTR );
|
|
/* Need to include the last '\0' character as well */
|
|
name_size++;
|
|
new_buffer_size += name_size;
|
|
while( name_size != 0 ) {
|
|
htonc(answer_ptr, *temp_ptr);
|
|
answer_ptr++;
|
|
temp_ptr++;
|
|
name_size--;
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
|
|
response_ptr = (DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_)answer_ptr;
|
|
|
|
htons(response_ptr->TYPE, rr_ptr->TYPE);
|
|
htons(response_ptr->CLASS, rr_ptr->CLASS);
|
|
htonl(response_ptr->TTL, rr_ptr->TTL);
|
|
|
|
new_buffer_size += sizeof( DNS_RESPONSE_RR_MIDDLE_STRUCT );
|
|
answer_ptr += sizeof( DNS_RESPONSE_RR_MIDDLE_STRUCT );
|
|
|
|
switch ( rr_ptr->TYPE ) {
|
|
case DNS_A:
|
|
htons(response_ptr->RDLENGTH, sizeof( _ip_address ));
|
|
htonl(answer_ptr,
|
|
((DNS_ADDR_RECORD_STRUCT _PTR_)((void _PTR_)rr_ptr))->IPADDR);
|
|
new_buffer_size += sizeof( _ip_address );
|
|
break;
|
|
|
|
case DNS_PTR:
|
|
case DNS_CNAME:
|
|
case DNS_NS:
|
|
name_location = DNS_check_packet_for_name(buffer_ptr, *buffer_size_ptr,
|
|
((DNS_NAME_RECORD_STRUCT _PTR_)((void _PTR_)rr_ptr))->ANS_NAME_PTR);
|
|
if(name_location) {
|
|
/* Name is already in packet, use offset */
|
|
pack_variable = (DNS_COMPRESSED_NAME_MASK << 8) | name_location;
|
|
htons(answer_ptr, pack_variable);
|
|
new_buffer_size += sizeof( uint_16 );
|
|
answer_ptr += sizeof( uint_16 );
|
|
} else {
|
|
temp_ptr = ((DNS_NAME_RECORD_STRUCT _PTR_)
|
|
((void _PTR_)rr_ptr))->ANS_NAME_PTR;
|
|
name_size = strlen((char _PTR_)temp_ptr);
|
|
name_size++; /* need the '\0' char */
|
|
htons(response_ptr->RDLENGTH, name_size);
|
|
new_buffer_size += name_size;
|
|
while ( name_size != 0 ) {
|
|
htonc(answer_ptr, *temp_ptr);
|
|
answer_ptr++;
|
|
temp_ptr++;
|
|
name_size--;
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
** Unknown rr type, set new_buffer_size to 0, so cached data
|
|
** will not be used.
|
|
*/
|
|
new_buffer_size = 0;
|
|
} /* Endswitch */
|
|
|
|
if (new_buffer_size) {
|
|
*buffer_size_ptr = new_buffer_size;
|
|
} /* Endif */
|
|
|
|
return( new_buffer_size );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_fill_response_buffer_with_rr_data()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_fill_response_buffer_with_rr_data
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
DNS_RR_HEADER_STRUCT _PTR_ record_ptr,
|
|
boolean all_data,
|
|
boolean resolver_query
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ temp_rr_ptr;
|
|
int_32 _PTR_ buffer_size_ptr;
|
|
uchar _PTR_ buffer_ptr;
|
|
uint_32 buffer_size = 0;
|
|
uint_16 num_answers = 0;
|
|
uint_16 pack_variable;
|
|
|
|
temp_rr_ptr = record_ptr;
|
|
|
|
if ( resolver_query == TRUE ) {
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT_PTR)control_ptr->RES_BUFFER;
|
|
buffer_size_ptr = &control_ptr->RES_BUFFER_SIZE;
|
|
} else {
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT_PTR)control_ptr->NS_BUFFER;
|
|
buffer_size_ptr = &control_ptr->NS_BUFFER_SIZE;
|
|
} /* Endif */
|
|
buffer_ptr = (uchar _PTR_)message_head_ptr;
|
|
|
|
pack_variable = ntohs( message_head_ptr->CONTROL );
|
|
|
|
if ( all_data == TRUE ) {
|
|
while ( temp_rr_ptr != NULL ) {
|
|
num_answers++;
|
|
buffer_size = DNS_fill_answer_section_of_buffer( control_ptr, temp_rr_ptr,
|
|
buffer_ptr, buffer_size_ptr );
|
|
temp_rr_ptr = temp_rr_ptr->NEXT;
|
|
} /* Endwhile */
|
|
} else {
|
|
num_answers++;
|
|
buffer_size = DNS_fill_answer_section_of_buffer( control_ptr, temp_rr_ptr, buffer_ptr,
|
|
buffer_size_ptr );
|
|
} /* Endif */
|
|
|
|
/* insert return information here */
|
|
htons(message_head_ptr->ANCOUNT, num_answers);
|
|
pack_variable |= DNS_RESPONSE;
|
|
htons(message_head_ptr->CONTROL, pack_variable);
|
|
|
|
return( buffer_size );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_rr_canonical_data_exists()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_rr_canonical_data_exists
|
|
(
|
|
DNS_RECURSIVE_CACHE_STRUCT_PTR cache_ptr
|
|
)
|
|
{ /* Body */
|
|
uint_32 buffer_size = 0;
|
|
DNS_RR_LIST_STRUCT _PTR_ new_list_ptr = cache_ptr->CACHE_HEAD;
|
|
DNS_RR_HEADER_STRUCT _PTR_ record_ptr;
|
|
|
|
if (++cache_ptr->NUM_TRIES >= DNS_MAX_NUM_CNAME_RETRIES ) {
|
|
return 0;
|
|
} /* Endif */
|
|
|
|
while ( new_list_ptr != NULL ) {
|
|
if( strcmp((char _PTR_)new_list_ptr->NAME_PTR,
|
|
(char _PTR_)cache_ptr->NAME_PTR) == 0 ) {
|
|
/* The names match, see if the type of data requested exists */
|
|
record_ptr = new_list_ptr->RR_HEAD_PTR;
|
|
/* Search through the records for the data requested. */
|
|
while ( record_ptr != NULL ) {
|
|
if (( cache_ptr->NEW_QUERY_PTR->QTYPE == record_ptr->TYPE ) &&
|
|
( cache_ptr->NEW_QUERY_PTR->QCLASS == record_ptr->CLASS )) {
|
|
/* We have a hit on data & class, fill buffer with info. */
|
|
buffer_size =
|
|
DNS_fill_answer_section_of_buffer(cache_ptr->CONTROL_PTR,
|
|
record_ptr, cache_ptr->BUFFER_PTR,
|
|
cache_ptr->BUFFER_SIZE_PTR);
|
|
break;
|
|
} else if ( cache_ptr->NEW_QUERY_PTR->QCLASS == record_ptr->CLASS &&
|
|
record_ptr->TYPE == DNS_CNAME )
|
|
{
|
|
/*
|
|
** We have an alias, see if the data type exists for the
|
|
** Canonical Name.
|
|
*/
|
|
cache_ptr->NAME_PTR = ((DNS_NAME_RECORD_STRUCT _PTR_)
|
|
((void _PTR_)record_ptr))->ANS_NAME_PTR;
|
|
buffer_size = DNS_rr_canonical_data_exists(cache_ptr);
|
|
if (buffer_size) {
|
|
/* We've had a hit, put alias hit in the buffer as well.*/
|
|
buffer_size =
|
|
DNS_fill_answer_section_of_buffer(cache_ptr->CONTROL_PTR,
|
|
record_ptr, cache_ptr->BUFFER_PTR,
|
|
cache_ptr->BUFFER_SIZE_PTR);
|
|
} /* Endif */
|
|
break;
|
|
} else {
|
|
record_ptr = record_ptr->NEXT;
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
break;
|
|
} else {
|
|
new_list_ptr = new_list_ptr->NEXT;
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
|
|
return(buffer_size);
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_assign_answer_middle_ptr()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ DNS_assign_answer_middle_ptr
|
|
(
|
|
uchar _PTR_ answer_head_ptr,
|
|
uint_16 total_answers,
|
|
uint_16 current_answer_num
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ rr_middle_ptr = NULL;
|
|
uchar _PTR_ temp_ptr;
|
|
uint_32 name_size = 0;
|
|
|
|
if ( total_answers - 1 > current_answer_num ) {
|
|
temp_ptr = answer_head_ptr;
|
|
|
|
while( (ntohc(temp_ptr) != '\0') &&
|
|
name_size < DNS_MAX_CHARS_IN_NAME &&
|
|
!(ntohc(temp_ptr) & DNS_COMPRESSED_NAME_MASK)) {
|
|
name_size += ntohc(temp_ptr);
|
|
temp_ptr = temp_ptr + ntohc(temp_ptr) + 1;
|
|
} /* Endwhile */
|
|
|
|
if ( ntohc(temp_ptr) & DNS_COMPRESSED_NAME_MASK ) {
|
|
temp_ptr+= 2;
|
|
} else {
|
|
temp_ptr++;
|
|
}/* Endif */
|
|
|
|
rr_middle_ptr = (DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_)temp_ptr;
|
|
} /* Endif */
|
|
|
|
return( rr_middle_ptr );
|
|
|
|
} /* Endbody */
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_assign_answer_pointers()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void DNS_assign_answer_pointers
|
|
(
|
|
uchar _PTR_ buffer,
|
|
uchar _PTR_ _PTR_ answer_ptr,
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ _PTR_ answer_middle_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
uchar _PTR_ temp_ptr;
|
|
uint_32 name_size;
|
|
|
|
temp_ptr = buffer + sizeof(DNS_MESSAGE_HEADER_STRUCT);
|
|
name_size = strlen((char _PTR_)temp_ptr);
|
|
name_size++;
|
|
|
|
*answer_ptr = temp_ptr + name_size + sizeof(DNS_MESSAGE_TAIL_STRUCT);
|
|
temp_ptr = *answer_ptr;
|
|
|
|
/* Passing this function two hard coded values to force the assignment */
|
|
*answer_middle_ptr = DNS_assign_answer_middle_ptr( temp_ptr, 3, 0 );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_rr_data_exists()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static uint_32 DNS_rr_data_exists
|
|
(
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ new_query_ptr,
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
uchar _PTR_ buffer_ptr,
|
|
int_32 _PTR_ buffer_size_ptr,
|
|
uint_32 query_type
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_RR_LIST_STRUCT _PTR_ new_list_ptr = NULL;
|
|
DNS_RR_LIST_STRUCT _PTR_ cache_head;
|
|
DNS_RR_LIST_STRUCT _PTR_ previous_ptr = NULL;
|
|
DNS_RR_HEADER_STRUCT _PTR_ record_ptr;
|
|
DNS_RECURSIVE_CACHE_STRUCT cache;
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
uint_16 pack_variable;
|
|
uint_32 ans_count, i, buffer_size = 0;
|
|
int_32 cmp_result;
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ answer_middle_ptr;
|
|
uchar _PTR_ answer_head_ptr;
|
|
boolean resolver_query = FALSE;
|
|
|
|
if ( query_type == DNS_NS_CACHE_DATA ) {
|
|
new_list_ptr = control_ptr->CACHE_PTR;
|
|
resolver_query = FALSE;
|
|
} else if ( query_type == DNS_NS_AUTH_DATA ) {
|
|
new_list_ptr = control_ptr->NS_ZONE_AUTH_LIST;
|
|
resolver_query = FALSE;
|
|
} else if (query_type == DNS_RES_CACHE_DATA ) {
|
|
new_list_ptr = control_ptr->CACHE_PTR;
|
|
resolver_query = TRUE;
|
|
} /* Endif */
|
|
cache_head = new_list_ptr;
|
|
|
|
while ( new_list_ptr != NULL ) {
|
|
cmp_result = strcmp((char _PTR_)new_list_ptr->NAME_PTR,
|
|
(char _PTR_)new_query_ptr->QNAME_PTR );
|
|
if ( cmp_result == 0 ) {
|
|
/* The names match, see if the type of data requested exists */
|
|
record_ptr = new_list_ptr->RR_HEAD_PTR;
|
|
if ( new_query_ptr->QTYPE == DNS_ALL ) {
|
|
buffer_size = DNS_fill_response_buffer_with_rr_data(
|
|
control_ptr,
|
|
record_ptr,
|
|
TRUE,
|
|
resolver_query );
|
|
} else {
|
|
/*
|
|
** We have a hit on the name, but we only want one specific record,
|
|
** search through the records for this name for the data requested.
|
|
*/
|
|
while ( record_ptr != NULL ) {
|
|
if (( new_query_ptr->QTYPE == record_ptr->TYPE ) &&
|
|
( new_query_ptr->QCLASS == record_ptr->CLASS )) {
|
|
/* We have a hit on data & class, fill buffer with info. */
|
|
buffer_size = DNS_fill_response_buffer_with_rr_data(
|
|
control_ptr,
|
|
record_ptr,
|
|
FALSE,
|
|
resolver_query );
|
|
break;
|
|
} else if ( new_query_ptr->QCLASS == record_ptr->CLASS &&
|
|
record_ptr->TYPE == DNS_CNAME )
|
|
{
|
|
/*
|
|
** We have an alias, see if the data type exists for the
|
|
** Canonical Name.
|
|
*/
|
|
ans_count = ntohs(((DNS_MESSAGE_HEADER_STRUCT _PTR_)buffer_ptr)->ANCOUNT );
|
|
if(ans_count != 0 ) {
|
|
/*
|
|
** We are checking a response, not a new query, see if the
|
|
** answer exists in the packet already.
|
|
*/
|
|
DNS_assign_answer_pointers(buffer_ptr, &answer_head_ptr,
|
|
&answer_middle_ptr);
|
|
for (i = 0; (i <= ans_count) && answer_middle_ptr; i++) {
|
|
if ((new_query_ptr->QTYPE == ntohs(answer_middle_ptr->TYPE)) &&
|
|
(new_query_ptr->QCLASS == ntohs(answer_middle_ptr->CLASS)))
|
|
{
|
|
buffer_size = *buffer_size_ptr;
|
|
break;
|
|
} /* Endif */
|
|
answer_head_ptr = ((uchar _PTR_)(answer_middle_ptr + 1)) +
|
|
ntohs(answer_middle_ptr->RDLENGTH);
|
|
answer_middle_ptr = DNS_assign_answer_middle_ptr(
|
|
answer_head_ptr, ans_count, i);
|
|
} /* Endfor */
|
|
break;
|
|
} else {
|
|
cache.NEW_QUERY_PTR = new_query_ptr;
|
|
cache.CONTROL_PTR = control_ptr;
|
|
cache.CACHE_HEAD = cache_head;
|
|
cache.NAME_PTR = record_ptr->DOMAIN_NAME_PTR;
|
|
cache.BUFFER_PTR = buffer_ptr;
|
|
cache.BUFFER_SIZE_PTR = buffer_size_ptr;
|
|
cache.NUM_TRIES = 0;
|
|
buffer_size = DNS_rr_canonical_data_exists(&cache);
|
|
if (buffer_size) {
|
|
/* insert return information here */
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)buffer_ptr;
|
|
htons(message_head_ptr->ANCOUNT, cache.NUM_TRIES);
|
|
pack_variable = ntohs(message_head_ptr->CONTROL);
|
|
pack_variable |= DNS_RESPONSE;
|
|
htons(message_head_ptr->CONTROL, pack_variable);
|
|
} /* Endif */
|
|
break;
|
|
} /* Endif */
|
|
} else {
|
|
record_ptr = record_ptr->NEXT;
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
} /* Endif */
|
|
|
|
break;
|
|
} else {
|
|
previous_ptr = new_list_ptr;
|
|
new_list_ptr = new_list_ptr->NEXT;
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
|
|
if ( previous_ptr != NULL && new_list_ptr != NULL &&
|
|
(query_type == DNS_NS_CACHE_DATA ||
|
|
query_type == DNS_RES_CACHE_DATA) ) {
|
|
/*
|
|
** The most recently accessed data in the cache should always be at
|
|
** the head of the list. If the new_list_ptr is NULL, cached
|
|
** data for the name doesn't exist in the list.
|
|
*/
|
|
previous_ptr->NEXT = new_list_ptr->NEXT;
|
|
new_list_ptr->NEXT = control_ptr->CACHE_PTR;
|
|
control_ptr->CACHE_PTR = new_list_ptr;
|
|
} /* Endif */
|
|
|
|
return( buffer_size );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_is_valid_IP_addr()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_is_valid_IP_addr
|
|
(
|
|
uchar _PTR_ buffer_ptr,
|
|
uchar _PTR_ domain_name,
|
|
uchar _PTR_ _PTR_ local_addr_buffer
|
|
)
|
|
|
|
{ /* Body */
|
|
uchar _PTR_ check_ptr;
|
|
uchar _PTR_ temp_ptr;
|
|
uchar _PTR_ free_buffer;
|
|
uchar appended_name[] = "in-addr.arpa";
|
|
uint_16 new_location;
|
|
uint_16 label_size;
|
|
int_32 byte_num;
|
|
uint_32 digit_count;
|
|
uint_32 total_size = 0;
|
|
uint_32 i;
|
|
uint_32 j;
|
|
|
|
temp_ptr = (uchar _PTR_)RTCS_mem_alloc_zero( DNS_MAX_CHARS_IN_NAME );
|
|
if ( temp_ptr == NULL ) {
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 1, 0, 0);
|
|
return( DNS_SERVER_FAILURE );
|
|
} /* Endif */
|
|
|
|
free_buffer = temp_ptr;
|
|
|
|
/* first check to see if name is written in correct IP address format */
|
|
|
|
check_ptr = domain_name;
|
|
|
|
for ( i = 0; i < 4; i++) {
|
|
label_size = ntohc(check_ptr);
|
|
|
|
if ( label_size & DNS_COMPRESSED_NAME_MASK ) {
|
|
new_location = ntohs(check_ptr) & DNS_COMPRESSED_LOCATION_MASK;
|
|
check_ptr = buffer_ptr + new_location;
|
|
label_size = ntohc(check_ptr);
|
|
} /* Endif */
|
|
|
|
/*
|
|
** Some IP addresses using "in-addr.arpa" do not always have four
|
|
** labels, if this is the case, break out of the loop.
|
|
*/
|
|
if ( label_size == 7 ) {
|
|
break;
|
|
} /* Endif */
|
|
|
|
*temp_ptr++ = label_size;
|
|
check_ptr++;
|
|
total_size++;
|
|
digit_count = 0;
|
|
|
|
if (( label_size < 1 ) || ( label_size > 3 )) {
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
|
|
for ( j = 0; j < label_size; j++ ) {
|
|
if ( digit_count == 0 ) {
|
|
byte_num = 0;
|
|
} /* Endif */
|
|
digit_count++;
|
|
|
|
if ( isdigit(ntohc(check_ptr)) ) {
|
|
/* number is in range */
|
|
byte_num = byte_num + ntohc(check_ptr) - '0';
|
|
byte_num = byte_num * 10;
|
|
*temp_ptr++ = ntohc(check_ptr);
|
|
check_ptr++;
|
|
total_size++;
|
|
} else {
|
|
/* if the characters are not decimal digits it's invalid */
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
} /* Endfor */
|
|
|
|
byte_num = byte_num / 10; /* shift back */
|
|
|
|
if ( (byte_num < 0 ) || (byte_num > 255) ) {
|
|
/* if the number does fall within this range it's invalid */
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
} /* Endfor */
|
|
|
|
if ( ntohc(check_ptr) != 7 ) {
|
|
if ( ntohc(check_ptr) & DNS_COMPRESSED_NAME_MASK ) {
|
|
new_location = ntohs(check_ptr) & DNS_COMPRESSED_LOCATION_MASK;
|
|
check_ptr = buffer_ptr + new_location;
|
|
if ( ntohc(check_ptr) != 7 ) {
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
|
|
}else {
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
*temp_ptr++ = ntohc(check_ptr);
|
|
check_ptr++;
|
|
|
|
/* should be "in-addr" */
|
|
for ( i = 0; i < 7; i++) {
|
|
if ( tolower(ntohc(check_ptr)) != appended_name[i] ) {
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
*temp_ptr++ = appended_name[i];
|
|
check_ptr++;
|
|
} /* Endfor */
|
|
|
|
if ( ntohc(check_ptr) != 4 ) {
|
|
if ( ntohc(check_ptr) & DNS_COMPRESSED_NAME_MASK ) {
|
|
new_location = ntohs(check_ptr) & DNS_COMPRESSED_LOCATION_MASK;
|
|
check_ptr = buffer_ptr + new_location;
|
|
if ( ntohc(check_ptr) != 4 ) {
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
|
|
}else {
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
*temp_ptr++ = ntohc(check_ptr);
|
|
check_ptr++;
|
|
i++;
|
|
|
|
/* should be "arpa" */
|
|
for ( ; i < 12; i++) {
|
|
if ( tolower(ntohc(check_ptr)) != appended_name[i] ) {
|
|
_mem_free( free_buffer );
|
|
return( RTCSERR_DNS_INVALID_IP_ADDR );
|
|
} /* Endif */
|
|
*temp_ptr++ = appended_name[i];
|
|
check_ptr++;
|
|
} /* Endfor */
|
|
|
|
/*
|
|
** If we got this far, it's a legal IP addr, get a buffer,
|
|
** fill it with the address.
|
|
*/
|
|
|
|
/*
|
|
** Total size is the size of the IP address, 14 is the size of
|
|
** "in-addr.arpa" including all label length chars and the terminating
|
|
** '\0' character.
|
|
*/
|
|
total_size += sizeof(appended_name) + 2;
|
|
*local_addr_buffer = (uchar _PTR_)RTCS_mem_alloc_zero( total_size );
|
|
if ( *local_addr_buffer == NULL ) {
|
|
// START CR 2178
|
|
_mem_free( free_buffer );
|
|
// END CR 2178
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 2, 0, 0);
|
|
return( DNS_SERVER_FAILURE );
|
|
} /* Endif */
|
|
|
|
_mem_copy(free_buffer, *local_addr_buffer, total_size);
|
|
_mem_free( free_buffer );
|
|
|
|
return( DNS_OK );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_is_valid_domain_name()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
uint_32 DNS_is_valid_domain_name
|
|
(
|
|
uchar _PTR_ buffer_ptr,
|
|
uchar _PTR_ domain_name,
|
|
uchar _PTR_ _PTR_ local_name_buffer
|
|
)
|
|
|
|
{ /* Body */
|
|
uchar _PTR_ fill_ptr;
|
|
uchar _PTR_ free_ptr;
|
|
uchar _PTR_ check_name;
|
|
uint_16 new_location;
|
|
uint_32 total_length = 0;
|
|
uint_32 label_size;
|
|
uint_32 error;
|
|
uint_32 i;
|
|
|
|
error = DNS_is_valid_IP_addr(buffer_ptr, domain_name, local_name_buffer);
|
|
if ( error != DNS_OK ) {
|
|
/* If the request is for the ROOT Domain Name */
|
|
if ( ntohc(domain_name) == '\0' ) {
|
|
*local_name_buffer = (uchar _PTR_)RTCS_mem_alloc_zero( 1 );
|
|
if ( *local_name_buffer == NULL ) {
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 3, 0, 0);
|
|
return( DNS_SERVER_FAILURE );
|
|
} /* Endif */
|
|
|
|
(*local_name_buffer)[0] = '\0';
|
|
return( DNS_OK );
|
|
} /* Endif */
|
|
|
|
fill_ptr = (uchar _PTR_)RTCS_mem_alloc_zero( DNS_MAX_CHARS_IN_NAME );
|
|
if ( fill_ptr == NULL ) {
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 4, 0, 0);
|
|
return( DNS_SERVER_FAILURE );
|
|
} /* Endif */
|
|
|
|
free_ptr = fill_ptr;
|
|
check_name = domain_name;
|
|
while ( ntohc(check_name) != '\0' ) {
|
|
if ( ntohc(check_name) & DNS_COMPRESSED_NAME_MASK ) {
|
|
new_location = ntohs(check_name) & DNS_COMPRESSED_LOCATION_MASK;
|
|
check_name = buffer_ptr + new_location;
|
|
} /* Endif */
|
|
|
|
label_size = ntohc(check_name);
|
|
*fill_ptr++ = label_size;
|
|
check_name++;
|
|
total_length++;
|
|
|
|
/*
|
|
** RFC 1035 says labels must start with a letter, but in practice
|
|
** some aren't
|
|
*/
|
|
if ( isalnum(ntohc(check_name)) ) {
|
|
*fill_ptr++ = ntohc(check_name);
|
|
check_name++;
|
|
total_length++;
|
|
} else {
|
|
_mem_free( free_ptr );
|
|
return( RTCSERR_DNS_INVALID_NAME );
|
|
} /* Endif */
|
|
|
|
|
|
for ( i = 1; i < label_size; i++ ) {
|
|
/* Domain Name characters can only be letters, hyphens, or numbers */
|
|
if ((isalnum(ntohc(check_name)) || ntohc(check_name) == '-' ) &&
|
|
total_length < DNS_MAX_CHARS_IN_NAME ) {
|
|
*fill_ptr++ = ntohc(check_name);
|
|
check_name++;
|
|
total_length++;
|
|
} else {
|
|
_mem_free( free_ptr );
|
|
return( RTCSERR_DNS_INVALID_NAME );
|
|
} /* Endif */
|
|
} /* Endfor */
|
|
} /* Endwhile */
|
|
|
|
/* This is to append the terminating '\0' character to the string */
|
|
*fill_ptr = '\0';
|
|
total_length++;
|
|
|
|
*local_name_buffer = (uchar _PTR_)RTCS_mem_alloc_zero( total_length );
|
|
if ( *local_name_buffer == NULL ) {
|
|
/* START CR 2178 */
|
|
_mem_free( free_ptr );
|
|
/* END CR 2178 */
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 5, 0, 0);
|
|
return( DNS_SERVER_FAILURE );
|
|
} /* Endif */
|
|
|
|
_mem_copy(free_ptr, *local_name_buffer, total_length);
|
|
_mem_free( free_ptr );
|
|
error = DNS_OK;
|
|
} /* Endif */
|
|
|
|
return( error );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_handle_new_query()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_handle_new_query
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
sockaddr_in _PTR_ client_sin_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ new_query_ptr;
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
DNS_MESSAGE_TAIL_STRUCT _PTR_ message_tail_ptr;
|
|
uchar _PTR_ qname_ptr;
|
|
uchar _PTR_ temp_ptr;
|
|
TIME_STRUCT time;
|
|
uint_32 buffer_size;
|
|
uint_32 local_name_size;
|
|
/* Start CR 2171 */
|
|
int_32 error=DNS_OK;
|
|
/* End CR 2171 */
|
|
|
|
_time_get( &time );
|
|
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)control_ptr->RES_BUFFER;
|
|
qname_ptr = control_ptr->RES_BUFFER + sizeof( DNS_MESSAGE_HEADER_STRUCT );
|
|
|
|
|
|
new_query_ptr = (DNS_INTERNAL_QUERY_STRUCT _PTR_)
|
|
RTCS_part_alloc_zero(control_ptr->INT_QUERY_PARTID);
|
|
if ( new_query_ptr == NULL ) {
|
|
RTCS_log_error( ERROR_DNS, RTCSERR_DNS_UNABLE_TO_ALLOCATE_MEMORY, 0, 0, 0);
|
|
DNS_send_no_query_error_response( control_ptr, DNS_SERVER_FAILURE,
|
|
client_sin_ptr );
|
|
return( DNS_SERVER_FAILURE );
|
|
} /* Endif */
|
|
|
|
temp_ptr = qname_ptr;
|
|
|
|
local_name_size = 0;
|
|
while( (ntohc(temp_ptr) != '\0') &&
|
|
local_name_size < DNS_MAX_CHARS_IN_NAME ) {
|
|
local_name_size = local_name_size + ntohc(temp_ptr) + 1;
|
|
temp_ptr = temp_ptr + ntohc(temp_ptr) + 1;
|
|
} /* Endwhile */
|
|
|
|
/* to include the last NULL (or compressed pointer) char */
|
|
temp_ptr++;
|
|
message_tail_ptr = (DNS_MESSAGE_TAIL_STRUCT _PTR_)temp_ptr;
|
|
|
|
switch ( ntohs(message_tail_ptr->QTYPE) ) {
|
|
|
|
case DNS_A:
|
|
error = DNS_is_valid_domain_name( control_ptr->RES_BUFFER, qname_ptr,
|
|
&new_query_ptr->QNAME_PTR );
|
|
break;
|
|
|
|
case DNS_PTR:
|
|
error = DNS_is_valid_IP_addr( control_ptr->RES_BUFFER, qname_ptr,
|
|
&new_query_ptr->QNAME_PTR );
|
|
break;
|
|
|
|
default:
|
|
// Start CR 2171
|
|
DNS_free_internal_query( new_query_ptr );
|
|
DNS_send_no_query_error_response(control_ptr, DNS_QUERY_NOT_IMPLEMENTED,
|
|
client_sin_ptr );
|
|
return DNS_OK;
|
|
// End CR 2171
|
|
} /* Endswitch */
|
|
|
|
if ( error == RTCSERR_DNS_INVALID_NAME || error == RTCSERR_DNS_INVALID_IP_ADDR ) {
|
|
DNS_free_internal_query( new_query_ptr );
|
|
DNS_send_no_query_error_response( control_ptr, DNS_NAME_ERROR,
|
|
client_sin_ptr );
|
|
return( DNS_OK );
|
|
} /* Endif */
|
|
|
|
if ( error == DNS_SERVER_FAILURE ) {
|
|
DNS_free_internal_query( new_query_ptr );
|
|
DNS_send_no_query_error_response( control_ptr, DNS_SERVER_FAILURE,
|
|
client_sin_ptr );
|
|
return( DNS_OK );
|
|
} /* Endif */
|
|
|
|
new_query_ptr->QTYPE = ntohs(message_tail_ptr->QTYPE);
|
|
new_query_ptr->QCLASS = ntohs(message_tail_ptr->QCLASS);
|
|
new_query_ptr->CONTROL = ntohs(message_head_ptr->CONTROL)
|
|
| DNS_RECURSION_DESIRED;
|
|
|
|
new_query_ptr->CLIENT_SIN.sin_family = client_sin_ptr->sin_family;
|
|
new_query_ptr->CLIENT_SIN.sin_port = client_sin_ptr->sin_port;
|
|
new_query_ptr->CLIENT_SIN.sin_addr.s_addr =
|
|
client_sin_ptr->sin_addr.s_addr;
|
|
/*
|
|
** Check to see if the information is in the local cache. If it is,
|
|
** return it to the client, otherwise, make the query to a name server
|
|
*/
|
|
buffer_size = DNS_rr_data_exists( new_query_ptr, control_ptr,
|
|
control_ptr->RES_BUFFER, &control_ptr->RES_BUFFER_SIZE,
|
|
DNS_RES_CACHE_DATA );
|
|
|
|
if ( buffer_size != 0 ) {
|
|
error = DNS_return_UDP_response_to_query( new_query_ptr,
|
|
control_ptr->RES_BUFFER,
|
|
buffer_size,
|
|
control_ptr->RES_SOCKET );
|
|
return( DNS_OK );
|
|
} /* Endif */
|
|
|
|
new_query_ptr->TTL = DNS_QUERY_RETRY_TIME;
|
|
new_query_ptr->QUERY_ID = DNS_get_query_id();
|
|
new_query_ptr->QUERY_RETRIES = DNS_MAX_NUMBER_OF_QUERY_TRIES;
|
|
new_query_ptr->LAST_TTL_CHECK = time.SECONDS;
|
|
new_query_ptr->NEXT = NULL;
|
|
new_query_ptr->SERVER_IPADDR = 0;
|
|
|
|
error = DNS_get_best_name_server_for_query( new_query_ptr,
|
|
control_ptr );
|
|
if ( error != DNS_OK ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER, new_query_ptr,
|
|
DNS_SERVER_FAILURE, control_ptr->RES_SOCKET,
|
|
error );
|
|
return( RTCSERR_DNS_UNABLE_TO_SEND_QUERY );
|
|
} /* Endif */
|
|
|
|
error = DNS_Send_UDP_Query( control_ptr, new_query_ptr, FALSE );
|
|
if ( error != DNS_OK ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER, new_query_ptr,
|
|
DNS_SERVER_FAILURE, control_ptr->RES_SOCKET,
|
|
error );
|
|
return( RTCSERR_DNS_UNABLE_TO_SEND_QUERY );
|
|
} /* Endif */
|
|
|
|
error = DNS_add_query_to_list( &control_ptr->RES_QUERY_HEAD_PTR,
|
|
new_query_ptr );
|
|
if ( error != DNS_OK ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER, new_query_ptr,
|
|
DNS_SERVER_FAILURE, control_ptr->RES_SOCKET,
|
|
error );
|
|
} /* Endif */
|
|
|
|
return( error );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_retrieve_query()
|
|
* Returned Value : DNS_INTERNAL_QUERY_STRUCT_PTR
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static DNS_INTERNAL_QUERY_STRUCT _PTR_ DNS_retrieve_query
|
|
(
|
|
uint_16 id,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ _PTR_ query_head_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ previous_ptr = NULL;
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ next_query_ptr;
|
|
|
|
next_query_ptr = *query_head_ptr;
|
|
|
|
while ( next_query_ptr != NULL ) {
|
|
if ( next_query_ptr->QUERY_ID == id ) {
|
|
if ( previous_ptr != NULL ) {
|
|
previous_ptr->NEXT = next_query_ptr->NEXT;
|
|
break;
|
|
} else {
|
|
*query_head_ptr = next_query_ptr->NEXT;
|
|
break;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
previous_ptr = next_query_ptr;
|
|
next_query_ptr = next_query_ptr->NEXT;
|
|
} /* Endwhile */
|
|
|
|
return( next_query_ptr );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_remove_last_entry_from_cache
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
static void DNS_remove_last_entry_from_cache
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr
|
|
)
|
|
{ /* Body */
|
|
DNS_RR_LIST_STRUCT _PTR_ _PTR_ rr_list_ptr = &control_ptr->CACHE_PTR;
|
|
DNS_RR_HEADER_STRUCT _PTR_ rr_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ free_ptr;
|
|
|
|
|
|
if (*rr_list_ptr) {
|
|
while ((*rr_list_ptr)->NEXT) {
|
|
/* Run the list, we have to delete the last entry. */
|
|
rr_list_ptr = &(*rr_list_ptr)->NEXT;
|
|
} /* Endwhile */
|
|
|
|
/* Delete the entry */
|
|
if ( control_ptr->NUM_NAMES_CACHED > 0 ) {
|
|
control_ptr->NUM_NAMES_CACHED--;
|
|
}/* Endif */
|
|
|
|
rr_ptr = (*rr_list_ptr)->RR_HEAD_PTR;
|
|
while (rr_ptr) {
|
|
free_ptr = rr_ptr;
|
|
rr_ptr = rr_ptr->NEXT;
|
|
DNS_free_resource_record(free_ptr);
|
|
} /* Endwhile */
|
|
|
|
_mem_free((*rr_list_ptr)->NAME_PTR);
|
|
RTCS_part_free(*rr_list_ptr);
|
|
*rr_list_ptr = NULL;
|
|
}/* Endif */
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_add_to_cache()
|
|
* Returned Value : void
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void DNS_add_to_cache
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
uint_32 module
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ answer_middle_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ rr_head_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ temp_cache_ptr;
|
|
DNS_RR_HEADER_STRUCT _PTR_ previous_cache_ptr = NULL;
|
|
DNS_RR_LIST_STRUCT _PTR_ rr_list_ptr;
|
|
DNS_ADDR_RECORD_STRUCT _PTR_ addr_rr_ptr;
|
|
DNS_NAME_RECORD_STRUCT _PTR_ name_rr_ptr;
|
|
TIME_STRUCT time;
|
|
uchar _PTR_ buffer_ptr = NULL;
|
|
uchar _PTR_ answer_head_ptr;
|
|
uchar _PTR_ temp_ptr;
|
|
uint_16 num_answers;
|
|
uint_16 control;
|
|
uint_16 answer_length;
|
|
uint_32 i;
|
|
uint_32 error;
|
|
int_32 cmp_val;
|
|
int_32 ttl;
|
|
|
|
if ( module == DNS_NS_CACHE_DATA ) {
|
|
buffer_ptr = control_ptr->NS_BUFFER;
|
|
} /* Endif */
|
|
|
|
if ( module == DNS_RES_CACHE_DATA ) {
|
|
buffer_ptr = control_ptr->RES_BUFFER;
|
|
} /* Endif */
|
|
|
|
if ( buffer_ptr != NULL ) {
|
|
DNS_assign_answer_pointers(buffer_ptr, &answer_head_ptr,
|
|
&answer_middle_ptr );
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)buffer_ptr;
|
|
num_answers = ntohs(message_head_ptr->ANCOUNT);
|
|
|
|
control = ntohs(message_head_ptr->CONTROL);
|
|
if ( (control & DNS_TRUNCATION) == 0 ) {
|
|
/* If the truncation bit is not set, cache information */
|
|
for ( i = 0; (i < num_answers) && answer_middle_ptr; i++ ) {
|
|
ttl = ntohl(answer_middle_ptr->TTL);
|
|
answer_length = ntohs(answer_middle_ptr->RDLENGTH);
|
|
temp_ptr = (uchar _PTR_)answer_middle_ptr;
|
|
temp_ptr += sizeof(DNS_RESPONSE_RR_MIDDLE_STRUCT);
|
|
|
|
if ( (ttl == 0) || (ttl > DNS_MAX_ALLOWED_TTL)) {
|
|
|
|
/* bypass this answer, set the pointers for the next one */
|
|
temp_ptr = temp_ptr + answer_length;
|
|
answer_head_ptr = temp_ptr;
|
|
answer_middle_ptr = DNS_assign_answer_middle_ptr(answer_head_ptr,
|
|
num_answers, i);
|
|
continue;
|
|
} /* Endif */
|
|
|
|
if ((control & DNS_NAME_ERROR) != 0 ) {
|
|
if ((control & DNS_AUTHORITATIVE_NAME_ERROR) !=
|
|
DNS_AUTHORITATIVE_NAME_ERROR ) {
|
|
/*
|
|
** Don't cache this answer if the name error isn't
|
|
** authoritative.
|
|
*/
|
|
break;
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
switch ( ntohs(answer_middle_ptr->TYPE) ) {
|
|
case DNS_A:
|
|
addr_rr_ptr = (DNS_ADDR_RECORD_STRUCT _PTR_)
|
|
RTCS_part_alloc_zero(control_ptr->ADDR_RR_PARTID);
|
|
if (!addr_rr_ptr) {
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 5, 0, 0);
|
|
return;
|
|
}/* Endif */
|
|
addr_rr_ptr->IPADDR = ntohl((uchar_ptr)temp_ptr);
|
|
rr_head_ptr = (DNS_RR_HEADER_STRUCT _PTR_)
|
|
((void _PTR_)addr_rr_ptr);
|
|
break;
|
|
|
|
case DNS_PTR:
|
|
case DNS_CNAME:
|
|
case DNS_NS:
|
|
name_rr_ptr = (DNS_NAME_RECORD_STRUCT _PTR_)
|
|
RTCS_part_alloc_zero(control_ptr->NAME_RR_PARTID);
|
|
if (!name_rr_ptr) {
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 5, 0, 0);
|
|
return;
|
|
}/* Endif */
|
|
error = DNS_is_valid_domain_name(buffer_ptr, temp_ptr,
|
|
&name_rr_ptr->ANS_NAME_PTR );
|
|
if ( error != DNS_OK ) {
|
|
RTCS_part_free(name_rr_ptr);
|
|
/* set pointers for next answer */
|
|
temp_ptr = temp_ptr + answer_length;
|
|
answer_head_ptr = temp_ptr;
|
|
answer_middle_ptr = DNS_assign_answer_middle_ptr(
|
|
answer_head_ptr,
|
|
num_answers, i );
|
|
continue;
|
|
} /* Endif */
|
|
rr_head_ptr = (DNS_RR_HEADER_STRUCT _PTR_)
|
|
((void _PTR_)name_rr_ptr);
|
|
break;
|
|
|
|
default:
|
|
/* Unknown type, don't cache */
|
|
/* set pointers for next answer */
|
|
temp_ptr = temp_ptr + answer_length;
|
|
answer_head_ptr = temp_ptr;
|
|
answer_middle_ptr = DNS_assign_answer_middle_ptr(
|
|
answer_head_ptr,
|
|
num_answers, i );
|
|
continue;
|
|
} /* Endswitch */
|
|
|
|
if ( (control & DNS_AUTHORITATIVE_NAME_ERROR) !=
|
|
DNS_AUTHORITATIVE_NAME_ERROR ) {
|
|
rr_head_ptr->TTL = ttl;
|
|
} else {
|
|
rr_head_ptr->TTL = DNS_NAME_ERROR_TTL;
|
|
} /* Endif */
|
|
|
|
rr_head_ptr->CLASS = ntohs(answer_middle_ptr->CLASS);
|
|
rr_head_ptr->TYPE = ntohs(answer_middle_ptr->TYPE);
|
|
rr_head_ptr->NEXT = NULL;
|
|
|
|
/*
|
|
** May have to check name format here. Answers may truncate
|
|
** differently when same answer name is used more than once.
|
|
*/
|
|
error = DNS_is_valid_domain_name(buffer_ptr, answer_head_ptr,
|
|
&rr_head_ptr->DOMAIN_NAME_PTR );
|
|
if ( error != DNS_OK ) {
|
|
DNS_free_resource_record( rr_head_ptr );
|
|
/* set pointers for next answer */
|
|
temp_ptr = temp_ptr + answer_length;
|
|
answer_head_ptr = temp_ptr;
|
|
answer_middle_ptr = DNS_assign_answer_middle_ptr(
|
|
answer_head_ptr,
|
|
num_answers, i );
|
|
continue;
|
|
} /* Endif */
|
|
|
|
_time_get( &time );
|
|
rr_head_ptr->LAST_TTL_CHECK = time.SECONDS;
|
|
/*
|
|
** need exclusive access, both the Resolver and Name Server can
|
|
** modify the cache
|
|
*/
|
|
RTCS_mutex_lock(&control_ptr->CACHE_MUTEX);
|
|
rr_list_ptr = control_ptr->CACHE_PTR;
|
|
|
|
while ( rr_list_ptr != NULL ) {
|
|
cmp_val = strcmp((char _PTR_)rr_head_ptr->DOMAIN_NAME_PTR,
|
|
(char _PTR_)rr_list_ptr->NAME_PTR );
|
|
if ( cmp_val == 0 ) {
|
|
/* The two are equal, cached data for this name exists. */
|
|
break;
|
|
} /* Endif */
|
|
rr_list_ptr = rr_list_ptr->NEXT;
|
|
} /* Endwhile */
|
|
|
|
if ( rr_list_ptr == NULL ) {
|
|
/* We're either at the head or the tail of the list */
|
|
rr_list_ptr = (DNS_RR_LIST_STRUCT _PTR_)
|
|
RTCS_part_alloc_zero(control_ptr->RR_LIST_PARTID);
|
|
if ( rr_list_ptr == NULL ) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_ALLOCATE_MEMORY, 0, 0, 0);
|
|
_mem_free( rr_head_ptr->DOMAIN_NAME_PTR );
|
|
DNS_free_resource_record( rr_head_ptr );
|
|
/* set pointers for next answer */
|
|
temp_ptr = temp_ptr + answer_length;
|
|
answer_head_ptr = temp_ptr;
|
|
answer_middle_ptr = DNS_assign_answer_middle_ptr(
|
|
answer_head_ptr,
|
|
num_answers, i );
|
|
continue;
|
|
} /* Endif */
|
|
|
|
rr_list_ptr->NAME_PTR = rr_head_ptr->DOMAIN_NAME_PTR;
|
|
rr_list_ptr->RR_HEAD_PTR = rr_head_ptr;
|
|
rr_list_ptr->NEXT = control_ptr->CACHE_PTR;
|
|
control_ptr->CACHE_PTR = rr_list_ptr;
|
|
control_ptr->NUM_NAMES_CACHED++;
|
|
} else {
|
|
/*
|
|
** Cached data using the same name exists, search the
|
|
** existing sub-list under the name for the same record type
|
|
*/
|
|
temp_cache_ptr = rr_list_ptr->RR_HEAD_PTR;
|
|
while ( temp_cache_ptr != NULL ) {
|
|
if ( temp_cache_ptr->TYPE == rr_head_ptr->TYPE ) {
|
|
/* cached data of this type exists, replace with new stuff */
|
|
break;
|
|
} /* Endif */
|
|
previous_cache_ptr = temp_cache_ptr;
|
|
temp_cache_ptr = temp_cache_ptr->NEXT;
|
|
} /* Endwhile */
|
|
|
|
if ( temp_cache_ptr == NULL ) {
|
|
/* data of this type doesn't exist. Insert new stuff */
|
|
rr_head_ptr->NEXT = rr_list_ptr->RR_HEAD_PTR;
|
|
} else {
|
|
/* This data exists previously, replace it */
|
|
rr_head_ptr->NEXT = rr_list_ptr->RR_HEAD_PTR->NEXT;
|
|
|
|
if ( previous_cache_ptr == NULL ) {
|
|
/* We're at the head of the list */
|
|
DNS_free_resource_record( rr_list_ptr->RR_HEAD_PTR );
|
|
} else {
|
|
previous_cache_ptr->NEXT = temp_cache_ptr->NEXT;
|
|
DNS_free_resource_record( temp_cache_ptr );
|
|
} /* Endif */
|
|
} /* Endif */
|
|
rr_list_ptr->RR_HEAD_PTR = rr_head_ptr;
|
|
/*
|
|
** We only keep one reference to the name for the resource
|
|
** records for any given name. Since a node was pre-existing,
|
|
** just have this record refer to it's string, and free the
|
|
** one we allocated.
|
|
*/
|
|
_mem_free(rr_head_ptr->DOMAIN_NAME_PTR);
|
|
rr_head_ptr->DOMAIN_NAME_PTR = rr_list_ptr->NAME_PTR;
|
|
} /* Endif */
|
|
RTCS_mutex_unlock(&control_ptr->CACHE_MUTEX);
|
|
temp_ptr = temp_ptr + answer_length;
|
|
answer_head_ptr = temp_ptr;
|
|
answer_middle_ptr = DNS_assign_answer_middle_ptr( answer_head_ptr,
|
|
num_answers, i );
|
|
} /* Endfor */
|
|
|
|
while(DNS_CACHE_NAME_LIMIT &&
|
|
(control_ptr->NUM_NAMES_CACHED > DNS_CACHE_NAME_LIMIT) &&
|
|
/* This is here as a paranoid check to break out of loop. */
|
|
control_ptr->CACHE_PTR)
|
|
{
|
|
/*
|
|
** We're over the limit, delete the last entry in the cache until
|
|
** we're at the limit.
|
|
*/
|
|
DNS_remove_last_entry_from_cache(control_ptr);
|
|
}/* Endwhile */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_retry_query_with_CNAME()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_retry_query_with_CNAME
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr,
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ answer_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
DNS_CNAME_STRUCT _PTR_ _PTR_ previous_ptr;
|
|
DNS_CNAME_STRUCT _PTR_ temp_ptr;
|
|
DNS_CNAME_STRUCT _PTR_ new_cname_ptr;
|
|
uchar _PTR_ cname_ptr;
|
|
int_32 error;
|
|
uint_32 cname_retries = 0;
|
|
int_32 cmp_result;
|
|
|
|
cname_ptr = (uchar _PTR_)answer_ptr;
|
|
cname_ptr += sizeof( DNS_RESPONSE_RR_MIDDLE_STRUCT );
|
|
|
|
new_cname_ptr = (DNS_CNAME_STRUCT _PTR_)
|
|
RTCS_part_alloc_zero(control_ptr->CNAME_PARTID);
|
|
if ( !new_cname_ptr ) {
|
|
RTCS_log_error(ERROR_DNS, DNS_SERVER_FAILURE, 5, 0, 0);
|
|
return( DNS_SERVER_FAILURE );
|
|
}/* Endif */
|
|
error = DNS_is_valid_domain_name( control_ptr->RES_BUFFER, cname_ptr,
|
|
(uchar _PTR_ _PTR_)&new_cname_ptr->CNAME_PTR );
|
|
if ( error != DNS_OK ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER,
|
|
query_ptr, DNS_NAME_ERROR,
|
|
control_ptr->RES_SOCKET, DNS_OK );
|
|
} /* Endif */
|
|
|
|
previous_ptr = &query_ptr->CNAME;
|
|
|
|
temp_ptr = *previous_ptr;
|
|
|
|
while ( temp_ptr != NULL ) {
|
|
cmp_result = strcmp((char _PTR_)new_cname_ptr->CNAME_PTR,
|
|
(char _PTR_)temp_ptr->CNAME_PTR );
|
|
if ( cmp_result == 0 ) {
|
|
/* the names are equal, we have a CNAME loop, return error */
|
|
_mem_free(new_cname_ptr->CNAME_PTR);
|
|
RTCS_part_free(new_cname_ptr);
|
|
DNS_send_error_response( control_ptr->RES_BUFFER,
|
|
query_ptr, DNS_NAME_ERROR,
|
|
control_ptr->RES_SOCKET, DNS_OK );
|
|
error = DNS_NAME_ERROR;
|
|
break;
|
|
} /* Endif */
|
|
cname_retries++;
|
|
if ( cname_retries == DNS_MAX_NUM_CNAME_RETRIES ) {
|
|
/* BIND only allows for 8 CNAME query retries */
|
|
_mem_free(new_cname_ptr->CNAME_PTR);
|
|
RTCS_part_free(new_cname_ptr);
|
|
error = DNS_return_UDP_response_to_query( query_ptr,
|
|
control_ptr->RES_BUFFER,
|
|
control_ptr->RES_BUFFER_SIZE,
|
|
control_ptr->RES_SOCKET );
|
|
error = DNS_NAME_ERROR;
|
|
break;
|
|
} /* Endif */
|
|
previous_ptr = &(*previous_ptr)->NEXT;
|
|
temp_ptr = *previous_ptr;
|
|
} /* Endwhile */
|
|
|
|
if ( error == DNS_OK ) {
|
|
*previous_ptr = new_cname_ptr;
|
|
new_cname_ptr->NEXT = NULL;
|
|
query_ptr->QUERY_ID = DNS_get_query_id();
|
|
|
|
error = DNS_Send_UDP_Query( control_ptr, query_ptr, TRUE );
|
|
if ( error == RTCS_ERROR ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER, query_ptr,
|
|
DNS_SERVER_FAILURE, control_ptr->RES_SOCKET,
|
|
error );
|
|
} else {
|
|
|
|
DNS_add_query_to_list( &control_ptr->RES_QUERY_HEAD_PTR, query_ptr );
|
|
|
|
} /* Endif */
|
|
} /* Endif */
|
|
|
|
return( error );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_search_response_for_referral()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_search_response_for_referral
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
/* NOT IMPLEMENTED */
|
|
|
|
/* SPR P122-0258-01
|
|
** This is here to get the resolver to return quickly when a name
|
|
** that doesn't exist is queried for, since we only support queries
|
|
** to a single DNS Server for now. When multiple DNS Server support
|
|
** is added, remove this function call and allow for proper resend
|
|
** behaviour.
|
|
*/
|
|
|
|
DNS_send_error_response( control_ptr->RES_BUFFER,
|
|
query_ptr, DNS_QUERY_NOT_IMPLEMENTED,
|
|
control_ptr->RES_SOCKET, DNS_OK );
|
|
/* END SPR P122-0258-01 */
|
|
|
|
return( DNS_OK );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_handle_internal_query()
|
|
* Returned Value : DNS_INTERNAL_QUERY_STRUCT_PTR
|
|
* Comments : This function is for the Name Server or Resolver to
|
|
* make queries for NS records to be used to make queries
|
|
* for authoritative data if the original query fails.
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_handle_internal_query
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
return( DNS_OK );
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_Send_TCP_Query()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static uint_32 DNS_Send_TCP_Query
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr,
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
/* NOT IMPLEMENTED */
|
|
DNS_send_error_response( control_ptr->RES_BUFFER,
|
|
query_ptr, DNS_QUERY_NOT_IMPLEMENTED,
|
|
control_ptr->RES_SOCKET, DNS_OK );
|
|
|
|
return( DNS_OK );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_handle_UDP_response()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_handle_UDP_response
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr
|
|
)
|
|
|
|
{ /* Body */
|
|
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
DNS_MESSAGE_TAIL_STRUCT _PTR_ message_tail_ptr;
|
|
DNS_INTERNAL_QUERY_STRUCT _PTR_ query_ptr;
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT _PTR_ answer_middle_ptr;
|
|
uchar _PTR_ answer_ptr;
|
|
TIME_STRUCT time;
|
|
uint_16 answer_count;
|
|
uint_16 control;
|
|
uint_16 answer_type;
|
|
int_32 error = DNS_OK;
|
|
|
|
_time_get( &time );
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)control_ptr->RES_BUFFER;
|
|
answer_count = ntohs( message_head_ptr->ANCOUNT );
|
|
control = ntohs( message_head_ptr->CONTROL );
|
|
query_ptr = DNS_retrieve_query( ntohs(message_head_ptr->ID),
|
|
&control_ptr->RES_QUERY_HEAD_PTR );
|
|
if ( query_ptr != NULL ) {
|
|
/* Query still exists, respond accordingly */
|
|
|
|
/* Start CR 1965 */
|
|
if ( query_ptr->INTERNAL_QUERY == TRUE ) {
|
|
/* Name Server query was made by resolver, not for a client */
|
|
error = DNS_handle_internal_query( control_ptr, query_ptr );
|
|
if ( error != DNS_OK ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER,
|
|
query_ptr, DNS_SERVER_FAILURE,
|
|
control_ptr->RES_SOCKET, error );
|
|
} /* Endif */
|
|
} else {
|
|
if ( answer_count != 0 ) {
|
|
/* An answer was received, respond accordingly */
|
|
/*
|
|
** Cache the response, so we don't have to request whatever was
|
|
** given to us in the future.
|
|
*/
|
|
DNS_add_to_cache( control_ptr, DNS_RES_CACHE_DATA );
|
|
DNS_assign_answer_pointers( control_ptr->RES_BUFFER, &answer_ptr,
|
|
&answer_middle_ptr );
|
|
if ( answer_middle_ptr ) {
|
|
message_tail_ptr = (DNS_MESSAGE_TAIL_STRUCT _PTR_)(answer_ptr
|
|
- sizeof(DNS_MESSAGE_TAIL_STRUCT));
|
|
answer_type = ntohs(answer_middle_ptr->TYPE);
|
|
|
|
if ( answer_type == ntohs(message_tail_ptr->QTYPE) ) {
|
|
/* Answer is what we wanted as a response, return to client */
|
|
error = DNS_return_UDP_response_to_query( query_ptr,
|
|
control_ptr->RES_BUFFER, control_ptr->RES_BUFFER_SIZE,
|
|
control_ptr->RES_SOCKET );
|
|
} else {
|
|
/*
|
|
** An answer exists, but it's not what we want. Check all
|
|
** the answers to see if what we are looking for is in the
|
|
** buffer at all. If it is, return the buffer to the client,
|
|
** if not, use the information received to make another query
|
|
*/
|
|
if ( answer_type == DNS_CNAME ) {
|
|
if ( query_ptr->QUERY_RETRIES-- <= 0 ) {
|
|
DNS_send_error_response( control_ptr->RES_BUFFER,
|
|
query_ptr, DNS_QUERY_REFUSED,
|
|
control_ptr->RES_SOCKET, DNS_OK );
|
|
} else {
|
|
/*
|
|
** If we get here, an answer exists, but doesn't
|
|
** match query type, or there is more than one
|
|
** answer, since we've cached the response, check
|
|
** the cache again to see if the answer was in the
|
|
** packet we received. If it isn't there, retry the
|
|
** query using the cannonical name reference.
|
|
*/
|
|
if (DNS_rr_data_exists( query_ptr, control_ptr,
|
|
control_ptr->RES_BUFFER,
|
|
&control_ptr->RES_BUFFER_SIZE, DNS_RES_CACHE_DATA))
|
|
{
|
|
error = DNS_return_UDP_response_to_query(
|
|
query_ptr, control_ptr->RES_BUFFER,
|
|
control_ptr->RES_BUFFER_SIZE,
|
|
control_ptr->RES_SOCKET );
|
|
} else {
|
|
error = DNS_retry_query_with_CNAME( control_ptr,
|
|
query_ptr, answer_middle_ptr);
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} else {
|
|
/*
|
|
** No answer exists in the response. Check Name Server records
|
|
** for referrals to retry query. Also check additional records.
|
|
** and RCODE for clues to retry the query.
|
|
*/
|
|
error = DNS_search_response_for_referral( control_ptr,
|
|
query_ptr );
|
|
|
|
if ( control & DNS_TRUNCATION ) {
|
|
/* If the message was truncated, retry the query using TCP */
|
|
error = DNS_Send_TCP_Query( control_ptr, query_ptr );
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endif */
|
|
/* End CR 1965 */
|
|
/* Start CR 1119 */
|
|
#if 0
|
|
} else {
|
|
/*
|
|
** Query doesn't exist anymore. Cache if answer is authoritative,
|
|
** otherwise, do nothing
|
|
*/
|
|
if ( ((control & DNS_RCODE_MASK) == DNS_NO_ERROR ||
|
|
(control & DNS_RCODE_MASK) == DNS_NAME_ERROR) &&
|
|
(control & DNS_AUTHORITATIVE_ANSWER) ) {
|
|
DNS_add_to_cache( control_ptr, DNS_RES_CACHE_DATA );
|
|
} /* Endif */
|
|
#endif
|
|
/* End CR 1119 */
|
|
} /* Endif */
|
|
|
|
return( error );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_refresh_root_servers_task()
|
|
* Returned Value :
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static void DNS_refresh_root_servers_task
|
|
(
|
|
uint_32 temp_ptr
|
|
)
|
|
{ /* Body */
|
|
|
|
/*NOT IMPLEMENTED */
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_refresh_root_servers()
|
|
* Returned Value :
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static uint_32 DNS_refresh_root_servers
|
|
(
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr
|
|
)
|
|
{ /* Body */
|
|
|
|
/* NOT IMPLEMENTED */
|
|
return( DNS_OK );
|
|
|
|
} /* Endbody */
|
|
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : DNS_Resolver_task()
|
|
* Returned Value :
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
void DNS_Resolver_task
|
|
(
|
|
pointer new_control_ptr,
|
|
pointer creator
|
|
)
|
|
{ /* Body */
|
|
|
|
DNS_CONTROL_STRUCT _PTR_ control_ptr;
|
|
DNS_MESSAGE_HEADER_STRUCT _PTR_ message_head_ptr;
|
|
DNS_SLIST_STRUCT _PTR_ first_root_ptr;
|
|
sockaddr_in addr;
|
|
TIME_STRUCT time;
|
|
uint_32 difference;
|
|
uint_16 rlen;
|
|
int_32 error;
|
|
|
|
control_ptr = (DNS_CONTROL_STRUCT _PTR_)new_control_ptr;
|
|
|
|
/*
|
|
** Root Server List updating is not yet implemented,
|
|
** remove "control_ptr->UPDATING = TRUE;" when it is coded.
|
|
*/
|
|
control_ptr->UPDATING = TRUE;
|
|
|
|
_mem_zero((uchar _PTR_) &addr, sizeof(addr));
|
|
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = DNS_RESOLVER_PORT;
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
error = RTCS_attachsock( control_ptr->RES_SOCKET );
|
|
if ( error == (int_32)RTCS_SOCKET_ERROR ) {
|
|
RTCS_task_exit(creator, RTCSERR_DNS_INITIALIZATION_FAILURE);
|
|
} /* Endif */
|
|
|
|
error = bind(control_ptr->RES_SOCKET, &addr, sizeof(sockaddr_in));
|
|
if ( error != RTCS_OK ) {
|
|
RTCS_task_exit(creator, RTCSERR_DNS_INITIALIZATION_FAILURE);
|
|
} /* Endif */
|
|
RTCS_task_resume_creator(creator, RTCS_OK);
|
|
|
|
while ( TRUE ) {
|
|
|
|
_time_get ( &time );
|
|
|
|
/*
|
|
** Check the TTL expiry time for root name servers, if expired
|
|
** call refresh function to update them
|
|
*/
|
|
first_root_ptr = (DNS_SLIST_STRUCT _PTR_)control_ptr->ROOT_SLIST_PTR;
|
|
difference = time.SECONDS - first_root_ptr->LAST_TTL_CHECK;
|
|
first_root_ptr->LAST_TTL_CHECK = time.SECONDS;
|
|
|
|
RTCS_mutex_lock(&control_ptr->CACHE_MUTEX);
|
|
if (first_root_ptr->TTL <= difference
|
|
&& ( control_ptr->UPDATING == FALSE )) {
|
|
RTCS_mutex_unlock(&control_ptr->CACHE_MUTEX);
|
|
error = DNS_refresh_root_servers( control_ptr );
|
|
if ( error != DNS_OK ) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_UNABLE_TO_UPDATE_ROOT_SERVERS, 0, 0, 0);
|
|
} /* Endif */
|
|
} else {
|
|
RTCS_mutex_unlock(&control_ptr->CACHE_MUTEX);
|
|
first_root_ptr->TTL = first_root_ptr->TTL - difference;
|
|
} /* Endif */
|
|
|
|
DNS_check_outstanding_queries( control_ptr );
|
|
|
|
if ( control_ptr->NS_BUFFER == NULL ) {
|
|
/*
|
|
** If the Name Server task is running, it has the responsibility
|
|
** to update the cache(using the mutex!), if it isn't, let the
|
|
** resolver do it.
|
|
*/
|
|
/*
|
|
** Don't need the mutex here, since the DNS Server doesn't exist on
|
|
** the target, the resolver will be the only task accessing it.
|
|
*/
|
|
DNS_update_cache(control_ptr);
|
|
} /* Endif */
|
|
|
|
/*
|
|
** now wait for queries or responses, bypass rest of while loop
|
|
** if none are received
|
|
*/
|
|
|
|
error = (uint_32)RTCS_selectset( &control_ptr->RES_SOCKET, 1,
|
|
DNS_RESOLVER_RETRY_TIME );
|
|
|
|
if (( error == (uint_32)NULL ) || ( error == RTCS_ERROR )) {
|
|
continue;
|
|
} /* Endif */
|
|
|
|
|
|
/* Received a message, respond accordingly */
|
|
rlen = sizeof(addr);
|
|
control_ptr->RES_BUFFER_SIZE = recvfrom(control_ptr->RES_SOCKET,
|
|
control_ptr->RES_BUFFER,
|
|
DNS_MAX_UDP_MESSAGE_SIZE,
|
|
0, &addr, &rlen);
|
|
if (control_ptr->RES_BUFFER_SIZE == RTCS_ERROR) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_SOCKET_RECV_ERROR, 0, 0, 0);
|
|
continue;
|
|
} /* Endif */
|
|
|
|
/* Start CR 1119 */
|
|
if (control_ptr->RES_BUFFER_SIZE < sizeof(DNS_MESSAGE_HEADER_STRUCT)) {
|
|
RTCS_log_error(ERROR_DNS, RTCSERR_DNS_SHORT_MESSAGE_ERROR, 0, 0, 0);
|
|
continue;
|
|
} /* Endif */
|
|
/* End CR 1119 */
|
|
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT_PTR)control_ptr->RES_BUFFER;
|
|
|
|
if ( ntohs(message_head_ptr->CONTROL) & DNS_RESPONSE ) {
|
|
/* It's a response to a query, parse and return it to client */
|
|
error = DNS_handle_UDP_response( control_ptr );
|
|
if ( error != DNS_OK ) {
|
|
RTCS_log_error( ERROR_DNS, error, 0, 0, 0);
|
|
} /* Endif */
|
|
} else {
|
|
if (addr.sin_addr.s_addr == INADDR_LOOPBACK) {
|
|
/* It's a new query */
|
|
error = DNS_handle_new_query( control_ptr, &addr );
|
|
} else {
|
|
error = ERROR_DNS;
|
|
} /* Endif */
|
|
if ( error != DNS_OK ) {
|
|
RTCS_log_error( ERROR_DNS, error, 0, 0, 0);
|
|
} /* Endif */
|
|
} /* Endif */
|
|
} /* Endwhile */
|
|
|
|
} /* Endbody */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if RTCSCFG_ENABLE_LWDNS
|
|
|
|
_ip_address LWDNS_server_ipaddr = 0;
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : LWDNS_Send_Query()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
|
|
static uint_32 LWDNS_Send_Query
|
|
(
|
|
uint_32 sock,
|
|
char_ptr name_to_resolve,
|
|
char_ptr send_buffer,
|
|
uint_32_ptr id_ptr
|
|
)
|
|
{
|
|
DNS_MESSAGE_HEADER_STRUCT_PTR message_head_ptr;
|
|
DNS_MESSAGE_TAIL_STRUCT_PTR message_tail_ptr;
|
|
int_32 error;
|
|
uint_32 i;
|
|
uint_32 name_size;
|
|
char_ptr name_ptr,len_ptr;
|
|
uint_16 id;
|
|
uchar len;
|
|
|
|
|
|
name_size = strlen((char _PTR_)name_to_resolve ) ; //To include the terminating NULL char
|
|
|
|
/* set up buffer for sending query. */
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT _PTR_)send_buffer;
|
|
name_ptr = &send_buffer[sizeof(DNS_MESSAGE_HEADER_STRUCT)];
|
|
id = RTCS_rand(); // TASK_NUMBER_FROM_TASKID(_task_get_id()) ;
|
|
if (id_ptr) {
|
|
*id_ptr = id;
|
|
}
|
|
htons(message_head_ptr->ID, id );
|
|
htons(message_head_ptr->CONTROL, DNS_STANDARD_QUERY|DNS_RECURSION_DESIRED);
|
|
htons(message_head_ptr->QDCOUNT, DNS_SINGLE_QUERY);
|
|
htons(message_head_ptr->ANCOUNT, 0);
|
|
htons(message_head_ptr->NSCOUNT, 0);
|
|
htons(message_head_ptr->ARCOUNT, 0);
|
|
|
|
len_ptr=name_ptr;
|
|
len=0;
|
|
if (*name_ptr != '.')
|
|
name_ptr++;
|
|
|
|
for (i=0;i<name_size;i++) {
|
|
if (name_to_resolve[i] == '.') {
|
|
*len_ptr = len;
|
|
len = 0;
|
|
len_ptr = name_ptr;
|
|
} else {
|
|
htonc(name_ptr, name_to_resolve[i]);
|
|
len++;
|
|
}
|
|
name_ptr++;
|
|
}
|
|
*len_ptr = len;
|
|
*name_ptr++ = 0;
|
|
|
|
message_tail_ptr = (DNS_MESSAGE_TAIL_STRUCT _PTR_) name_ptr;
|
|
name_ptr += sizeof(DNS_MESSAGE_TAIL_STRUCT);
|
|
|
|
htons(message_tail_ptr->QTYPE, DNS_A);
|
|
htons(message_tail_ptr->QCLASS, DNS_IN);
|
|
|
|
|
|
error = send(sock, send_buffer, (name_ptr-send_buffer), 0);
|
|
|
|
if (error == RTCS_ERROR) {
|
|
error = RTCS_geterror(sock);
|
|
} else {
|
|
error = DNS_OK;
|
|
}
|
|
|
|
return( error );
|
|
}
|
|
|
|
static boolean domains_equal(char_ptr req_domain, char_ptr res_domain)
|
|
{
|
|
uint_32 req_index=0,res_index=0,i;
|
|
uchar len, c;
|
|
|
|
len = ntohc (res_domain + res_index);
|
|
res_index++;
|
|
do {
|
|
if ( len & DNS_COMPRESSED_NAME_MASK ) {
|
|
return FALSE;
|
|
}
|
|
for (i=0;i<len;i++) {
|
|
if (req_domain[req_index++] != tolower(res_domain[res_index++])) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
len = ntohc (res_domain + res_index);
|
|
res_index++;
|
|
c = ntohc (req_domain + req_index);
|
|
req_index++;
|
|
} while (len && (c == '.'));
|
|
return (len ==0) && (c==0);
|
|
}
|
|
|
|
static boolean domain_name_extract(uint_32 start, char_ptr rx_buffer,char_ptr ipname,uint_32 ipnamesize)
|
|
{
|
|
uint_32 s_index=start, d_index=0,i;
|
|
uchar b;
|
|
|
|
do {
|
|
b = ntohc (rx_buffer + s_index);
|
|
if ( b & DNS_COMPRESSED_NAME_MASK ) {
|
|
s_index = ntohs(rx_buffer + s_index) & DNS_COMPRESSED_LOCATION_MASK;
|
|
} else {
|
|
s_index++;
|
|
for (i=0;i<b;i++) {
|
|
if (d_index >= ipnamesize-1) break;
|
|
ipname[d_index++] = rx_buffer[s_index++];
|
|
}
|
|
if (d_index >= ipnamesize-1) break;
|
|
ipname[d_index++] = '.';
|
|
}
|
|
} while (rx_buffer[s_index]);
|
|
|
|
if (d_index) {
|
|
ipname[--d_index] = 0;
|
|
} else {
|
|
ipname[0] = 0;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static uint_32 domain_name_fragment_length(uchar_ptr name)
|
|
{
|
|
uint_32 i=0;
|
|
|
|
while ( (name[i] != 0) && ((ntohc (name + i) & DNS_COMPRESSED_NAME_MASK) == 0)) {
|
|
i++;
|
|
}
|
|
return (name[i]?i+2:i+1);
|
|
}
|
|
|
|
|
|
/*FUNCTION*-------------------------------------------------------------
|
|
*
|
|
* Function Name : LWDNS_Get_Response()
|
|
* Returned Value : uint_32
|
|
* Comments :
|
|
*
|
|
*END*-----------------------------------------------------------------*/
|
|
|
|
static boolean LWDNS_Get_Response
|
|
(
|
|
uint_32 sock,
|
|
char_ptr name_to_resolve,
|
|
char_ptr rx_buffer,
|
|
uint_32 req_id,
|
|
_ip_address _PTR_ ipaddr_ptr,
|
|
char_ptr ipname,
|
|
uint_32 ipnamesize
|
|
)
|
|
{
|
|
DNS_MESSAGE_HEADER_STRUCT_PTR message_head_ptr;
|
|
DNS_RESPONSE_RR_MIDDLE_STRUCT_PTR answer_middle_ptr;
|
|
uchar_ptr answer_ptr;
|
|
uint_16 answer_count,query_count;
|
|
uint_16 control, rdlength;
|
|
uint_16 answer_type;
|
|
_ip_address ip_addr = INADDR_ANY;
|
|
sockaddr_in addr;
|
|
uint_16 rlen,id;
|
|
int_32 response_size;
|
|
char_ptr temp_ptr;
|
|
_ip_address * ip_answer_ptr;
|
|
uint_32 i,offset;
|
|
|
|
|
|
|
|
rlen = sizeof(addr);
|
|
response_size = recv(sock,rx_buffer, DNS_MAX_UDP_MESSAGE_SIZE, 0);
|
|
if ((response_size != RTCS_ERROR) && (response_size >= sizeof(DNS_MESSAGE_HEADER_STRUCT))) {
|
|
message_head_ptr = (DNS_MESSAGE_HEADER_STRUCT_PTR) rx_buffer;
|
|
id = ntohs( message_head_ptr->ID );
|
|
query_count = ntohs( message_head_ptr->QDCOUNT );
|
|
answer_count = ntohs( message_head_ptr->ANCOUNT );
|
|
control = ntohs( message_head_ptr->CONTROL );
|
|
|
|
if ( (id == req_id ) && (query_count==1) && answer_count) {
|
|
|
|
temp_ptr = &rx_buffer[sizeof(DNS_MESSAGE_HEADER_STRUCT)];
|
|
|
|
|
|
if (domains_equal(name_to_resolve, temp_ptr)) {
|
|
temp_ptr +=strlen(temp_ptr) + 1 + sizeof(DNS_MESSAGE_TAIL_STRUCT);
|
|
|
|
for (i=0;i<answer_count;i++) {
|
|
answer_ptr = (uchar_ptr)temp_ptr;
|
|
|
|
offset = domain_name_fragment_length(answer_ptr);
|
|
|
|
answer_middle_ptr = (DNS_RESPONSE_RR_MIDDLE_STRUCT_PTR) &answer_ptr[offset];
|
|
answer_type = ntohs( answer_middle_ptr->TYPE );
|
|
rdlength = ntohs( answer_middle_ptr->RDLENGTH );
|
|
if ( (answer_type == DNS_A ) && (rdlength == 4)) {
|
|
if (ipname != NULL) {
|
|
domain_name_extract(temp_ptr-rx_buffer,rx_buffer,ipname,ipnamesize);
|
|
}
|
|
ip_answer_ptr = (_ip_address *) &answer_ptr[offset + sizeof(DNS_RESPONSE_RR_MIDDLE_STRUCT)];
|
|
if (ipaddr_ptr != NULL) {
|
|
*ipaddr_ptr = ntohl ((uchar_ptr)ip_answer_ptr);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
temp_ptr += offset + sizeof(DNS_RESPONSE_RR_MIDDLE_STRUCT) + rdlength;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
boolean LWDNS_resolve(
|
|
char_ptr name_to_resolve,
|
|
_ip_address _PTR_ ipaddr_ptr,
|
|
char_ptr ipname,
|
|
uint_32 ipnamesize
|
|
)
|
|
{
|
|
boolean success=FALSE;
|
|
sockaddr_in laddr,raddr;
|
|
uint_32 sock=0;
|
|
char_ptr buf=NULL;
|
|
uint_32 result,id;
|
|
int_32 error;
|
|
|
|
*ipaddr_ptr = 0;
|
|
if (LWDNS_server_ipaddr) {
|
|
buf= RTCS_mem_alloc(DNS_MAX_UDP_MESSAGE_SIZE);
|
|
if (buf) {
|
|
_mem_set_type(buf,MEM_TYPE_DNS_UDP_MESSAGE);
|
|
_mem_zero((uchar _PTR_) &laddr, sizeof(laddr));
|
|
laddr.sin_family = AF_INET;
|
|
laddr.sin_port = 0; // DNS_RESOLVER_PORT;
|
|
laddr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
_mem_zero((uchar _PTR_) &raddr, sizeof(raddr));
|
|
/* Remote address, Name Servers use port 53 */
|
|
raddr.sin_family = AF_INET;
|
|
raddr.sin_port = DNS_NAMESERVER_PORT;
|
|
raddr.sin_addr.s_addr = LWDNS_server_ipaddr;
|
|
|
|
#if RTCSCFG_ENABLE_UDP
|
|
/* Bind to UDP port */
|
|
sock = socket(PF_INET, SOCK_DGRAM, 0);
|
|
#else
|
|
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
#endif
|
|
if (sock) {
|
|
error = bind(sock, (const sockaddr *)&laddr, sizeof(laddr));
|
|
if ( error == RTCS_OK ) {
|
|
error = connect(sock, (const sockaddr *)(&raddr), sizeof(raddr));
|
|
if (error == RTCS_OK ) {
|
|
error = LWDNS_Send_Query(sock, name_to_resolve, buf, &id);
|
|
if (error == RTCS_OK ) {
|
|
result = (uint_32)RTCS_selectset( &sock, 1, 3000 );
|
|
|
|
if (result==sock) {
|
|
success = LWDNS_Get_Response(sock, name_to_resolve, buf, id, ipaddr_ptr, ipname, ipnamesize);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
shutdown(sock,0);
|
|
}
|
|
_mem_free(buf);
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
#endif
|
|
/* EOF */
|