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