⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dns.c

📁 cryptlib是功能强大的安全工具集。允许开发人员快速在自己的软件中集成加密和认证服务。
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************
*																			*
*						cryptlib DNS Interface Routines						*
*						Copyright Peter Gutmann 1998-2004					*
*																			*
****************************************************************************/

#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#if defined( INC_ALL )
  #include "crypt.h"
  #include "stream.h"
  #include "tcp.h"
#elif defined( INC_CHILD )
  #include "../crypt.h"
  #include "stream.h"
  #include "tcp.h"
#else
  #include "crypt.h"
  #include "io/stream.h"
  #include "io/tcp.h"
#endif /* Compiler-specific includes */

#ifdef USE_TCP

/****************************************************************************
*																			*
*						 		Init/Shutdown Routines						*
*																			*
****************************************************************************/

#ifdef __WINDOWS__

/* Global function pointers.  These are necessary because the functions need
   to be dynamically linked since not all systems contain the necessary
   libraries */

#if ( defined( sun ) && OSVERSION > 4 )
#undef htonl	/* Slowaris has defines that conflict with our ones */
#undef htons
#undef ntohl
#undef ntohs
#endif /* Slowaris */

static INSTANCE_HANDLE hDNS;

typedef void ( SOCKET_API *FREEADDRINFO )( struct addrinfo *ai );
typedef int ( SOCKET_API *GETADDRINFO )( const char *nodename,
										 const char *servname,
										 const struct addrinfo *hints,
										 struct addrinfo **res );
typedef struct hostent FAR * ( SOCKET_API *GETHOSTBYNAME )( const char FAR *name );
typedef struct hostent FAR * ( SOCKET_API *GETHOSTNAME )( char FAR * name,
														  int namelen );
typedef int ( SOCKET_API *GETNAMEINFO )( const struct sockaddr *sa,
										 SIZE_TYPE salen, char *node,
										 SIZE_TYPE nodelen, char *service,
										 SIZE_TYPE servicelen, int flags );
typedef u_long ( SOCKET_API *HTONL )( u_long hostlong );
typedef u_short ( SOCKET_API *HTONS )( u_short hostshort );
typedef unsigned long ( SOCKET_API *INET_ADDR )( const char FAR *cp );
typedef char FAR * ( SOCKET_API *INET_NTOA )( struct in_addr in );
typedef u_long ( SOCKET_API *NTOHL )( u_long netlong );
typedef u_short ( SOCKET_API *NTOHS )( u_short netshort );
typedef DNS_STATUS ( WINAPI *DNSQUERY )( const LPSTR lpstrName,
										 const WORD wType, const DWORD fOptions,
										 const PIP4_ARRAY aipServers,
										 PDNS_RECORD *ppQueryResultsSet,
										 PVOID *pReserved );
typedef DNS_STATUS ( WINAPI *DNSQUERYCONFIG )( const DNS_CONFIG_TYPE Config,
											   const DWORD Flag,
											   const PWSTR pwsAdapterName,
											   PVOID pReserved, PVOID pBuffer,
											   PDWORD pBufferLength );
typedef VOID ( WINAPI *DNSRECORDLISTFREE )( PDNS_RECORD pRecordList,
											DNS_FREE_TYPE FreeType );
typedef int ( SOCKET_API *WSAGETLASTERROR )( void );

static FREEADDRINFO pfreeaddrinfo = NULL;
static GETADDRINFO pgetaddrinfo = NULL;
static GETHOSTBYNAME pgethostbyname = NULL;
static GETHOSTNAME pgethostname = NULL;
static GETNAMEINFO pgetnameinfo = NULL;
static HTONL phtonl = NULL;
static HTONS phtons = NULL;
static INET_ADDR pinet_addr = NULL;
static INET_NTOA pinet_ntoa = NULL;
static NTOHL pntohl = NULL;
static NTOHS pntohs = NULL;
static DNSQUERY pDnsQuery = NULL;
static DNSQUERYCONFIG pDnsQueryConfig = NULL;
static DNSRECORDLISTFREE pDnsRecordListFree = NULL;
static WSAGETLASTERROR pWSAGetLastError = NULL;

