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

📄 net_tcp.c

📁 老外写的加密库cryptlib(版本3.1)
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 */
	sockAddrPtr->sin_family = AF_INET;
	sockAddrPtr->sin_port = htons( ( in_port_t ) port );
	memcpy( &sockAddrPtr->sin_addr.s_addr, address, IP_ADDR_SIZE );
	*addrInfoPtrPtr = addrInfoPtr;
	return( 0 );
	}

static int 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 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 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__ */

/* 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;

	/* 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 );
		}

	/* If we're doing a full autodetect, we first have to determine the
	   local host's FQDN.  This gets quite tricky because the behavior of
	   gethostbyaddr() changed with Win2K so we have to use the DNS API, but
	   this isn't available in older versions of Windows.  If we're using
	   the DNS API, we have to use the barely-documented
	   DNS_QUERY_BYPASS_CACHE option to get what we want */
	if( gethostname( cachedFQDN, MAX_DNS_SIZE ) == 0 && \
		( hostInfo = gethostbyname( cachedFQDN ) ) != NULL )
		{
		int i;

		for( i = 0; hostInfo->h_addr_list[ i ] != NULL; i++ )
			{
			struct in_addr address;

			/* Reverse the byte order for the in-addr.arpa lookup and
			   convert the address to dotted-decimal notation */
			address.S_un.S_addr = *( ( DWORD * ) hostInfo->h_addr_list[ i ] );
			sprintf( cachedFQDN, "%s.in-addr.arpa", inet_ntoa( address ) );

			/* Check for a name */
			if( DnsQuery( cachedFQDN, DNS_TYPE_PTR, DNS_QUERY_BYPASS_CACHE,
						  NULL, &pDns, NULL ) == 0 )
				break;
			}
		}
	if( pDns == NULL )
		return( setSocketError( stream, "Couldn't determine FQDN of local "
								"machine", CRYPT_ERROR_NOTFOUND, TRUE ) );
	convertToSrv( cachedFQDN, pDns->Data.PTR.pNameHost );
	DnsRecordListFree( pDns, DnsFreeRecordList );

	/* Remember the value we just found to lighten the load on the
	   resolver */
	strcpy( fqdn, cachedFQDN );
	lastFetchTime = getTime();

	return( CRYPT_OK );
	}

static int findHostInfo( STREAM *stream, char *hostName, int *hostPort,
						 const char *name )
	{
	PDNS_RECORD pDns = NULL, pDnsInfo = NULL, pDnsCursor;
	DWORD dwRet;
	int nameLength, priority = 32767;

	/* If we're running on anything other than a heavily-SP'd Win2K or WinXP,
	   there's not much that we can do */
	if( hDNS == NULL_INSTANCE )
		return( setSocketError( stream, "DNS services not available",
								CRYPT_ERROR_NOTFOUND, TRUE ) );

	/* If we're doing a full autodetect, we construct the SRV query using
	   the local machine's FQDN.  This fails more often than not because of
	   NATing and use of private networks, but at least we can try */
	if( !strCompareZ( name, "[Autodetect]" ) )
		{
		const int status = getSrvFQDN( stream, hostName );
		if( cryptStatusError( status ) )
			return( status );
		name = hostName;
		}

	/* Perform a DNS SRV lookup to find the host info.  SRV has basic load-
	   balancing facilities, but for now we just use the highest-priority
	   host we find (it's rarely-enough used that we'll be lucky to find SRV
	   info, let alone any load-balancing setup) */
	dwRet = DnsQuery( ( const LPSTR ) name, DNS_TYPE_SRV, DNS_QUERY_STANDARD,
					  NULL, &pDns, NULL );
	if( dwRet != 0 || pDns == NULL )
		return( getSocketError( stream, CRYPT_ERROR_NOTFOUND ) );
	for( pDnsCursor = pDns; pDnsCursor != NULL;
		 pDnsCursor = pDnsCursor->pNext )
		if( pDnsCursor->Data.SRV.wPriority < priority )
			{
			priority = pDnsCursor->Data.SRV.wPriority;
			pDnsInfo = pDnsCursor;
			}
	if( pDnsInfo == NULL || \
		strlen( pDnsInfo->Data.SRV.pNameTarget ) > MAX_URL_SIZE - 1 )
		{
		DnsRecordListFree( pDns, DnsFreeRecordList );
		return( setSocketError( stream, "Invalid DNS SRV entry for host",
								CRYPT_ERROR_NOTFOUND, TRUE ) );
		}

	/* Copy over the host info for this SRV record */
	nameLength = strlen( pDnsInfo->Data.SRV.pNameTarget ) + 1;
	memcpy( hostName, pDnsInfo->Data.SRV.pNameTarget, nameLength );
	*hostPort = pDnsInfo->Data.SRV.wPort;

	/* Clean up */
	DnsRecordListFree( pDns, DnsFreeRecordList );
	return( CRYPT_OK );
	}

