📄 net.c
字号:
/****************************************************************************
* *
* Network Stream I/O Functions *
* Copyright Peter Gutmann 1993-2007 *
* *
****************************************************************************/
#if defined( INC_ALL )
#include "stream_int.h"
#else
#include "io/stream_int.h"
#endif /* Compiler-specific includes */
/* When we allocate the readahead/write buffers for the network transport
(see the comment at the start of net_trans.c) we try and make them an
optimal size to minimise unnecessary copying and not negatively affect
network I/O. If we make them too big then we'll have to move too much
data around when we partially empty them, if we make them too small then
the buffering effect is suboptimal. Since what we're buffering is PKI
traffic a 4K buffer should get most messages in one go. This also
matches many network stacks that use 4K I/O buffers, the BSD default */
#define NETWORK_BUFFER_SIZE 4096
#if NETWORK_BUFFER_SIZE > MAX_INTLENGTH_SHORT
#error NETWORK_BUFFER_SIZE exceeds buffered I/O length check size
#endif /* NETWORK_BUFFER_SIZE > MAX_INTLENGTH_SHORT */
#ifdef USE_TCP
/****************************************************************************
* *
* Utility Functions *
* *
****************************************************************************/
#if defined( __WIN32__ ) && !defined( NDEBUG ) && 0
/* Code to test HTTP header parsing, call from just before the
openConnection() call in completeConnect() */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
static int transportFileFunction( INOUT STREAM *stream,
IN_BUFFER( length ) void *buffer,
IN_LENGTH const int length,
IN_FLAGS_Z( TRANSPORT ) const int flags )
{
FILE *filePtr = ( FILE * ) stream->callbackFunction;
return( fread( buffer, 1, length, filePtr ) );
}
STDC_NONNULL_ARG( ( 1 ) ) \
static void testHttp( INOUT STREAM *stream )
{
STREAM streamCopy;
ERROR_INFO errorInfoCopy;
FILE *reportFile = stdout;
void *buffer;
int i, status;
stream->protocol = STREAM_PROTOCOL_HTTP;
stream->transportReadFunction = transportFileFunction;
sioctl( stream, STREAM_IOCTL_HTTPREQTYPES, STREAM_HTTPREQTYPE_GET );
if( ( buffer = clAlloc( "testHTTP", 16384 ) ) == NULL )
{
puts( "Out of memory." );
return;
}
#if 1 /* Either stdout or a file */
reportFile = fopen( "r:/http_report.txt", "w" );
if( reportFile == NULL )
{
printf( "Couldn't open file for report, hit a key." );
getchar();
putchar( '\n' );
exit( EXIT_FAILURE );
}
#endif
// for( i = 1455; i <= 2000; i++ )
// for( i = 0; i < 1000; i++ )
// for( i = 1000; i < 1999; i++ )
// for( i = 2000; i < 2999; i++ )
// for( i = 3000; i < 3999; i++ )
for( i = 0; i <= 3965; i++ )
{
FILE *filePtr;
char fileName[ 128 ];
sprintf( fileName, "d:/tmp/testcases/%08d", i );
filePtr = fopen( fileName, "rb" );
if( filePtr == NULL )
{
printf( "Failed to open file #%d, hit a key.", i );
getchar();
putchar( '\n' );
continue;
}
memcpy( &streamCopy, stream, sizeof( STREAM ) );
memcpy( &errorInfoCopy, stream->errorInfo, sizeof( ERROR_INFO ) );
stream->callbackFunction = ( CALLBACKFUNCTION ) filePtr;/* Kludge */
fprintf( reportFile, "%04d: ", i );
if( reportFile != stdout )
{
if( !( i % 10 ) )
putchar( '\n' );
printf( "%04d ", i );
}
status = sread( stream, buffer, 16384 );
fclose( filePtr );
if( !cryptStatusError( status ) )
{
fprintf( reportFile,
"%d: cryptlib error: HTTP error not detected.\n",
status );
}
else
{
fprintf( reportFile, "%d %s.\n", status,
stream->errorInfo->errorString );
}
fflush( reportFile );
memcpy( stream, &streamCopy, sizeof( STREAM ) );
memcpy( stream->errorInfo, &errorInfoCopy, sizeof( ERROR_INFO ) );
}
if( reportFile != stdout )
fclose( reportFile );
putchar( '\n' );
}
#else
#define testHttp( stream )
#endif /* Win32 debug build only */
/* Copy error information from a cryptlib transport-layer session into a
stream */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int getSessionErrorInfo( INOUT NET_STREAM_INFO *netStream,
IN_ERROR const int errorStatus )
{
MESSAGE_DATA msgData;
char errorString[ MAX_ERRMSG_SIZE + 8 ];
int status;
assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
REQUIRES( cryptStatusError( errorStatus ) );
status = krnlSendMessage( netStream->iTransportSession,
IMESSAGE_GETATTRIBUTE,
&netStream->errorInfo.errorCode,
CRYPT_ATTRIBUTE_INT_ERRORCODE );
if( cryptStatusError( status ) )
netStream->errorInfo.errorCode = 0;
clearErrorString( &netStream->errorInfo );
setMessageData( &msgData, errorString, MAX_ERRMSG_SIZE );
status = krnlSendMessage( netStream->iTransportSession,
IMESSAGE_GETATTRIBUTE, &msgData,
CRYPT_ATTRIBUTE_INT_ERRORMESSAGE );
if( cryptStatusOK( status ) )
setErrorString( NETSTREAM_ERRINFO, errorString, msgData.length );
return( errorStatus );
}
/* Check for the use of a proxy when opening a stream */
CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 3, 4, 6, 8 ) ) \
static int checkForProxy( INOUT NET_STREAM_INFO *netStream,
IN_ENUM( STREAM_PROTOCOL ) \
const STREAM_PROTOCOL_TYPE protocol,
const NET_CONNECT_INFO *connectInfo,
IN_BUFFER( hostLen ) const char *host,
IN_LENGTH_DNS const int hostLen,
OUT_BUFFER( proxyUrlMaxLen, *proxyUrlLen ) \
char *proxyUrlBuffer,
IN_LENGTH_DNS const int proxyUrlMaxLen,
OUT_LENGTH_DNS_Z int *proxyUrlLen )
{
MESSAGE_DATA msgData;
int status;
assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
assert( isReadPtr( connectInfo, sizeof( NET_CONNECT_INFO ) ) );
assert( isWritePtr( proxyUrlBuffer, proxyUrlMaxLen ) );
assert( isWritePtr( proxyUrlLen, sizeof( int ) ) );
REQUIRES( protocol > STREAM_PROTOCOL_NONE && \
protocol < STREAM_PROTOCOL_LAST );
REQUIRES( proxyUrlMaxLen > 10 && proxyUrlMaxLen <= MAX_DNS_SIZE );
/* Clear return value */
memset( proxyUrlBuffer, 0, min( 16, proxyUrlMaxLen ) );
*proxyUrlLen = 0;
/* Check for a local connection, which always bypasses the proxy. We
only use the case-insensitive string compares for the text-format
host names since the numeric forms don't need this */
if( ( hostLen == 9 && !memcmp( host, "127.0.0.1", 9 ) ) || \
( hostLen == 3 && !memcmp( host, "::1", 3 ) ) || \
( hostLen == 9 && !strCompare( host, "localhost", 9 ) ) || \
( hostLen == 10 && !strCompare( host, "localhost.", 10 ) ) )
/* Are you local? */
{
/* This is a local socket! We'll have no proxies here! */
return( CRYPT_OK );
}
/* Check to see whether we're going through a proxy. First we check for
a protocol-specific HTTP proxy (if appropriate), if there's none then
we check for the more generic case of a SOCKS proxy. In addition to
the obvious use of an HTTP proxy for HTTP we also check for an HTTP
URL specified for use with other protocols (specifcally SSL/TLS)
since these can also go via a proxy even if the they're not an
explicit use of HTTP */
if( ( protocol == STREAM_PROTOCOL_HTTP || \
connectInfo->options == NET_OPTION_HOSTNAME_TUNNEL ) )
{
/* Check whether there's an HTTP proxy configured */
setMessageData( &msgData, proxyUrlBuffer, proxyUrlMaxLen );
status = krnlSendMessage( connectInfo->iUserObject,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_OPTION_NET_HTTP_PROXY );
if( cryptStatusOK( status ) )
{
netStream->nFlags |= \
( connectInfo->options == NET_OPTION_HOSTNAME ) ? \
STREAM_NFLAG_HTTPPROXY : STREAM_NFLAG_HTTPTUNNEL;
*proxyUrlLen = msgData.length;
return( OK_SPECIAL );
}
}
/* Check whether there's a SOCKS proxy configured */
setMessageData( &msgData, proxyUrlBuffer, proxyUrlMaxLen );
status = krnlSendMessage( connectInfo->iUserObject,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_OPTION_NET_SOCKS_SERVER );
if( cryptStatusOK( status ) )
{
*proxyUrlLen = msgData.length;
return( OK_SPECIAL );
}
/* There's no proxy configured */
return( CRYPT_OK );
}
/* Connect a network stream */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
static int openNetworkConnection( INOUT NET_STREAM_INFO *netStream,
IN_ENUM( NET_OPTION ) \
const NET_OPTION_TYPE options,
IN_BUFFER_OPT( proxyUrlLen ) const char *proxyUrl,
IN_LENGTH_DNS_Z const int proxyUrlLen )
{
URL_INFO urlInfo;
char urlBuffer[ MAX_DNS_SIZE + 8 ];
const char *url = proxyUrl;
int urlLen = proxyUrlLen, status;
assert( isWritePtr( netStream, sizeof( NET_STREAM_INFO ) ) );
assert( ( proxyUrl == NULL && proxyUrlLen == 0 ) || \
isReadPtr( proxyUrl, proxyUrlLen ) );
REQUIRES( options > NET_OPTION_NONE && options < NET_OPTION_LAST );
REQUIRES( ( proxyUrl == NULL && proxyUrlLen == 0 ) || \
( proxyUrl != NULL && \
proxyUrlLen > 0 && proxyUrlLen <= MAX_DNS_SIZE ) );
/* If we're using an already-active network socket supplied by the
user, there's nothing to do */
if( netStream->nFlags & STREAM_NFLAG_USERSOCKET )
{
/* If it's a dummy open to check parameters that can't be validated
at a higher level pass the info on down to the low-level checking
routines */
if( options == NET_OPTION_NETWORKSOCKET_DUMMY )
return( netStream->transportCheckFunction( netStream ) );
return( CRYPT_OK );
}
/* If we're not going via a proxy, perform a direct open */
if( proxyUrl == NULL )
{
return( netStream->transportConnectFunction( netStream, netStream->host,
netStream->hostLen,
netStream->port ) );
}
/* We're going via a proxy, if the user has specified automatic proxy
detection try and locate the proxy information */
if( !strCompareZ( proxyUrl, "[Autodetect]" ) )
{
status = findProxyUrl( urlBuffer, MAX_DNS_SIZE, &urlLen,
netStream->host, netStream->hostLen );
if( cryptStatusError( status ) )
{
/* The proxy URL was invalid, provide more information for the
caller */
netStream->errorInfo.errorCode = CRYPT_ERROR_NOTFOUND;
setErrorString( NETSTREAM_ERRINFO,
"Couldn't auto-detect HTTP proxy", 31 );
return( CRYPT_ERROR_OPEN );
}
url = urlBuffer;
}
/* Process the proxy details. Since this is an HTTP proxy we specify
the default port as port 80 */
status = parseURL( &urlInfo, url, urlLen, 80, URL_TYPE_HTTP );
if( cryptStatusError( status ) )
{
/* The proxy URL was invalid, provide more information for the
caller */
netStream->errorInfo.errorCode = CRYPT_ERROR_BADDATA;
setErrorString( NETSTREAM_ERRINFO, "Invalid HTTP proxy URL", 22 );
return( CRYPT_ERROR_OPEN );
}
/* Since we're going via a proxy, open the connection to the proxy
rather than directly to the target system. */
return( netStream->transportConnectFunction( netStream, urlInfo.host,
urlInfo.hostLen,
urlInfo.port ) );
}
/****************************************************************************
* *
* Network Stream Init/Shutdown Functions *
* *
****************************************************************************/
/* Initialise the network stream */
CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 4 ) ) \
static int initStream( OUT STREAM *stream,
OUT NET_STREAM_INFO *netStream,
IN_ENUM( STREAM_PROTOCOL ) \
const STREAM_PROTOCOL_TYPE protocol,
INOUT const NET_CONNECT_INFO *connectInfo,
const BOOLEAN isServer )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -