📄 dns.c
字号:
/****************************************************************************
* *
* cryptlib DNS Interface Routines *
* Copyright Peter Gutmann 1998-2007 *
* *
****************************************************************************/
#include <ctype.h>
#if defined( INC_ALL )
#include "crypt.h"
#include "stream_int.h"
#include "tcp.h"
#else
#include "crypt.h"
#include "io/stream_int.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 */
#ifndef TEXT
#define TEXT /* Win32 windows.h defines this, but not the Win16 one */
#endif /* TEXT */
#if defined( _MSC_VER ) && defined( _PREFAST_ )
#define OUT_STRING_OPT __out_bcount_z
#else
#define OUT_STRING_OPT( size )
#endif /* Additional markups for Win32 API functions */
typedef void ( SOCKET_API *FREEADDRINFO )( INOUT struct addrinfo *ai ) \
STDC_NONNULL_ARG( ( 1 ) );
typedef CHECK_RETVAL int ( SOCKET_API *GETADDRINFO )\
( IN_STRING const char *nodename,
IN_STRING const char *servname,
const struct addrinfo *hints,
OUT_PTR struct addrinfo **res );
typedef CHECK_RETVAL struct hostent FAR * ( SOCKET_API *GETHOSTBYNAME )\
( IN_STRING const char FAR *name ) \
STDC_NONNULL_ARG( ( 1 ) );
typedef CHECK_RETVAL int ( SOCKET_API *GETNAMEINFO )\
( IN_BUFFER( salen ) const struct sockaddr *sa,
IN SIZE_TYPE salen,
OUT_BUFFER_FIXED( nodelen ) char *node,
IN SIZE_TYPE nodelen,
OUT_STRING_OPT( servicelen ) char *service,
IN SIZE_TYPE servicelen, int flags ) \
STDC_NONNULL_ARG( ( 1, 3, 5 ) );
typedef CHECK_RETVAL u_long ( SOCKET_API *HTONL )( u_long hostlong );
typedef CHECK_RETVAL u_short ( SOCKET_API *HTONS )( u_short hostshort );
typedef CHECK_RETVAL unsigned long ( SOCKET_API *INET_ADDR )\
( IN_STRING const char FAR *cp ) \
STDC_NONNULL_ARG( ( 1 ) );
typedef CHECK_RETVAL char FAR * ( SOCKET_API *INET_NTOA )( struct in_addr in );
typedef CHECK_RETVAL u_long ( SOCKET_API *NTOHL )( u_long netlong );
typedef CHECK_RETVAL u_short ( SOCKET_API *NTOHS )( u_short netshort );
typedef int ( SOCKET_API *WSAGETLASTERROR )( void );
static FREEADDRINFO pfreeaddrinfo = NULL;
static GETADDRINFO pgetaddrinfo = NULL;
static GETHOSTBYNAME pgethostbyname = 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 WSAGETLASTERROR pWSAGetLastError = NULL;
#define freeaddrinfo pfreeaddrinfo
#define getaddrinfo pgetaddrinfo
#define gethostbyname pgethostbyname
#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
#ifndef WSAGetLastError
/* In some environments WSAGetLastError() is a macro that maps to
GetLastError() */
#define WSAGetLastError pWSAGetLastError
#define DYNLOAD_WSAGETLASTERROR
#endif /* WSAGetLastError */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
static int SOCKET_API my_getaddrinfo( IN_STRING const char *nodename,
IN_STRING const char *servname,
const struct addrinfo *hints,
OUT_PTR struct addrinfo **res );
STDC_NONNULL_ARG( ( 1 ) ) \
static void SOCKET_API my_freeaddrinfo( IN struct addrinfo *ai );
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 SIZE_TYPE nodelen,
OUT_BUFFER_FIXED( servicelen ) \
char *service,
IN SIZE_TYPE servicelen, IN int flags );
CHECK_RETVAL \
int initDNS( const INSTANCE_HANDLE hTCP, const INSTANCE_HANDLE hAddr )
{
/* Get the required TCP/IP functions */
gethostbyname = ( GETHOSTBYNAME ) DynamicBind( hTCP, TEXT( "gethostbyname" ) );
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 || 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;
}
/* If the DNS SRV init fails it's not a serious problem, we can continue
without it */
( void ) initDNSSRV( hTCP );
return( CRYPT_OK );
}
void endDNS( const INSTANCE_HANDLE hTCP )
{
endDNSSRV( hTCP );
}
#endif /* __WINDOWS__ */
/****************************************************************************
* *
* IPv6 Emulation *
* *
****************************************************************************/
/* Emulation of IPv6 networking functions. We include these unconditionally
under Windows because with dynamic binding we can't be sure whether
they're needed or not */
#if !defined( IPv6 ) || defined( __WINDOWS__ )
CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
static int addAddrInfo( INOUT_OPT struct addrinfo *prevAddrInfoPtr,
OUT_PTR struct addrinfo **addrInfoPtrPtr,
IN_BUFFER( addrLen ) const void *address,
IN_RANGE( IP_ADDR_SIZE, IP_ADDR_SIZE ) \
const int addrLen, IN_PORT const int port )
{
struct addrinfo *addrInfoPtr;
struct sockaddr_in *sockAddrPtr;
assert( prevAddrInfoPtr == NULL || \
isWritePtr( prevAddrInfoPtr, sizeof( struct addrinfo ) ) );
assert( isWritePtr( addrInfoPtrPtr, sizeof( struct addrinfo * ) ) );
assert( isReadPtr( address, addrLen ) );
REQUIRES( addrLen == IP_ADDR_SIZE );
REQUIRES( port >= 22 && port < 65536L );
/* Clear return value */
*addrInfoPtrPtr = NULL;
/* 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, addrLen );
*addrInfoPtrPtr = addrInfoPtr;
return( 0 );
}
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
static int SOCKET_API my_getaddrinfo( IN_STRING const char *nodename,
IN_STRING const char *servname,
const struct addrinfo *hints,
OUT_PTR 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 ) ) );
assert( isWritePtr( res, sizeof( struct addrinfo * ) ) );
assert( sizeof( in_addr_t ) == IP_ADDR_SIZE );
/* Clear return value */
*res = NULL;
/* 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( ( nodename == NULL && !( hints->ai_flags & AI_PASSIVE ) ) || \
servname == NULL || hints == NULL || res == 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 that it finds */
if( nodename == NULL && ( hints->ai_flags & AI_PASSIVE ) )
{
const in_addr_t address = INADDR_ANY;
return( addAddrInfo( NULL, res, &address, sizeof( in_addr_t ),
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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -