653 lines
11 KiB
C
653 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 2000-2001 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
addr.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Domain Name System (DNS) Library
|
|||
|
|
|||
|
IP address routines
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Jim Gilroy (jamesg) June 2000
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
|
|||
|
#include "local.h"
|
|||
|
#include "ws2atm.h" // ATM addressing
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Address info table
|
|||
|
//
|
|||
|
|
|||
|
FAMILY_INFO AddrFamilyTable[] =
|
|||
|
{
|
|||
|
AF_INET,
|
|||
|
DNS_TYPE_A,
|
|||
|
sizeof(IP4_ADDRESS),
|
|||
|
sizeof(SOCKADDR_IN),
|
|||
|
(DWORD) FIELD_OFFSET( SOCKADDR_IN, sin_addr ),
|
|||
|
//sizeof(DWORD),
|
|||
|
|
|||
|
AF_INET6,
|
|||
|
DNS_TYPE_AAAA,
|
|||
|
sizeof(IP6_ADDRESS),
|
|||
|
sizeof(SOCKADDR_IN6),
|
|||
|
(DWORD) FIELD_OFFSET( SOCKADDR_IN6, sin6_addr ),
|
|||
|
//(2 * sizeof(DWORD)),
|
|||
|
|
|||
|
AF_ATM,
|
|||
|
DNS_TYPE_ATMA,
|
|||
|
sizeof(ATM_ADDRESS),
|
|||
|
sizeof(SOCKADDR_ATM),
|
|||
|
sizeof(DWORD),
|
|||
|
(DWORD) FIELD_OFFSET( SOCKADDR_ATM, satm_number ),
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
|
|||
|
PFAMILY_INFO
|
|||
|
FamilyInfo_GetForFamily(
|
|||
|
IN DWORD Family
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get address family info for family.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Family -- address family
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Ptr to address family info for family.
|
|||
|
NULL if family is unknown.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PFAMILY_INFO pinfo = NULL;
|
|||
|
|
|||
|
// switch on type
|
|||
|
|
|||
|
if ( Family == AF_INET )
|
|||
|
{
|
|||
|
pinfo = pFamilyInfoIp4;
|
|||
|
}
|
|||
|
else if ( Family == AF_INET6 )
|
|||
|
{
|
|||
|
pinfo = pFamilyInfoIp6;
|
|||
|
}
|
|||
|
else if ( Family == AF_ATM )
|
|||
|
{
|
|||
|
pinfo = pFamilyInfoAtm;
|
|||
|
}
|
|||
|
|
|||
|
return pinfo;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// IPUNION routines
|
|||
|
//
|
|||
|
|
|||
|
BOOL
|
|||
|
Dns_EqualIpUnion(
|
|||
|
IN PIP_UNION pIp1,
|
|||
|
IN PIP_UNION pIp2
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Test IP union for equality
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIp1 -- IP address union
|
|||
|
|
|||
|
pIp2 -- IP address union
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if Ip1 and Ip2 equal.
|
|||
|
FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
//
|
|||
|
// DCR: when stamp flat, can make this memory compare
|
|||
|
//
|
|||
|
|
|||
|
// IP4 match?
|
|||
|
|
|||
|
if ( IPUNION_IS_IP4(pIp1) )
|
|||
|
{
|
|||
|
if ( IPUNION_IS_IP4(pIp2) &&
|
|||
|
IPUNION_GET_IP4(pIp1) == IPUNION_GET_IP4(pIp2) )
|
|||
|
{
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// IP6 match?
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
if ( IPUNION_IS_IP6(pIp2) &&
|
|||
|
RtlEqualMemory(
|
|||
|
IPUNION_IP6_PTR(pIp1),
|
|||
|
IPUNION_IP6_PTR(pIp2),
|
|||
|
sizeof(IP6_ADDRESS) ) )
|
|||
|
{
|
|||
|
return( TRUE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return( FALSE );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Sockaddr
|
|||
|
//
|
|||
|
|
|||
|
IP6_ADDRESS
|
|||
|
Ip6AddressFromSockaddr(
|
|||
|
IN PSOCKADDR pSockaddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get IP6 address from sockaddr.
|
|||
|
|
|||
|
If IP4 sockaddr, IP6 address is mapped.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pSockaddr -- any kind of sockaddr
|
|||
|
must have actual length for sockaddr family
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
IP6 address corresponding to sockaddr.
|
|||
|
If IP4 sockaddr it's IP4_MAPPED address.
|
|||
|
If not IP4 or IP6 sockaddr IP6 addresss is zero.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
IP6_ADDRESS ip6;
|
|||
|
|
|||
|
//
|
|||
|
// switch on family
|
|||
|
// - IP6 gets copy
|
|||
|
// - IP4 gets IP4_MAPPED
|
|||
|
// - bogus gets zero
|
|||
|
//
|
|||
|
|
|||
|
switch ( pSockaddr->sa_family )
|
|||
|
{
|
|||
|
case AF_INET:
|
|||
|
|
|||
|
IP6_SET_ADDR_V4MAPPED(
|
|||
|
& ip6,
|
|||
|
((PSOCKADDR_IN)pSockaddr)->sin_addr.s_addr );
|
|||
|
break;
|
|||
|
|
|||
|
case AF_INET6:
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
&ip6,
|
|||
|
& ((PSOCKADDR_IN6)pSockaddr)->sin6_addr,
|
|||
|
sizeof(IP6_ADDRESS) );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
RtlZeroMemory(
|
|||
|
&ip6,
|
|||
|
sizeof(IP6_ADDRESS) );
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
return ip6;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InitSockaddrWithIp6Address(
|
|||
|
OUT PSOCKADDR pSockaddr,
|
|||
|
IN IP6_ADDRESS Ip6Addr,
|
|||
|
IN WORD Port
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Write IP6 address (straight 6 or v4 mapped) to sockaddr.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pSockaddr -- ptr to sockaddr to write to;
|
|||
|
must be at least size of SOCKADDR_IN6
|
|||
|
|
|||
|
Ip6Addr -- IP6 addresss being written
|
|||
|
|
|||
|
Port -- port in net byte order
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
// zero
|
|||
|
|
|||
|
RtlZeroMemory(
|
|||
|
pSockaddr,
|
|||
|
sizeof(SOCKADDR_IN6) );
|
|||
|
|
|||
|
//
|
|||
|
// determine whether IP6 or IP4
|
|||
|
//
|
|||
|
|
|||
|
if ( IP6_IS_ADDR_V4MAPPED( &Ip6Addr ) )
|
|||
|
{
|
|||
|
PSOCKADDR_IN psa = (PSOCKADDR_IN) pSockaddr;
|
|||
|
|
|||
|
psa->sin_family = AF_INET;
|
|||
|
psa->sin_port = Port;
|
|||
|
|
|||
|
psa->sin_addr.s_addr = IP6_GET_V4_ADDR( &Ip6Addr );
|
|||
|
}
|
|||
|
else // IP6
|
|||
|
{
|
|||
|
PSOCKADDR_IN6 psa = (PSOCKADDR_IN6) pSockaddr;
|
|||
|
|
|||
|
psa->sin6_family = AF_INET6;
|
|||
|
psa->sin6_port = Port;
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
&psa->sin6_addr,
|
|||
|
&Ip6Addr,
|
|||
|
sizeof(IP6_ADDRESS) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DNS_STATUS
|
|||
|
Dns_AddressToSockaddr(
|
|||
|
OUT PSOCKADDR pSockaddr,
|
|||
|
IN OUT PDWORD pSockaddrLength,
|
|||
|
IN BOOL fClearSockaddr,
|
|||
|
IN PBYTE pAddr,
|
|||
|
IN DWORD AddrLength,
|
|||
|
IN DWORD AddrFamily
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Convert address in ptr\family\length to sockaddr.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pSockaddr -- sockaddr buffer to recv address
|
|||
|
|
|||
|
pSockaddrLength -- addr with length of sockaddr buffer
|
|||
|
receives the actual sockaddr length
|
|||
|
|
|||
|
fClearSockaddr -- start with zero buffer
|
|||
|
|
|||
|
pAddr -- ptr to address
|
|||
|
|
|||
|
AddrLength -- address length
|
|||
|
|
|||
|
AddrFamily -- address family (AF_INET, AF_INET6)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR if successful.
|
|||
|
ERROR_INSUFFICIENT_BUFFER -- if buffer too small
|
|||
|
WSAEAFNOSUPPORT -- if invalid family
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PFAMILY_INFO pinfo;
|
|||
|
DWORD lengthIn = *pSockaddrLength;
|
|||
|
DWORD lengthSockAddr;
|
|||
|
|
|||
|
|
|||
|
// clear to start
|
|||
|
|
|||
|
if ( fClearSockaddr )
|
|||
|
{
|
|||
|
RtlZeroMemory(
|
|||
|
pSockaddr,
|
|||
|
lengthIn );
|
|||
|
}
|
|||
|
|
|||
|
// switch on type
|
|||
|
|
|||
|
if ( AddrFamily == AF_INET )
|
|||
|
{
|
|||
|
pinfo = pFamilyInfoIp4;
|
|||
|
}
|
|||
|
else if ( AddrFamily == AF_INET6 )
|
|||
|
{
|
|||
|
pinfo = pFamilyInfoIp6;
|
|||
|
}
|
|||
|
else if ( AddrFamily == AF_ATM )
|
|||
|
{
|
|||
|
pinfo = pFamilyInfoAtm;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return WSAEAFNOSUPPORT;
|
|||
|
}
|
|||
|
|
|||
|
// validate lengths
|
|||
|
|
|||
|
if ( AddrLength != pinfo->LengthAddr )
|
|||
|
{
|
|||
|
return DNS_ERROR_INVALID_IP_ADDRESS;
|
|||
|
}
|
|||
|
|
|||
|
lengthSockAddr = pinfo->LengthSockaddr;
|
|||
|
*pSockaddrLength = lengthSockAddr;
|
|||
|
|
|||
|
if ( lengthIn < lengthSockAddr )
|
|||
|
{
|
|||
|
return ERROR_INSUFFICIENT_BUFFER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// fill out sockaddr
|
|||
|
// - set family
|
|||
|
// - copy address to sockaddr
|
|||
|
// - return length was set above
|
|||
|
//
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
(PBYTE)pSockaddr + pinfo->OffsetToAddrInSockaddr,
|
|||
|
pAddr,
|
|||
|
AddrLength );
|
|||
|
|
|||
|
pSockaddr->sa_family = (WORD)AddrFamily;
|
|||
|
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if 0
|
|||
|
// without family info
|
|||
|
DNS_STATUS
|
|||
|
Dns_AddressToSockaddr(
|
|||
|
OUT PSOCKADDR pSockaddr,
|
|||
|
IN OUT PDWORD pSockaddrLength,
|
|||
|
IN BOOL fClearSockaddr,
|
|||
|
IN PBYTE pAddr,
|
|||
|
IN DWORD AddrLength,
|
|||
|
IN DWORD AddrFamily
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Convert address in ptr\family\length to sockaddr.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pSockaddr -- sockaddr buffer to recv address
|
|||
|
|
|||
|
pSockaddrLength -- addr with length of sockaddr buffer
|
|||
|
receives the actual sockaddr length
|
|||
|
|
|||
|
fClearSockaddr -- start with zero buffer
|
|||
|
|
|||
|
pAddr -- ptr to address
|
|||
|
|
|||
|
AddrLength -- address length
|
|||
|
|
|||
|
AddrFamily -- address family (AF_INET, AF_INET6)
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NO_ERROR if successful.
|
|||
|
ERROR_INSUFFICIENT_BUFFER -- if buffer too small
|
|||
|
WSAEAFNOSUPPORT -- if invalid family
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
DWORD lengthIn = *pSockaddrLength;
|
|||
|
DWORD lengthSockAddr;
|
|||
|
DWORD lengthAddr;
|
|||
|
PBYTE paddrInSockaddr;
|
|||
|
|
|||
|
|
|||
|
// clear to start
|
|||
|
|
|||
|
if ( fClearSockaddr )
|
|||
|
{
|
|||
|
RtlZeroMemory(
|
|||
|
pSockaddr,
|
|||
|
lengthIn );
|
|||
|
}
|
|||
|
|
|||
|
// switch on type
|
|||
|
|
|||
|
if ( Family == AF_INET )
|
|||
|
{
|
|||
|
lengthSockAddr = sizeof(SOCKADDR_IN);
|
|||
|
lengthAddr = sizeof(IP4_ADDRESS);
|
|||
|
paddrInSockaddr = (PBYTE) &((PSOCKADDR_IN)pSockaddr)->sin_addr,
|
|||
|
}
|
|||
|
else if ( Family == AF_INET6 )
|
|||
|
{
|
|||
|
lengthSockAddr = sizeof(SOCKADDR_IN6);
|
|||
|
lengthAddr = sizeof(IP6_ADDRESS);
|
|||
|
paddrInSockaddr = (PBYTE) &((PSOCKADDR_IN6)pSockaddr)->sin6_addr,
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return WSAEAFNOSUPPORT;
|
|||
|
}
|
|||
|
|
|||
|
// validate lengths
|
|||
|
|
|||
|
if ( AddrLength != lengthAddr )
|
|||
|
{
|
|||
|
return DNS_ERROR_INVALID_IP_ADDRESS;
|
|||
|
}
|
|||
|
if ( lengthIn < lengthSockAddr )
|
|||
|
{
|
|||
|
*pSockaddrLength = lengthSockAddr;
|
|||
|
return ERROR_INSUFFICIENT_BUFFER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// fill out sockaddr
|
|||
|
// - set family
|
|||
|
// - copy address to sockaddr
|
|||
|
// - set return length
|
|||
|
//
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
paddrInSockaddr,
|
|||
|
pAddr,
|
|||
|
lengthAddr );
|
|||
|
|
|||
|
}
|
|||
|
else // IP6
|
|||
|
{
|
|||
|
if ( length < sizeof(SOCKADDR_IN) )
|
|||
|
{
|
|||
|
return ERROR_INSUFFICIENT_BUFFER;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
& ((PSOCKADDR_IN6)pSockaddr)->sin6_addr,
|
|||
|
pAddr,
|
|||
|
AddrLength );
|
|||
|
}
|
|||
|
|
|||
|
// DCR: ATM sockaddr
|
|||
|
|
|||
|
|
|||
|
pSockaddr->sa_family = Family;
|
|||
|
|
|||
|
return NO_ERROR;
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
|
|||
|
BOOL
|
|||
|
Dns_SockaddrToIpUnion(
|
|||
|
OUT PIP_UNION pIpUnion,
|
|||
|
IN PSOCKADDR pSockaddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Build IP union from sockaddr.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pIpUnion -- ptr IP union to build
|
|||
|
|
|||
|
pSockaddr -- sockaddr
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE if successfully created IP union.
|
|||
|
FALSE otherwise.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PFAMILY_INFO pinfo;
|
|||
|
WORD family = pSockaddr->sa_family;
|
|||
|
BOOL fIs6;
|
|||
|
|
|||
|
//
|
|||
|
// only support IP4 and IP6
|
|||
|
//
|
|||
|
// DCR: could add IP_UNION support to family info
|
|||
|
//
|
|||
|
|
|||
|
if ( family == AF_INET )
|
|||
|
{
|
|||
|
fIs6 = FALSE;
|
|||
|
}
|
|||
|
else if ( family == AF_INET6 )
|
|||
|
{
|
|||
|
fIs6 = TRUE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get family info for unitary copy
|
|||
|
//
|
|||
|
|
|||
|
pinfo = FamilyInfo_GetForFamily( family );
|
|||
|
if ( !pinfo )
|
|||
|
{
|
|||
|
DNS_ASSERT( FALSE );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
(PBYTE) &pIpUnion->Addr,
|
|||
|
(PBYTE)pSockaddr + pinfo->OffsetToAddrInSockaddr,
|
|||
|
pinfo->LengthAddr );
|
|||
|
|
|||
|
pIpUnion->IsIp6 = fIs6;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
Family_SockaddrLength(
|
|||
|
IN WORD Family
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Extract info for family.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Family -- address family
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Length of sockaddr for address family.
|
|||
|
Zero if unknown family.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PFAMILY_INFO pinfo;
|
|||
|
|
|||
|
// get family -- extract info
|
|||
|
|
|||
|
pinfo = FamilyInfo_GetForFamily( Family );
|
|||
|
if ( pinfo )
|
|||
|
{
|
|||
|
return pinfo->LengthSockaddr;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
Sockaddr_Length(
|
|||
|
IN PSOCKADDR pSockaddr
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Get length of sockaddr.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pSockaddr -- sockaddr buffer to recv address
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
Length of sockaddr for address family.
|
|||
|
Zero if unknown family.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
return Family_SockaddrLength( pSockaddr->sa_family );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// End addr.c
|
|||
|
//
|