#define freeaddrinfo		pfreeaddrinfo
#define getaddrinfo			pgetaddrinfo
#define gethostbyname		pgethostbyname
#define gethostname			pgethostname
#define getnameinfo			pgetnameinfo
#define htonl				phtonl
#define htons				phtons
#define inet_addr			pinet_addr
#define inet_ntoa			pinet_ntoa
#define ntohl				pntohl
#define ntohs				pntohs
#define DnsQuery			pDnsQuery
#define DnsQueryConfig		pDnsQueryConfig
#define DnsRecordListFree	pDnsRecordListFree
#ifndef WSAGetLastError
  /* In some environments WSAGetLastError() is a macro that maps to
     GetLastError() */
  #define WSAGetLastError	pWSAGetLastError
  #define DYNLOAD_WSAGETLASTERROR
#endif /* WSAGetLastError */

static int SOCKET_API my_getaddrinfo( const char *nodename, 
									  const char *servname,
									  const struct addrinfo *hints,
									  struct addrinfo **res );
static void SOCKET_API my_freeaddrinfo( struct addrinfo *ai );
static int SOCKET_API my_getnameinfo( const struct sockaddr *sa, 
									  SIZE_TYPE salen, char *node, 
									  SIZE_TYPE nodelen, char *service,
									  SIZE_TYPE servicelen, int flags );

int initDNS( INSTANCE_HANDLE hTCP, INSTANCE_HANDLE hAddr )
	{
	/* Get the required TCP/IP functions */
	gethostbyname = ( GETHOSTBYNAME ) DynamicBind( hTCP, TEXT( "gethostbyname" ) );
	gethostname = ( GETHOSTNAME ) DynamicBind( hTCP, TEXT( "gethostname" ) );
	htonl = ( HTONL ) DynamicBind( hTCP, TEXT( "htonl" ) );
	htons = ( HTONS ) DynamicBind( hTCP, TEXT( "htons" ) );
	inet_addr = ( INET_ADDR ) DynamicBind( hTCP, TEXT( "inet_addr" ) );
	inet_ntoa = ( INET_NTOA ) DynamicBind( hTCP, TEXT( "inet_ntoa" ) );
	ntohl = ( NTOHL ) DynamicBind( hTCP, TEXT( "ntohl" ) );
	ntohs = ( NTOHS ) DynamicBind( hTCP, TEXT( "ntohs" ) );
  #ifdef DYNLOAD_WSAGETLASTERROR
	WSAGetLastError = ( WSAGETLASTERROR ) DynamicBind( hTCP, TEXT( "WSAGetLastError" ) );
  #endif /* DYNLOAD_WSAGETLASTERROR */
	if( gethostbyname == NULL || gethostname == NULL || htonl == NULL || \
		htons == NULL || inet_addr == NULL || inet_ntoa == NULL || \
		ntohl == NULL || ntohs == NULL )
		return( CRYPT_ERROR );

	/* Set up the IPv6-style name/address functions */
	if( hAddr != NULL_INSTANCE )
		{
		freeaddrinfo = ( FREEADDRINFO ) DynamicBind( hAddr, TEXT( "freeaddrinfo" ) );
		getaddrinfo = ( GETADDRINFO ) DynamicBind( hAddr, TEXT( "getaddrinfo" ) );
		getnameinfo = ( GETNAMEINFO ) DynamicBind( hAddr, TEXT( "getnameinfo" ) );
		if( freeaddrinfo == NULL || getaddrinfo == NULL || \
			getnameinfo == NULL )
			return( CRYPT_ERROR );
		}
	else
		{
		/* If we couldn't dynamically bind the IPv6 name/address functions,
		   use a local emulation */
		getaddrinfo = my_getaddrinfo;
		freeaddrinfo = my_freeaddrinfo;
		getnameinfo = my_getnameinfo;
		}

	/* Get the required DNS functions if they're available */
#if defined( __WIN16__ )
	hDNS = NULL_INSTANCE;
#elif defined( __WIN32__ )
	hDNS = DynamicLoad( "dnsapi.dll" );
#elif defined( __WINCE__ )
	hDNS = hTCP;
#endif /* Win16/Win32/WinCE */
	if( hDNS != NULL_INSTANCE )
		{
		DnsQuery = ( DNSQUERY ) DynamicBind( hDNS, TEXT( "DnsQuery_A" ) );
		DnsQueryConfig = ( DNSQUERYCONFIG ) DynamicBind( hDNS, TEXT( "DnsQueryConfig" ) );
		DnsRecordListFree = ( DNSRECORDLISTFREE ) DynamicBind( hDNS, TEXT( "DnsRecordListFree" ) );
		if( ( DnsQuery == NULL || DnsQueryConfig == NULL || \
			  DnsRecordListFree == NULL ) && hDNS != hTCP )
			{
			DynamicUnload( hDNS );
			hDNS = NULL_INSTANCE;
			return( CRYPT_ERROR );
			}
		}
	
	return( CRYPT_OK );
	}

