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

📄 dns.c

📁 cryptlib安全工具包
💻 C
📖 第 1 页 / 共 2 页
字号:
		return( addAddrInfo( NULL, res, &address, sizeof( in_addr_t  ), 
							 port ) );
		}

	/* It's a host name, convert it to the in_addr form */
	gethostbyname_threadsafe( nodename, pHostent, hostErrno );
	if( pHostent == NULL ) 
		return( -1 );
	ENSURES( pHostent->h_length == IP_ADDR_SIZE );
	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 ], 
								  pHostent->h_length, port );
			currentAddrInfoPtr = *res;
			}
		else
			status = addAddrInfo( currentAddrInfoPtr, &currentAddrInfoPtr,
								  pHostent->h_addr_list[ i ], 
								  pHostent->h_length, port );
		if( status != 0 )
			{
			freeaddrinfo( *res );
			return( status );
			}
		}
	return( 0 );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
static void SOCKET_API my_freeaddrinfo( INOUT struct addrinfo *ai )
	{
	int i;

	assert( isWritePtr( ai, sizeof( struct addrinfo ) ) );

	/* Perform basic error checking.  Since this is supposed to be an 
	   emulation of a (normally) built-in function we don't perform any 
	   REQUIRES()-style checking but only apply the basic checks that the 
	   normal built-in form does */
	if( ai == NULL )
		return;

	for( i = 0; ai != NULL && i < IP_ADDR_COUNT; i++ )
		{
		struct addrinfo *addrInfoCursor = ai;

		ai = ai->ai_next;
		if( addrInfoCursor->ai_addr != NULL )
			clFree( "my_freeaddrinfo", addrInfoCursor->ai_addr );
		clFree( "my_freeaddrinfo", addrInfoCursor );
		}
	}
									  
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
static int SOCKET_API my_getnameinfo( IN_BUFFER( salen ) const struct sockaddr *sa, 
									  IN SIZE_TYPE salen,
									  OUT_BUFFER_FIXED( nodelen ) char *node, 
									  IN_LENGTH_SHORT SIZE_TYPE nodelen,
									  OUT_BUFFER_FIXED( servicelen ) char *service, 
									  IN_LENGTH_SHORT SIZE_TYPE servicelen,
									  IN int flags )
	{
	const struct sockaddr_in *sockAddr = ( struct sockaddr_in * ) sa;
	const char *ipAddress;

	assert( isReadPtr( sa, salen ) && salen >= sizeof( struct sockaddr ) );
	assert( isReadPtr( node, nodelen ) && nodelen >= 10 );
	assert( isReadPtr( service, servicelen ) && servicelen >= 8 );

	/* Perform basic error checking.  Since this is supposed to be an 
	   emulation of a (normally) built-in function we don't perform any 
	   REQUIRES()-style checking but only apply the basic checks that the 
	   normal built-in form does */
	if( sa == NULL || \
		salen < sizeof( struct sockaddr ) || salen > MAX_INTLENGTH_SHORT || \
		node == NULL || \
		nodelen < 10 || nodelen > MAX_INTLENGTH_SHORT || \
		service == NULL || \
		servicelen < 8 || servicelen > MAX_INTLENGTH_SHORT )
		return( -1 );

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

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

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

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

/* Get a host's IP address */

CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
int getAddressInfo( INOUT NET_STREAM_INFO *netStream, 
					OUT_PTR struct addrinfo **addrInfoPtrPtr,
					IN_BUFFER( nameLen ) const char *name, 
					IN_LENGTH_DNS const int nameLen, 
					IN_PORT const int port, const BOOLEAN isServer )
	{
	struct addrinfo hints;
	char nameBuffer[ MAX_DNS_SIZE + 8 ], portBuffer[ 16 + 8 ];

	assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
	assert( isWritePtr( addrInfoPtrPtr, sizeof( struct addrinfo * ) ) );
	assert( isServer || name != NULL );

	REQUIRES( port >= 22 && port < 65536L );
	REQUIRES( isServer || \
			  ( !isServer && name != NULL ) );
	REQUIRES( ( name == NULL && nameLen == 0 ) || \
			  ( nameLen > 0 && nameLen < MAX_DNS_SIZE ) );

	/* Convert the name and port into the null-terminated text-string format 
	   required by getaddrinfo().  The reason why the port is given as a 
	   string rather than a port number is that we can also optionally 
	   specify the port to connect to via a service name.  Of course it's 
	   more or less pot luck whether the service you want is a recognised 
	   one so everyone specifies the port anyway, however the reason why 
	   this unnecessary flexibility is there is because getaddrinfo() was 
	   seen as a universal replacement for a pile of other functions, 
	   including (for this case) getservbyname() */
	if( name != NULL )
		{
		memcpy( nameBuffer, name, nameLen );
		nameBuffer[ nameLen ] = '\0';
		name = nameBuffer;
		}
	sprintf_s( portBuffer, 8, "%d", port );

	/* If we're a client and using auto-detection of a PKI service, try and
	   locate it via DNS SRV */
	if( !isServer && name != NULL && nameLen == 12 && \
		( !memcmp( name, "[Autodetect]", 12 ) || *name == '_' ) )
		{
		int localPort, status;

		status = findHostInfo( netStream, nameBuffer, MAX_DNS_SIZE, 
							   &localPort, name, nameLen );
		if( cryptStatusError( status ) )
			return( status );
		name = nameBuffer;
		sprintf_s( portBuffer, 8, "%d", localPort );
		}

	/* Convert the address information to the system character set if 
	   required */
#ifdef EBCDIC_CHARS
	if( name != NULL )
		bufferToEbcdic( nameBuffer, nameBuffer );
	bufferToEbcdic( portBuffer, portBuffer );
#endif /* EBCDIC_CHARS */

	/* Set up the port information and hint information needed by
	   getaddrinfo().  The use of PF_UNSPEC is a bit problematic because RFC
	   2553 is usually interpreted to mean "look for all addresses" rather
	   than the more sensible "look for any address".  The reason why this
	   is a problem is because getaddrinfo() ends up looking for unnecessary
	   IPv6 addresses, either by returning IPv6 addresses when the system
	   doesn't do IPv6 or spending a lot of time groping around for IPv6
	   stuff and/or further unnecessary addresses when it's already got what
	   it needs.  This is made worse by confusion over implementation
	   details, for example early implementations of getaddrinfo() in glibc
	   would always try an AAAA lookup even on an IPv4-only system/network,
	   resulting in long delays as the resolver timed out and fell back to a
	   straight A lookup.  There was some disagreement over whether this was
	   right or wrong, and how to fix it (IPv6 purists who never noticed the
	   problem seemed to think that it was right, everyone else thought that
	   it was wrong).  Variations of this problem exist, e.g. if an IPv4
	   address is in /etc/hosts and DNS is down, the resolver will still
	   spend ages (several minutes in some cases) groping around for an IPv6
	   address before it finally gives up and falls back to what it already
	   knows from /etc/hosts.  Switching the hint from AF_UNSPEC to AF_INET
	   bypasses this problem, but has the downside of disabling IPv6 use.

	   This problem was partially fixed post-RFC 2553 by adding the
	   AI_ADDRCONFIG flag, which tells getaddrinfo() to only do AAAA queries
	   if the system has at least one IPv6 source address configured, and
	   the same for A and IPv4 (in other words it applies some common sense,
	   which is how it should have behaved in the first place).
	   Unfortunately this flag isn't very widely supported yet, so it usually
	   ends up being no-op'd out by the auto-config.

	   Bounds Checker 6.x may crash in the getaddrinfo() call if maximum 
	   checking is enabled.  To fix this, set the checking level to normal 
	   rather than maximum */
	memset( &hints, 0, sizeof( struct addrinfo ) );
	hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
	if( isServer )
		{
		/* If it's a server, set the AI_PASSIVE flag so that if the
		   interface that we're binding to isn't explicitly specified we get
		   any interface */
		hints.ai_flags |= AI_PASSIVE;
		}
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	if( getaddrinfo( name, portBuffer, &hints, addrInfoPtrPtr ) )
		return( getHostError( netStream, CRYPT_ERROR_OPEN ) );
	return( CRYPT_OK );
	}

STDC_NONNULL_ARG( ( 1 ) ) \
void freeAddressInfo( struct addrinfo *addrInfoPtr )
	{
	assert( addrInfoPtr != NULL );

	freeaddrinfo( addrInfoPtr );
	}

STDC_NONNULL_ARG( ( 1, 2, 4, 5 ) ) \
void getNameInfo( const struct sockaddr *sockAddr, 
				  OUT_BUFFER( addressMaxLen, *addressLen ) char *address, 
				  IN_LENGTH_DNS const int addressMaxLen, 
				  OUT_LENGTH_DNS_Z int *addressLen, 
				  OUT_PORT_Z int *port )
	{
	char nameBuffer[ MAX_DNS_SIZE + 8 ];
	char portBuffer[ 32 + 8 ];
	int nameLength, portLength, localPort, status;

	assert( isReadPtr( sockAddr, sizeof( struct sockaddr ) ) );
	assert( isWritePtr( address, addressMaxLen ) );
	assert( isWritePtr( port, sizeof( int ) ) );

	REQUIRES_V( addressMaxLen >= CRYPT_MAX_TEXTSIZE / 2 && \
				addressMaxLen <= MAX_DNS_SIZE );

	/* Clear return values */
	memcpy( address, "<Unknown>", 9 );
	*addressLen = 9;
	*port = 0;

	/* Some Windows implementations of getnameinfo() call down to
	   getservbyport() assuming that it will always succeed and therefore
	   leave the port/service arg unchanged when it doesn't, so the following
	   call must be made with the NI_NUMERICSERV flag specified (which it
	   would be anyway, cryptlib always treats the port as a numeric arg).
	   Oddly enough the macro version of this function in wspiapi.h used for
	   IPv4-only situations does get it correct */
	if( getnameinfo( sockAddr, sizeof( struct sockaddr ), nameBuffer,
					 MAX_DNS_SIZE, portBuffer, 32,
					 NI_NUMERICHOST | NI_NUMERICSERV ) != 0 )
		{
		assert( DEBUG_WARN );
		return;
		}
	nameLength = strlen( nameBuffer );
	portLength = strlen( portBuffer );
	if( nameLength <= 0 || nameLength > addressMaxLen || \
		portLength <= 0 || portLength > 8 )
		{
		assert( DEBUG_WARN );
		return;
		}
#ifdef EBCDIC_CHARS
	ebcdicToAscii( nameBuffer, nameBuffer, nameLength );
	ebcdicToAscii( portBuffer, portBuffer, portLength );
#endif /* EBCDIC_CHARS */
	memcpy( address, nameBuffer, nameLength );
	*addressLen = nameLength;
	status = strGetNumeric( portBuffer, portLength, &localPort, 1, 65536 );
	if( cryptStatusError( status ) )
		{
		assert( DEBUG_WARN );
		return;
		}
	*port = localPort;
	}
#endif /* USE_TCP */

⌨️ 快捷键说明

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