#elif defined( __UNIX__ )

#define SRV_PRIORITY_OFFSET	( NS_RRFIXEDSZ + 0 )
#define SRV_WEIGHT_OFFSET	( NS_RRFIXEDSZ + 2 )
#define SRV_PORT_OFFSET		( NS_RRFIXEDSZ + 4 )
#define SRV_NAME_OFFSET		( NS_RRFIXEDSZ + 6 )

static int getFQDN( STREAM *stream, char *fqdn )
	{
	struct hostent *hostInfo;
	char *hostNamePtr = NULL;
	int i;

	/* First, get the host name, and if it's the FQDN, exit */
	if( gethostname( fqdn, MAX_DNS_SIZE ) == -1 )
		return( CRYPT_ERROR_NOTFOUND );
	if( strchr( fqdn, '.' ) != NULL )
		/* If the hostname has a dot in it, it's the FQDN */
		return( CRYPT_OK );

	/* Now get the hostent info and walk through it looking for the FQDN */
	if( ( hostInfo = gethostbyname( fqdn ) ) == NULL )
		return( CRYPT_ERROR_NOTFOUND );
	for( i = 0; hostInfo->h_addr_list[ i ] != NULL; i++ )
		{
		char **aliasPtrPtr;

		/* If the hostname has a dot in it, it's the FQDN.  This should be
		   the same as the gethostname() output, but we check again just in
		   case */
		if( strchr( hostInfo->h_name, '.' ) != NULL )
			{
			hostNamePtr = hostInfo->h_name;
			break;
			}

		/* Try for the FQDN in the aliases */
		if( hostInfo->h_aliases == NULL )
			continue;
		for( aliasPtrPtr = hostInfo->h_aliases;
			 *aliasPtrPtr != NULL && !strchr( *aliasPtrPtr, '.' );
			 aliasPtrPtr++ );
		if( *aliasPtrPtr != NULL )
			{
			hostNamePtr = *aliasPtrPtr;
			break;
			}
		}
	if( hostNamePtr == NULL )
		return( CRYPT_ERROR_NOTFOUND );

	/* We found the FQDN, return it to the caller */
	strcpy( fqdn, hostNamePtr );
	return( CRYPT_OK );
	}

static int findHostInfo( STREAM *stream, char *hostName, int *hostPort,
						 const char *name )
	{
	union {
		HEADER header;
		BYTE buffer[ NS_PACKETSZ ];
		} dnsQueryInfo;
	char *namePtr, *endPtr;
	int resultLen, nameLen, qCount, aCount, minPriority = 32767, i;

	/* If we're doing a full autodetect, we construct the SRV query using
	   the local machine's FQDN.  This fails more often than not because of
	   NATing and use of private networks, but at least we can try */
	if( !strCompareZ( name, "[Autodetect]" ) )
		{
		const int status = getFQDN( stream, hostName );
		if( cryptStatusError( status ) )
			return( status );
		name = hostName;
		}
#ifdef EBCDIC_CHARS
	else
		/* We're about to use OS functions, convert the input to EBCDIC.  If
		   we've used autodetection, the output from getFQDN will already be
		   in EBCDIC form */
		name = bufferToEbcdic( hostName, name );
#endif /* EBCDIC_CHARS */

	/* Try and fetch a DNS SRV record (RFC 2782) matching the host info */
	resultLen = res_query( name, C_IN, T_SRV, dnsQueryInfo.buffer,
						   NS_PACKETSZ );
	if( resultLen < NS_HFIXEDSZ || resultLen > NS_PACKETSZ )
		return( getSocketError( stream, CRYPT_ERROR_NOTFOUND ) );
	if( dnsQueryInfo.header.rcode || dnsQueryInfo.header.tc )
		/* If we get a non-zero response code (rcode) or the results were
		   truncated (tc), we can't go any further.  In theory a truncated
		   response is probably OK since many servers return the address
		 

⌨️ 快捷键说明

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