mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2095 lines
50 KiB
2095 lines
50 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Nsptcpip.c
|
|
|
|
Abstract:
|
|
|
|
This module contains support for the Name Space Provider for TCPIP,
|
|
which includes four actual NSPs:
|
|
|
|
- local lookup for "loopback", "localhost", and the host name.
|
|
|
|
- hosts file lookup.
|
|
|
|
- DNS queries
|
|
|
|
- WINS (Netbt) lookups
|
|
|
|
Author:
|
|
|
|
David Treadwell (davidtr) 22-Apr-1994
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#if defined(CHICAGO)
|
|
#undef UNICODE
|
|
#else
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
#endif
|
|
|
|
#include "winsockp.h"
|
|
#include <nspapi.h>
|
|
#include <nspapip.h>
|
|
#include <svcguid.h>
|
|
#include <nspmisc.h>
|
|
|
|
#define host_aliases ACCESS_THREAD_DATA( host_aliases, GETHOST )
|
|
|
|
extern GUID HostnameGuid;
|
|
|
|
#define DNS_PORT (htons(53))
|
|
#define HOSTENT_CACHING_ENABLED
|
|
|
|
#if defined(CHICAGO)
|
|
|
|
struct hostent * localhostent ( void);
|
|
struct hostent * myhostent ( void);
|
|
|
|
#define UDP_NAME "UDP/IP"
|
|
#define TCP_NAME "TCP/IP"
|
|
|
|
#if PACKETSZ > 1024
|
|
#define MAXPACKET PACKETSZ
|
|
#else
|
|
#define MAXPACKET 1024
|
|
#endif
|
|
|
|
typedef union {
|
|
HEADER hdr;
|
|
unsigned char buf[MAXPACKET];
|
|
} querybuf;
|
|
|
|
struct hostent *
|
|
getanswer(
|
|
IN LPSOCK_THREAD pThread,
|
|
OUT querybuf *answer,
|
|
OUT int * ttl,
|
|
IN int anslen,
|
|
IN int iquery
|
|
);
|
|
|
|
LPHOSTENT
|
|
GetHostentFromName(
|
|
IN LPSOCK_THREAD pThread,
|
|
IN LPSTR Name
|
|
);
|
|
|
|
#define _gethtbyname(name) GetHostentFromName(pThread, (LPSTR)name)
|
|
|
|
ULONG
|
|
SockNbtResolveName (
|
|
IN PCHAR Name
|
|
);
|
|
|
|
struct hostent *
|
|
dnshostent (
|
|
void
|
|
);
|
|
|
|
DWORD
|
|
CopyHostentToBuffer (
|
|
char FAR *Buffer,
|
|
int BufferLength,
|
|
PHOSTENT Hostent
|
|
);
|
|
|
|
DWORD
|
|
BytesInHostent (
|
|
PHOSTENT Hostent
|
|
);
|
|
|
|
#endif // defined(CHICAGO)
|
|
|
|
#if defined(HOSTENT_CACHING_ENABLED)
|
|
|
|
LIST_ENTRY HostentCacheListHead = { &HostentCacheListHead, &HostentCacheListHead };
|
|
DWORD MaxHostentCacheSize = 10;
|
|
DWORD CurrentHostentCacheSize = 0;
|
|
|
|
#if defined(CHICAGO)
|
|
#define MY_LARGE_INTEGER DWORD
|
|
#define QUADPART(x) (x)
|
|
#define LSTRCMPI lstrcmpi
|
|
#define REG_OPEN_KEY_EX RegOpenKeyExA
|
|
#else
|
|
#define MY_LARGE_INTEGER LARGE_INTEGER
|
|
#define QUADPART(x) (x).QuadPart
|
|
#define LSTRCMPI _stricmp
|
|
#define REG_OPEN_KEY_EX RegOpenKeyExW
|
|
#endif
|
|
|
|
typedef struct _HOSTENT_CACHE_ENTRY {
|
|
LIST_ENTRY HostentListEntry;
|
|
MY_LARGE_INTEGER LastAccessTime;
|
|
MY_LARGE_INTEGER ExpirationTime;
|
|
HOSTENT HostEntry;
|
|
// BYTE[*]; // other hostent info
|
|
} HOSTENT_CACHE_ENTRY, *PHOSTENT_CACHE_ENTRY;
|
|
|
|
VOID
|
|
CacheHostent (
|
|
IN PHOSTENT HostEntry,
|
|
IN INT Ttl
|
|
);
|
|
|
|
PHOSTENT
|
|
QueryHostentCache (
|
|
IN LPSTR Name OPTIONAL,
|
|
IN DWORD IpAddress OPTIONAL
|
|
);
|
|
|
|
#endif // defined(HOSTENT_CACHING_ENABLED)
|
|
|
|
#define NSP_VERSION 1
|
|
|
|
VOID
|
|
CopyToAliasBuffer (
|
|
IN PSTR Alias,
|
|
IN OUT LPTSTR AliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN OUT LPDWORD AliasBytesUsed
|
|
);
|
|
|
|
INT
|
|
GuidToPort (
|
|
IN LPGUID lpServiceType,
|
|
IN LPINT lpiProtocols,
|
|
OUT LPWORD Port,
|
|
OUT LPBOOL IsTcp
|
|
);
|
|
|
|
INT
|
|
HostentToCsaddr (
|
|
IN PHOSTENT HostEntry,
|
|
IN WORD Port,
|
|
IN BOOL IsTcp,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN OUT LPDWORD Count
|
|
);
|
|
|
|
VOID
|
|
ReadPriorities (
|
|
VOID
|
|
);
|
|
|
|
INT
|
|
ServiceCsaddr (
|
|
IN WORD Port,
|
|
IN BOOL IsTcp,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength
|
|
);
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipLocalGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
);
|
|
|
|
DWORD
|
|
APIENTRY
|
|
TcpipLocalSetService (
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN BOOL fUnicodeBlob,
|
|
IN LPSERVICE_INFO lpServiceInfo
|
|
);
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipHostsGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
);
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipDnsGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
);
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipNetbtGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
);
|
|
|
|
DWORD LocalPriority = NS_STANDARD_FAST_PRIORITY - 1;
|
|
DWORD HostsPriority = NS_STANDARD_FAST_PRIORITY;
|
|
DWORD DnsPriority = NS_STANDARD_PRIORITY;
|
|
DWORD NetbtPriority = NS_STANDARD_PRIORITY + 1;
|
|
|
|
|
|
INT
|
|
APIENTRY
|
|
NPLoadNameSpaces (
|
|
IN OUT LPDWORD lpdwVersion,
|
|
IN OUT LPNS_ROUTINE nsrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength
|
|
)
|
|
{
|
|
DWORD bufferLengthRequired;
|
|
PNS_ROUTINE nsRoutineLocal;
|
|
PNS_ROUTINE nsRoutineHosts;
|
|
PNS_ROUTINE nsRoutineDns;
|
|
PNS_ROUTINE nsRoutineNetbt;
|
|
|
|
//
|
|
// Calculate the size of a buffer the caller will need to specify.
|
|
// We support four name spaces in this DLL, each of which exports
|
|
// a single NSP API.
|
|
//
|
|
|
|
bufferLengthRequired = 4 * (sizeof(NS_ROUTINE) + (4 * sizeof(LPFN_NSPAPI)) );
|
|
|
|
//
|
|
// If the caller specified too small a buffer, fail and tell them
|
|
// how large a buffer is required.
|
|
//
|
|
|
|
if ( bufferLengthRequired > *lpdwBufferLength ) {
|
|
*lpdwBufferLength = bufferLengthRequired;
|
|
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Read the name space priorities from the registry.
|
|
//
|
|
|
|
ReadPriorities( );
|
|
|
|
//
|
|
// Tell the caller the version of the NSP API interface which we
|
|
// support.
|
|
//
|
|
|
|
*lpdwVersion = 1;
|
|
|
|
//
|
|
// Calculate where in the buffer we'll put the NS_ROUTINE structures
|
|
// for each of our name spaces.
|
|
//
|
|
|
|
nsRoutineLocal = nsrBuffer;
|
|
nsRoutineHosts = nsrBuffer + 1;
|
|
nsRoutineDns = nsrBuffer + 2;
|
|
nsRoutineNetbt = nsrBuffer + 3;
|
|
|
|
//
|
|
// Calculate where in the buffer each of the function pointer arrays
|
|
// will go.
|
|
//
|
|
|
|
nsRoutineLocal->alpfnFunctions = (LPFN_NSPAPI *)( nsRoutineNetbt + 1 );
|
|
nsRoutineHosts->alpfnFunctions = nsRoutineLocal->alpfnFunctions + 4;
|
|
nsRoutineDns->alpfnFunctions = nsRoutineHosts->alpfnFunctions + 4;
|
|
nsRoutineNetbt->alpfnFunctions = nsRoutineDns->alpfnFunctions + 4;
|
|
|
|
//
|
|
// Fill in each of the NS_ROUTINE structures.
|
|
//
|
|
|
|
nsRoutineLocal->dwFunctionCount = 4;
|
|
nsRoutineLocal->alpfnFunctions[NSPAPI_GET_ADDRESS_BY_NAME] =
|
|
(LPFN_NSPAPI)TcpipLocalGetAddressByName;
|
|
nsRoutineLocal->alpfnFunctions[NSPAPI_GET_SERVICE] = NULL;
|
|
nsRoutineLocal->alpfnFunctions[NSPAPI_SET_SERVICE] =
|
|
(LPFN_NSPAPI)TcpipLocalSetService;
|
|
nsRoutineLocal->alpfnFunctions[3] = NULL;
|
|
nsRoutineLocal->dwNameSpace = NS_TCPIP_LOCAL;
|
|
nsRoutineLocal->dwPriority = LocalPriority;
|
|
|
|
nsRoutineHosts->dwFunctionCount = 4;
|
|
nsRoutineHosts->alpfnFunctions[NSPAPI_GET_ADDRESS_BY_NAME] =
|
|
(LPFN_NSPAPI)TcpipHostsGetAddressByName;
|
|
nsRoutineHosts->alpfnFunctions[NSPAPI_GET_SERVICE] = NULL;
|
|
nsRoutineHosts->alpfnFunctions[NSPAPI_SET_SERVICE] = NULL;
|
|
nsRoutineHosts->alpfnFunctions[3] = NULL;
|
|
nsRoutineHosts->dwNameSpace = NS_TCPIP_HOSTS;
|
|
nsRoutineHosts->dwPriority = HostsPriority;
|
|
|
|
nsRoutineDns->dwFunctionCount = 4;
|
|
nsRoutineDns->alpfnFunctions[NSPAPI_GET_ADDRESS_BY_NAME] =
|
|
(LPFN_NSPAPI)TcpipDnsGetAddressByName;
|
|
nsRoutineDns->alpfnFunctions[NSPAPI_GET_SERVICE] = NULL;
|
|
nsRoutineDns->alpfnFunctions[NSPAPI_SET_SERVICE] = NULL;
|
|
nsRoutineDns->alpfnFunctions[3] = NULL;
|
|
nsRoutineDns->dwNameSpace = NS_DNS;
|
|
nsRoutineDns->dwPriority = DnsPriority;
|
|
|
|
nsRoutineNetbt->dwFunctionCount = 4;
|
|
nsRoutineNetbt->alpfnFunctions[NSPAPI_GET_ADDRESS_BY_NAME] =
|
|
(LPFN_NSPAPI)TcpipNetbtGetAddressByName;
|
|
nsRoutineNetbt->alpfnFunctions[NSPAPI_GET_SERVICE] = NULL;
|
|
nsRoutineNetbt->alpfnFunctions[NSPAPI_SET_SERVICE] = NULL;
|
|
nsRoutineNetbt->alpfnFunctions[3] = NULL;
|
|
nsRoutineNetbt->dwNameSpace = NS_NETBT;
|
|
nsRoutineNetbt->dwPriority = NetbtPriority;
|
|
|
|
return 4;
|
|
|
|
} // NpLoadNameSpaces
|
|
|
|
|
|
VOID
|
|
ReadPriorities (
|
|
VOID
|
|
)
|
|
{
|
|
HKEY tcpipKey;
|
|
INT error;
|
|
DWORD entryLength = sizeof(DWORD);
|
|
DWORD type;
|
|
|
|
//
|
|
// First open the TCPIP network provider key.
|
|
//
|
|
|
|
error = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
TCPIP_SERVICE_PROVIDER_KEY,
|
|
0,
|
|
KEY_READ,
|
|
&tcpipKey
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read each of the priority values. If any of these fails, we'll
|
|
// just go with the default values.
|
|
//
|
|
|
|
RegQueryValueEx(
|
|
tcpipKey,
|
|
TEXT("LocalPriority"),
|
|
NULL,
|
|
&type,
|
|
(PVOID)&LocalPriority,
|
|
&entryLength
|
|
);
|
|
|
|
RegQueryValueEx(
|
|
tcpipKey,
|
|
TEXT("HostsPriority"),
|
|
NULL,
|
|
&type,
|
|
(PVOID)&HostsPriority,
|
|
&entryLength
|
|
);
|
|
|
|
RegQueryValueEx(
|
|
tcpipKey,
|
|
TEXT("DnsPriority"),
|
|
NULL,
|
|
&type,
|
|
(PVOID)&DnsPriority,
|
|
&entryLength
|
|
);
|
|
|
|
RegQueryValueEx(
|
|
tcpipKey,
|
|
TEXT("NetbtPriority"),
|
|
NULL,
|
|
&type,
|
|
(PVOID)&NetbtPriority,
|
|
&entryLength
|
|
);
|
|
|
|
#if defined(HOSTENT_CACHING_ENABLED)
|
|
RegQueryValueEx(
|
|
tcpipKey,
|
|
TEXT("MaxHostentCacheSize"),
|
|
NULL,
|
|
&type,
|
|
(PVOID)&MaxHostentCacheSize,
|
|
&entryLength
|
|
);
|
|
#endif
|
|
|
|
RegCloseKey( tcpipKey );
|
|
return;
|
|
|
|
} // ReadPriorities
|
|
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipLocalGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
)
|
|
{
|
|
WORD port;
|
|
INT error;
|
|
BOOL isTcp;
|
|
PHOSTENT hostEntry;
|
|
DWORD count;
|
|
PSTR hostName;
|
|
PTSTR compareHostName;
|
|
|
|
#if defined(UNICODE)
|
|
UNICODE_STRING unicodeHostName;
|
|
ANSI_STRING ansiHostName;
|
|
#endif
|
|
NTSTATUS status;
|
|
|
|
if(!SockEnterApi(FALSE, TRUE, TRUE))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// Find the port number for this service. We do this before other
|
|
// resolutions to save time in case this fails.
|
|
//
|
|
|
|
error = GuidToPort( lpServiceType, lpiProtocols, &port, &isTcp );
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// If this is a service resolution, we don't actually want to do a
|
|
// lookup. Just fill in the appropriate bind address immediately.
|
|
//
|
|
|
|
if ( (dwResolution & RES_SERVICE) != 0 ) {
|
|
return ServiceCsaddr( port, isTcp, lpCsaddrBuffer, lpdwBufferLength );
|
|
}
|
|
|
|
//
|
|
// Check whether we have information for this name cached. Note
|
|
// that we don't look in the cache if RES_FIND_MULTIPLE is set since
|
|
// we'll be going to all the providers anyway and the info returned
|
|
// here will be extraneous and could cause problems with
|
|
// lpdwBufferLength if the app makes multiple calls for the same
|
|
// data.
|
|
//
|
|
|
|
#if defined(HOSTENT_CACHING_ENABLED)
|
|
|
|
if ( (dwResolution & RES_FIND_MULTIPLE) == 0 &&
|
|
CurrentHostentCacheSize > 0 ) {
|
|
|
|
//
|
|
// Get the host name in ansi for cache comparisons.
|
|
//
|
|
|
|
#if defined(UNICODE)
|
|
RtlInitUnicodeString( &unicodeHostName, lpServiceName );
|
|
|
|
status = RtlUnicodeStringToAnsiString( &ansiHostName, &unicodeHostName, TRUE );
|
|
#else
|
|
status = STATUS_SUCCESS;
|
|
#endif
|
|
|
|
if ( NT_SUCCESS(status) ) {
|
|
|
|
//
|
|
// We hold the hostent cache lock until we're completely
|
|
// done with any returned hostent. This prevents another
|
|
// thread from screwing with the list or the returned
|
|
// hostent while we're processing.
|
|
//
|
|
|
|
SockAcquireGlobalLockExclusive( );
|
|
|
|
//
|
|
// Attempt to find the name in the hostent cache.
|
|
//
|
|
|
|
#if defined(UNICODE)
|
|
hostEntry = QueryHostentCache( ansiHostName.Buffer, 0 );
|
|
|
|
RtlFreeAnsiString( &ansiHostName );
|
|
#else
|
|
hostEntry = QueryHostentCache(lpServiceName, 0);
|
|
#endif
|
|
|
|
//
|
|
// If we found it, copy it to the user buffer and return.
|
|
//
|
|
|
|
if ( hostEntry != NULL ) {
|
|
|
|
error = HostentToCsaddr(
|
|
hostEntry,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
|
|
SockReleaseGlobalLock( );
|
|
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
SockReleaseGlobalLock( );
|
|
}
|
|
}
|
|
#endif // defined(HOSTENT_CACHING_ENABLED)
|
|
|
|
|
|
//
|
|
// If the service name is present and equal to "localhost" or
|
|
// "loopback", return 127.0.0.1.
|
|
//
|
|
|
|
if ( lpServiceName != NULL &&
|
|
(_tcscmp( lpServiceName, TEXT("localhost") ) == 0 ||
|
|
_tcscmp( lpServiceName, TEXT("loopback") ) == 0) ) {
|
|
|
|
hostEntry = localhostent( );
|
|
if ( hostEntry == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
error = HostentToCsaddr(
|
|
hostEntry,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
//
|
|
// If the service name is NULL and the caller is requesting info on
|
|
// DNS addresses, return information on the DNS server IP addresses
|
|
// that we know about.
|
|
//
|
|
|
|
if ( lpServiceName == NULL && port == DNS_PORT ) {
|
|
|
|
hostEntry = dnshostent( );
|
|
if ( hostEntry == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
error = HostentToCsaddr(
|
|
hostEntry,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
//
|
|
// Check whether the service name is the same as the local host
|
|
// name. Note that we consider lpServiceName == NULL to be the
|
|
// local host.
|
|
//
|
|
|
|
hostName = ALLOCATE_HEAP( 256 );
|
|
if ( hostName == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
error = gethostname( hostName, 256 );
|
|
if ( error ) {
|
|
return 0;
|
|
}
|
|
|
|
#if defined(UNICODE)
|
|
RtlInitAnsiString( &ansiHostName, hostName );
|
|
status = RtlAnsiStringToUnicodeString( &unicodeHostName, &ansiHostName, TRUE );
|
|
FREE_HEAP( hostName );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return 0;
|
|
}
|
|
compareHostName = unicodeHostName.Buffer;
|
|
#else
|
|
compareHostName = hostName;
|
|
#endif
|
|
|
|
if ( lpServiceName == NULL ||
|
|
_tcscmp( lpServiceName, compareHostName ) == 0 ) {
|
|
|
|
#if defined(UNICODE)
|
|
RtlFreeUnicodeString( &unicodeHostName );
|
|
#endif
|
|
|
|
hostEntry = myhostent( );
|
|
if ( hostEntry == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
error = HostentToCsaddr(
|
|
hostEntry,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
#if defined(UNICODE)
|
|
RtlFreeUnicodeString( &unicodeHostName );
|
|
#endif
|
|
|
|
//
|
|
// If we're not inside gethostbyname(), check if the service name is
|
|
// really an IP address. We intentionally disable this for
|
|
// gethostbyname() calls because we don't want to break apps which
|
|
// depend on gethostname() not resolving IP addresses. However,
|
|
// this is a useful feature for general RNR applications.
|
|
//
|
|
|
|
if ( (dwResolution & RES_GETHOSTBYNAME) == 0 ) {
|
|
|
|
PSTR serviceString;
|
|
IN_ADDR inAddr;
|
|
HOSTENT hostEntryStruct;
|
|
PBYTE nullAlias = NULL;
|
|
PBYTE addrs[2];
|
|
|
|
#if defined(UNICODE)
|
|
RtlInitUnicodeString( &unicodeHostName, lpServiceName );
|
|
status = RtlUnicodeStringToAnsiString( &ansiHostName, &unicodeHostName, TRUE );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
return 0;
|
|
}
|
|
serviceString = ansiHostName.Buffer;
|
|
#else
|
|
serviceString = lpServiceName;
|
|
#endif
|
|
|
|
//
|
|
// Attempt to translate the string into an IP address value.
|
|
//
|
|
|
|
inAddr.s_addr = inet_addr( serviceString );
|
|
|
|
if ( inAddr.s_addr != INADDR_NONE ) {
|
|
|
|
hostEntryStruct.h_name = serviceString;
|
|
hostEntryStruct.h_aliases = &nullAlias;
|
|
hostEntryStruct.h_addrtype = AF_INET;
|
|
hostEntryStruct.h_length = sizeof(DWORD);
|
|
hostEntryStruct.h_addr_list = addrs;
|
|
addrs[0] = (char *)(&inAddr);
|
|
addrs[1] = NULL;
|
|
|
|
error = HostentToCsaddr(
|
|
&hostEntryStruct,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
} // TcpipLocalGetAddressByName
|
|
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipHostsGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
)
|
|
{
|
|
WORD port;
|
|
INT error;
|
|
BOOL isTcp;
|
|
PHOSTENT hostEntry;
|
|
DWORD count;
|
|
PSTR hostName;
|
|
|
|
#if defined(CHICAGO)
|
|
LPSOCK_THREAD pThread;
|
|
#endif
|
|
|
|
if(!SockEnterApi(FALSE, TRUE, TRUE))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// If this is a service resolution, don't do anything here. Only the
|
|
// TCP/IP local NSP will handle RES_SERVICE requests. This prevents
|
|
// getting back multiple TCP/IP addresses to bind to, one from each
|
|
// TCP/IP NSP.
|
|
//
|
|
|
|
if ( (dwResolution & RES_SERVICE) != 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Find the port number for this service. We do this before other
|
|
// resolutions to save time in case this fails.
|
|
//
|
|
|
|
error = GuidToPort( lpServiceType, lpiProtocols, &port, &isTcp );
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Convert the service name to ANSI.
|
|
//
|
|
|
|
hostName = GetAnsiName( lpServiceName );
|
|
if ( hostName == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Attempt to get a host entry from the hosts file lookup routine.
|
|
//
|
|
|
|
hostEntry = _gethtbyname( hostName );
|
|
|
|
FREE_HEAP( hostName );
|
|
|
|
if ( hostEntry == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
error = HostentToCsaddr(
|
|
hostEntry,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
return count;
|
|
|
|
} // TcpipHostsGetAddressByName
|
|
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipDnsGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
)
|
|
{
|
|
WORD port;
|
|
INT error;
|
|
BOOL isTcp;
|
|
PHOSTENT hostEntry;
|
|
INT count;
|
|
querybuf queryBuffer;
|
|
INT ttl;
|
|
PSTR hostName;
|
|
|
|
#if defined(CHICAGO)
|
|
LPSOCK_THREAD pThread;
|
|
#endif
|
|
|
|
if(!SockEnterApi(FALSE, TRUE, TRUE))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// If this is a service resolution, don't do anything here. Only the
|
|
// TCP/IP local NSP will handle RES_SERVICE requests. This prevents
|
|
// getting back multiple TCP/IP addresses to bind to, one from each
|
|
// TCP/IP NSP.
|
|
//
|
|
|
|
if ( (dwResolution & RES_SERVICE) != 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Initialize the resolver.
|
|
//
|
|
|
|
if (res_init() == -1) {
|
|
SetLastError( ERROR_FILE_NOT_FOUND );
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
//
|
|
// Find the port number for this service. We do this before other
|
|
// resolutions to save time in case this fails.
|
|
//
|
|
|
|
error = GuidToPort( lpServiceType, lpiProtocols, &port, &isTcp );
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Convert the service name to ANSI.
|
|
//
|
|
|
|
hostName = GetAnsiName( lpServiceName );
|
|
if ( hostName == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Attempt to get a host entry from the DNR lookup routines.
|
|
//
|
|
|
|
hostEntry = NULL;
|
|
|
|
count = res_search( hostName, C_IN, T_A,
|
|
queryBuffer.buf, sizeof(queryBuffer) );
|
|
|
|
if ( count >= 0 ) {
|
|
|
|
#if defined(CHICAGO)
|
|
hostEntry = getanswer( pThread, &queryBuffer, &ttl, count, 0 );
|
|
#else
|
|
hostEntry = getanswer( &queryBuffer, &ttl, count, 0 );
|
|
#endif
|
|
|
|
}
|
|
|
|
FREE_HEAP( hostName );
|
|
|
|
if ( hostEntry == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
error = HostentToCsaddr(
|
|
hostEntry,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Store the host's information in our cache.
|
|
//
|
|
|
|
#if defined(HOSTENT_CACHING_ENABLED)
|
|
CacheHostent( hostEntry, ttl );
|
|
#endif
|
|
|
|
return count;
|
|
|
|
} // TcpipDnsGetAddressByName
|
|
|
|
|
|
INT
|
|
APIENTRY
|
|
TcpipNetbtGetAddressByName (
|
|
IN LPGUID lpServiceType,
|
|
IN LPTSTR lpServiceName,
|
|
IN LPINT lpiProtocols,
|
|
IN DWORD dwResolution,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN HANDLE hCancellationEvent
|
|
)
|
|
{
|
|
WORD port;
|
|
INT error;
|
|
BOOL isTcp;
|
|
HOSTENT hostEntry;
|
|
DWORD count;
|
|
DWORD ipAddress;
|
|
PVOID addressPtrs[2];
|
|
PSTR hostName;
|
|
|
|
#if defined(CHICAGO)
|
|
LPSOCK_THREAD pThread;
|
|
#endif
|
|
|
|
//
|
|
// If this is a service resolution, don't do anything here. Only the
|
|
// TCP/IP local NSP will handle RES_SERVICE requests. This prevents
|
|
// getting back multiple TCP/IP addresses to bind to, one from each
|
|
// TCP/IP NSP.
|
|
//
|
|
|
|
if(!SockEnterApi(FALSE, TRUE, TRUE))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
if ( (dwResolution & RES_SERVICE) != 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// If we're not supposed to do WINS name resolution for this thread,
|
|
// stop.
|
|
//
|
|
|
|
if ( SockDisableWinsNameResolution ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Find the port number for this service. We do this before other
|
|
// resolutions to save time in case this fails.
|
|
//
|
|
|
|
error = GuidToPort( lpServiceType, lpiProtocols, &port, &isTcp );
|
|
if ( error != NO_ERROR ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Convert the service name to ANSI.
|
|
//
|
|
|
|
hostName = GetAnsiName( lpServiceName );
|
|
if ( hostName == NULL ) {
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Attempt to get the IP address from the WINS client.
|
|
//
|
|
|
|
ipAddress = SockNbtResolveName( hostName );
|
|
if ( ipAddress == INADDR_NONE ) {
|
|
FREE_HEAP( hostName );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Fake up a hostent and convert to a CSADDR structure.
|
|
//
|
|
|
|
hostEntry.h_name = hostName;
|
|
|
|
hostEntry.h_addr_list = (PCHAR *)addressPtrs;
|
|
addressPtrs[0] = &ipAddress;
|
|
addressPtrs[1] = NULL;
|
|
|
|
hostEntry.h_length = sizeof (unsigned long);
|
|
hostEntry.h_addrtype = AF_INET;
|
|
hostEntry.h_aliases = host_aliases;
|
|
host_aliases[0] = NULL;
|
|
|
|
error = HostentToCsaddr(
|
|
&hostEntry,
|
|
port,
|
|
isTcp,
|
|
lpCsaddrBuffer,
|
|
lpdwBufferLength,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&count
|
|
);
|
|
if ( error != NO_ERROR ) {
|
|
FREE_HEAP( hostName );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Store the host's information in our cache with a 10-minute timeout.
|
|
//
|
|
|
|
#if defined(HOSTENT_CACHING_ENABLED)
|
|
CacheHostent( &hostEntry, 60*10 );
|
|
#endif
|
|
|
|
FREE_HEAP( hostName );
|
|
return count;
|
|
|
|
} // TcpipNetbtGetAddressByName
|
|
|
|
|
|
DWORD
|
|
APIENTRY
|
|
TcpipLocalSetService (
|
|
IN DWORD dwOperation,
|
|
IN DWORD dwFlags,
|
|
IN BOOL fUnicodeBlob,
|
|
IN LPSERVICE_INFO lpServiceInfo
|
|
)
|
|
{
|
|
DWORD err;
|
|
HKEY hkey = NULL;
|
|
HKEY hkeyType = NULL;
|
|
|
|
SERVICE_TYPE_INFO *pSvcTypeInfo = (SERVICE_TYPE_INFO *)
|
|
lpServiceInfo->ServiceSpecificInfo.pBlobData;
|
|
LPTSTR pszSvcTypeName;
|
|
DWORD i;
|
|
PSERVICE_TYPE_VALUE pVal;
|
|
#if defined(UNICODE)
|
|
UNICODE_STRING uniStr;
|
|
#endif
|
|
|
|
//
|
|
// We need to take action only on SERVICE_ADD_TYPE. The rest are
|
|
// meaningless for the static name spaces we support.
|
|
//
|
|
|
|
if ( dwOperation != SERVICE_ADD_TYPE ) {
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Get the new service type name
|
|
//
|
|
|
|
#if defined(UNICODE)
|
|
|
|
if ( fUnicodeBlob ) {
|
|
|
|
pszSvcTypeName = (LPWSTR) (((LPBYTE) pSvcTypeInfo) +
|
|
pSvcTypeInfo->dwTypeNameOffset );
|
|
|
|
} else {
|
|
|
|
ANSI_STRING ansiStr;
|
|
|
|
RtlInitAnsiString( &ansiStr,
|
|
(LPSTR) (((LPBYTE) pSvcTypeInfo) +
|
|
pSvcTypeInfo->dwTypeNameOffset ));
|
|
|
|
err = RtlAnsiStringToUnicodeString( &uniStr, &ansiStr, TRUE );
|
|
if ( err )
|
|
return err;
|
|
|
|
pszSvcTypeName = uniStr.Buffer;
|
|
}
|
|
#else
|
|
pszSvcTypeName = (LPSTR) (((LPBYTE) pSvcTypeInfo) +
|
|
pSvcTypeInfo->dwTypeNameOffset );
|
|
#endif
|
|
|
|
//
|
|
// If the service type name is an empty string, return error.
|
|
//
|
|
|
|
if ( ( pSvcTypeInfo->dwTypeNameOffset == 0 ) ||
|
|
( pszSvcTypeName == NULL ) ||
|
|
( *pszSvcTypeName == 0 ) ) {
|
|
|
|
err = ERROR_INVALID_PARAMETER;
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// The following keys should have already been created
|
|
//
|
|
|
|
err = REG_OPEN_KEY_EX(
|
|
HKEY_LOCAL_MACHINE,
|
|
NSP_SERVICE_KEY_NAME,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hkey
|
|
);
|
|
|
|
if ( err ) {
|
|
goto CleanExit;
|
|
}
|
|
|
|
err = REG_OPEN_KEY_EX(
|
|
hkey,
|
|
pszSvcTypeName,
|
|
0,
|
|
KEY_READ | KEY_WRITE,
|
|
&hkeyType
|
|
);
|
|
|
|
if ( err ) {
|
|
goto CleanExit;
|
|
}
|
|
|
|
//
|
|
// Loop through all values in the specific and add them one by one
|
|
// to the registry if it belongs to our name space
|
|
//
|
|
|
|
for ( i = 0, pVal = pSvcTypeInfo->Values;
|
|
i < pSvcTypeInfo->dwValueCount;
|
|
i++, pVal++ )
|
|
{
|
|
//
|
|
// Skip over values not aimed at one of the TCPIP name spaces.
|
|
//
|
|
|
|
if ( pVal->dwNameSpace != NS_TCPIP_LOCAL &&
|
|
pVal->dwNameSpace != NS_TCPIP_HOSTS &&
|
|
pVal->dwNameSpace != NS_DNS &&
|
|
pVal->dwNameSpace != NS_NETBT ) {
|
|
continue;
|
|
}
|
|
|
|
if ( fUnicodeBlob ) {
|
|
|
|
err = RegSetValueExW(
|
|
hkeyType,
|
|
(LPWSTR) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueNameOffset),
|
|
0,
|
|
pVal->dwValueType,
|
|
(LPBYTE) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueOffset),
|
|
pVal->dwValueSize
|
|
);
|
|
|
|
} else {
|
|
|
|
err = RegSetValueExA(
|
|
hkeyType,
|
|
(LPSTR) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueNameOffset),
|
|
0,
|
|
pVal->dwValueType,
|
|
(LPBYTE) ( ((LPBYTE) pSvcTypeInfo) + pVal->dwValueOffset),
|
|
pVal->dwValueSize
|
|
);
|
|
}
|
|
}
|
|
|
|
CleanExit:
|
|
|
|
#if defined(UNICODE)
|
|
if ( !fUnicodeBlob ) {
|
|
RtlFreeUnicodeString( &uniStr );
|
|
}
|
|
#endif
|
|
|
|
if ( hkeyType != NULL ) {
|
|
RegCloseKey( hkeyType );
|
|
}
|
|
|
|
if ( hkey != NULL ) {
|
|
RegCloseKey( hkey );
|
|
}
|
|
|
|
return err;
|
|
|
|
} // TcpipLocalSetService
|
|
|
|
|
|
INT
|
|
GuidToPort (
|
|
IN LPGUID lpServiceType,
|
|
IN LPINT lpiProtocols,
|
|
OUT LPWORD Port,
|
|
OUT LPBOOL IsTcp
|
|
)
|
|
{
|
|
TCHAR nameBuffer[256];
|
|
TCHAR keyNameBuffer[256];
|
|
BOOL isTcp;
|
|
BOOL isUdp;
|
|
BOOL guidIsTcp;
|
|
DWORD i;
|
|
BOOL ianaGuid;
|
|
HKEY serviceKey;
|
|
DWORD regPort;
|
|
DWORD type;
|
|
INT err;
|
|
DWORD bytesRequired;
|
|
|
|
//
|
|
// Determine whether they want TCP, UDP, or both. If there was no
|
|
// protocols list passed in, they want both. Otherwise, they must
|
|
// specify on or both manually.
|
|
//
|
|
|
|
isTcp = FALSE;
|
|
isUdp = FALSE;
|
|
|
|
if ( !ARGUMENT_PRESENT( lpiProtocols ) ) {
|
|
|
|
isTcp = TRUE;
|
|
isUdp = TRUE;
|
|
|
|
} else {
|
|
|
|
for ( i = 0; lpiProtocols[i] != 0; i++ ) {
|
|
|
|
if ( lpiProtocols[i] == IPPROTO_TCP ) {
|
|
isTcp = TRUE;
|
|
}
|
|
|
|
if ( lpiProtocols[i] == IPPROTO_UDP ) {
|
|
isUdp = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If they want neither TCP nor UDP, bail.
|
|
//
|
|
|
|
if ( !isTcp && !isUdp ) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// If this is the special hostname GUID, we don't need to find a
|
|
// port.
|
|
//
|
|
|
|
if ( GuidEqual( lpServiceType, &HostnameGuid ) ) {
|
|
*Port = 0;
|
|
*IsTcp = TRUE;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// If this is an IANA GUID, shortcut to the answer.
|
|
//
|
|
|
|
ianaGuid = FALSE;
|
|
|
|
if ( IS_SVCID_TCP( lpServiceType ) ) {
|
|
guidIsTcp = TRUE;
|
|
ianaGuid = TRUE;
|
|
*Port = htons(PORT_FROM_SVCID_TCP( lpServiceType ));
|
|
}
|
|
|
|
if ( IS_SVCID_UDP( lpServiceType ) ) {
|
|
guidIsTcp = FALSE;
|
|
ianaGuid = TRUE;
|
|
*Port = htons(PORT_FROM_SVCID_UDP( lpServiceType ));
|
|
}
|
|
|
|
if ( ianaGuid ) {
|
|
|
|
//
|
|
// If an incorrect protocol type was specified for the GUID, fail.
|
|
//
|
|
|
|
if ( (guidIsTcp && !isTcp) || (!guidIsTcp && !isUdp) ) {
|
|
return -1;
|
|
}
|
|
|
|
*IsTcp = guidIsTcp;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Convert the GUID into a service name. We'll first check whether
|
|
// port information is in the registry. An application/service
|
|
// writes this information to the registry by using SetService()
|
|
// with SERVICE_ADD_TYPE.
|
|
//
|
|
|
|
err = GetNameByType( lpServiceType, nameBuffer, sizeof(nameBuffer) );
|
|
if ( err != NO_ERROR ) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Attempt to open the service type key.
|
|
//
|
|
|
|
_tcscpy( keyNameBuffer, NSP_SERVICE_KEY_NAME TEXT("\\") );
|
|
_tcscat( keyNameBuffer, nameBuffer );
|
|
|
|
err = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
keyNameBuffer,
|
|
0,
|
|
KEY_READ,
|
|
&serviceKey
|
|
);
|
|
|
|
if ( err != NO_ERROR ) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Attempt to read the "TcpPort" or "UdpPort" values from this key.
|
|
// Note that we sort of ignore errors here; we act based on whether
|
|
// the regPort local variable changes from 0xFFFFFFFF.
|
|
//
|
|
// Also, we don't have any support for a single GUID which supports
|
|
// both TCP and UDP. This currently requires separate GUIDs.
|
|
//
|
|
|
|
regPort = 0xFFFFFFFF;
|
|
guidIsTcp = TRUE;
|
|
bytesRequired = sizeof(regPort);
|
|
|
|
if ( isTcp ) {
|
|
RegQueryValueEx(
|
|
serviceKey,
|
|
TEXT("TcpPort"),
|
|
NULL,
|
|
&type,
|
|
(PVOID)®Port,
|
|
&bytesRequired
|
|
);
|
|
}
|
|
|
|
if ( regPort == 0xFFFFFFFF && isUdp ) {
|
|
RegQueryValueEx(
|
|
serviceKey,
|
|
TEXT("UdpPort"),
|
|
NULL,
|
|
&type,
|
|
(PVOID)®Port,
|
|
&bytesRequired
|
|
);
|
|
guidIsTcp = FALSE;
|
|
}
|
|
|
|
RegCloseKey( serviceKey );
|
|
|
|
//
|
|
// If we got a hit, then we're all set. Use this port.
|
|
//
|
|
|
|
if ( regPort != 0xFFFFFFFF ) {
|
|
*IsTcp = guidIsTcp;
|
|
*Port = htons( (WORD)regPort );
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// We coultn't find a port number for this service type. Fail.
|
|
//
|
|
|
|
return -1;
|
|
|
|
} // GuidToPort
|
|
|
|
|
|
INT
|
|
HostentToCsaddr (
|
|
IN PHOSTENT HostEntry,
|
|
IN WORD Port,
|
|
IN BOOL IsTcp,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength,
|
|
IN OUT LPTSTR lpAliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN OUT LPDWORD Count
|
|
)
|
|
{
|
|
DWORD count;
|
|
DWORD i;
|
|
DWORD requiredBufferLength;
|
|
PSOCKADDR_IN sockaddrIn;
|
|
PCSADDR_INFO csaddrInfo;
|
|
DWORD aliasBytesUsed;
|
|
|
|
//
|
|
// Count the number of IP addresses in the hostent.
|
|
//
|
|
|
|
for ( count = 0; HostEntry->h_addr_list[count] != NULL; count++ );
|
|
|
|
//
|
|
// Make sure that the buffer is large enough to hold all the entries
|
|
// which will be necessary.
|
|
//
|
|
|
|
requiredBufferLength = count * (sizeof(CSADDR_INFO) + 2*sizeof(SOCKADDR_IN));
|
|
|
|
if ( *lpdwBufferLength < requiredBufferLength ) {
|
|
*lpdwBufferLength = requiredBufferLength;
|
|
return (DWORD)-1;
|
|
}
|
|
|
|
*lpdwBufferLength = requiredBufferLength;
|
|
|
|
//
|
|
// For each IP address, fill in the user buffer with one entry.
|
|
//
|
|
|
|
sockaddrIn = (PSOCKADDR_IN)((PCSADDR_INFO)lpCsaddrBuffer + count);
|
|
csaddrInfo = lpCsaddrBuffer;
|
|
|
|
for ( i = 0; i < count; i++, csaddrInfo++, sockaddrIn++ ) {
|
|
|
|
//
|
|
// First fill in the local address. It should remain basically
|
|
// all zeros except for the family so that it is a "wildcard"
|
|
// address for binding.
|
|
//
|
|
|
|
RtlZeroMemory( csaddrInfo, sizeof(*csaddrInfo) );
|
|
|
|
csaddrInfo->LocalAddr.lpSockaddr = (LPSOCKADDR)sockaddrIn;
|
|
csaddrInfo->LocalAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
|
|
|
|
RtlZeroMemory( sockaddrIn, sizeof(*sockaddrIn) );
|
|
sockaddrIn->sin_family = AF_INET;
|
|
|
|
//
|
|
// Now the remote address.
|
|
//
|
|
|
|
sockaddrIn++;
|
|
|
|
csaddrInfo->RemoteAddr.lpSockaddr = (PSOCKADDR)( sockaddrIn );
|
|
csaddrInfo->RemoteAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
|
|
|
|
sockaddrIn = (PSOCKADDR_IN)csaddrInfo->RemoteAddr.lpSockaddr;
|
|
RtlZeroMemory( sockaddrIn, sizeof(*sockaddrIn) );
|
|
sockaddrIn->sin_family = AF_INET;
|
|
|
|
//
|
|
// Fill in the remote address with the actual address, both port
|
|
// and IP address.
|
|
//
|
|
|
|
sockaddrIn->sin_port = Port;
|
|
sockaddrIn->sin_addr.s_addr =
|
|
*((long *)(HostEntry->h_addr_list[i]));
|
|
|
|
//
|
|
// Lastly, fill in the protocol information.
|
|
//
|
|
|
|
if ( IsTcp ) {
|
|
csaddrInfo->iSocketType = SOCK_STREAM;
|
|
csaddrInfo->iProtocol = IPPROTO_TCP;
|
|
} else {
|
|
csaddrInfo->iSocketType = SOCK_DGRAM;
|
|
csaddrInfo->iProtocol = IPPROTO_UDP;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copy the aliases to the alias buffer. The "official" name from the
|
|
// hostent goes as the first alias, then the actual aliases.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpAliasBuffer ) &&
|
|
ARGUMENT_PRESENT( lpdwAliasBufferLength ) ) {
|
|
|
|
//
|
|
// Copy over the official name first.
|
|
//
|
|
|
|
aliasBytesUsed = 0;
|
|
|
|
CopyToAliasBuffer(
|
|
HostEntry->h_name,
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&aliasBytesUsed
|
|
);
|
|
|
|
if ( HostEntry->h_aliases != NULL ) {
|
|
|
|
for ( i = 0; HostEntry->h_aliases[i] != NULL; i++ ) {
|
|
|
|
CopyToAliasBuffer(
|
|
HostEntry->h_aliases[i],
|
|
lpAliasBuffer,
|
|
lpdwAliasBufferLength,
|
|
&aliasBytesUsed
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set up the final zero-terminator on the alias list.
|
|
//
|
|
|
|
aliasBytesUsed += sizeof(TCHAR);
|
|
|
|
if ( aliasBytesUsed <= *lpdwAliasBufferLength ) {
|
|
lpAliasBuffer[(aliasBytesUsed / sizeof(TCHAR)) - 1] = L'\0';
|
|
}
|
|
|
|
//
|
|
// Tell the caller how much of the alias buffer we used.
|
|
//
|
|
|
|
*lpdwAliasBufferLength = aliasBytesUsed;
|
|
}
|
|
|
|
*Count = count;
|
|
|
|
return NO_ERROR;
|
|
|
|
} // HostentToCsaddr
|
|
|
|
|
|
VOID
|
|
CopyToAliasBuffer (
|
|
IN PSTR Alias,
|
|
IN OUT LPTSTR AliasBuffer,
|
|
IN OUT LPDWORD lpdwAliasBufferLength,
|
|
IN OUT LPDWORD AliasBytesUsed
|
|
)
|
|
{
|
|
#if defined(UNICODE)
|
|
UNICODE_STRING unicodeString;
|
|
ANSI_STRING ansiString;
|
|
#endif
|
|
|
|
//
|
|
// Point to the first unused byte in the alias buffer.
|
|
//
|
|
|
|
AliasBuffer = (LPTSTR)( (PBYTE)AliasBuffer + *AliasBytesUsed );
|
|
|
|
//
|
|
// Initialize string structures for the alias.
|
|
//
|
|
|
|
#if defined(UNICODE)
|
|
RtlInitAnsiString( &ansiString, Alias );
|
|
|
|
unicodeString.Buffer = AliasBuffer;
|
|
unicodeString.MaximumLength =
|
|
(USHORT)(*lpdwAliasBufferLength - *AliasBytesUsed);
|
|
#endif
|
|
|
|
//
|
|
// Make sure that there is enough room left in the alias buffer.
|
|
//
|
|
|
|
*AliasBytesUsed += (strlen( Alias ) + 1) * sizeof(TCHAR);
|
|
if ( *AliasBytesUsed > *lpdwAliasBufferLength ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Convert the ANSI name to Unicode and copy it to the alias buffer.
|
|
//
|
|
|
|
#if defined(UNICODE)
|
|
RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, FALSE );
|
|
#else
|
|
_tcscpy( AliasBuffer, Alias );
|
|
#endif
|
|
|
|
return;
|
|
|
|
} // CopyToAliasBuffer
|
|
|
|
#if defined(HOSTENT_CACHING_ENABLED)
|
|
|
|
|
|
VOID
|
|
CacheHostent (
|
|
IN PHOSTENT HostEntry,
|
|
IN INT Ttl
|
|
)
|
|
{
|
|
MY_LARGE_INTEGER currentTime;
|
|
MY_LARGE_INTEGER liTtl;
|
|
DWORD bytesRequired;
|
|
PHOSTENT_CACHE_ENTRY cacheEntry;
|
|
PLIST_ENTRY listEntry;
|
|
PHOSTENT_CACHE_ENTRY testCacheEntry;
|
|
PHOSTENT_CACHE_ENTRY oldestCacheEntry;
|
|
|
|
//
|
|
// If the TTL is 0, do not cache the entry.
|
|
//
|
|
|
|
if ( ( Ttl <= 0 ) || ( MaxHostentCacheSize == 0 ) ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get the current time and convert the TTL to 64 bit time.
|
|
//
|
|
|
|
#if defined(CHICAGO)
|
|
currentTime = time(NULL);
|
|
liTtl = Ttl;
|
|
#else
|
|
NtQuerySystemTime( ¤tTime );
|
|
liTtl = RtlEnlargedIntegerMultiply( Ttl, 10*1000*1000 );
|
|
#endif
|
|
|
|
//
|
|
// Allocate space to hold the hostent information.
|
|
//
|
|
|
|
bytesRequired = sizeof(*cacheEntry) + BytesInHostent( HostEntry ) + 20;
|
|
|
|
cacheEntry = ALLOCATE_HEAP( bytesRequired );
|
|
if ( cacheEntry == NULL ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Set up the cache entry.
|
|
//
|
|
|
|
cacheEntry->LastAccessTime = currentTime;
|
|
QUADPART(cacheEntry->ExpirationTime) = QUADPART(currentTime) + QUADPART(liTtl);
|
|
|
|
CopyHostentToBuffer(
|
|
(char FAR *)&cacheEntry->HostEntry,
|
|
bytesRequired - sizeof(*cacheEntry),
|
|
HostEntry
|
|
);
|
|
|
|
//
|
|
// Acquire the global lock exclusively to protect our lists and
|
|
// counts, and test whether we're at the limit of the caching we'll
|
|
// do.
|
|
//
|
|
|
|
SockAcquireGlobalLockExclusive( );
|
|
|
|
if ( CurrentHostentCacheSize < MaxHostentCacheSize ) {
|
|
|
|
CurrentHostentCacheSize++;
|
|
|
|
} else {
|
|
|
|
//
|
|
// We're at our limit for cached entries. Remove the oldest
|
|
// entry from the cache.
|
|
//
|
|
|
|
oldestCacheEntry = NULL;
|
|
|
|
for ( listEntry = HostentCacheListHead.Flink;
|
|
listEntry != &HostentCacheListHead;
|
|
listEntry = listEntry->Flink ) {
|
|
|
|
|
|
testCacheEntry = CONTAINING_RECORD(
|
|
listEntry,
|
|
HOSTENT_CACHE_ENTRY,
|
|
HostentListEntry
|
|
);
|
|
|
|
if ( oldestCacheEntry == NULL ||
|
|
QUADPART(testCacheEntry->LastAccessTime) <
|
|
QUADPART(oldestCacheEntry->LastAccessTime) ) {
|
|
|
|
oldestCacheEntry = testCacheEntry;
|
|
}
|
|
}
|
|
|
|
RemoveEntryList( &oldestCacheEntry->HostentListEntry );
|
|
FREE_HEAP( oldestCacheEntry );
|
|
}
|
|
|
|
//
|
|
// Place the new entry at the front of the global list and return;
|
|
//
|
|
|
|
InsertHeadList( &HostentCacheListHead, &cacheEntry->HostentListEntry );
|
|
|
|
SockReleaseGlobalLock( );
|
|
|
|
return;
|
|
|
|
} // CacheHostent
|
|
|
|
|
|
PHOSTENT
|
|
QueryHostentCache (
|
|
IN LPSTR Name OPTIONAL,
|
|
IN DWORD IpAddress OPTIONAL
|
|
)
|
|
{
|
|
PLIST_ENTRY listEntry;
|
|
PHOSTENT_CACHE_ENTRY testCacheEntry;
|
|
DWORD i;
|
|
MY_LARGE_INTEGER currentTime;
|
|
PHOSTENT hostEntry;
|
|
|
|
//
|
|
// *** It is assumed that this routine is called while the caller
|
|
// holds the appropriate global cache lock!
|
|
//
|
|
|
|
//
|
|
// First get the current system time. We'll use this to reset the
|
|
// LastAccessTime if we find a hit.
|
|
//
|
|
|
|
#if defined(CHICAGO)
|
|
currentTime = time(NULL);
|
|
#else
|
|
NtQuerySystemTime( ¤tTime );
|
|
#endif
|
|
|
|
//
|
|
// Walk the host entry cache. As soon as we find a match, quit
|
|
// walking the list.
|
|
//
|
|
|
|
for ( listEntry = HostentCacheListHead.Flink;
|
|
listEntry != &HostentCacheListHead; ) {
|
|
|
|
testCacheEntry = CONTAINING_RECORD(
|
|
listEntry,
|
|
HOSTENT_CACHE_ENTRY,
|
|
HostentListEntry
|
|
);
|
|
hostEntry = &testCacheEntry->HostEntry;
|
|
|
|
//
|
|
// If this entry has expired, remove it from the list.
|
|
//
|
|
|
|
if ( QUADPART(currentTime) > QUADPART(testCacheEntry->ExpirationTime) ) {
|
|
|
|
CurrentHostentCacheSize--;
|
|
RemoveEntryList( &testCacheEntry->HostentListEntry );
|
|
listEntry = listEntry->Flink;
|
|
FREE_HEAP( testCacheEntry );
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// First check for a matching name. A match on either the
|
|
// primary name or any of the aliases results in a hit.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( Name ) ) {
|
|
|
|
if ( LSTRCMPI( Name, hostEntry->h_name ) == 0 ) {
|
|
testCacheEntry->LastAccessTime = currentTime;
|
|
return hostEntry;
|
|
}
|
|
|
|
for ( i = 0; hostEntry->h_aliases[i] != NULL; i++ ) {
|
|
if ( LSTRCMPI( Name, hostEntry->h_aliases[i] ) == 0 ) {
|
|
testCacheEntry->LastAccessTime = currentTime;
|
|
return hostEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now check for a match against any of the IP addresses in
|
|
// the hostent.
|
|
//
|
|
|
|
if ( IpAddress != 0 ) {
|
|
|
|
for ( i = 0; hostEntry->h_addr_list[i] != NULL; i++ ) {
|
|
if ( IpAddress == *(PDWORD)hostEntry->h_addr_list[i] ) {
|
|
testCacheEntry->LastAccessTime = currentTime;
|
|
return hostEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
listEntry = listEntry->Flink;
|
|
}
|
|
|
|
//
|
|
// We didn't find a match in the hostent cache.
|
|
//
|
|
|
|
return NULL;
|
|
|
|
} // QueryHostentCache
|
|
|
|
#endif // defined(HOSTENT_CACHING_ENABLED)
|
|
|
|
|
|
INT
|
|
ServiceCsaddr (
|
|
IN WORD Port,
|
|
IN BOOL IsTcp,
|
|
IN OUT LPVOID lpCsaddrBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength
|
|
)
|
|
{
|
|
DWORD requiredBufferLength;
|
|
PCSADDR_INFO csaddrInfo;
|
|
PSOCKADDR_IN sockaddrIn;
|
|
|
|
//
|
|
// We're going to return exactly one sockaddr and csaddr structure.
|
|
// Make sure that the user buffer is large enough.
|
|
//
|
|
|
|
requiredBufferLength = sizeof(CSADDR_INFO) + 2*sizeof(SOCKADDR_IN);
|
|
|
|
if ( *lpdwBufferLength < requiredBufferLength ) {
|
|
*lpdwBufferLength = requiredBufferLength;
|
|
return (DWORD)-1;
|
|
}
|
|
|
|
*lpdwBufferLength = requiredBufferLength;
|
|
|
|
//
|
|
// Fill in the appropriate information. Set the local sockaddr's
|
|
// port to the port for the service, and leave the remote's port
|
|
// zero. All IP addresses remain INADDR_ANY (0).
|
|
//
|
|
|
|
csaddrInfo = lpCsaddrBuffer;
|
|
RtlZeroMemory( csaddrInfo, sizeof(*csaddrInfo) );
|
|
|
|
sockaddrIn = (PSOCKADDR_IN)(csaddrInfo + 1);
|
|
csaddrInfo->LocalAddr.lpSockaddr = (LPSOCKADDR)sockaddrIn;
|
|
csaddrInfo->LocalAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
|
|
|
|
if ( IsTcp ) {
|
|
csaddrInfo->iSocketType = SOCK_STREAM;
|
|
csaddrInfo->iProtocol = IPPROTO_TCP;
|
|
} else {
|
|
csaddrInfo->iSocketType = SOCK_DGRAM;
|
|
csaddrInfo->iProtocol = IPPROTO_UDP;
|
|
}
|
|
|
|
RtlZeroMemory( sockaddrIn, sizeof(*sockaddrIn) );
|
|
sockaddrIn->sin_family = AF_INET;
|
|
sockaddrIn->sin_port = Port;
|
|
|
|
sockaddrIn += 1;
|
|
csaddrInfo->RemoteAddr.lpSockaddr = (LPSOCKADDR)sockaddrIn;
|
|
csaddrInfo->RemoteAddr.iSockaddrLength = sizeof(SOCKADDR_IN);
|
|
|
|
RtlZeroMemory( sockaddrIn, sizeof(*sockaddrIn) );
|
|
sockaddrIn->sin_family = AF_INET;
|
|
|
|
//
|
|
// Return a count of one entry.
|
|
//
|
|
|
|
return 1;
|
|
|
|
} // ServiceCsaddr
|
|
|
|
#if defined(CHICAGO)
|
|
|
|
|
|
INT
|
|
WSHEnumProtocols (
|
|
IN LPINT lpiProtocols,
|
|
IN LPSTR lpTransportKeyName,
|
|
IN OUT LPVOID lpProtocolBuffer,
|
|
IN OUT LPDWORD lpdwBufferLength
|
|
)
|
|
{
|
|
DWORD bytesRequired;
|
|
PPROTOCOL_INFO11 tcpProtocolInfo;
|
|
PPROTOCOL_INFO11 udpProtocolInfo;
|
|
BOOL useTcp = FALSE;
|
|
BOOL useUdp = FALSE;
|
|
DWORD i;
|
|
|
|
lpTransportKeyName; // Avoid compiler warnings.
|
|
|
|
//
|
|
// Make sure that the caller cares about TCP and/or UDP.
|
|
//
|
|
|
|
if ( ARGUMENT_PRESENT( lpiProtocols ) ) {
|
|
|
|
for ( i = 0; lpiProtocols[i] != 0; i++ ) {
|
|
if ( lpiProtocols[i] == IPPROTO_TCP ) {
|
|
useTcp = TRUE;
|
|
}
|
|
if ( lpiProtocols[i] == IPPROTO_UDP ) {
|
|
useUdp = TRUE;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
useTcp = TRUE;
|
|
useUdp = TRUE;
|
|
}
|
|
|
|
if ( !useTcp && !useUdp ) {
|
|
*lpdwBufferLength = 0;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Make sure that the caller has specified a sufficiently large
|
|
// buffer.
|
|
//
|
|
|
|
bytesRequired = (sizeof(PROTOCOL_INFO11) * 2) +
|
|
( (lstrlen( TCP_NAME ) + 1) * sizeof(TCHAR)) +
|
|
( (lstrlen( UDP_NAME ) + 1) * sizeof(TCHAR));
|
|
|
|
if ( bytesRequired > *lpdwBufferLength ) {
|
|
*lpdwBufferLength = bytesRequired;
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Fill in TCP info, if requested.
|
|
//
|
|
|
|
if ( useTcp ) {
|
|
|
|
tcpProtocolInfo = lpProtocolBuffer;
|
|
|
|
tcpProtocolInfo->dwServiceFlags = XP_GUARANTEED_DELIVERY |
|
|
XP_GUARANTEED_ORDER |
|
|
XP_GRACEFUL_CLOSE |
|
|
XP_EXPEDITED_DATA |
|
|
XP_FRAGMENTATION;
|
|
tcpProtocolInfo->iAddressFamily = AF_INET;
|
|
tcpProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_IN);
|
|
tcpProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_IN);
|
|
tcpProtocolInfo->iSocketType = SOCK_STREAM;
|
|
tcpProtocolInfo->iProtocol = IPPROTO_TCP;
|
|
tcpProtocolInfo->dwMessageSize = 0;
|
|
tcpProtocolInfo->lpProtocol = (LPSTR)
|
|
( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
|
|
( (lstrlen( TCP_NAME ) + 1) * sizeof(TCHAR) ) );
|
|
lstrcpy( tcpProtocolInfo->lpProtocol, TCP_NAME );
|
|
|
|
udpProtocolInfo = tcpProtocolInfo + 1;
|
|
udpProtocolInfo->lpProtocol = (LPSTR)
|
|
( (PBYTE)tcpProtocolInfo->lpProtocol -
|
|
( (lstrlen( UDP_NAME ) + 1) * sizeof(TCHAR) ) );
|
|
|
|
} else {
|
|
|
|
udpProtocolInfo = lpProtocolBuffer;
|
|
udpProtocolInfo->lpProtocol = (LPSTR)
|
|
( (PBYTE)lpProtocolBuffer + *lpdwBufferLength -
|
|
( (lstrlen( UDP_NAME ) + 1) * sizeof(TCHAR) ) );
|
|
}
|
|
|
|
//
|
|
// Fill in UDP info, if requested.
|
|
//
|
|
|
|
if ( useUdp ) {
|
|
|
|
udpProtocolInfo->dwServiceFlags = XP_CONNECTIONLESS |
|
|
XP_MESSAGE_ORIENTED |
|
|
XP_SUPPORTS_BROADCAST |
|
|
XP_SUPPORTS_MULTICAST |
|
|
XP_FRAGMENTATION;
|
|
udpProtocolInfo->iAddressFamily = AF_INET;
|
|
udpProtocolInfo->iMaxSockAddr = sizeof(SOCKADDR_IN);
|
|
udpProtocolInfo->iMinSockAddr = sizeof(SOCKADDR_IN);
|
|
udpProtocolInfo->iSocketType = SOCK_DGRAM;
|
|
udpProtocolInfo->iProtocol = IPPROTO_UDP;
|
|
udpProtocolInfo->dwMessageSize = 65535-68;
|
|
lstrcpy( udpProtocolInfo->lpProtocol, UDP_NAME );
|
|
}
|
|
|
|
*lpdwBufferLength = bytesRequired;
|
|
|
|
return (useTcp && useUdp) ? 2 : 1;
|
|
|
|
} // WSHEnumProtocols
|
|
|
|
#endif
|