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