void endDNS( INSTANCE_HANDLE hTCP )
	{
	if( hDNS != NULL_INSTANCE && hDNS != hTCP )
		DynamicUnload( hDNS );
	hDNS = NULL_INSTANCE;
	}
#endif /* __WINDOWS__ */

/****************************************************************************
*																			*
*						 		IPv6 Emulation								*
*																			*
****************************************************************************/

/* Emulation of IPv6 networking functions.  We include these unconditionally
   under Windows because with dynamic binding we can't be sure that they're
   needed or not */

#if !defined( IPv6 ) || defined( __WINDOWS__ )

static int addAddrInfo( struct addrinfo *prevAddrInfoPtr,
						struct addrinfo **addrInfoPtrPtr,
						const void *address, const int port )
	{
	struct addrinfo *addrInfoPtr;
	struct sockaddr_in *sockAddrPtr;

	/* Allocate the new element, clear it, and set fixed fields for IPv4 */
	if( ( addrInfoPtr = clAlloc( "addAddrInfo", \
								 sizeof( struct addrinfo ) ) ) == NULL || \
		( sockAddrPtr = clAlloc( "addAddrInfo", \
								 sizeof( struct sockaddr ) ) ) == NULL )
		{
		if( addrInfoPtr != NULL )
			clFree( "addAddrInfo", addrInfoPtr );
		return( -1 );
		}
	memset( addrInfoPtr, 0, sizeof( struct addrinfo ) );
	memset( sockAddrPtr, 0, sizeof( struct sockaddr ) );
	if( prevAddrInfoPtr != NULL )
		prevAddrInfoPtr->ai_next = addrInfoPtr;
	addrInfoPtr->ai_family = PF_INET;
	addrInfoPtr->ai_socktype = SOCK_STREAM;
	addrInfoPtr->ai_protocol = IPPROTO_TCP;
	addrInfoPtr->ai_addrlen = sizeof( struct sockaddr_in );
	addrInfoPtr->ai_addr = ( struct sockaddr * ) sockAddrPtr;

	/* Set the port and address information.  In general we'd copy the
	   address to the sockAddrPtr->sin_addr.s_addr member, however on
	   Crays, which don't have 32-bit data types, this is a 32-bit 
	   bitfield, so we have to use the encapsulating struct */
	sockAddrPtr->sin_family = AF_INET;
	sockAddrPtr->sin_port = htons( ( in_port_t ) port );
	memcpy( &sockAddrPtr->sin_addr, address, IP_ADDR_SIZE );
	*addrInfoPtrPtr = addrInfoPtr;
	return( 0 );
	}

static int SOCKET_API my_getaddrinfo( const char *nodename, 
									  const char *servname,
									  const struct addrinfo *hints,
									  struct addrinfo **res )
	{
	struct hostent *pHostent;
	struct addrinfo *currentAddrInfoPtr = NULL;
	const int port = aToI( servname );
	int hostErrno, i;
	gethostbyname_vars();

	assert( nodename != NULL || ( hints->ai_flags & AI_PASSIVE ) );
	assert( servname != NULL );
	assert( isReadPtr( hints, sizeof( struct addrinfo ) ) );

	/* Clear return value */
	*res = NULL;

	/* Perform basic error checking */
	if( ( nodename == NULL && !( hints->ai_flags & AI_PASSIVE ) ) || \
		servname == NULL )
		return( -1 );

	/* If there's no interface specified and we're creating a server-side
	   socket, prepare to listen on any interface.  Note that BeOS can only
	   bind to one interface at a time, so INADDR_ANY actually binds to the
	   first interface it finds */
	if( nodename == NULL && ( hints->ai_flags & AI_PASSIVE ) )
		{
		const in_addr_t address = INADDR_ANY;

		return( addAddrInfo( NULL, res, &address, port ) );
		}

	/* If it's a dotted address, there's a single address, convert it to
	   in_addr form and return it.  Note for EBCDIC use that since this is
	   an emulation of an OS function the string is already in EBCDIC form,
	   so we don't use the cryptlib-internal functions for this */
	if( isdigit( *nodename ) )
		{
		const in_addr_t address = inet_addr( nodename );

		if( isBadAddress( address ) )
			return( -1 );
		return( addAddrInfo( NULL, res, &address, port ) );
		}

	/* It's a host name, convert it to the in_addr form */
	gethostbyname_threadsafe( nodename, pHostent, hostErrno );
	if( pHostent == NULL || pHostent->h_length != IP_ADDR_SIZE )
		return( -1 );
	for( i = 0; pHostent->h_addr_list[ i ] != NULL && i < IP_ADDR_COUNT; i++ )
		{
		int status;

		if( currentAddrInfoPtr == NULL )
			{
			status = addAddrInfo( NULL, res, pHostent->h_addr_list[ i ], port );
			currentAddrInfoPtr = *res;
			}
		else
			status = addAddrInfo( currentAddrInfoPtr, &currentAddrInfoPtr,
								  pHostent->h_addr_list[ i ], port );
		if( status != 0 )
			{
			freeaddrinfo( *res );
			return( status );
			}
		}
	return( 0 );
	}

