📄 net.c
字号:
static int transportDirectReadFunction( STREAM *stream, void *buffer,
const int length )
{
return( stream->transportReadFunction( stream, buffer, length,
TRANSPORT_FLAG_NONE ) );
}
static int transportDirectWriteFunction( STREAM *stream, const void *buffer,
const int length )
{
return( stream->transportWriteFunction( stream, buffer, length,
TRANSPORT_FLAG_NONE ) );
}
static int setStreamLayerDirect( STREAM *stream )
{
stream->writeFunction = transportDirectWriteFunction;
stream->readFunction = transportDirectReadFunction;
return( CRYPT_OK );
}
/* Send and receive data with a cryptlib session as the transport layer */
static int transportSessionConnectFunction( STREAM *stream,
const char *server,
const int port )
{
int isActive, status;
assert( server == NULL );
assert( port == 0 );
/* If the transport session hasn't been activated yet, activate it now */
status = krnlSendMessage( stream->iTransportSession,
IMESSAGE_GETATTRIBUTE, &isActive,
CRYPT_SESSINFO_ACTIVE );
if( cryptStatusOK( status ) && isActive )
return( CRYPT_OK );
status = krnlSendMessage( stream->iTransportSession,
IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_TRUE,
CRYPT_SESSINFO_ACTIVE );
if( cryptStatusError( status ) )
return( getSessionErrorInfo( stream, status ) );
return( CRYPT_OK );
}
static void transportSessionDisconnectFunction( STREAM *stream,
const BOOLEAN fullDisconnect )
{
krnlSendNotifier( stream->iTransportSession, IMESSAGE_DECREFCOUNT );
}
static BOOLEAN transportSessionOKFunction( void )
{
return( TRUE );
}
static int transportSessionReadFunction( STREAM *stream, BYTE *buffer,
const int length, const int flags )
{
RESOURCE_DATA msgData;
int newTimeout = CRYPT_UNUSED, status;
/* Read data from the session, overriding the timeout handling if
requested */
if( ( flags & TRANSPORT_FLAG_NONBLOCKING ) && stream->timeout > 0 )
newTimeout = 0;
else
if( ( flags & TRANSPORT_FLAG_BLOCKING ) && stream->timeout == 0 )
newTimeout = 30;
if( newTimeout != CRYPT_UNUSED )
krnlSendMessage( stream->iTransportSession, IMESSAGE_SETATTRIBUTE,
&newTimeout, CRYPT_OPTION_NET_READTIMEOUT );
setMessageData( &msgData, buffer, length );
status = krnlSendMessage( stream->iTransportSession, IMESSAGE_ENV_POPDATA,
&msgData, 0 );
if( newTimeout != CRYPT_UNUSED )
krnlSendMessage( stream->iTransportSession, IMESSAGE_SETATTRIBUTE,
&stream->timeout, CRYPT_OPTION_NET_READTIMEOUT );
if( cryptStatusError( status ) )
return( getSessionErrorInfo( stream, status ) );
if( msgData.length < length )
retExtStream( stream, CRYPT_ERROR_READ,
"Only read %d out of %d bytes via cryptlib session "
"object", msgData.length, length );
return( length );
}
static int transportSessionWriteFunction( STREAM *stream, const BYTE *buffer,
const int length, const int flags )
{
RESOURCE_DATA msgData;
int status;
setMessageData( &msgData, ( void * ) buffer, length );
status = krnlSendMessage( stream->iTransportSession,
IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
if( cryptStatusOK( status ) )
{
setMessageData( &msgData, NULL, 0 );
status = krnlSendMessage( stream->iTransportSession,
IMESSAGE_ENV_PUSHDATA, &msgData, 0 );
}
if( cryptStatusError( status ) )
return( getSessionErrorInfo( stream, status ) );
return( CRYPT_OK );
}
/****************************************************************************
* *
* Proxy Management Functions *
* *
****************************************************************************/
/* Open a connection through a Socks proxy. This is currently disabled
since it doesn't appear to be used by anyone */
#if 0
static int connectViaSocksProxy( STREAM *stream )
{
RESOURCE_DATA msgData;
BYTE socksBuffer[ 64 + CRYPT_MAX_TEXTSIZE ], *bufPtr = socksBuffer;
char userName[ CRYPT_MAX_TEXTSIZE + 1 ];
int length, status;
/* Get the SOCKS user name, defaulting to "cryptlib" if there's none
set */
setMessageData( &msgData, userName, CRYPT_MAX_TEXTSIZE );
status = krnlSendMessage( DEFAULTUSER_OBJECT_HANDLE,
IMESSAGE_GETATTRIBUTE_S, &msgData,
CRYPT_OPTION_NET_SOCKS_USERNAME );
if( cryptStatusOK( status ) )
userName[ msgData.length ] = '\0';
else
strcpy( userName, "cryptlib" );
/* Build up the socks request string:
BYTE: version = 4
BYTE: command = 1 (connect)
WORD: port
LONG: IP address
STRING: userName + '\0' */
*bufPtr++ = 4; *bufPtr++ = 1;
mputWord( bufPtr, stream->port );
status = getIPAddress( stream, bufPtr, stream->host );
strcpy( bufPtr + 4, userName );
length = 1 + 1 + 2 + 4 + strlen( userName ) + 1;
if( cryptStatusError( status ) )
{
stream->transportDisconnectFunction( stream, TRUE );
return( status );
}
/* Send the data to the server and read back the reply */
status = stream->transportWriteFunction( stream, socksBuffer, length,
TRANSPORT_FLAG_FLUSH );
if( cryptStatusOK( status ) )
status = stream->transportReadFunction( stream, socksBuffer, 8,
TRANSPORT_FLAG_BLOCKING );
if( cryptStatusError( status ) )
{
/* The involvement of a proxy complicates matters somewhat because
we can usually connect to the proxy OK but may run into problems
going from the proxy to the remote server, so if we get an error
at this stage (which will typically show up as a read error from
the proxy) we report it as an open error instead */
if( status == CRYPT_ERROR_READ || status == CRYPT_ERROR_COMPLETE )
status = CRYPT_ERROR_OPEN;
stream->transportDisconnectFunction( stream, TRUE );
return( status );
}
/* Make sure that everything is OK, the second returned byte should be
90 */
if( socksBuffer[ 1 ] != 90 )
{
int i;
stream->transportDisconnectFunction( stream, TRUE );
strcpy( stream->errorMessage, "Socks proxy returned" );
for( i = 0; i < 8; i++ )
sPrintf( stream->errorMessage + 20 + ( i * 3 ),
" %02X", socksBuffer[ i ] );
strcat( stream->errorMessage, "." );
stream->errorCode = socksBuffer[ 1 ];
return( CRYPT_ERROR_OPEN );
}
return( CRYPT_OK );
}
#endif /* 0 */
static int connectViaHttpProxy( STREAM *stream, int *errorCode,
char *errorMessage )
{
BYTE buffer[ 64 ];
int status;
/* Open the connection via the proxy. To do this we temporarily layer
HTTP I/O over the TCP I/O, then once the proxy messaging has been
completely we re-set the stream to pure TCP I/O and clear any stream
flags that were set during the proxying */
setStreamLayerHTTP( stream );
status = stream->writeFunction( stream, "", 0 );
if( cryptStatusOK( status ) )
status = stream->readFunction( stream, buffer, 64 );
setStreamLayerDirect( stream );
stream->flags = 0;
if( cryptStatusError( status ) )
{
/* The involvement of a proxy complicates matters somewhat because
we can usually connect to the proxy OK but may run into problems
going from the proxy to the remote server, so if we get an error
at this stage (which will typically show up as a read error from
the proxy) we report it as an open error instead */
if( status == CRYPT_ERROR_READ || status == CRYPT_ERROR_COMPLETE )
status = CRYPT_ERROR_OPEN;
*errorCode = stream->errorCode;
strcpy( errorMessage, stream->errorMessage );
stream->transportDisconnectFunction( stream, TRUE );
}
return( status );
}
/* Try and auto-detect HTTP proxy information */
#if defined( __WIN32__ )
/* The autoproxy functions were only documented in WinHTTP 5.1, so we have to
provide the necessary defines and structures ourselves */
#ifndef WINHTTP_ACCESS_TYPE_DEFAULT_PROXY
#define HINTERNET HANDLE
typedef struct {
DWORD dwFlags;
DWORD dwAutoDetectFlags;
LPCWSTR lpszAutoConfigUrl;
LPVOID lpvReserved;
DWORD dwReserved;
BOOL fAutoLogonIfChallenged;
} WINHTTP_AUTOPROXY_OPTIONS;
typedef struct {
DWORD dwAccessType;
LPWSTR lpszProxy;
LPWSTR lpszProxyBypass;
} WINHTTP_PROXY_INFO;
typedef struct {
BOOL fAutoDetect;
LPWSTR lpszAutoConfigUrl;
LPWSTR lpszProxy;
LPWSTR lpszProxyBypass;
} WINHTTP_CURRENT_USER_IE_PROXY_CONFIG;
#define WINHTTP_AUTOPROXY_AUTO_DETECT 1
#define WINHTTP_AUTO_DETECT_TYPE_DHCP 1
#define WINHTTP_AUTO_DETECT_TYPE_DNS_A 2
#define WINHTTP_ACCESS_TYPE_NO_PROXY 1
#define WINHTTP_NO_PROXY_NAME NULL
#define WINHTTP_NO_PROXY_BYPASS NULL
#endif /* WinHTTP 5.1 defines and structures */
typedef HINTERNET ( *WINHTTPOPEN )( LPCWSTR pwszUserAgent, DWORD dwAccessType,
LPCWSTR pwszProxyName, LPCWSTR pwszProxyBypass,
DWORD dwFlags );
typedef BOOL ( *WINHTTPGETDEFAULTPROXYCONFIGURATION )( WINHTTP_PROXY_INFO* pProxyInfo );
typedef BOOL ( *WINHTTPGETIEPROXYCONFIGFORCURRENTUSER )(
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig );
typedef BOOL ( *WINHTTPGETPROXYFORURL )( HINTERNET hSession, LPCWSTR lpcwszUrl,
WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions,
WINHTTP_PROXY_INFO *pProxyInfo );
typedef BOOL ( *WINHTTPCLOSEHANDLE )( HINTERNET hInternet );
static int findProxyURL( char *proxy, const char *url )
{
static HMODULE hWinHTTP = NULL;
static WINHTTPOPEN pWinHttpOpen = NULL;
static WINHTTPGETDEFAULTPROXYCONFIGURATION pWinHttpGetDefaultProxyConfiguration = NULL;
static WINHTTPGETIEPROXYCONFIGFORCURRENTUSER pWinHttpGetIEProxyConfigForCurrentUser = NULL;
static WINHTTPGETPROXYFORURL pWinHttpGetProxyForUrl = NULL;
static WINHTTPCLOSEHANDLE pWinHttpCloseHandle = NULL;
WINHTTP_AUTOPROXY_OPTIONS autoProxyOptions = \
{ WINHTTP_AUTOPROXY_AUTO_DETECT,
WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A,
NULL, NULL, 0, FALSE };
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxyInfo;
WINHTTP_PROXY_INFO proxyInfo;
HINTERNET hSession;
char urlBuffer[ MAX_DNS_SIZE + 1 ];
wchar_t unicodeURL[ MAX_DNS_SIZE + 1 ];
const int urlLen = strlen( url );
int offset = 0, count;
/* Under Win2K SP3, XP and 2003 (or at least Windows versions with
WinHTTP 5.1 installed in some way, it officially shipped with the
versions mentioned earlier) we can use WinHTTP AutoProxy support,
which implements the Web Proxy Auto-Discovery (WPAD) protocol from
an internet draft that expired in May 2001. Under older versions of
Windows we have to use the WinINet InternetGetProxyInfo, however this
consists of a ghastly set of kludges that were never meant to be
exposed to the outside world (they were only crowbarred out of MS
as part of the DoJ consent decree), and user experience with them is
that they don't really work except in the one special way in which
MS-internal code calls them. Since we don't know what this is, we
use the WinHTTP functions instead */
if( hWinHTTP == NULL )
{
if( ( hWinHTTP = LoadLibrary( "WinHTTP.dll" ) ) == NULL )
return( CRYPT_ERROR_NOTFOUND );
pWinHttpOpen = ( WINHTTPOPEN ) \
GetProcAddress( hWinHTTP, "WinHttpOpen" );
pWinHttpGetDefaultProxyConfiguration = ( WINHTTPGETDEFAULTPROXYCONFIGURATION ) \
GetProcAddress( hWinHTTP, "WinHttpGetDefaultProxyConfiguration" );
pWinHttpGetIEProxyConfigForCurrentUser = ( WINHTTPGETIEPROXYCONFIGFORCURRENTUSER ) \
GetProcAddress( hWinHTTP, "WinHttpGetIEProxyConfigForCurrentUser" );
pWinHttpGetProxyForUrl = ( WINHTTPGETPROXYFORURL ) \
GetProcAddress( hWinHTTP, "WinHttpGetProxyForUrl" );
pWinHttpCloseHandle = ( WINHTTPCLOSEHANDLE ) \
GetProcAddress( hWinHTTP, "WinHttpCloseHandle" );
if( pWinHttpOpen == NULL || pWinHttpGetProxyForUrl == NULL || \
pWinHttpCloseHandle == NULL )
{
FreeLibrary( hWinHTTP );
return( CRYPT_ERROR_NOTFOUND );
}
}
/* Autoproxy discovery using WinHttpGetProxyForUrl() can be awfully slow,
often taking several seconds, since it requires probing for proxy info
first using DHCP and then if that fails using DNS. Since this is done
via a blocking call, everything blocks while it's in progress. To
help mitigate this, we try for proxy info direct from the registry if
it's available, avoiding the lengthy autodiscovery process. This also
means that discovery will work if no auto-discovery support is present,
for example on servers where the admin has set the proxy config
directly with ProxyCfg.exe */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -