windows-nt/Source/XPSP1/NT/ds/dns/dnslib/addr.c
2020-09-26 16:20:57 +08:00

653 lines
11 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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
//