static void SOCKET_API my_freeaddrinfo( struct addrinfo *ai )
	{
	while( ai != NULL )
		{
		struct addrinfo *addrInfoCursor = ai;

		ai = ai->ai_next;
		if( addrInfoCursor->ai_addr != NULL )
			clFree( "my_freeaddrinfo", addrInfoCursor->ai_addr );
		clFree( "my_freeaddrinfo", addrInfoCursor );
		}
	}

static int SOCKET_API my_getnameinfo( const struct sockaddr *sa, 
									  SIZE_TYPE salen, char *node, 
									  SIZE_TYPE nodelen, char *service,
									  SIZE_TYPE servicelen, int flags )
	{
	const struct sockaddr_in *sockAddr = ( struct sockaddr_in * ) sa;
	const char *ipAddress;

	/* Clear return values */
	strcpy( node, "<Unknown>" );
	strcpy( service, "0" );

	/* Get the remote system's address and port number */
	if( ( ipAddress = inet_ntoa( sockAddr->sin_addr ) ) == NULL )
		return( -1 );
	strncpy( node, ipAddress, nodelen );
	node[ nodelen - 1 ] = '\0';
	sPrintf( service, "%d", ntohs( sockAddr->sin_port ) );

	return( 0 );
	}
#endif /* !IPv6 || __WINDOWS__ */

/****************************************************************************
*																			*
*						 		DNS SRV Interface							*
*																			*
****************************************************************************/

/* Use DNS SRV to auto-detect host information */

#if defined( __WINDOWS__ )

static void convertToSrv( char *srvName, const char *hostName )
	{
	const int nameLength = strlen( hostName );
	int i;

	/* Prepend the service info to the start of the host name.  This
	   converts foo.bar.com into _pkiboot._tcp.bar.com in preparation for
	   the DNS SRV lookup */
	for( i = 0; i < nameLength; i++ )
		if( hostName[ i ] == '.' )
			break;
	if( i < nameLength && ( nameLength - i ) < MAX_URL_SIZE - 16 )
		{
		memcpy( srvName, "_pkiboot._tcp.", 14 );
		memcpy( srvName + 14, hostName + i, nameLength - i + 1 );
		}
	else
		strcpy( srvName, "_pkiboot._tcp.localhost" );
	}

static int getSrvFQDN( STREAM *stream, char *fqdn )
	{
	PDNS_RECORD pDns = NULL;
	struct hostent *hostInfo;
	static char cachedFQDN[ MAX_URL_SIZE + 1 ];
	static time_t lastFetchTime = 0;
#ifdef __WINCE__
	char fqdnBuffer[ MAX_URL_SIZE + 1 ], *fqdnPtr = fqdnBuffer;
#else
	char *fqdnPtr;
#endif /* Win32 vs. WinCE */

	/* The uncached FQDN check is quite slow and resource-intensive (it
	   seems to do a full reload of the DNS subsystem), to lighten the load
	   we only try a new one once a minute */
	if( lastFetchTime >= getTime() - 60 )
		{
		strcpy( fqdn, cachedFQDN );
		return( CRYPT_OK );
		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -