//============================================================================= // Copyright (c) 2001 Microsoft Corporation // Abstract: // This module implements IPv6 configuration commands. // // This code is based off ipv6.c from Rich Draves //============================================================================= #include "precomp.h" #pragma hdrstop HANDLE Handle = INVALID_HANDLE_VALUE; BOOL AdminAccess = TRUE; #define IPv6_MINIMUM_MTU 1280 DWORD SetString( IN HKEY hKey, IN LPCTSTR lpName, IN PWCHAR pwcValue ); PWCHAR FormatTime( IN DWORD dwLife, OUT PWCHAR pwszLife ) { DWORD dwDays, dwHours, dwMinutes; PWCHAR pwszNext = pwszLife; if (dwLife == INFINITE_LIFETIME) { swprintf(pwszNext, L"%s", TOKEN_VALUE_INFINITE); return pwszLife; } if (dwLife < MINUTES) goto FormatSeconds; if (dwLife < HOURS) goto FormatMinutes; if (dwLife < DAYS) goto FormatHours; dwDays = dwLife / DAYS; pwszNext += swprintf(pwszNext, L"%ud", dwDays); dwLife -= dwDays * DAYS; FormatHours: dwHours = dwLife / HOURS; if (dwHours != 0) pwszNext += swprintf(pwszNext, L"%uh", dwHours); dwLife -= dwHours * HOURS; FormatMinutes: dwMinutes = dwLife / MINUTES; if (dwMinutes != 0) pwszNext += swprintf(pwszNext, L"%um", dwMinutes); dwLife -= dwMinutes * MINUTES; if (dwLife == 0) { return pwszLife; } FormatSeconds: swprintf(pwszNext, L"%us", dwLife); return pwszLife; } DWORD OpenIPv6( VOID ) { WSADATA wsaData; BOOL bInstalled; DWORD dwErr = NO_ERROR; if (Handle != INVALID_HANDLE_VALUE) { return NO_ERROR; } dwErr = IsIpv6Installed(&bInstalled); if (dwErr != NO_ERROR) { return dwErr; } if (!bInstalled) { DisplayMessage(g_hModule, EMSG_PROTO_NOT_INSTALLED); return ERROR_SUPPRESS_OUTPUT; } // // We initialize Winsock just so we can have access // to WSAStringToAddress and WSAAddressToString. // if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { return WSAGetLastError(); } // // First request write access. // This will fail if the process does not have local Administrator privs. // Handle = CreateFileW(WIN_IPV6_DEVICE_NAME, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, // security attributes OPEN_EXISTING, 0, // flags & attributes NULL); // template file if (Handle == INVALID_HANDLE_VALUE) { // // We will not have Administrator access to the stack. // AdminAccess = FALSE; Handle = CreateFileW(WIN_IPV6_DEVICE_NAME, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, // security attributes OPEN_EXISTING, 0, // flags & attributes NULL); // template file if (Handle == INVALID_HANDLE_VALUE) { return GetLastError(); } } return NO_ERROR; } ////////////////////////////////////////////////////////////////////////////// // Generic interface-related functions ////////////////////////////////////////////////////////////////////////////// IPV6_INFO_INTERFACE * GetInterfaceByIpv6IfIndex( IN DWORD dwIfIndex ) { IPV6_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; DWORD dwInfoSize, dwBytesReturned; Query.Index = dwIfIndex; dwInfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH; IF = (IPV6_INFO_INTERFACE *) MALLOC(dwInfoSize); if (IF == NULL) { return NULL; } if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_INTERFACE, &Query, sizeof Query, IF, dwInfoSize, &dwBytesReturned, NULL)) { FREE(IF); return NULL; } if ((dwBytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (dwBytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) { FREE(IF); return NULL; } return IF; } DWORD GetInterfaceByFriendlyName( IN PWCHAR pwszFriendlyName, IN IP_ADAPTER_ADDRESSES *pAdapterInfo, IN BOOL bPersistent, OUT IPV6_INFO_INTERFACE **pIF ) { DWORD dwIfIndex; DWORD dwErr; // // TODO: we cannot yet query an interface by GUID, so we can't // yet work for a persistent interface which is not currently present. // dwErr = MapFriendlyNameToIpv6IfIndex(pwszFriendlyName, pAdapterInfo, &dwIfIndex); if (dwErr != NO_ERROR) { return dwErr; } *pIF = GetInterfaceByIpv6IfIndex(dwIfIndex); return (*pIF)? NO_ERROR : ERROR_NOT_FOUND; } DWORD MyGetAdaptersInfo( OUT PIP_ADAPTER_ADDRESSES *ppAdapterInfo ) { IP_ADAPTER_ADDRESSES *pAdapterInfo; DWORD dwErr, BufLen = 0; DWORD Flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST; dwErr = GetAdaptersAddresses(AF_INET6, Flags, NULL, NULL, &BufLen); if (dwErr != ERROR_BUFFER_OVERFLOW) { return dwErr; } pAdapterInfo = (IP_ADAPTER_ADDRESSES *) MALLOC(BufLen); if (pAdapterInfo == NULL) { return GetLastError(); } dwErr = GetAdaptersAddresses(AF_INET6, Flags, NULL, pAdapterInfo, &BufLen); if (dwErr != NO_ERROR) { FREE(pAdapterInfo); return dwErr; } *ppAdapterInfo = pAdapterInfo; return NO_ERROR; } DWORD ForEachPersistentInterface( IN DWORD (*pfnFunc)(IPV6_INFO_INTERFACE *,PIP_ADAPTER_ADDRESSES,DWORD,FORMAT), IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format ) { IPV6_PERSISTENT_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; DWORD dwInfoSize, dwBytesReturned; DWORD dwCount = 0; dwInfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH; IF = (IPV6_INFO_INTERFACE *) MALLOC(dwInfoSize); if (IF == NULL) { return 0; } for (Query.RegistryIndex = 0; ; Query.RegistryIndex++) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_QUERY_INTERFACE, &Query, sizeof Query, IF, dwInfoSize, &dwBytesReturned, NULL)) { break; } if ((dwBytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (dwBytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) { break; } if ((*pfnFunc)(IF, pAdapterInfo, dwCount, Format) == NO_ERROR) { dwCount++; } } FREE(IF); return dwCount; } DWORD ForEachInterface( IN DWORD (*pfnFunc)(IPV6_INFO_INTERFACE *,PIP_ADAPTER_ADDRESSES,DWORD,FORMAT), IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format, IN BOOL bPersistent ) { IPV6_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; DWORD dwInfoSize, dwBytesReturned; DWORD dwCount = 0; if (bPersistent) { return ForEachPersistentInterface(pfnFunc, pAdapterInfo, Format); } dwInfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH; IF = (IPV6_INFO_INTERFACE *) MALLOC(dwInfoSize); if (IF == NULL) { return 0; } Query.Index = (u_int) -1; for (;;) { if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_INTERFACE, &Query, sizeof Query, IF, dwInfoSize, &dwBytesReturned, NULL)) { break; } if (Query.Index != (u_int) -1) { if ((dwBytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (dwBytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) { break; } if ((*pfnFunc)(IF, pAdapterInfo, dwCount, Format) == NO_ERROR) { dwCount++; } } else { if (dwBytesReturned != sizeof IF->Next) { break; } } if (IF->Next.Index == (u_int) -1) break; Query = IF->Next; } FREE(IF); return dwCount; } ////////////////////////////////////////////////////////////////////////////// // Site prefix table functions ////////////////////////////////////////////////////////////////////////////// DWORD ForEachSitePrefix( IN DWORD (*pfnFunc)(IPV6_INFO_SITE_PREFIX *,FORMAT,DWORD,IP_ADAPTER_ADDRESSES *), IN FORMAT Format, IN IP_ADAPTER_ADDRESSES *pAdapterInfo ) { IPV6_QUERY_SITE_PREFIX Query, NextQuery; IPV6_INFO_SITE_PREFIX SPE; DWORD dwBytesReturned; DWORD dwCount = 0; NextQuery.IF.Index = 0; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_SITE_PREFIX, &Query, sizeof Query, &SPE, sizeof SPE, &dwBytesReturned, NULL)) { break; } NextQuery = SPE.Query; if (Query.IF.Index != 0) { SPE.Query = Query; if ((*pfnFunc)(&SPE, Format, dwCount, pAdapterInfo) == NO_ERROR) { dwCount++; } } if (NextQuery.IF.Index == 0) { break; } } return dwCount; } DWORD PrintSitePrefix( IN IPV6_INFO_SITE_PREFIX *SPE, IN FORMAT Format, IN DWORD dwCount, IN IP_ADAPTER_ADDRESSES *pAdapterInfo ) { DWORD dwErr; WCHAR *FriendlyName; WCHAR wszValid[64]; dwErr = MapIpv6IfIndexToFriendlyName(SPE->Query.IF.Index, pAdapterInfo, &FriendlyName); if (dwErr != NO_ERROR) { return dwErr; } FormatTime(SPE->ValidLifetime, wszValid); if (Format == FORMAT_DUMP) { DisplayMessageT(DMP_IPV6_ADD_SITEPREFIX); DisplayMessageT(DMP_STRING_ARG, TOKEN_PREFIX, FormatIPv6Prefix(&SPE->Query.Prefix, SPE->Query.PrefixLength)); DisplayMessageT(DMP_QUOTED_STRING_ARG, TOKEN_INTERFACE, FriendlyName); DisplayMessageT(DMP_STRING_ARG, TOKEN_LIFETIME, wszValid); DisplayMessage(g_hModule, MSG_NEWLINE); } else { if (!dwCount) { DisplayMessage(g_hModule, MSG_IPV6_SITE_PREFIX_HDR); } DisplayMessage(g_hModule, MSG_IPV6_SITE_PREFIX, FormatIPv6Prefix(&SPE->Query.Prefix, SPE->Query.PrefixLength), SPE->ValidLifetime, FriendlyName); // wszValid, FriendlyName); } return NO_ERROR; } DWORD QuerySitePrefixTable( IN FORMAT Format ) { DWORD dwErr, dwCount = 0; IP_ADAPTER_ADDRESSES *pAdapterInfo; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != ERROR_NO_DATA) { if (dwErr == NO_ERROR) { dwCount = ForEachSitePrefix(PrintSitePrefix, Format, pAdapterInfo); FREE(pAdapterInfo); } else if (dwErr == ERROR_NO_DATA) { dwErr = NO_ERROR; } } if (!dwCount && (Format != FORMAT_DUMP)) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } return dwErr; } ////////////////////////////////////////////////////////////////////////////// // General global parameters functions ////////////////////////////////////////////////////////////////////////////// DWORD QueryGlobalParameters( IN FORMAT Format, IN BOOL bPersistent ) { IPV6_GLOBAL_PARAMETERS Params; DWORD dwBytesReturned, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (Format != FORMAT_DUMP) { // DisplayMessage(g_hModule, (bPersistent)? MSG_PERSISTENT : MSG_ACTIVE); } if (!DeviceIoControl(Handle, (bPersistent)? IOCTL_IPV6_PERSISTENT_QUERY_GLOBAL_PARAMETERS : IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS, NULL, 0, &Params, sizeof Params, &dwBytesReturned, NULL) || (dwBytesReturned != sizeof Params)) { return GetLastError(); } if (Format == FORMAT_DUMP) { DisplayMessageT(DMP_IPV6_SET_GLOBAL); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_DEFAULTCURHOPLIMIT, Params.DefaultCurHopLimit); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_NEIGHBORCACHELIMIT, Params.NeighborCacheLimit); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_DESTINATIONCACHELIMIT, Params.RouteCacheLimit); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_REASSEMBLYLIMIT, Params.ReassemblyLimit); DisplayMessage(g_hModule, MSG_NEWLINE); } else { DisplayMessage(g_hModule, MSG_IPV6_GLOBAL_PARAMETERS, Params.DefaultCurHopLimit, Params.NeighborCacheLimit, Params.RouteCacheLimit); // Params.RouteCacheLimit, Params.ReassemblyLimit); } return NO_ERROR; } DWORD QueryPrivacyParameters( IN FORMAT Format, IN BOOL bPersistent ) { IPV6_GLOBAL_PARAMETERS Params; DWORD dwBytesReturned, dwErr; WCHAR wszValid[64], wszPreferred[64], wszRegenerate[64]; WCHAR wszMaxRandom[64], wszRandom[64]; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (Format != FORMAT_DUMP) { // DisplayMessage(g_hModule, (bPersistent)? MSG_PERSISTENT : MSG_ACTIVE); } if (!DeviceIoControl(Handle, (bPersistent)? IOCTL_IPV6_PERSISTENT_QUERY_GLOBAL_PARAMETERS : IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS, NULL, 0, &Params, sizeof Params, &dwBytesReturned, NULL) || (dwBytesReturned != sizeof Params)) { return GetLastError(); } FormatTime(Params.MaxAnonValidLifetime, wszValid); FormatTime(Params.MaxAnonPreferredLifetime, wszPreferred); FormatTime(Params.AnonRegenerateTime, wszRegenerate); FormatTime(Params.MaxAnonRandomTime, wszMaxRandom); FormatTime(Params.AnonRandomTime, wszRandom); if (Format == FORMAT_DUMP) { DisplayMessageT(DMP_IPV6_SET_PRIVACY); DisplayMessageT(DMP_STRING_ARG, TOKEN_STATE, ((Params.UseAnonymousAddresses == USE_ANON_NO)? TOKEN_VALUE_DISABLED : TOKEN_VALUE_ENABLED)); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_MAXDADATTEMPTS, Params.MaxAnonDADAttempts); DisplayMessageT(DMP_STRING_ARG, TOKEN_MAXVALIDLIFETIME, wszValid); DisplayMessageT(DMP_STRING_ARG, TOKEN_MAXPREFERREDLIFETIME, wszPreferred); DisplayMessageT(DMP_STRING_ARG, TOKEN_REGENERATETIME, wszRegenerate); DisplayMessageT(DMP_STRING_ARG, TOKEN_MAXRANDOMTIME, wszMaxRandom); DisplayMessageT(DMP_STRING_ARG, TOKEN_RANDOMTIME, wszRandom); DisplayMessage(g_hModule, MSG_NEWLINE); } else { DisplayMessage( g_hModule, MSG_IPV6_PRIVACY_PARAMETERS, ((Params.UseAnonymousAddresses == USE_ANON_NO) ? TOKEN_VALUE_DISABLED : TOKEN_VALUE_ENABLED), Params.MaxAnonDADAttempts, Params.MaxAnonValidLifetime, Params.MaxAnonPreferredLifetime, Params.AnonRegenerateTime, Params.MaxAnonRandomTime, Params.AnonRandomTime); } return NO_ERROR; } DWORD UpdateGlobalParameters( IN DWORD dwDefaultCurHopLimit, IN DWORD dwNeighborCacheLimit, IN DWORD dwRouteCacheLimit, IN DWORD dwReassemblyLimit, IN BOOL bPersistent ) { IPV6_GLOBAL_PARAMETERS Params; DWORD dwBytesReturned; DWORD dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } Params.DefaultCurHopLimit = dwDefaultCurHopLimit; Params.UseAnonymousAddresses = (u_int) -1; Params.MaxAnonDADAttempts = (u_int) -1; Params.MaxAnonValidLifetime = (u_int) -1; Params.MaxAnonPreferredLifetime = (u_int) -1; Params.AnonRegenerateTime = (u_int) -1; Params.MaxAnonRandomTime = (u_int) -1; Params.AnonRandomTime = (u_int) -1; Params.NeighborCacheLimit = dwNeighborCacheLimit; Params.RouteCacheLimit = dwRouteCacheLimit; Params.ReassemblyLimit = dwReassemblyLimit; dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_UPDATE_GLOBAL_PARAMETERS, &Params, sizeof Params, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_GLOBAL_PARAMETERS, &Params, sizeof Params, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } DWORD UpdatePrivacyParameters( IN DWORD dwUseAnonymousAddresses, IN DWORD dwMaxDadAttempts, IN DWORD dwMaxValidLifetime, IN DWORD dwMaxPrefLifetime, IN DWORD dwRegenerateTime, IN DWORD dwMaxRandomTime, IN DWORD dwRandomTime, IN BOOL bPersistent ) { IPV6_GLOBAL_PARAMETERS Params; DWORD dwBytesReturned; DWORD dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } Params.DefaultCurHopLimit = -1; Params.UseAnonymousAddresses = dwUseAnonymousAddresses; Params.MaxAnonDADAttempts = dwMaxDadAttempts; Params.MaxAnonValidLifetime = dwMaxValidLifetime; Params.MaxAnonPreferredLifetime = dwMaxPrefLifetime; Params.AnonRegenerateTime = dwRegenerateTime; Params.MaxAnonRandomTime = dwMaxRandomTime; Params.AnonRandomTime = dwRandomTime; Params.NeighborCacheLimit = -1; Params.RouteCacheLimit = -1; Params.ReassemblyLimit = (u_int) -1; dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_UPDATE_GLOBAL_PARAMETERS, &Params, sizeof Params, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_GLOBAL_PARAMETERS, &Params, sizeof Params, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } ////////////////////////////////////////////////////////////////////////////// // Mobility-related functions ////////////////////////////////////////////////////////////////////////////// DWORD ForEachBinding( IN DWORD (*pfnFunc)(IPV6_INFO_BINDING_CACHE *) ) { IPV6_QUERY_BINDING_CACHE Query, NextQuery; IPV6_INFO_BINDING_CACHE BCE; DWORD dwBytesReturned; DWORD dwCount = 0; NextQuery.HomeAddress = in6addr_any; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_BINDING_CACHE, &Query, sizeof Query, &BCE, sizeof BCE, &dwBytesReturned, NULL)) { DisplayMessage(g_hModule, IPV6_MESSAGE_126, FormatIPv6Address(&Query.HomeAddress, 0)); break; } NextQuery = BCE.Query; if (!IN6_ADDR_EQUAL(&Query.HomeAddress, &in6addr_any)) { BCE.Query = Query; if ((*pfnFunc)(&BCE) == NO_ERROR) { dwCount++; } } if (IN6_ADDR_EQUAL(&NextQuery.HomeAddress, &in6addr_any)) { break; } } return dwCount; } DWORD PrintBindingCacheEntry( IN IPV6_INFO_BINDING_CACHE *BCE ) { WCHAR wszTime[64]; DisplayMessage(g_hModule, IPV6_MESSAGE_127, FormatIPv6Address(&BCE->HomeAddress, 0)); DisplayMessage(g_hModule, IPV6_MESSAGE_128, FormatIPv6Address(&BCE->CareOfAddress, 0)); DisplayMessage(g_hModule, IPV6_MESSAGE_129, BCE->BindingSeqNumber, BCE->BindingLifetime); // FormatTime(BCE->BindingLifetime, wszTime)); return NO_ERROR; } DWORD QueryBindingCache( VOID ) { DWORD dwCount, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwCount = ForEachBinding(PrintBindingCacheEntry); if (dwCount == 0) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } return NO_ERROR; } DWORD QueryMobilityParameters( IN FORMAT Format, IN BOOL bPersistent ) { IPV6_GLOBAL_PARAMETERS Params; DWORD dwBytesReturned, dwErr; PWCHAR pwszTempString; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (Format != FORMAT_DUMP) { // DisplayMessage(g_hModule, (bPersistent)? MSG_PERSISTENT : MSG_ACTIVE); } if (!DeviceIoControl(Handle, (bPersistent)? IOCTL_IPV6_PERSISTENT_QUERY_GLOBAL_PARAMETERS : IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS, NULL, 0, &Params, sizeof Params, &dwBytesReturned, NULL) || (dwBytesReturned != sizeof Params)) { return GetLastError(); } pwszTempString = Params.MobilitySecurity ? TOKEN_VALUE_ENABLED : TOKEN_VALUE_DISABLED; if (Format == FORMAT_DUMP) { DisplayMessageT(DMP_IPV6_SET_MOBILITY); DisplayMessageT(DMP_STRING_ARG, TOKEN_SECURITY, pwszTempString); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_BINDINGCACHELIMIT, Params.BindingCacheLimit); DisplayMessage(g_hModule, MSG_NEWLINE); } else { DisplayMessage(g_hModule, MSG_IPV6_MOBILITY_PARAMETERS, pwszTempString, Params.BindingCacheLimit); } return NO_ERROR; } DWORD UpdateMobilityParameters( IN DWORD dwSecurity, IN DWORD dwBindingCacheLimit, IN BOOL bPersistent ) { DWORD dwBytesReturned; DWORD dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = ERROR_OKAY; if ((dwBindingCacheLimit != -1) || (dwSecurity != -1)) { IPV6_GLOBAL_PARAMETERS Params; Params.DefaultCurHopLimit = (u_int) -1; Params.UseAnonymousAddresses = (u_int) -1; Params.MaxAnonDADAttempts = (u_int) -1; Params.MaxAnonValidLifetime = (u_int) -1; Params.MaxAnonPreferredLifetime = (u_int) -1; Params.AnonRegenerateTime = (u_int) -1; Params.MaxAnonRandomTime = (u_int) -1; Params.AnonRandomTime = (u_int) -1; Params.NeighborCacheLimit = (u_int) -1; Params.RouteCacheLimit = (u_int) -1; Params.ReassemblyLimit = (u_int) -1; Params.BindingCacheLimit = dwBindingCacheLimit; Params.MobilitySecurity = dwSecurity; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_UPDATE_GLOBAL_PARAMETERS, &Params, sizeof Params, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_GLOBAL_PARAMETERS, &Params, sizeof Params, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } } return dwErr; } ////////////////////////////////////////////////////////////////////////////// // Prefix policy table functions ////////////////////////////////////////////////////////////////////////////// DWORD ForEachPrefixPolicy( IN DWORD (*pfnFunc)(IPV6_INFO_PREFIX_POLICY *,FORMAT,DWORD), IN FORMAT Format, IN BOOL bPersistent ) { IPV6_QUERY_PREFIX_POLICY Query; IPV6_INFO_PREFIX_POLICY PPE; DWORD dwBytesReturned, dwCount = 0; Query.PrefixLength = (u_int) -1; for (;;) { if (!DeviceIoControl(Handle, (bPersistent)? IOCTL_IPV6_PERSISTENT_QUERY_PREFIX_POLICY : IOCTL_IPV6_QUERY_PREFIX_POLICY, &Query, sizeof Query, &PPE, sizeof PPE, &dwBytesReturned, NULL)) { break; } if (Query.PrefixLength != (u_int) -1) { if (dwBytesReturned != sizeof PPE) break; if ((*pfnFunc)(&PPE, Format, dwCount) == NO_ERROR) { dwCount++; } } else { if (dwBytesReturned != sizeof PPE.Next) break; } if (PPE.Next.PrefixLength == (u_int) -1) break; Query = PPE.Next; } return dwCount; } DWORD PrintPrefixPolicyEntry( IN IPV6_INFO_PREFIX_POLICY *PPE, IN FORMAT Format, IN DWORD dwCount ) { if (Format == FORMAT_DUMP) { DisplayMessageT(DMP_IPV6_ADD_PREFIXPOLICY); DisplayMessageT(DMP_STRING_ARG, TOKEN_PREFIX, FormatIPv6Prefix(&PPE->This.Prefix, PPE->This.PrefixLength)); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_PRECEDENCE, PPE->Precedence); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_LABEL, PPE->SrcLabel); DisplayMessage(g_hModule, MSG_NEWLINE); } else { if (!dwCount) { DisplayMessage(g_hModule, MSG_IPV6_PREFIX_POLICY_HDR); } DisplayMessage(g_hModule, MSG_IPV6_PREFIX_POLICY, FormatIPv6Prefix(&PPE->This.Prefix, PPE->This.PrefixLength), PPE->Precedence, PPE->SrcLabel, PPE->DstLabel); } return NO_ERROR; } DWORD QueryPrefixPolicy( IN FORMAT Format, IN BOOL bPersistent ) { DWORD dwCount, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (Format != FORMAT_DUMP) { // DisplayMessage(g_hModule, (bPersistent)? MSG_PERSISTENT : MSG_ACTIVE); } dwCount = ForEachPrefixPolicy(PrintPrefixPolicyEntry, Format, bPersistent); if (!dwCount && (Format != FORMAT_DUMP)) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } return NO_ERROR; } DWORD UpdatePrefixPolicy( IN IN6_ADDR *IpAddress, IN DWORD dwPrefixLength, IN DWORD dwPrecedence, IN DWORD dwLabel, IN BOOL bPersistent ) { IPV6_INFO_PREFIX_POLICY Info; DWORD dwBytesReturned, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } Info.This.Prefix = *IpAddress; Info.This.PrefixLength = dwPrefixLength; Info.Precedence = dwPrecedence; Info.SrcLabel = Info.DstLabel = dwLabel; dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_UPDATE_PREFIX_POLICY, &Info, sizeof Info, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_PREFIX_POLICY, &Info, sizeof Info, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } DWORD DeletePrefixPolicy( IN IN6_ADDR *IpAddress, IN DWORD dwPrefixLength, IN BOOL bPersistent ) { IPV6_QUERY_PREFIX_POLICY Query; DWORD dwBytesReturned, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } Query.Prefix = *IpAddress; Query.PrefixLength = dwPrefixLength; dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_DELETE_PREFIX_POLICY, &Query, sizeof Query, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_DELETE_PREFIX_POLICY, &Query, sizeof Query, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } ////////////////////////////////////////////////////////////////////////////// // Address table functions ////////////////////////////////////////////////////////////////////////////// DWORD ForEachAddress( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format, IN DWORD (*pfnFunc)(IPV6_INFO_INTERFACE *IF, PIP_ADAPTER_ADDRESSES, FORMAT, DWORD, IPV6_INFO_ADDRESS *)) { IPV6_QUERY_ADDRESS Query; IPV6_INFO_ADDRESS ADE; DWORD BytesReturned, dwCount = 0; Query.IF = IF->This; Query.Address = in6addr_any; for (;;) { if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_ADDRESS, &Query, sizeof Query, &ADE, sizeof ADE, &BytesReturned, NULL)) { break; } if (!IN6_ADDR_EQUAL(&Query.Address, &in6addr_any)) { if (BytesReturned != sizeof ADE) break; if ((*pfnFunc)(IF, pAdapterInfo, Format, dwCount, &ADE) == NO_ERROR) { dwCount++; } } else { if (BytesReturned != sizeof ADE.Next) break; } if (IN6_ADDR_EQUAL(&ADE.Next.Address, &in6addr_any)) break; Query = ADE.Next; } return dwCount; } PWCHAR GetDadState( IN DWORD dwDadState, OUT BOOL *bDynamic ) { PWCHAR pwszTemp; DWORD dwMsg = 0; static WCHAR wszDadState[128]; switch (dwDadState) { case DAD_STATE_INVALID: dwMsg = STRING_INVALID; break; case DAD_STATE_DUPLICATE: dwMsg = STRING_DUPLICATE; break; case DAD_STATE_TENTATIVE: dwMsg = STRING_TENTATIVE; break; case DAD_STATE_DEPRECATED: dwMsg = STRING_DEPRECATED; break; case DAD_STATE_PREFERRED: dwMsg = STRING_PREFERRED; break; default: swprintf(wszDadState, L"%u", dwDadState); *bDynamic = FALSE; return wszDadState; } *bDynamic = TRUE; pwszTemp = MakeString(g_hModule, dwMsg); return pwszTemp; } PWCHAR GetAddressType( IN DWORD dwScope, IN DWORD dwPrefixConf, IN DWORD dwIidConf ) { DWORD dwMsg = 0; if ((dwScope == ADE_LINK_LOCAL) && (dwPrefixConf == PREFIX_CONF_WELLKNOWN) && (dwIidConf == IID_CONF_WELLKNOWN)) { dwMsg = STRING_LOOPBACK; } else if ((dwScope == ADE_LINK_LOCAL) && (dwPrefixConf == PREFIX_CONF_WELLKNOWN) && (dwIidConf == IID_CONF_LL_ADDRESS)) { dwMsg = STRING_LINK; } else if ((dwPrefixConf == PREFIX_CONF_MANUAL) && (dwIidConf == IID_CONF_MANUAL)) { dwMsg = STRING_MANUAL; } else if ((dwPrefixConf == PREFIX_CONF_RA) && (dwIidConf == IID_CONF_LL_ADDRESS)) { dwMsg = STRING_PUBLIC; } else if ((dwPrefixConf == PREFIX_CONF_RA) && (dwIidConf == IID_CONF_RANDOM)) { dwMsg = STRING_ANONYMOUS; } else if ((dwPrefixConf == PREFIX_CONF_DHCP) && (dwIidConf == IID_CONF_DHCP)) { dwMsg = STRING_DHCP; } else { dwMsg = STRING_OTHER; } return MakeString(g_hModule, dwMsg); } PWCHAR GetScopeNoun( IN DWORD dwScope, OUT BOOL *bDynamic ) { PWCHAR pwszTemp; DWORD dwMsg = 0; static WCHAR wszScopeLevel[128]; switch (dwScope) { case ADE_INTERFACE_LOCAL: dwMsg = STRING_INTERFACE; break; case ADE_LINK_LOCAL: dwMsg = STRING_LINK; break; case ADE_SUBNET_LOCAL: dwMsg = STRING_SUBNET; break; case ADE_ADMIN_LOCAL: dwMsg = STRING_ADMIN; break; case ADE_SITE_LOCAL: dwMsg = STRING_SITE; break; case ADE_ORG_LOCAL: dwMsg = STRING_ORG; break; case ADE_GLOBAL: dwMsg = STRING_GLOBAL; break; default: swprintf(wszScopeLevel, L"%u", dwScope); *bDynamic = FALSE; return wszScopeLevel; } *bDynamic = TRUE; pwszTemp = MakeString(g_hModule, dwMsg); return pwszTemp; } DWORD rgdwPrefixConfMsg[] = { 0, STRING_MANUAL, STRING_WELLKNOWN, STRING_DHCP, STRING_RA }; #define PREFIX_CONF_MSG_COUNT (sizeof(rgdwPrefixConfMsg)/sizeof(DWORD)) DWORD rgdwIidConfMsg[] = { 0, STRING_MANUAL, STRING_WELLKNOWN, STRING_DHCP, STRING_LL_ADDRESS, STRING_RANDOM }; #define IID_CONF_MSG_COUNT (sizeof(rgdwIidConfMsg)/sizeof(DWORD)) DWORD PrintMulticastAddress( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format, IN DWORD dwCount, IN IPV6_INFO_ADDRESS *ADE ) { BOOL bDynamicDadState, bDynamicScope; PWCHAR pwszDadState, pwszScope, pwszFriendlyName; DWORD dwErr = NO_ERROR; PWCHAR pwszLastReporter, pwszNever; WCHAR wszTime[64]; if (ADE->Type != ADE_MULTICAST) { return ERROR_NO_DATA; } if (dwCount == 0) { dwErr = MapIpv6IfIndexToFriendlyName(IF->This.Index, pAdapterInfo, &pwszFriendlyName); if (dwErr != NO_ERROR) { return dwErr; } DisplayMessage(g_hModule, (Format == FORMAT_VERBOSE)? MSG_IPV6_ADDRESS_HDR_VERBOSE : MSG_IPV6_MULTICAST_ADDRESS_HDR, IF->This.Index, pwszFriendlyName); } pwszScope = GetScopeNoun(ADE->Scope, &bDynamicScope); pwszNever = MakeString(g_hModule, STRING_NEVER); pwszLastReporter = MakeString(g_hModule, (ADE->MCastFlags & 0x02)? STRING_YES : STRING_NO); if (Format == FORMAT_VERBOSE) { DisplayMessage(g_hModule, MSG_IPV6_MULTICAST_ADDRESS_VERBOSE, pwszScope, FormatIPv6Address(&ADE->This.Address, 0), ADE->MCastRefCount, (ADE->MCastFlags & 0x01) ? ADE->MCastTimer : 0, pwszLastReporter); } else { DisplayMessage(g_hModule, MSG_IPV6_MULTICAST_ADDRESS, pwszScope, FormatIPv6Address(&ADE->This.Address, 0), ADE->MCastRefCount, (ADE->MCastFlags & 0x01) ? FormatTime(ADE->MCastTimer, wszTime) : pwszNever, pwszLastReporter); } FreeString(pwszLastReporter); FreeString(pwszNever); if (bDynamicScope) { FreeString(pwszScope); } return dwErr; } DWORD PrintAddress( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format, IN DWORD dwCount, IN IPV6_INFO_ADDRESS *ADE ) { DWORD dwPrefixConf, dwInterfaceIdConf; BOOL bDynamicDadState, bDynamicScope, bDynamicType; PWCHAR pwszDadState, pwszScope, pwszFriendlyName, pwszType; WCHAR wszValid[64], wszPreferred[64]; DWORD dwErr = NO_ERROR; if (Format != FORMAT_VERBOSE) { // // Suppress invalid addresses. // if ((ADE->Type == ADE_UNICAST) && (ADE->DADState == DAD_STATE_INVALID)) { return ERROR_NO_DATA; } // // Multicast addresses are handled by PrintMulticastAddress() // instead. // if (ADE->Type == ADE_MULTICAST) { return ERROR_NO_DATA; } } if (dwCount == 0) { dwErr = MapIpv6IfIndexToFriendlyName(IF->This.Index, pAdapterInfo, &pwszFriendlyName); if (dwErr != NO_ERROR) { return dwErr; } DisplayMessage(g_hModule, ((Format == FORMAT_VERBOSE)? MSG_IPV6_ADDRESS_HDR_VERBOSE : MSG_IPV6_ADDRESS_HDR), IF->This.Index, pwszFriendlyName); } pwszScope = GetScopeNoun(ADE->Scope, &bDynamicScope); switch (ADE->Type) { case ADE_UNICAST: pwszDadState = GetDadState(ADE->DADState, &bDynamicDadState); pwszType = GetAddressType(ADE->Scope, ADE->PrefixConf, ADE->InterfaceIdConf); DisplayMessage(g_hModule, ((Format == FORMAT_VERBOSE)? MSG_IPV6_UNICAST_ADDRESS_VERBOSE : MSG_IPV6_UNICAST_ADDRESS), pwszType, pwszDadState, FormatIPv6Address(&ADE->This.Address, 0), ADE->ValidLifetime, // FormatTime(ADE->ValidLifetime, wszValid), ADE->PreferredLifetime, // FormatTime(ADE->PreferredLifetime, wszPreferred), pwszScope); if (bDynamicDadState) { FreeString(pwszDadState); } FreeString(pwszType); if (Format == FORMAT_VERBOSE) { // // Show prefix origin / interface id origin // DisplayMessage(g_hModule, MSG_IPV6_PREFIX_ORIGIN); dwPrefixConf = ADE->PrefixConf; if ((dwPrefixConf == PREFIX_CONF_OTHER) || (dwPrefixConf >= PREFIX_CONF_MSG_COUNT)) { DisplayMessage(g_hModule, MSG_IPV6_INTEGER, dwPrefixConf); } else { DisplayMessage(g_hModule, rgdwPrefixConfMsg[dwPrefixConf]); } DisplayMessage(g_hModule, MSG_NEWLINE); DisplayMessage(g_hModule, MSG_IPV6_IID_ORIGIN); dwInterfaceIdConf = ADE->InterfaceIdConf; if ((dwInterfaceIdConf == IID_CONF_OTHER) || (dwInterfaceIdConf >= IID_CONF_MSG_COUNT)) { DisplayMessage(g_hModule, MSG_IPV6_INTEGER, dwInterfaceIdConf); } else { DisplayMessage(g_hModule, rgdwIidConfMsg[dwInterfaceIdConf]); } DisplayMessage(g_hModule, MSG_NEWLINE); } break; case ADE_ANYCAST: DisplayMessage(g_hModule, ((Format == FORMAT_VERBOSE)? MSG_IPV6_ANYCAST_ADDRESS_VERBOSE : MSG_IPV6_ANYCAST_ADDRESS), FormatIPv6Address(&ADE->This.Address, 0), pwszScope); break; case ADE_MULTICAST: default: dwErr = ERROR_NO_DATA; break; } if (bDynamicScope) { FreeString(pwszScope); } return dwErr; } DWORD PrintAddressTable( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwIfCount, IN FORMAT Format ) { DWORD dwCount = ForEachAddress(IF, pAdapterInfo, Format, PrintAddress); return (dwCount > 0)? NO_ERROR : ERROR_NO_DATA; } DWORD PrintMulticastAddressTable( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwIfCount, IN FORMAT Format ) { DWORD dwCount = ForEachAddress(IF, pAdapterInfo, Format, PrintMulticastAddress); return (dwCount > 0)? NO_ERROR : ERROR_NO_DATA; } DWORD QueryAddressTable( IN PWCHAR pwszIfFriendlyName, IN FORMAT Format, IN BOOL bPersistent ) { DWORD dwErr, dwCount = 0; IP_ADAPTER_ADDRESSES *pAdapterInfo; IPV6_INFO_INTERFACE *IF; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (Format != FORMAT_DUMP) { // DisplayMessage(g_hModule, (bPersistent)? MSG_PERSISTENT : MSG_ACTIVE); } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != ERROR_NO_DATA) { if (dwErr == NO_ERROR) { if (pwszIfFriendlyName == NULL) { dwCount = ForEachInterface(PrintAddressTable, pAdapterInfo, Format, bPersistent); } else { dwErr = GetInterfaceByFriendlyName(pwszIfFriendlyName, pAdapterInfo, bPersistent, &IF); if (dwErr == NO_ERROR) { PrintAddressTable(IF, pAdapterInfo, 0, Format); FREE(IF); } } FREE(pAdapterInfo); } else if (dwErr == ERROR_NO_DATA) { dwErr = NO_ERROR; } } if (!dwCount && (Format != FORMAT_DUMP)) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } return dwErr; } DWORD QueryMulticastAddressTable( IN PWCHAR pwszIfFriendlyName, IN FORMAT Format ) { DWORD dwErr, dwCount = 0; IP_ADAPTER_ADDRESSES *pAdapterInfo; IPV6_INFO_INTERFACE *IF; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != ERROR_NO_DATA) { if (dwErr == NO_ERROR) { if (pwszIfFriendlyName == NULL) { ForEachInterface(PrintMulticastAddressTable, pAdapterInfo, Format, FALSE); } else { dwErr = GetInterfaceByFriendlyName(pwszIfFriendlyName, pAdapterInfo, FALSE, &IF); if (dwErr == NO_ERROR) { dwErr = PrintMulticastAddressTable(IF, pAdapterInfo, 0, Format); FREE(IF); } } FREE(pAdapterInfo); } else if (dwErr == ERROR_NO_DATA) { dwErr = NO_ERROR; } } return dwErr; } DWORD UpdateAddress( IN PWCHAR pwszIfFriendlyName, IN IN6_ADDR *pipAddress, IN DWORD dwType, IN DWORD dwValidLifetime, IN DWORD dwPreferredLifetime, IN BOOL bPersistent ) { IPV6_UPDATE_ADDRESS Update; DWORD dwBytesReturned, dwErr; PIP_ADAPTER_ADDRESSES pAdapterInfo; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MapFriendlyNameToIpv6IfIndex(pwszIfFriendlyName, pAdapterInfo, &Update.This.IF.Index); FREE(pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } Update.This.Address = *pipAddress; Update.Type = dwType; Update.PrefixConf = PREFIX_CONF_MANUAL; Update.InterfaceIdConf = IID_CONF_MANUAL; Update.ValidLifetime = dwValidLifetime; Update.PreferredLifetime = dwPreferredLifetime; dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_UPDATE_ADDRESS, &Update, sizeof Update, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_ADDRESS, &Update, sizeof Update, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } ////////////////////////////////////////////////////////////////////////////// // Interface table functions ////////////////////////////////////////////////////////////////////////////// DWORD RenewViaReconnect( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwCount, IN FORMAT Format ) { DWORD dwBytesReturned; if (!DeviceIoControl(Handle, IOCTL_IPV6_RENEW_INTERFACE, &IF->This, sizeof IF->This, NULL, 0, &dwBytesReturned, NULL)) { return GetLastError(); } return NO_ERROR; } DWORD RenewInterface( IN PWCHAR wszIfFriendlyName ) { DWORD dwErr; BOOL PokeService = FALSE; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (wszIfFriendlyName == NULL) { ForEachInterface(RenewViaReconnect, NULL, FALSE, FALSE); PokeService = TRUE; } else { IP_ADAPTER_ADDRESSES *pAdapterInfo; dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr == NO_ERROR) { IPV6_INFO_INTERFACE *IF; dwErr = GetInterfaceByFriendlyName(wszIfFriendlyName, pAdapterInfo, FALSE, &IF); FREE(pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } dwErr = RenewViaReconnect(IF, NULL, 0, FALSE); // // Poke the 6to4 service if it manages the interface being renewed. // PokeService = (IF->Type == IPV6_IF_TYPE_TUNNEL_6TO4) || (IF->Type == IPV6_IF_TYPE_TUNNEL_TEREDO) || (IF->Type == IPV6_IF_TYPE_TUNNEL_AUTO); FREE(IF); } else if (dwErr == ERROR_NO_DATA) { dwErr = NO_ERROR; } } if (PokeService) { Ip6to4PokeService(); } return dwErr; } DWORD dwMediaSenseMsg[] = { STRING_DISCONNECTED, STRING_RECONNECTED, STRING_CONNECTED, }; #define MEDIA_SENSE_MSG_COUNT (sizeof(dwMediaSenseMsg)/sizeof(DWORD)) DWORD PrintInterface( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwCount, IN FORMAT Format ) { PWCHAR pwszFriendlyName, pwszTemp; DWORD dwErr, dwMsg, dwScope; WCHAR wszReachable[64], wszBaseReachable[64], wszRetransTimer[64]; PIP_ADAPTER_ADDRESSES pIf; CHAR szGuid[41]; dwErr = MapGuidToFriendlyName(NULL, &IF->This.Guid, pAdapterInfo, &pwszFriendlyName); if (dwErr != NO_ERROR) { return dwErr; } if (IF->MediaStatus < MEDIA_SENSE_MSG_COUNT) { dwMsg = dwMediaSenseMsg[IF->MediaStatus]; } else { dwMsg = STRING_UNKNOWN; } switch (Format) { case FORMAT_DUMP: switch (IF->Type) { case IPV6_IF_TYPE_TUNNEL_6OVER4: DisplayMessageT(DMP_IPV6_ADD_6OVER4TUNNEL); DisplayMessageT(DMP_QUOTED_STRING_ARG, TOKEN_INTERFACE, pwszFriendlyName); if (IF->LocalLinkLayerAddress != 0) { DisplayMessageT(DMP_STRING_ARG, TOKEN_LOCALADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (char *)IF + IF->LocalLinkLayerAddress)); } DisplayMessage(g_hModule, MSG_NEWLINE); break; case IPV6_IF_TYPE_TUNNEL_V6V4: DisplayMessageT(DMP_IPV6_ADD_V6V4TUNNEL); DisplayMessageT(DMP_QUOTED_STRING_ARG, TOKEN_INTERFACE, pwszFriendlyName); if (IF->LocalLinkLayerAddress != 0) { DisplayMessageT(DMP_STRING_ARG, TOKEN_LOCALADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (char *)IF + IF->LocalLinkLayerAddress)); } if (IF->RemoteLinkLayerAddress != 0) { DisplayMessageT(DMP_STRING_ARG, TOKEN_REMOTEADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (char *)IF + IF->RemoteLinkLayerAddress)); } if (IF->NeighborDiscovers) { DisplayMessageT(DMP_STRING_ARG, TOKEN_NEIGHBORDISCOVERY, TOKEN_VALUE_ENABLED); } DisplayMessage(g_hModule, MSG_NEWLINE); break; } DisplayMessageT(DMP_IPV6_SET_INTERFACE); DisplayMessageT(DMP_QUOTED_STRING_ARG, TOKEN_INTERFACE, pwszFriendlyName); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_METRIC, IF->Preference); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_MTU, IF->LinkMTU); DisplayMessage(g_hModule, MSG_NEWLINE); break; case FORMAT_NORMAL: if (dwCount == 0) { DisplayMessage(g_hModule, MSG_IPV6_INTERFACE_HDR); } pwszTemp = MakeString(g_hModule, dwMsg); DisplayMessage(g_hModule, MSG_IPV6_INTERFACE, IF->This.Index, IF->Preference, IF->LinkMTU, pwszTemp, pwszFriendlyName); FreeString(pwszTemp); break; case FORMAT_VERBOSE: DisplayMessage(g_hModule, MSG_SEPARATOR); ForEachAddress(IF, pAdapterInfo, FORMAT_NORMAL, PrintAddress); // // Get extra interface information. // pIf = MapIfIndexToAdapter(AF_INET6, IF->This.Index, pAdapterInfo); pwszTemp = MakeString(g_hModule, dwMsg); ConvertGuidToStringA(&IF->This.Guid, szGuid); DisplayMessage(g_hModule, MSG_IPV6_INTERFACE_VERBOSE, szGuid, pwszTemp, IF->Preference, IF->LinkMTU, IF->TrueLinkMTU, IF->CurHopLimit, IF->ReachableTime, // FormatTime(IF->ReachableTime, wszReachable), IF->BaseReachableTime, // FormatTime(IF->BaseReachableTime, wszBaseReachable), IF->RetransTimer, // FormatTime(IF->RetransTimer, wszRetransTimer), IF->DupAddrDetectTransmits, (pIf)? pIf->DnsSuffix : L"" // , pwszFriendlyName ); FreeString(pwszTemp); for (dwScope = ADE_LINK_LOCAL; dwScope < ADE_GLOBAL; dwScope++) { DWORD Expected = 0; // // Always print link & site. // if ((dwScope != ADE_LINK_LOCAL) && (dwScope != ADE_SITE_LOCAL)) { Expected = IF->ZoneIndices[dwScope + 1]; } if (IF->ZoneIndices[dwScope] != Expected) { BOOL bDynamic; pwszTemp = GetScopeNoun(dwScope, &bDynamic); DisplayMessage(g_hModule, MSG_IPV6_INTERFACE_SCOPE, pwszTemp, IF->ZoneIndices[dwScope]); if (bDynamic) { FreeString(pwszTemp); } } } DisplayMessage(g_hModule, MSG_IPV6_ND_ENABLED); DisplayMessage(g_hModule, (IF->NeighborDiscovers ? STRING_YES : STRING_NO)); DisplayMessage(g_hModule, MSG_NEWLINE); DisplayMessage(g_hModule, MSG_IPV6_SENDS_RAS); DisplayMessage(g_hModule, (IF->Advertises ? STRING_YES : STRING_NO)); DisplayMessage(g_hModule, MSG_NEWLINE); DisplayMessage(g_hModule, MSG_IPV6_FORWARDS); DisplayMessage(g_hModule, (IF->Forwards ? STRING_YES : STRING_NO)); DisplayMessage(g_hModule, MSG_NEWLINE); if (IF->LocalLinkLayerAddress != 0) { DisplayMessage(g_hModule, MSG_IPV6_LL_ADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (char *)IF + IF->LocalLinkLayerAddress)); } if (IF->RemoteLinkLayerAddress != 0) { DisplayMessage(g_hModule, MSG_IPV6_REMOTE_LL_ADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (char *)IF + IF->RemoteLinkLayerAddress)); } break; } return NO_ERROR; } DWORD QueryInterface( IN PWCHAR pwszIfFriendlyName, IN FORMAT Format, IN BOOL bPersistent ) { IPV6_INFO_INTERFACE *IF; PIP_ADAPTER_ADDRESSES pAdapterInfo; DWORD dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (Format != FORMAT_DUMP) { // DisplayMessage(g_hModule, (bPersistent)? MSG_PERSISTENT : MSG_ACTIVE); } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr == ERROR_NO_DATA) { if (Format != FORMAT_DUMP) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } return NO_ERROR; } if (dwErr != NO_ERROR) { return dwErr; } if (pwszIfFriendlyName == NULL) { ForEachInterface(PrintInterface, pAdapterInfo, Format, bPersistent); } else { dwErr = GetInterfaceByFriendlyName(pwszIfFriendlyName, pAdapterInfo, bPersistent, &IF); if (dwErr == NO_ERROR) { dwErr = PrintInterface(IF, pAdapterInfo, 0, Format); FREE(IF); } } FREE(pAdapterInfo); return dwErr; } DWORD DeleteInterface( IN PWCHAR pwszIfFriendlyName, IN BOOL bPersistent ) { IPV6_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; IP_ADAPTER_ADDRESSES *pAdapterInfo; DWORD dwBytesReturned, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MapFriendlyNameToIpv6IfIndex(pwszIfFriendlyName, pAdapterInfo, &Query.Index); FREE(pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } dwErr = ERROR_OKAY; if (!DeviceIoControl(Handle, (bPersistent) ? IOCTL_IPV6_PERSISTENT_DELETE_INTERFACE : IOCTL_IPV6_DELETE_INTERFACE, &Query, sizeof Query, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } #define KEY_TCPIP6_IF L"System\\CurrentControlSet\\Services\\Tcpip6\\Parameters\\Interfaces" DWORD SetFriendlyName( IN GUID *pGuid, IN PWCHAR pwszFriendlyName ) { DWORD dwErr; HKEY hInterfaces = NULL, hIf = NULL; UNICODE_STRING usGuid; dwErr = RtlStringFromGUID(pGuid, &usGuid); if (!NT_SUCCESS(dwErr)) { return dwErr; } dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE, KEY_TCPIP6_IF, 0, GENERIC_READ, &hInterfaces); if (dwErr != NO_ERROR) { goto Cleanup; } dwErr = RegOpenKeyExW(hInterfaces, usGuid.Buffer, 0, GENERIC_WRITE, &hIf); if (dwErr != NO_ERROR) { goto Cleanup; } dwErr = SetString(hIf, L"FriendlyName", pwszFriendlyName); Cleanup: if (hInterfaces) { RegCloseKey(hInterfaces); } if (hIf) { RegCloseKey(hIf); } RtlFreeUnicodeString(&usGuid); return dwErr; } DWORD AddTunnelInterface( IN PWCHAR pwszFriendlyName, IN IN_ADDR *pipLocalAddr, IN IN_ADDR *pipRemoteAddr, IN DWORD dwType, IN DWORD dwDiscovery, IN BOOL bPersistent ) { struct { IPV6_INFO_INTERFACE Info; IN_ADDR SrcAddr; IN_ADDR DstAddr; } Create; IPV6_QUERY_INTERFACE Result; DWORD dwBytesReturned, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } // // TODO: use pwszFriendlyName when persistent config is ready // IPV6_INIT_INFO_INTERFACE(&Create.Info); Create.Info.Type = dwType; Create.Info.NeighborDiscovers = dwDiscovery; Create.Info.RouterDiscovers = dwDiscovery; Create.Info.LinkLayerAddressLength = sizeof(IN_ADDR); if (pipLocalAddr != NULL) { Create.SrcAddr = *pipLocalAddr; Create.Info.LocalLinkLayerAddress = (u_int) ((char *)&Create.SrcAddr - (char *)&Create.Info); } if (pipRemoteAddr != NULL) { Create.DstAddr = *pipRemoteAddr; Create.Info.RemoteLinkLayerAddress = (u_int) ((char *)&Create.DstAddr - (char *)&Create.Info); } dwErr = ERROR_OKAY; if (!DeviceIoControl(Handle, (bPersistent) ? IOCTL_IPV6_PERSISTENT_CREATE_INTERFACE : IOCTL_IPV6_CREATE_INTERFACE, &Create, sizeof Create, &Result, sizeof Result, &dwBytesReturned, NULL) || (dwBytesReturned != sizeof Result)) { dwErr = GetLastError(); } else if (bPersistent) { SetFriendlyName(&Result.Guid, pwszFriendlyName); } return dwErr; } DWORD UpdateInterface( IN PWCHAR pwszIfFriendlyName, IN DWORD dwForwarding, IN DWORD dwAdvertises, IN DWORD dwMtu, IN DWORD dwSiteId, IN DWORD dwMetric, IN BOOL bPersistent ) { IPV6_INFO_INTERFACE Update; DWORD dwBytesReturned, dwErr; PIP_ADAPTER_ADDRESSES pAdapterInfo; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } IPV6_INIT_INFO_INTERFACE(&Update); dwErr = MapFriendlyNameToIpv6IfIndex(pwszIfFriendlyName, pAdapterInfo, &Update.This.Index); FREE(pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } Update.Advertises = dwAdvertises; Update.Forwards = dwForwarding; Update.LinkMTU = dwMtu; Update.Preference = dwMetric; Update.ZoneIndices[ADE_SITE_LOCAL] = dwSiteId; dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_UPDATE_INTERFACE, &Update, sizeof Update, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_INTERFACE, &Update, sizeof Update, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } ////////////////////////////////////////////////////////////////////////////// // Neighbor cache functions ////////////////////////////////////////////////////////////////////////////// DWORD PrintNeighborCacheEntry( IN IPV6_INFO_NEIGHBOR_CACHE *NCE, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwCount ) { DWORD dwErr; PWCHAR pwszLinkLayerAddress = L""; PWCHAR pwszUnreachable; if (NCE->NDState != ND_STATE_INCOMPLETE) { pwszLinkLayerAddress = FormatLinkLayerAddress( NCE->LinkLayerAddressLength, (u_char *)(NCE + 1)); } if (!dwCount) { PWCHAR pwszFriendlyName; dwErr = MapIpv6IfIndexToFriendlyName(NCE->Query.IF.Index, pAdapterInfo, &pwszFriendlyName); if (dwErr != NO_ERROR) { return dwErr; } DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_CACHE_HDR, NCE->Query.IF.Index, pwszFriendlyName); } pwszUnreachable = MakeString(g_hModule, MSG_IPV6_NEIGHBOR_UNREACHABLE); DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_CACHE_ENTRY, FormatIPv6Address(&NCE->Query.Address, 0), ((NCE->IsUnreachable)? pwszUnreachable : pwszLinkLayerAddress)); FreeString(pwszUnreachable); switch (NCE->NDState) { case ND_STATE_INCOMPLETE: DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_INCOMPLETE); break; case ND_STATE_PROBE: DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_PROBE); break; case ND_STATE_DELAY: DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_DELAY); break; case ND_STATE_STALE: DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_STALE); break; case ND_STATE_REACHABLE: DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_REACHABLE, NCE->ReachableTimer / 1000); break; case ND_STATE_PERMANENT: DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_PERMANENT); break; default: DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_UNKNOWN, NCE->NDState); break; } if (NCE->IsRouter) { DisplayMessage(g_hModule, MSG_IPV6_NEIGHBOR_ISROUTER); } DisplayMessage(g_hModule, MSG_NEWLINE); return NO_ERROR; } DWORD ForEachNeighborCacheEntry( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD (*pfnFunc)(IPV6_INFO_NEIGHBOR_CACHE *,PIP_ADAPTER_ADDRESSES,DWORD) ) { IPV6_QUERY_NEIGHBOR_CACHE Query, NextQuery; IPV6_INFO_NEIGHBOR_CACHE *NCE; DWORD dwInfoSize, dwBytesReturned; DWORD dwCount = 0; dwInfoSize = sizeof *NCE + MAX_LINK_LAYER_ADDRESS_LENGTH; NCE = (IPV6_INFO_NEIGHBOR_CACHE *) MALLOC(dwInfoSize); if (NCE == NULL) { return 0; } NextQuery.IF = IF->This; NextQuery.Address = in6addr_any; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_NEIGHBOR_CACHE, &Query, sizeof Query, NCE, dwInfoSize, &dwBytesReturned, NULL)) { return dwCount; } NextQuery = NCE->Query; if (!IN6_ADDR_EQUAL(&Query.Address, &in6addr_any)) { if ((dwBytesReturned < sizeof *NCE) || (dwBytesReturned != sizeof *NCE + NCE->LinkLayerAddressLength)) { return dwCount; } NCE->Query = Query; if ((*pfnFunc)(NCE,pAdapterInfo,dwCount) == NO_ERROR) { dwCount++; } } if (IN6_ADDR_EQUAL(&NextQuery.Address, &in6addr_any)) break; } FREE(NCE); return dwCount; } DWORD PrintNeighborCache( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwIfCount, IN FORMAT Format ) { DWORD dwCount = ForEachNeighborCacheEntry(IF, pAdapterInfo, PrintNeighborCacheEntry); return (dwCount > 0)? NO_ERROR : ERROR_NO_DATA; } IPV6_INFO_NEIGHBOR_CACHE * GetNeighborCacheEntry( IN IPV6_INFO_INTERFACE *IF, IN IN6_ADDR *Address ) { IPV6_QUERY_NEIGHBOR_CACHE Query; IPV6_INFO_NEIGHBOR_CACHE *NCE; DWORD dwInfoSize, dwBytesReturned; dwInfoSize = sizeof *NCE + MAX_LINK_LAYER_ADDRESS_LENGTH; NCE = (IPV6_INFO_NEIGHBOR_CACHE *) malloc(dwInfoSize); if (NCE == NULL) { return NULL; } Query.IF = IF->This; Query.Address = *Address; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_NEIGHBOR_CACHE, &Query, sizeof Query, NCE, dwInfoSize, &dwBytesReturned, NULL)) { return NULL; } if ((dwBytesReturned < sizeof *NCE) || (dwBytesReturned != sizeof *NCE + NCE->LinkLayerAddressLength)) { return NULL; } NCE->Query = Query; return NCE; } DWORD QueryNeighborCache( IN PWCHAR pwszInterface, IN IN6_ADDR *pipAddress ) { IPV6_INFO_INTERFACE *IF; IPV6_INFO_NEIGHBOR_CACHE *NCE; PIP_ADAPTER_ADDRESSES pAdapterInfo; DWORD dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } if (!pwszInterface) { ForEachInterface(PrintNeighborCache, pAdapterInfo, FORMAT_NORMAL, FALSE); FREE(pAdapterInfo); return NO_ERROR; } dwErr = GetInterfaceByFriendlyName(pwszInterface, pAdapterInfo, FALSE, &IF); if (dwErr != NO_ERROR) { return dwErr; } if (!pipAddress) { PrintNeighborCache(IF, pAdapterInfo, 0, FALSE); } else { NCE = GetNeighborCacheEntry(IF, pipAddress); PrintNeighborCacheEntry(NCE, pAdapterInfo, 0); FREE(NCE); } FREE(IF); FREE(pAdapterInfo); return dwErr; } DWORD FlushNeighborCacheForInterface( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwCount, IN FORMAT Format ) { IPV6_QUERY_NEIGHBOR_CACHE Query; DWORD dwBytesReturned; Query.IF = IF->This; Query.Address = in6addr_any; if (!DeviceIoControl(Handle, IOCTL_IPV6_FLUSH_NEIGHBOR_CACHE, &Query, sizeof Query, NULL, 0, &dwBytesReturned, NULL)) { return GetLastError(); } return NO_ERROR; } DWORD FlushNeighborCache( IN PWCHAR pwszInterface, IN IN6_ADDR *pipAddress ) { IPV6_QUERY_NEIGHBOR_CACHE Query; DWORD dwBytesReturned, dwErr; PIP_ADAPTER_ADDRESSES pAdapterInfo; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (!pwszInterface) { ForEachInterface(FlushNeighborCacheForInterface, NULL, FORMAT_NORMAL, FALSE); return NO_ERROR; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MapFriendlyNameToIpv6IfIndex(pwszInterface, pAdapterInfo, &Query.IF.Index); if (dwErr != NO_ERROR) { return dwErr; } if (pipAddress) { Query.Address = *pipAddress; } else { Query.Address = in6addr_any; } if (!DeviceIoControl(Handle, IOCTL_IPV6_FLUSH_NEIGHBOR_CACHE, &Query, sizeof Query, NULL, 0, &dwBytesReturned, NULL)) { return GetLastError(); } return ERROR_OKAY; } ////////////////////////////////////////////////////////////////////////////// // Destination cache functions ////////////////////////////////////////////////////////////////////////////// DWORD PrintDestination( IN IPV6_INFO_ROUTE_CACHE *RCE, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwCount, IN FORMAT Format ) { DWORD dwErr; PWCHAR pwszTemp; WCHAR wszTime[64]; if (!dwCount) { PWCHAR pwszFriendlyName; dwErr = MapIpv6IfIndexToFriendlyName(RCE->Query.IF.Index, pAdapterInfo, &pwszFriendlyName); if (dwErr != NO_ERROR) { return dwErr; } DisplayMessage(g_hModule, ((Format == FORMAT_VERBOSE)? MSG_IPV6_DESTINATION_HDR_VERBOSE : MSG_IPV6_DESTINATION_HDR), RCE->Query.IF.Index, pwszFriendlyName); } DisplayMessage(g_hModule, ((Format == FORMAT_VERBOSE)? MSG_IPV6_DESTINATION_ENTRY_VERBOSE : MSG_IPV6_DESTINATION_ENTRY), ((RCE->PathMTU == 0)? IPv6_MINIMUM_MTU : RCE->PathMTU), FormatIPv6Address(&RCE->Query.Address, 0)); DisplayMessage(g_hModule, ((Format == FORMAT_VERBOSE)? MSG_IPV6_DESTINATION_NEXTHOP_VERBOSE : MSG_IPV6_DESTINATION_NEXTHOP), FormatIPv6Address(&RCE->NextHopAddress, 0)); if (Format == FORMAT_VERBOSE) { DisplayMessage(g_hModule, MSG_IPV6_DESTINATION_SOURCE_ADDR, FormatIPv6Address(&RCE->SourceAddress, 0)); pwszTemp = MakeString(g_hModule, ((RCE->Valid)? STRING_NO : STRING_YES)); DisplayMessage(g_hModule, MSG_IPV6_STALE, pwszTemp); FreeString(pwszTemp); switch (RCE->Flags) { case RCE_FLAG_CONSTRAINED: DisplayMessage(g_hModule, MSG_IPV6_IF_SPECIFIC); break; case RCE_FLAG_CONSTRAINED_SCOPEID: DisplayMessage(g_hModule, MSG_IPV6_ZONE_SPECIFIC); break; } if (RCE->PMTUProbeTimer != INFINITE_LIFETIME) { DisplayMessage(g_hModule, MSG_IPV6_PMTU_PROBE_TIME, RCE->PMTUProbeTimer/1000); // FormatTime(RCE->PMTUProbeTimer/1000, wszTime)); } if ((RCE->ICMPLastError != 0) && (RCE->ICMPLastError < 10*60*1000)) { DisplayMessage(g_hModule, MSG_IPV6_ICMP_ERROR_TIME, RCE->ICMPLastError/1000); // FormatTime(RCE->ICMPLastError/1000, wszTime)); } if ((RCE->BindingSeqNumber != 0) || (RCE->BindingLifetime != 0) || ! IN6_ADDR_EQUAL(&RCE->CareOfAddress, &in6addr_any)) { DisplayMessage(g_hModule, MSG_IPV6_CAREOF, FormatIPv6Address(&RCE->CareOfAddress, 0), RCE->BindingSeqNumber, RCE->BindingLifetime); // FormatTime(RCE->BindingLifetime, wszTime)); } } return NO_ERROR; } DWORD ForEachDestination( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format, IN DWORD (*pfnFunc)(IPV6_INFO_ROUTE_CACHE *,PIP_ADAPTER_ADDRESSES,DWORD,FORMAT) ) { IPV6_QUERY_ROUTE_CACHE Query, NextQuery; IPV6_INFO_ROUTE_CACHE RCE; DWORD dwInfoSize, dwBytesReturned, dwCount = 0; NextQuery.IF.Index = 0; NextQuery.Address = in6addr_any; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_ROUTE_CACHE, &Query, sizeof Query, &RCE, sizeof(RCE), &dwBytesReturned, NULL)) { return dwCount; } NextQuery = RCE.Query; if (Query.IF.Index == IF->This.Index) { RCE.Query = Query; if ((*pfnFunc)(&RCE,pAdapterInfo,dwCount,Format) == NO_ERROR) { dwCount++; } } else if (dwCount > 0) { // // Stop if we're done with the desired interface. // break; } if (NextQuery.IF.Index == 0) { break; } } return dwCount; } IPV6_INFO_ROUTE_CACHE * GetDestination( IN IPV6_QUERY_INTERFACE *IF, IN IN6_ADDR *Address ) { IPV6_QUERY_ROUTE_CACHE Query; IPV6_INFO_ROUTE_CACHE *RCE; DWORD dwBytesReturned; Query.IF = *IF; Query.Address = *Address; RCE = (IPV6_INFO_ROUTE_CACHE *) malloc(sizeof *RCE); if (RCE == NULL) { return NULL; } if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_ROUTE_CACHE, &Query, sizeof Query, RCE, sizeof *RCE, &dwBytesReturned, NULL)) { return NULL; } RCE->Query = Query; return RCE; } DWORD PrintRouteCache( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwIfCount, IN FORMAT Format ) { DWORD dwCount = ForEachDestination(IF, pAdapterInfo, Format, PrintDestination); return (dwCount > 0)? NO_ERROR : ERROR_NO_DATA; } DWORD QueryRouteCache( IN PWCHAR pwszInterface, IN IN6_ADDR *pipAddress, IN FORMAT Format ) { IPV6_INFO_INTERFACE *IF; IPV6_INFO_ROUTE_CACHE *RCE; PIP_ADAPTER_ADDRESSES pAdapterInfo; DWORD dwCount, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } if (!pwszInterface) { dwCount = ForEachInterface(PrintRouteCache, pAdapterInfo, Format, FALSE); FREE(pAdapterInfo); if (dwCount == 0) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } return NO_ERROR; } dwErr = GetInterfaceByFriendlyName(pwszInterface, pAdapterInfo, FALSE, &IF); if (dwErr != NO_ERROR) { return dwErr; } if (!pipAddress) { if (PrintRouteCache(IF, pAdapterInfo, 0, Format) == ERROR_NO_DATA) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } } else { RCE = GetDestination(&IF->This, pipAddress); PrintDestination(RCE, pAdapterInfo, 0, Format); FREE(RCE); } FREE(IF); FREE(pAdapterInfo); return dwErr; } DWORD FlushRouteCacheForInterface( IN IPV6_INFO_INTERFACE *IF, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN DWORD dwCount, IN FORMAT Format ) { IPV6_QUERY_ROUTE_CACHE Query; DWORD dwBytesReturned; Query.IF = IF->This; Query.Address = in6addr_any; if (!DeviceIoControl(Handle, IOCTL_IPV6_FLUSH_ROUTE_CACHE, &Query, sizeof Query, NULL, 0, &dwBytesReturned, NULL)) { return GetLastError(); } return NO_ERROR; } DWORD FlushRouteCache( IN PWCHAR pwszInterface, IN IN6_ADDR *pipAddress ) { IPV6_QUERY_ROUTE_CACHE Query; DWORD dwBytesReturned, dwErr; PIP_ADAPTER_ADDRESSES pAdapterInfo; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (!pwszInterface) { ForEachInterface(FlushRouteCacheForInterface, NULL, FORMAT_NORMAL, FALSE); return NO_ERROR; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MapFriendlyNameToIpv6IfIndex(pwszInterface, pAdapterInfo, &Query.IF.Index); if (dwErr != NO_ERROR) { return dwErr; } if (pipAddress) { Query.Address = *pipAddress; } else { Query.Address = in6addr_any; } if (!DeviceIoControl(Handle, IOCTL_IPV6_FLUSH_ROUTE_CACHE, &Query, sizeof Query, NULL, 0, &dwBytesReturned, NULL)) { return GetLastError(); } return ERROR_OKAY; } ////////////////////////////////////////////////////////////////////////////// // Route table functions ////////////////////////////////////////////////////////////////////////////// DWORD ForEachRoute( IN DWORD (*pfnFunc)(IPV6_INFO_ROUTE_TABLE *, DWORD, DWORD, PIP_ADAPTER_ADDRESSES, FORMAT), IN DWORD dwArg, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format, IN BOOL bPersistent ) { IPV6_QUERY_ROUTE_TABLE Query, NextQuery; IPV6_INFO_ROUTE_TABLE RTE; DWORD dwBytesReturned, dwCount = 0; ZeroMemory(&NextQuery, sizeof(NextQuery)); for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, (bPersistent)? IOCTL_IPV6_PERSISTENT_QUERY_ROUTE_TABLE : IOCTL_IPV6_QUERY_ROUTE_TABLE, &Query, sizeof Query, &RTE, sizeof RTE, &dwBytesReturned, NULL)) { return dwCount; } NextQuery = RTE.Next; if (Query.Neighbor.IF.Index != 0) { RTE.This = Query; if ((*pfnFunc)(&RTE, dwArg, dwCount, pAdapterInfo, Format) == NO_ERROR) { dwCount++; } } if (NextQuery.Neighbor.IF.Index == 0) break; } return dwCount; } // // These are RFC 2465 ipv6RouteProtocol values, and must match // RTE_TYPE_... in ntddip6.h. // DWORD RteTypeMsg[] = { 0,0, STRING_SYSTEM, STRING_MANUAL, STRING_AUTOCONF, STRING_RIP, STRING_OSPF, STRING_BGP, STRING_IDRP, STRING_IGRP }; #define RTE_TYPE_MSG_COUNT (sizeof(RteTypeMsg)/sizeof(DWORD)) DWORD PrintRouteTableEntry( IN IPV6_INFO_ROUTE_TABLE *RTE, IN DWORD dwArg, IN DWORD dwCount, IN PIP_ADAPTER_ADDRESSES pAdapterInfo, IN FORMAT Format ) { DWORD dwTypeMsg, dwErr; PWCHAR pwszPublishMsg, pwszFriendlyName; if (Format != FORMAT_VERBOSE) { // // Suppress system routes (used for loopback). // if (RTE->Type == RTE_TYPE_SYSTEM) { return ERROR_NO_DATA; } } dwErr = MapIpv6IfIndexToFriendlyName(RTE->This.Neighbor.IF.Index, pAdapterInfo, &pwszFriendlyName); if (dwErr != NO_ERROR) { return dwErr; } pwszPublishMsg = TOKEN_VALUE_NO; if (RTE->Publish) { pwszPublishMsg = (RTE->Immortal)? TOKEN_VALUE_YES : TOKEN_VALUE_AGE; } if (Format == FORMAT_DUMP) { DisplayMessageT(DMP_IPV6_ADD_ROUTE); DisplayMessageT(DMP_STRING_ARG, TOKEN_PREFIX, FormatIPv6Prefix(&RTE->This.Prefix, RTE->This.PrefixLength)); DisplayMessageT(DMP_QUOTED_STRING_ARG, TOKEN_INTERFACE, pwszFriendlyName); DisplayMessageT(DMP_INTEGER_ARG, TOKEN_METRIC, RTE->Preference); if (!IN6_ADDR_EQUAL(&RTE->This.Neighbor.Address, &in6addr_any)) { DisplayMessageT(DMP_STRING_ARG, TOKEN_NEXTHOP, FormatIPv6Address(&RTE->This.Neighbor.Address, 0)); } if (RTE->Publish) { DisplayMessageT(DMP_STRING_ARG, TOKEN_PUBLISH, pwszPublishMsg); if ((RTE->SitePrefixLength != 0) && IN6_ADDR_EQUAL(&RTE->This.Neighbor.Address, &in6addr_any)) { DisplayMessageT(DMP_STRING_ARG, TOKEN_SITEPREFIXLENGTH, RTE->SitePrefixLength); } } DisplayMessage(g_hModule, MSG_NEWLINE); } else { WCHAR wszValid[64], wszPreferred[64]; PWCHAR pwszTemp, pwszPrefix, pwszGateway; IPV6_INFO_INTERFACE *IF; if ((Format == FORMAT_NORMAL) && (dwCount == 0)) { DisplayMessage(g_hModule, MSG_IPV6_ROUTE_TABLE_HDR); } dwTypeMsg = (RTE->Type < RTE_TYPE_MSG_COUNT)? RteTypeMsg[RTE->Type] : STRING_UNKNOWN; pwszTemp = MakeString(g_hModule, dwTypeMsg); pwszPrefix = FormatIPv6Prefix(&RTE->This.Prefix, RTE->This.PrefixLength); if (IN6_ADDR_EQUAL(&RTE->This.Neighbor.Address, &in6addr_any)) { pwszGateway = pwszFriendlyName; } else { pwszGateway = FormatIPv6Address(&RTE->This.Neighbor.Address, 0); } IF = GetInterfaceByIpv6IfIndex(RTE->This.Neighbor.IF.Index); if (!IF) { FreeString(pwszTemp); return ERROR_NO_DATA; } DisplayMessage(g_hModule, ((Format == FORMAT_VERBOSE)? MSG_IPV6_ROUTE_TABLE_ENTRY_VERBOSE : MSG_IPV6_ROUTE_TABLE_ENTRY), pwszPrefix, RTE->This.Neighbor.IF.Index, pwszGateway, IF->Preference + RTE->Preference, pwszPublishMsg, pwszTemp, pwszFriendlyName, RTE->ValidLifetime, // FormatTime(RTE->ValidLifetime, wszValid), RTE->PreferredLifetime, // FormatTime(RTE->PreferredLifetime, wszPreferred), RTE->SitePrefixLength); FREE(IF); FreeString(pwszTemp); } return NO_ERROR; } DWORD QueryRouteTable( IN FORMAT Format, IN BOOL bPersistent ) { DWORD dwErr, dwCount = 0; PIP_ADAPTER_ADDRESSES pAdapterInfo; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } if (Format != FORMAT_DUMP) { // DisplayMessage(g_hModule, (bPersistent)? MSG_PERSISTENT : MSG_ACTIVE); } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != ERROR_NO_DATA) { if (dwErr != NO_ERROR) { return dwErr; } dwCount = ForEachRoute(PrintRouteTableEntry, 0, pAdapterInfo, Format, bPersistent); FREE(pAdapterInfo); } if ((Format != FORMAT_DUMP) && !dwCount) { DisplayMessage(g_hModule, MSG_IP_NO_ENTRIES); } return NO_ERROR; } DWORD UpdateRouteTable( IN IN6_ADDR *pipPrefix, IN DWORD dwPrefixLength, IN PWCHAR pwszIfFriendlyName, IN IN6_ADDR *pipNextHop, IN DWORD dwMetric, IN PUBLISH Publish, IN DWORD dwSitePrefixLength, IN DWORD dwValidLifetime, IN DWORD dwPreferredLifetime, IN BOOL bPersistent ) { IPV6_INFO_ROUTE_TABLE Route; DWORD dwBytesReturned; PIP_ADAPTER_ADDRESSES pAdapterInfo; DWORD dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MyGetAdaptersInfo(&pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } dwErr = MapFriendlyNameToIpv6IfIndex(pwszIfFriendlyName, pAdapterInfo, &Route.This.Neighbor.IF.Index); FREE(pAdapterInfo); if (dwErr != NO_ERROR) { return dwErr; } Route.This.Prefix = *pipPrefix; Route.This.PrefixLength = dwPrefixLength; Route.This.Neighbor.Address = (pipNextHop)? *pipNextHop : in6addr_any; Route.SitePrefixLength = dwSitePrefixLength; Route.ValidLifetime = dwValidLifetime; Route.PreferredLifetime = dwPreferredLifetime; Route.Preference = dwMetric; Route.Type = RTE_TYPE_MANUAL; switch (Publish) { case PUBLISH_IMMORTAL: Route.Publish = TRUE; Route.Immortal = TRUE; break; case PUBLISH_AGE: Route.Publish = TRUE; Route.Immortal = FALSE; break; case PUBLISH_NO: Route.Publish = FALSE; Route.Immortal = FALSE; break; default: ASSERT(FALSE); } dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_UPDATE_ROUTE_TABLE, &Route, sizeof Route, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_ROUTE_TABLE, &Route, sizeof Route, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; } DWORD ResetIpv6Config( IN BOOL bPersistent ) { DWORD dwBytesReturned, dwErr; dwErr = OpenIPv6(); if (dwErr != NO_ERROR) { return dwErr; } dwErr = ERROR_OKAY; if (bPersistent) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_RESET, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) { dwErr = GetLastError(); } } if (!DeviceIoControl(Handle, IOCTL_IPV6_RESET, NULL, 0, NULL, 0, &dwBytesReturned, NULL)) { if (dwErr == ERROR_OKAY) { dwErr = GetLastError(); } } return dwErr; }