cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
dns.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib DNS Interface Routines *
4 * Copyright Peter Gutmann 1998-2007 *
5 * *
6 ****************************************************************************/
7 
8 #include <ctype.h>
9 #if defined( INC_ALL )
10  #include "crypt.h"
11  #include "stream_int.h"
12  #include "tcp.h"
13 #else
14  #include "crypt.h"
15  #include "io/stream_int.h"
16  #include "io/tcp.h"
17 #endif /* Compiler-specific includes */
18 
19 #ifdef USE_TCP
20 
21 /****************************************************************************
22 * *
23 * Init/Shutdown Routines *
24 * *
25 ****************************************************************************/
26 
27 #ifdef __WINDOWS__
28 
29 /* Global function pointers. These are necessary because the functions need
30  to be dynamically linked since not all systems contain the necessary
31  libraries */
32 
33 #if ( defined( sun ) && OSVERSION > 4 )
34 #undef htonl /* Slowaris has defines that conflict with our ones */
35 #undef htons
36 #undef ntohl
37 #undef ntohs
38 #endif /* Slowaris */
39 
40 #ifndef TEXT
41  #define TEXT /* Win32 windows.h defines this, but not the Win16 one */
42 #endif /* TEXT */
43 
44 #if defined( _MSC_VER ) && defined( _PREFAST_ )
45  #define OUT_STRING_OPT __out_bcount_z
46 #else
47  #define OUT_STRING_OPT( size )
48 #endif /* Additional markups for Win32 API functions */
49 
50 typedef void ( SOCKET_API *FREEADDRINFO )( INOUT struct addrinfo *ai ) \
51  STDC_NONNULL_ARG( ( 1 ) );
52 typedef CHECK_RETVAL int ( SOCKET_API *GETADDRINFO )\
53  ( IN_STRING const char *nodename,
54  IN_STRING const char *servname,
55  const struct addrinfo *hints,
56  OUT_PTR struct addrinfo **res );
57 typedef CHECK_RETVAL struct hostent FAR * ( SOCKET_API *GETHOSTBYNAME )\
58  ( IN_STRING const char FAR *name ) \
59  STDC_NONNULL_ARG( ( 1 ) );
60 typedef CHECK_RETVAL int ( SOCKET_API *GETNAMEINFO )\
61  ( IN_BUFFER( salen ) const struct sockaddr *sa,
62  IN SIZE_TYPE salen,
63  OUT_BUFFER_FIXED( nodelen ) char *node,
64  IN SIZE_TYPE nodelen,
65  OUT_STRING_OPT( servicelen ) char *service,
66  IN SIZE_TYPE servicelen, int flags ) \
67  STDC_NONNULL_ARG( ( 1, 3, 5 ) );
68 typedef CHECK_RETVAL u_long ( SOCKET_API *HTONL )( u_long hostlong );
69 typedef CHECK_RETVAL u_short ( SOCKET_API *HTONS )( u_short hostshort );
70 typedef CHECK_RETVAL unsigned long ( SOCKET_API *INET_ADDR )\
71  ( IN_STRING const char FAR *cp ) \
72  STDC_NONNULL_ARG( ( 1 ) );
73 typedef CHECK_RETVAL char FAR * ( SOCKET_API *INET_NTOA )( struct in_addr in );
74 typedef CHECK_RETVAL u_long ( SOCKET_API *NTOHL )( u_long netlong );
75 typedef CHECK_RETVAL u_short ( SOCKET_API *NTOHS )( u_short netshort );
76 typedef int ( SOCKET_API *WSAGETLASTERROR )( void );
77 
78 static FREEADDRINFO pfreeaddrinfo = NULL;
79 static GETADDRINFO pgetaddrinfo = NULL;
80 static GETHOSTBYNAME pgethostbyname = NULL;
81 static GETNAMEINFO pgetnameinfo = NULL;
82 static HTONL phtonl = NULL;
83 static HTONS phtons = NULL;
84 static INET_ADDR pinet_addr = NULL;
85 static INET_NTOA pinet_ntoa = NULL;
86 static NTOHL pntohl = NULL;
87 static NTOHS pntohs = NULL;
88 static WSAGETLASTERROR pWSAGetLastError = NULL;
89 
90 #define freeaddrinfo pfreeaddrinfo
91 #define getaddrinfo pgetaddrinfo
92 #define gethostbyname pgethostbyname
93 #define getnameinfo pgetnameinfo
94 #define htonl phtonl
95 #define htons phtons
96 #define inet_addr pinet_addr
97 #define inet_ntoa pinet_ntoa
98 #define ntohl pntohl
99 #define ntohs pntohs
100 #ifndef WSAGetLastError
101  /* In some environments WSAGetLastError() is a macro that maps to
102  GetLastError() */
103  #define WSAGetLastError pWSAGetLastError
104  #define DYNLOAD_WSAGETLASTERROR
105 #endif /* WSAGetLastError */
106 
107 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
108 static int SOCKET_API my_getaddrinfo( IN_STRING const char *nodename,
109  IN_STRING const char *servname,
110  const struct addrinfo *hints,
111  OUT_PTR struct addrinfo **res );
112 STDC_NONNULL_ARG( ( 1 ) ) \
113 static void SOCKET_API my_freeaddrinfo( IN struct addrinfo *ai );
114 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
115 static int SOCKET_API my_getnameinfo( IN_BUFFER( salen ) \
116  const struct sockaddr *sa,
117  IN SIZE_TYPE salen,
118  OUT_BUFFER_FIXED( nodelen ) char *node,
119  IN SIZE_TYPE nodelen,
120  OUT_BUFFER_FIXED( servicelen ) \
121  char *service,
122  IN SIZE_TYPE servicelen, IN int flags );
123 
124 CHECK_RETVAL \
125 int initDNS( const INSTANCE_HANDLE hTCP, const INSTANCE_HANDLE hAddr )
126  {
127  /* Get the required TCP/IP functions */
128  gethostbyname = ( GETHOSTBYNAME ) DynamicBind( hTCP, TEXT( "gethostbyname" ) );
129  htonl = ( HTONL ) DynamicBind( hTCP, TEXT( "htonl" ) );
130  htons = ( HTONS ) DynamicBind( hTCP, TEXT( "htons" ) );
131  inet_addr = ( INET_ADDR ) DynamicBind( hTCP, TEXT( "inet_addr" ) );
132  inet_ntoa = ( INET_NTOA ) DynamicBind( hTCP, TEXT( "inet_ntoa" ) );
133  ntohl = ( NTOHL ) DynamicBind( hTCP, TEXT( "ntohl" ) );
134  ntohs = ( NTOHS ) DynamicBind( hTCP, TEXT( "ntohs" ) );
135  #ifdef DYNLOAD_WSAGETLASTERROR
136  WSAGetLastError = ( WSAGETLASTERROR ) DynamicBind( hTCP, TEXT( "WSAGetLastError" ) );
137  #endif /* DYNLOAD_WSAGETLASTERROR */
138  if( gethostbyname == NULL || htonl == NULL || htons == NULL || \
139  inet_addr == NULL || inet_ntoa == NULL || ntohl == NULL || \
140  ntohs == NULL )
141  return( CRYPT_ERROR );
142 
143  /* Set up the IPv6-style name/address functions */
144  if( hAddr != NULL_INSTANCE )
145  {
146  freeaddrinfo = ( FREEADDRINFO ) DynamicBind( hAddr, TEXT( "freeaddrinfo" ) );
147  getaddrinfo = ( GETADDRINFO ) DynamicBind( hAddr, TEXT( "getaddrinfo" ) );
148  getnameinfo = ( GETNAMEINFO ) DynamicBind( hAddr, TEXT( "getnameinfo" ) );
149  if( freeaddrinfo == NULL || getaddrinfo == NULL || \
150  getnameinfo == NULL )
151  return( CRYPT_ERROR );
152  }
153  else
154  {
155  /* If we couldn't dynamically bind the IPv6 name/address functions,
156  use a local emulation */
157  getaddrinfo = my_getaddrinfo;
158  freeaddrinfo = my_freeaddrinfo;
159  getnameinfo = my_getnameinfo;
160  }
161 
162  /* If the DNS SRV init fails it's not a serious problem, we can continue
163  without it */
164  ( void ) initDNSSRV( hTCP );
165 
166  return( CRYPT_OK );
167  }
168 
169 void endDNS( const INSTANCE_HANDLE hTCP )
170  {
171  endDNSSRV( hTCP );
172  }
173 #endif /* __WINDOWS__ */
174 
175 /****************************************************************************
176 * *
177 * IPv6 Emulation *
178 * *
179 ****************************************************************************/
180 
181 /* Emulation of IPv6 networking functions. We include these unconditionally
182  under Windows because with dynamic binding we can't be sure whether
183  they're needed or not */
184 
185 #if !defined( IPv6 ) || defined( __WINDOWS__ )
186 
187 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
188 static int addAddrInfo( INOUT_OPT struct addrinfo *prevAddrInfoPtr,
189  OUT_PTR struct addrinfo **addrInfoPtrPtr,
190  IN_BUFFER( addrLen ) const void *address,
191  IN_RANGE( IP_ADDR_SIZE, IP_ADDR_SIZE ) \
192  const int addrLen, IN_PORT const int port )
193  {
194  struct addrinfo *addrInfoPtr;
195  struct sockaddr_in *sockAddrPtr;
196 
197  assert( prevAddrInfoPtr == NULL || \
198  isWritePtr( prevAddrInfoPtr, sizeof( struct addrinfo ) ) );
199  assert( isWritePtr( addrInfoPtrPtr, sizeof( struct addrinfo * ) ) );
200  assert( isReadPtr( address, addrLen ) );
201 
202  REQUIRES( addrLen == IP_ADDR_SIZE );
203  REQUIRES( port >= 22 && port < 65536L );
204 
205  /* Clear return value */
206  *addrInfoPtrPtr = NULL;
207 
208  /* Allocate the new element, clear it, and set fixed fields for IPv4 */
209  addrInfoPtr = clAlloc( "addAddrInfo", sizeof( struct addrinfo ) );
210  sockAddrPtr = clAlloc( "addAddrInfo", sizeof( struct sockaddr_in ) );
211  if( addrInfoPtr == NULL || sockAddrPtr == NULL )
212  {
213  if( addrInfoPtr != NULL )
214  clFree( "addAddrInfo", addrInfoPtr );
215  if( sockAddrPtr != NULL )
216  clFree( "addAddrInfo", sockAddrPtr );
217  return( -1 );
218  }
219  memset( addrInfoPtr, 0, sizeof( struct addrinfo ) );
220  memset( sockAddrPtr, 0, sizeof( struct sockaddr_in ) );
221  if( prevAddrInfoPtr != NULL )
222  prevAddrInfoPtr->ai_next = addrInfoPtr;
223  addrInfoPtr->ai_family = PF_INET;
224  addrInfoPtr->ai_socktype = SOCK_STREAM;
225  addrInfoPtr->ai_protocol = IPPROTO_TCP;
226  addrInfoPtr->ai_addrlen = sizeof( struct sockaddr_in );
227  addrInfoPtr->ai_addr = ( struct sockaddr * ) sockAddrPtr;
228 
229  /* Set the port and address information. In general we'd copy the
230  address to the sockAddrPtr->sin_addr.s_addr member, however on
231  Crays, which don't have 32-bit data types, this is a 32-bit
232  bitfield, so we have to use the encapsulating struct */
233  sockAddrPtr->sin_family = AF_INET;
234  sockAddrPtr->sin_port = htons( ( in_port_t ) port );
235  memcpy( &sockAddrPtr->sin_addr, address, addrLen );
236  *addrInfoPtrPtr = addrInfoPtr;
237  return( 0 );
238  }
239 
240 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3, 4 ) ) \
241 static int SOCKET_API my_getaddrinfo( IN_STRING const char *nodename,
242  IN_STRING const char *servname,
243  const struct addrinfo *hints,
244  OUT_PTR struct addrinfo **res )
245  {
246  struct hostent *pHostent;
247  struct addrinfo *currentAddrInfoPtr = NULL;
248  int port, hostErrno, i, status;
249  gethostbyname_vars();
250 
251  assert( isReadPtr( hints, sizeof( struct addrinfo ) ) );
252  assert( isWritePtr( res, sizeof( struct addrinfo * ) ) );
253 
254  static_assert( sizeof( in_addr_t ) == IP_ADDR_SIZE, \
255  "in_addr_t size" );
256 
257  REQUIRES( nodename != NULL || ( hints->ai_flags & AI_PASSIVE ) );
258  REQUIRES( servname != NULL );
259 
260  /* Clear return value */
261  *res = NULL;
262 
263  /* Perform basic error checking. Since this is supposed to be an
264  emulation of a (normally) built-in function we don't perform any
265  REQUIRES()-style checking but only apply the basic checks that the
266  normal built-in form does */
267  if( ( nodename == NULL && !( hints->ai_flags & AI_PASSIVE ) ) || \
268  servname == NULL || hints == NULL || res == NULL )
269  return( -1 );
270 
271  /* Convert the text-string port number into a numeric value */
272  status = strGetNumeric( servname, strlen( servname ), &port, 1, 65535 );
273  if( cryptStatusError( status ) )
274  return( - 1 );
275 
276  /* If there's no interface specified and we're creating a server-side
277  socket, prepare to listen on any interface. Note that BeOS can only
278  bind to one interface at a time, so INADDR_ANY actually binds to the
279  first interface that it finds */
280  if( nodename == NULL && ( hints->ai_flags & AI_PASSIVE ) )
281  {
282  const in_addr_t address = INADDR_ANY;
283 
284  return( addAddrInfo( NULL, res, &address, sizeof( in_addr_t ),
285  port ) );
286  }
287 
288  /* If it's a dotted address, there's a single address, convert it to
289  in_addr form and return it. Note for EBCDIC use that since this is
290  an emulation of an OS function the string is already in EBCDIC form,
291  so we don't use the cryptlib-internal functions for this */
292  if( isdigit( *nodename ) )
293  {
294  const in_addr_t address = inet_addr( nodename );
295 
296  if( isBadAddress( address ) )
297  return( -1 );
298  return( addAddrInfo( NULL, res, &address, sizeof( in_addr_t ),
299  port ) );
300  }
301 
302  /* It's a host name, convert it to the in_addr form */
303  gethostbyname_threadsafe( nodename, pHostent, hostErrno );
304  if( pHostent == NULL )
305  return( -1 );
306  ENSURES( pHostent->h_length == IP_ADDR_SIZE );
307  for( i = 0; i < IP_ADDR_COUNT && \
308  pHostent->h_addr_list[ i ] != NULL; i++ )
309  {
310  int status;
311 
312  if( currentAddrInfoPtr == NULL )
313  {
314  status = addAddrInfo( NULL, res, pHostent->h_addr_list[ i ],
315  pHostent->h_length, port );
316  currentAddrInfoPtr = *res;
317  }
318  else
319  status = addAddrInfo( currentAddrInfoPtr, &currentAddrInfoPtr,
320  pHostent->h_addr_list[ i ],
321  pHostent->h_length, port );
322  if( status != 0 )
323  {
324  freeaddrinfo( *res );
325  return( status );
326  }
327  }
328  return( 0 );
329  }
330 
331 STDC_NONNULL_ARG( ( 1 ) ) \
332 static void SOCKET_API my_freeaddrinfo( INOUT struct addrinfo *ai )
333  {
334  int i;
335 
336  assert( isWritePtr( ai, sizeof( struct addrinfo ) ) );
337 
338  /* Perform basic error checking. Since this is supposed to be an
339  emulation of a (normally) built-in function we don't perform any
340  REQUIRES()-style checking but only apply the basic checks that the
341  normal built-in form does */
342  if( ai == NULL )
343  return;
344 
345  for( i = 0; ai != NULL && i < IP_ADDR_COUNT; i++ )
346  {
347  struct addrinfo *addrInfoCursor = ai;
348 
349  ai = ai->ai_next;
350  if( addrInfoCursor->ai_addr != NULL )
351  clFree( "my_freeaddrinfo", addrInfoCursor->ai_addr );
352  clFree( "my_freeaddrinfo", addrInfoCursor );
353  }
354  }
355 
356 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 5 ) ) \
357 static int SOCKET_API my_getnameinfo( IN_BUFFER( salen ) \
358  const struct sockaddr *sa,
359  IN SIZE_TYPE salen,
360  OUT_BUFFER_FIXED( nodelen ) char *node,
361  IN_LENGTH_SHORT SIZE_TYPE nodelen,
362  OUT_BUFFER_FIXED( servicelen ) \
363  char *service,
364  IN_LENGTH_SHORT SIZE_TYPE servicelen,
365  IN int flags )
366  {
367  const struct sockaddr_in *sockAddr = ( struct sockaddr_in * ) sa;
368  const char *ipAddress;
369 
370  assert( isReadPtr( sa, salen ) && salen >= sizeof( struct sockaddr_in ) );
371  assert( isReadPtr( node, nodelen ) && nodelen >= 10 );
372  assert( isReadPtr( service, servicelen ) && servicelen >= 8 );
373 
374  /* Perform basic error checking. Since this is supposed to be an
375  emulation of a (normally) built-in function we don't perform any
376  REQUIRES()-style checking but only apply the basic checks that the
377  normal built-in form does */
378  if( sa == NULL || \
379  salen < sizeof( struct sockaddr_in ) || \
380  salen > MAX_INTLENGTH_SHORT || \
381  node == NULL || \
382  nodelen < 10 || nodelen > MAX_INTLENGTH_SHORT || \
383  service == NULL || \
384  servicelen < 8 || servicelen > MAX_INTLENGTH_SHORT )
385  return( -1 );
386 
387  /* Clear return values */
388  strlcpy_s( node, nodelen, "<Unknown>" );
389  strlcpy_s( service, servicelen, "0" );
390 
391  /* Get the remote system's address and port number */
392  if( ( ipAddress = inet_ntoa( sockAddr->sin_addr ) ) == NULL )
393  return( -1 );
394  memcpy( node, ipAddress, nodelen );
395  node[ nodelen - 1 ] = '\0';
396  if( sprintf_s( service, servicelen, "%d",
397  ntohs( sockAddr->sin_port ) ) < 0 )
398  return( -1 );
399 
400  return( 0 );
401  }
402 #endif /* !IPv6 || __WINDOWS__ */
403 
404 /****************************************************************************
405 * *
406 * DNS Interface *
407 * *
408 ****************************************************************************/
409 
410 /* Get a host's IP address */
411 
412 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
413 int getAddressInfo( INOUT NET_STREAM_INFO *netStream,
414  OUT_PTR struct addrinfo **addrInfoPtrPtr,
415  IN_BUFFER_OPT( nameLen ) const char *name,
416  IN_LENGTH_Z const int nameLen,
417  IN_PORT const int port, const BOOLEAN isServer )
418  {
419  struct addrinfo hints;
420  char nameBuffer[ MAX_DNS_SIZE + 8 ], portBuffer[ 16 + 8 ];
421 
422  assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
423  assert( isWritePtr( addrInfoPtrPtr, sizeof( struct addrinfo * ) ) );
424  assert( isServer || name != NULL );
425 
426  REQUIRES( port >= 22 && port < 65536L );
427  REQUIRES( isServer || \
428  ( !isServer && name != NULL ) );
429  REQUIRES( ( name == NULL && nameLen == 0 ) || \
430  ( name != NULL && \
431  nameLen > 0 && nameLen < MAX_DNS_SIZE ) );
432 
433  /* Convert the name and port into the null-terminated text-string format
434  required by getaddrinfo(). The reason why the port is given as a
435  string rather than a port number is that we can also optionally
436  specify the port to connect to via a service name. Of course it's
437  more or less pot luck whether the service you want is a recognised
438  one so everyone specifies the port anyway, however the reason why
439  this unnecessary flexibility is there is because getaddrinfo() was
440  seen as a universal replacement for a pile of other functions,
441  including (for this case) getservbyname() */
442  if( name != NULL )
443  {
444  memcpy( nameBuffer, name, nameLen );
445  nameBuffer[ nameLen ] = '\0';
446  name = nameBuffer;
447  }
448  sprintf_s( portBuffer, 8, "%d", port );
449 
450  /* If we're a client and using auto-detection of a PKI service, try and
451  locate it via DNS SRV */
452  if( !isServer && name != NULL && nameLen == 12 && \
453  ( !memcmp( name, "[Autodetect]", 12 ) || *name == '_' ) )
454  {
455  int localPort, status;
456 
457  status = findHostInfo( netStream, nameBuffer, MAX_DNS_SIZE,
458  &localPort, name, nameLen );
459  if( cryptStatusError( status ) )
460  return( status );
461  name = nameBuffer;
462  sprintf_s( portBuffer, 8, "%d", localPort );
463  }
464 
465  /* Convert the address information to the system character set if
466  required */
467 #ifdef EBCDIC_CHARS
468  if( name != NULL )
469  bufferToEbcdic( nameBuffer, nameBuffer );
470  bufferToEbcdic( portBuffer, portBuffer );
471 #endif /* EBCDIC_CHARS */
472 
473  /* Set up the port information and hint information needed by
474  getaddrinfo(). The use of PF_UNSPEC is a bit problematic because RFC
475  2553 is usually interpreted to mean "look for all addresses" rather
476  than the more sensible "look for any address". The reason why this
477  is a problem is because getaddrinfo() ends up looking for unnecessary
478  IPv6 addresses, either by returning IPv6 addresses when the system
479  doesn't do IPv6 or spending a lot of time groping around for IPv6
480  stuff and/or further unnecessary addresses when it's already got what
481  it needs. This is made worse by confusion over implementation
482  details, for example early implementations of getaddrinfo() in glibc
483  would always try an AAAA lookup even on an IPv4-only system/network,
484  resulting in long delays as the resolver timed out and fell back to a
485  straight A lookup. There was some disagreement over whether this was
486  right or wrong, and how to fix it (IPv6 purists who never noticed the
487  problem seemed to think that it was right, everyone else thought that
488  it was wrong). Variations of this problem exist, e.g. if an IPv4
489  address is in /etc/hosts and DNS is down, the resolver will still
490  spend ages (several minutes in some cases) groping around for an IPv6
491  address before it finally gives up and falls back to what it already
492  knows from /etc/hosts. Switching the hint from AF_UNSPEC to AF_INET
493  bypasses this problem, but has the downside of disabling IPv6 use.
494 
495  This problem was partially fixed post-RFC 2553 by adding the
496  AI_ADDRCONFIG flag, which tells getaddrinfo() to only do AAAA queries
497  if the system has at least one IPv6 source address configured, and
498  the same for A and IPv4 (in other words it applies some common sense,
499  which is how it should have behaved in the first place).
500  Unfortunately this flag isn't very widely supported yet, so it usually
501  ends up being no-op'd out by the auto-config.
502 
503  In addition under Windows Vista/Windows 7 there are always IPv6
504  addresses in use by a bunch of Windows services that simultaneously
505  listen on IPv4 and IPv6 addresses, so that things regress back to the
506  pre-AI_ADDRCONFIG behaviour, although there seems to be some
507  optimisation in place to prevent the DNS-lookup issues from coming
508  back as well. Unfortunately this also means that an attempt to look
509  up an address like "localhost" for a server-side socket will
510  preferentially return an IPv6 address [::1] rather than an IPv4
511  address 127.0.0.1, which works if the client also gets a IPv6 address
512  but not if it's expecting the more usual IPv4 one.
513 
514  Bounds Checker 6.x may crash in the getaddrinfo() call if maximum
515  checking is enabled. To fix this, set the checking level to normal
516  rather than maximum */
517  memset( &hints, 0, sizeof( struct addrinfo ) );
518  hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
519  if( isServer )
520  {
521  /* If it's a server, set the AI_PASSIVE flag so that if the
522  interface that we're binding to isn't explicitly specified we get
523  any interface */
524  hints.ai_flags |= AI_PASSIVE;
525  }
526 #if 1
527  hints.ai_family = PF_UNSPEC;
528 #else
529  BOOLEAN forceIPv4 = FALSE;
530  int preferIPV4;
531 
532  status = krnlSendMessage( certInfoPtr->ownerHandle,
533  IMESSAGE_GETATTRIBUTE, &preferIPV4,
534  CRYPT_OPTION_PREFERIPV4 );
535  if( cryptStatusOK( status ) && preferIPV4 )
536  {
537  /* Override any potential defaulting to IPv6 by the local system
538  to force the use of IPv4, which is going to be far more probable
539  than IPv6 for the foreseeable future */
540  hints.ai_family = PF_INET;
541  forceIPv4 = TRUE;
542  }
543  else
544  {
545  /* Just use whatever the local system gives us */
546  hints.ai_family = PF_UNSPEC;
547  }
548 #endif /* 1 */
549  hints.ai_socktype = SOCK_STREAM;
550  if( getaddrinfo( name, portBuffer, &hints, addrInfoPtrPtr ) )
551  {
552 #if 0
553  if( !forceIPv4 )
554  return( getHostError( netStream, CRYPT_ERROR_OPEN ) );
555 
556  /* We overrode the protocol-type selection, which may have been the
557  cause of the failure, try again with whatever we can get rather
558  than forcing IPv4 */
559  hints.ai_family = PF_UNSPEC;
560  if( getaddrinfo( name, portBuffer, &hints, addrInfoPtrPtr ) )
561  return( getHostError( netStream, CRYPT_ERROR_OPEN ) );
562 #else
563  return( getHostError( netStream, CRYPT_ERROR_OPEN ) );
564 #endif /* 0 */
565  }
566  return( CRYPT_OK );
567  }
568 
569 STDC_NONNULL_ARG( ( 1 ) ) \
570 void freeAddressInfo( struct addrinfo *addrInfoPtr )
571  {
572  assert( isWritePtr( addrInfoPtr, sizeof( struct addrinfo ) ) );
573 
574  freeaddrinfo( addrInfoPtr );
575  }
576 
577 STDC_NONNULL_ARG( ( 1, 3, 5, 6 ) ) \
578 void getNameInfo( IN_BUFFER( sockAddrLen ) const void *sockAddr,
579  IN_LENGTH_SHORT_MIN( 8 ) const int sockAddrLen,
580  OUT_BUFFER( addressMaxLen, *addressLen ) char *address,
581  IN_LENGTH_DNS const int addressMaxLen,
582  OUT_LENGTH_DNS_Z int *addressLen,
583  OUT_PORT_Z int *port )
584  {
585  char nameBuffer[ MAX_DNS_SIZE + 8 ];
586  char portBuffer[ 32 + 8 ];
587  int nameLength, portLength, localPort, status;
588 
589  assert( isReadPtr( sockAddr, sockAddrLen ) );
590  assert( isWritePtr( address, addressMaxLen ) );
591  assert( isWritePtr( port, sizeof( int ) ) );
592 
593  REQUIRES_V( sockAddrLen >= 8 && sockAddrLen < MAX_INTLENGTH_SHORT );
594  REQUIRES_V( addressMaxLen >= CRYPT_MAX_TEXTSIZE / 2 && \
595  addressMaxLen <= MAX_DNS_SIZE );
596 
597  /* Clear return values */
598  memcpy( address, "<Unknown>", 9 );
599  *addressLen = 9;
600  *port = 0;
601 
602  /* Some Windows implementations of getnameinfo() call down to
603  getservbyport() assuming that it will always succeed and therefore
604  leave the port/service argument unchanged when it doesn't, so the
605  following call must be made with the NI_NUMERICSERV flag specified
606  (which it would be anyway, cryptlib always treats the port as a
607  numeric arg). Oddly enough the macro version of this function in
608  wspiapi.h used for IPv4-only situations does get it correct */
609  if( getnameinfo( sockAddr, sockAddrLen, nameBuffer, MAX_DNS_SIZE,
610  portBuffer, 32, NI_NUMERICHOST | NI_NUMERICSERV ) != 0 )
611  {
612  DEBUG_DIAG(( "Couldn't get host name for socket" ));
613  assert( DEBUG_WARN );
614  return;
615  }
616  nameLength = strlen( nameBuffer );
617  portLength = strlen( portBuffer );
618  if( nameLength <= 0 || nameLength > addressMaxLen || \
619  portLength <= 0 || portLength > 8 )
620  {
621  DEBUG_DIAG(( "Returned host name data is invalid" ));
622  assert( DEBUG_WARN );
623  return;
624  }
625 #ifdef EBCDIC_CHARS
626  ebcdicToAscii( nameBuffer, nameBuffer, nameLength );
627  ebcdicToAscii( portBuffer, portBuffer, portLength );
628 #endif /* EBCDIC_CHARS */
629  memcpy( address, nameBuffer, nameLength );
630  *addressLen = nameLength;
631  status = strGetNumeric( portBuffer, portLength, &localPort, 1, 65536 );
632  if( cryptStatusError( status ) )
633  {
634  DEBUG_DIAG(( "Returned host port is invalid" ));
635  assert( DEBUG_WARN );
636  return;
637  }
638  *port = localPort;
639  }
640 #endif /* USE_TCP */