Leaked source code of windows server 2003
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.
 
 
 
 
 
 

471 lines
7.8 KiB

/*++
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 ),
AF_INET6,
DNS_TYPE_AAAA,
sizeof(IP6_ADDRESS),
sizeof(SOCKADDR_IN6),
(DWORD) FIELD_OFFSET( SOCKADDR_IN6, sin6_addr ),
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;
}
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;
}
WORD
Family_DnsType(
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->DnsType;
}
return 0;
}
DWORD
Family_GetFromDnsType(
IN WORD wType
)
/*++
Routine Description:
Get address family for a given DNS type.
Arguments:
wType -- DNS type
Return Value:
Address family if found.
Zero if wType doesn't map to known family.
--*/
{
// switch on type
if ( wType == DNS_TYPE_A )
{
return AF_INET;
}
if ( wType == DNS_TYPE_AAAA )
{
return AF_INET6;
}
if ( wType == DNS_TYPE_ATMA )
{
return AF_ATM;
}
return 0;
}
//
// Sockaddr
//
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 );
}
IP6_ADDRESS
Sockaddr_GetIp6(
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
Sockaddr_BuildFromIp6(
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
Sockaddr_BuildFromFlatAddr(
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;
}
//
// End addr.c
//