// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs) // // Copyright (c) 1998-2000 Microsoft Corporation // // This file is part of the Microsoft Research IPv6 Network Protocol Stack. // You should have received a copy of the Microsoft End-User License Agreement // for this software along with this release; see the file "license.txt". // If not, please see http://www.research.microsoft.com/msripv6/license.htm, // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399. // // Abstract: // // Dump current IPv6 state information. // #include #include #include #include #include #include #include #include #include #include #include // // Localization library and MessageIds. // #include #include #include "localmsg.h" HANDLE Handle; int Verbose = FALSE; int AdminAccess = TRUE; int Persistent = FALSE; void QueryInterface(int argc, char *argv[]); void CreateInterface(int argc, char *argv[]); void UpdateInterface(int argc, char *argv[]); void DeleteInterface(int argc, char *argv[]); void UpdateRouterLinkAddress(int argc, char *argv[]); void QueryNeighborCache(int argc, char *argv[]); void QueryRouteCache(int argc, char *argv[]); void QueryRouteTable(int argc, char *argv[]); void UpdateRouteTable(int argc, char *argv[]); void UpdateAddress(int argc, char *argv[]); void QueryBindingCache(int argc, char *argv[]); void FlushNeighborCache(int argc, char *argv[]); void FlushRouteCache(int argc, char *argv[]); void QuerySitePrefixTable(int argc, char *argv[]); void UpdateSitePrefixTable(int argc, char *argv[]); void QueryGlobalParameters(int argc, char *argv[]); void UpdateGlobalParameters(int argc, char *argv[]); void QueryPrefixPolicy(int argc, char *argv[]); void UpdatePrefixPolicy(int argc, char *argv[]); void DeletePrefixPolicy(int argc, char *argv[]); void ResetManualConfig(int argc, char *argv[]); void RenewInterface(int argc, char *argv[]); void AddOrRemoveIpv6(BOOL fAddIpv6); BOOL IsIpv6Installed(); void usage(void) { NlsPutMsg(STDOUT, IPV6_MESSAGE_14); // printf("usage: ipv6 [-p] [-v] if [ifindex]\n"); // printf(" ipv6 [-p] ifcr v6v4 v4src v4dst [nd] [pmld]\n"); // printf(" ipv6 [-p] ifcr 6over4 v4src\n"); // printf(" ipv6 [-p] ifc ifindex [forwards] [-forwards] [advertises] [-advertises] [mtu #bytes] [site site-identifier] [preference P]\n"); // printf(" ipv6 rlu ifindex v4dst\n"); // printf(" ipv6 [-p] ifd ifindex\n"); // printf(" ipv6 [-p] adu ifindex/address [life validlifetime[/preflifetime]] [anycast] [unicast]\n"); // printf(" ipv6 nc [ifindex [address]]\n"); // printf(" ipv6 ncf [ifindex [address]]\n"); // printf(" ipv6 rc [ifindex address]\n"); // printf(" ipv6 rcf [ifindex [address]]\n"); // printf(" ipv6 bc\n"); // printf(" ipv6 [-p] [-v] rt\n"); // printf(" ipv6 [-p] rtu prefix ifindex[/address] [life valid[/pref]] [preference P] [publish] [age] [spl SitePrefixLength]\n"); // printf(" ipv6 spt\n"); // printf(" ipv6 spu prefix ifindex [life L]\n"); // printf(" ipv6 [-p] gp\n"); // printf(" ipv6 [-p] gpu [parameter value] ... (try -?)\n"); // printf(" ipv6 renew [ifindex]\n"); // printf(" ipv6 [-p] ppt\n"); // printf(" ipv6 [-p] ppu prefix precedence P srclabel SL [dstlabel DL]\n"); // printf(" ipv6 [-p] ppd prefix\n"); // printf(" ipv6 [-p] reset\n"); // printf(" ipv6 install\n"); // printf(" ipv6 uninstall\n"); // printf("Some subcommands require local Administrator privileges.\n"); exit(1); } void ausage(void) { NlsPutMsg(STDOUT, IPV6_MESSAGE_15); // printf("You do not have local Administrator privileges.\n"); exit(1); } int __cdecl main(int argc, char **argv) { WSADATA wsaData; int i; // // This will ensure the correct language message is displayed when // NlsPutMsg is called. // SetThreadUILanguage(0); // // Parse any global options. // for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-v")) Verbose = TRUE; else if (!strcmp(argv[i], "-p")) Persistent = TRUE; else break; } argc -= i; argv += i; if (argc < 1) { usage(); } if (!strcmp(argv[0], "install")) { if (argc != 1) usage(); AddOrRemoveIpv6(TRUE); } else if (!strcmp(argv[0], "uninstall")) { if (argc != 1) usage(); AddOrRemoveIpv6(FALSE); } else { // // We initialize Winsock only to have access // to WSAStringToAddress and WSAAddressToString. // if (WSAStartup(MAKEWORD(2, 0), &wsaData)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_18); // printf("WSAStartup failed\n"); exit(1); } // // First request write access. // This will fail if the process does not have appropriate 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) { if (IsIpv6Installed()) { NlsPutMsg(STDOUT, IPV6_MESSAGE_IPV6_NOT_RUNNING); // printf("Could not access IPv6 protocol stack - the stack is not running.\n"); // printf("To start it, please use 'net start tcpip6'.\n"); } else { NlsPutMsg(STDOUT, IPV6_MESSAGE_IPV6_NOT_INSTALLED); // printf("Could not access IPv6 protocol stack - the stack is not installed.\n"); // printf("To install, please use 'ipv6 install'.\n"); } exit(1); } } if (!strcmp(argv[0], "if")) { QueryInterface(argc - 1, argv + 1); } else if (!strcmp(argv[0], "ifcr")) { if (! AdminAccess) ausage(); CreateInterface(argc - 1, argv + 1); } else if (!strcmp(argv[0], "ifc")) { if (! AdminAccess) ausage(); UpdateInterface(argc - 1, argv + 1); } else if (!strcmp(argv[0], "ifd")) { if (! AdminAccess) ausage(); DeleteInterface(argc - 1, argv + 1); } else if (!strcmp(argv[0], "renew")) { if (! AdminAccess) ausage(); RenewInterface(argc - 1, argv + 1); } else if (!strcmp(argv[0], "adu")) { if (! AdminAccess) ausage(); UpdateAddress(argc - 1, argv + 1); } else if (!strcmp(argv[0], "nc")) { QueryNeighborCache(argc - 1, argv + 1); } else if (!strcmp(argv[0], "ncf")) { if (! AdminAccess) ausage(); FlushNeighborCache(argc - 1, argv + 1); } else if (!strcmp(argv[0], "rc")) { QueryRouteCache(argc - 1, argv + 1); } else if (!strcmp(argv[0], "rcf")) { if (! AdminAccess) ausage(); FlushRouteCache(argc - 1, argv + 1); } else if (!strcmp(argv[0], "rlu")) { if (! AdminAccess) ausage(); UpdateRouterLinkAddress(argc - 1, argv + 1); } else if (!strcmp(argv[0], "rt")) { QueryRouteTable(argc - 1, argv + 1); } else if (!strcmp(argv[0], "rtu")) { if (! AdminAccess) ausage(); UpdateRouteTable(argc - 1, argv + 1); } else if (!strcmp(argv[0], "spt")) { QuerySitePrefixTable(argc - 1, argv + 1); } else if (!strcmp(argv[0], "spu")) { if (! AdminAccess) ausage(); UpdateSitePrefixTable(argc - 1, argv + 1); } else if (!strcmp(argv[0], "bc")) { QueryBindingCache(argc - 1, argv + 1); } else if (!strcmp(argv[0], "gp")) { QueryGlobalParameters(argc - 1, argv + 1); } else if (!strcmp(argv[0], "gpu")) { if (! AdminAccess) ausage(); UpdateGlobalParameters(argc - 1, argv + 1); } else if (!strcmp(argv[0], "ppt")) { QueryPrefixPolicy(argc - 1, argv + 1); } else if (!strcmp(argv[0], "ppu")) { if (! AdminAccess) ausage(); UpdatePrefixPolicy(argc - 1, argv + 1); } else if (!strcmp(argv[0], "ppd")) { if (! AdminAccess) ausage(); DeletePrefixPolicy(argc - 1, argv + 1); } else if (!strcmp(argv[0], "reset")) { if (! AdminAccess) ausage(); ResetManualConfig(argc - 1, argv + 1); } else { usage(); } } return 0; } int GetNumber(char *astr, u_int *number) { u_int num; num = 0; while (*astr != '\0') { if (('0' <= *astr) && (*astr <= '9')) num = 10 * num + (*astr - '0'); else return FALSE; astr++; } *number = num; return TRUE; } int GetGuid(char *astr, GUID *Guid) { WCHAR GuidStr[40+1]; UNICODE_STRING UGuidStr; MultiByteToWideChar(CP_ACP, 0, astr, -1, GuidStr, 40); RtlInitUnicodeString(&UGuidStr, GuidStr); return RtlGUIDFromString(&UGuidStr, Guid) == STATUS_SUCCESS; } char * FormatGuid(const GUID *pGuid) { static char buffer[40]; sprintf(buffer, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", pGuid->Data1, pGuid->Data2, pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]); return buffer; } int GetInterface(char *astr, IPV6_QUERY_INTERFACE *Query) { if (*astr == '{') { // // Read a guid. // Query->Index = 0; return GetGuid(astr, &Query->Guid); } else { // // Read a non-zero interface index. // return GetNumber(astr, &Query->Index) && (Query->Index != 0); } } #define SECONDS 1 #define MINUTES (60 * SECONDS) #define HOURS (60 * MINUTES) #define DAYS (24 * HOURS) int GetLifetime(char *astr, u_int *number) { char *pUnit; u_int units; u_int value; *number = 0; while ((pUnit = strpbrk(astr, "sSmMhHdD")) != NULL) { switch (*pUnit) { case 's': case 'S': units = SECONDS; break; case 'm': case 'M': units = MINUTES; break; case 'h': case 'H': units = HOURS; break; case 'd': case 'D': units = DAYS; break; } *pUnit = '\0'; if (! GetNumber(astr, &value)) return FALSE; *number += units * value; astr = pUnit + 1; if (*astr == '\0') return TRUE; } if (! GetNumber(astr, &value)) return FALSE; *number += value; return TRUE; } int GetLifetimes(char *astr, u_int *valid, u_int *preferred) { char *slash; u_int length; slash = strchr(astr, '/'); if (slash == NULL) { if (strcmp(astr, "infinite")) { if (! GetLifetime(astr, valid)) return FALSE; if (preferred != NULL) *preferred = *valid; } return TRUE; } if (preferred == NULL) return FALSE; *slash = '\0'; if (strcmp(astr, "infinite")) if (! GetLifetime(astr, valid)) return FALSE; if (strcmp(slash+1, "infinite")) if (! GetLifetime(slash+1, preferred)) return FALSE; return TRUE; } char * FormatLifetime(u_int Life) { static char buffer[64]; char *s = buffer; u_int Days, Hours, Minutes; if (Life == INFINITE_LIFETIME) return "infinite"; if (Verbose) goto FormatSeconds; if (Life < 2 * MINUTES) goto FormatSeconds; if (Life < 2 * HOURS) goto FormatMinutes; if (Life < 2 * DAYS) goto FormatHours; Days = Life / DAYS; if (Days != 0) s += sprintf(s, "%ud", Days); Life -= Days * DAYS; FormatHours: Hours = Life / HOURS; if (Hours != 0) s += sprintf(s, "%uh", Hours); Life -= Hours * HOURS; FormatMinutes: Minutes = Life / MINUTES; if (Minutes != 0) s += sprintf(s, "%um", Minutes); Life -= Minutes * MINUTES; if (Life == 0) return buffer; FormatSeconds: (void) sprintf(s, "%us", Life); return buffer; } char * FormatLifetimes(u_int Valid, u_int Preferred) { static char buffer[128]; char *s = buffer; s += sprintf(s, "%s", FormatLifetime(Valid)); if (Preferred != Valid) s += sprintf(s, "/%s", FormatLifetime(Preferred)); return buffer; } int GetAddress(char *astr, IPv6Addr *address) { struct sockaddr_in6 sin6; int addrlen = sizeof sin6; sin6.sin6_family = AF_INET6; // shouldn't be required but is if ((WSAStringToAddress(astr, AF_INET6, NULL, (struct sockaddr *)&sin6, &addrlen) == SOCKET_ERROR) || (sin6.sin6_port != 0) || (sin6.sin6_scope_id != 0)) return FALSE; // The user gave us a numeric IPv6 address. memcpy(address, &sin6.sin6_addr, sizeof *address); return TRUE; } int GetPrefix(char *astr, IPv6Addr *prefix, u_int *prefixlen) { struct sockaddr_in6 sin6; int addrlen = sizeof sin6; char *slash; u_int length; slash = strchr(astr, '/'); if (slash == NULL) return FALSE; *slash = '\0'; if (! GetNumber(slash+1, &length)) return FALSE; if (length > 128) return FALSE; sin6.sin6_family = AF_INET6; // shouldn't be required but is if ((WSAStringToAddress(astr, AF_INET6, NULL, (struct sockaddr *)&sin6, &addrlen) == SOCKET_ERROR) || (sin6.sin6_port != 0) || (sin6.sin6_scope_id != 0)) return FALSE; // The user gave us a numeric IPv6 address. memcpy(prefix, &sin6.sin6_addr, sizeof *prefix); *prefixlen = length; return TRUE; } const char *PrefixConfStr[] = { "other", "manual", "well-known", "dhcp", "ra", NULL }; #define MAX_PREFIX_CONF (sizeof(PrefixConfStr) / sizeof(char *)) const char *InterfaceIdConfStr[] = { "other", "manual", "well-known", "dhcp", "LL-address-derived", "random", NULL }; #define MAX_IID_CONF (sizeof(InterfaceIdConfStr) / sizeof(char *)) int GetPrefixOrigin(char *astr, u_int *origin) { int i; for (i=0; PrefixConfStr[i]; i++) { if (!strcmp(astr, PrefixConfStr[i])) { *origin = i; return TRUE; } } return FALSE; } int GetInterfaceIdOrigin(char *astr, u_int *origin) { int i; for (i=0; InterfaceIdConfStr[i]; i++) { if (!strcmp(astr, InterfaceIdConfStr[i])) { *origin = i; return TRUE; } } return FALSE; } int GetNeighbor(char *astr, IPV6_QUERY_INTERFACE *IF, IPv6Addr *addr) { struct sockaddr_in6 sin6; int addrlen = sizeof sin6; char *slash; u_int length; slash = strchr(astr, '/'); if (slash != NULL) *slash = '\0'; if (! GetInterface(astr, IF)) return FALSE; if (slash == NULL) { *addr = in6addr_any; return TRUE; } sin6.sin6_family = AF_INET6; // shouldn't be required but is if ((WSAStringToAddress(slash+1, AF_INET6, NULL, (struct sockaddr *)&sin6, &addrlen) == SOCKET_ERROR) || (sin6.sin6_port != 0) || (sin6.sin6_scope_id != 0)) return FALSE; // The user gave us a numeric IPv6 address. *addr = sin6.sin6_addr; return TRUE; } char * FormatIPv6Address(IPv6Addr *Address) { static char buffer[128]; DWORD buflen = sizeof buffer; struct sockaddr_in6 sin6; memset(&sin6, 0, sizeof sin6); sin6.sin6_family = AF_INET6; sin6.sin6_addr = *Address; if (WSAAddressToString((struct sockaddr *) &sin6, sizeof sin6, NULL, // LPWSAPROTOCOL_INFO buffer, &buflen) == SOCKET_ERROR) strcpy(buffer, ""); return buffer; } char * FormatIPv4Address(struct in_addr *Address) { static char buffer[128]; DWORD buflen = sizeof buffer; struct sockaddr_in sin; memset(&sin, 0, sizeof sin); sin.sin_family = AF_INET; sin.sin_addr = *Address; if (WSAAddressToString((struct sockaddr *) &sin, sizeof sin, NULL, // LPWSAPROTOCOL_INFO buffer, &buflen) == SOCKET_ERROR) strcpy(buffer, ""); return buffer; } char * FormatLinkLayerAddress(u_int length, u_char *addr) { static char buffer[128]; switch (length) { case 6: { int i, digit; char *s = buffer; for (i = 0; i < 6; i++) { if (i != 0) *s++ = '-'; digit = addr[i] >> 4; if (digit < 10) *s++ = digit + '0'; else *s++ = digit - 10 + 'a'; digit = addr[i] & 0xf; if (digit < 10) *s++ = digit + '0'; else *s++ = digit - 10 + 'a'; } *s = '\0'; break; } case 4: // // IPv4 address (6-over-4 link) // strcpy(buffer, FormatIPv4Address((struct in_addr *)addr)); break; case 0: // // Null or loop-back address // buffer[0] = '\0'; break; default: NlsPutMsg(STDOUT, IPV6_MESSAGE_21); // printf("unrecognized link-layer address format\n"); exit(1); } return buffer; } void ForEachAddress(IPV6_INFO_INTERFACE *IF, void (*func)(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *)) { IPV6_QUERY_ADDRESS Query; IPV6_INFO_ADDRESS ADE; u_int BytesReturned; Query.IF = IF->This; Query.Address = in6addr_any; for (;;) { if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_ADDRESS, &Query, sizeof Query, &ADE, sizeof ADE, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_22, FormatIPv6Address(&Query.Address)); // printf("bad address %s\n", FormatIPv6Address(&Query.Address)); exit(1); } if (!IN6_ADDR_EQUAL(&Query.Address, &in6addr_any)) { if (BytesReturned != sizeof ADE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_INCONSISTENT_ADDRESS); // printf("inconsistent address info length\n"); exit(1); } (*func)(IF, &ADE); } else { if (BytesReturned != sizeof ADE.Next) { NlsPutMsg(STDOUT, IPV6_MESSAGE_INCONSISTENT_ADDRESS); // printf("inconsistent address info length\n"); exit(1); } } if (IN6_ADDR_EQUAL(&ADE.Next.Address, &in6addr_any)) break; Query = ADE.Next; } } void ForEachPersistentAddress(IPV6_INFO_INTERFACE *IF, void (*func)(IPV6_INFO_INTERFACE *IF, IPV6_UPDATE_ADDRESS *)) { IPV6_PERSISTENT_QUERY_ADDRESS Query; IPV6_UPDATE_ADDRESS ADE; u_int BytesReturned; Query.IF.RegistryIndex = (u_int) -1; Query.IF.Guid = IF->This.Guid; for (Query.RegistryIndex = 0;; Query.RegistryIndex++) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_QUERY_ADDRESS, &Query, sizeof Query, &ADE, sizeof ADE, &BytesReturned, NULL) || (BytesReturned != sizeof ADE)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) break; NlsPutMsg(STDOUT, IPV6_MESSAGE_22, FormatIPv6Address(&Query.Address)); // printf("bad address %s\n", FormatIPv6Address(&Query.Address)); exit(1); } (*func)(IF, &ADE); } } const char * FormatDADState(u_int DADState) { static char buffer[128]; switch (DADState) { case DAD_STATE_INVALID: return "invalid"; case DAD_STATE_DUPLICATE: return "duplicate"; case DAD_STATE_TENTATIVE: return "tentative"; case DAD_STATE_DEPRECATED: return "deprecated"; case DAD_STATE_PREFERRED: return "preferred"; default: sprintf(buffer, "DAD state %u>", DADState); return buffer; } } const char * FormatScopeAdj(u_int Scope) { static char buffer[128]; switch (Scope) { case ADE_INTERFACE_LOCAL: return "interface-local"; case ADE_LINK_LOCAL: return "link-local"; case ADE_SUBNET_LOCAL: return "subnet-local"; case ADE_ADMIN_LOCAL: return "admin-local"; case ADE_SITE_LOCAL: return "site-local"; case ADE_ORG_LOCAL: return "org-local"; case ADE_GLOBAL: return "global"; default: sprintf(buffer, "scope %u", Scope); return buffer; } } const char * FormatScopeNoun(u_int Scope) { static char buffer[128]; switch (Scope) { case ADE_INTERFACE_LOCAL: return "if"; case ADE_LINK_LOCAL: return "link"; case ADE_SUBNET_LOCAL: return "subnet"; case ADE_ADMIN_LOCAL: return "admin"; case ADE_SITE_LOCAL: return "site"; case ADE_ORG_LOCAL: return "org"; case ADE_GLOBAL: return "global"; default: sprintf(buffer, "zone%u", Scope); return buffer; } } void PrintAddrOrigin(u_int PrefixConf, u_int InterfaceIdConf) { if ((PrefixConf == PREFIX_CONF_MANUAL) && (InterfaceIdConf == IID_CONF_MANUAL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_25); // printf(" (manual)"); } else if ((PrefixConf == PREFIX_CONF_RA) && (InterfaceIdConf == IID_CONF_LL_ADDRESS)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_26); // printf(" (public)"); } else if ((PrefixConf == PREFIX_CONF_RA) && (InterfaceIdConf == IID_CONF_RANDOM)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_27); // printf(" (temporary)"); } else if ((PrefixConf == PREFIX_CONF_DHCP) && (InterfaceIdConf == IID_CONF_DHCP)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_28); // printf(" (dhcp)"); } if (Verbose) { // // Show prefix origin / interface id origin // NlsPutMsg(STDOUT, IPV6_MESSAGE_29); // printf(" ("); if (PrefixConf >= MAX_PREFIX_CONF) NlsPutMsg(STDOUT, IPV6_MESSAGE_30, PrefixConf); // printf("unknown prefix origin %u", PrefixConf); else printf(PrefixConfStr[PrefixConf]); NlsPutMsg(STDOUT, IPV6_MESSAGE_32); // printf("/"); if (InterfaceIdConf >= MAX_IID_CONF) NlsPutMsg(STDOUT, IPV6_MESSAGE_33, InterfaceIdConf); // printf("unknown ifid origin %u", InterfaceIdConf); else printf(InterfaceIdConfStr[InterfaceIdConf]); NlsPutMsg(STDOUT, IPV6_MESSAGE_35); // printf(")"); } } void PrintAddress(IPV6_INFO_INTERFACE *IF, IPV6_INFO_ADDRESS *ADE) { if (!Verbose) { // // Suppress invalid addresses. // if ((ADE->Type == ADE_UNICAST) && (ADE->DADState == DAD_STATE_INVALID)) return; } switch (ADE->Type) { case ADE_UNICAST: NlsPutMsg(STDOUT, IPV6_MESSAGE_23, FormatDADState(ADE->DADState), FormatScopeAdj(ADE->Scope), FormatIPv6Address(&ADE->This.Address)); // printf(" %s %s %s, ", // FormatDADState(ADE->DADState), // FormatScopeAdj(ADE->Scope), // FormatIPv6Address(&ADE->This.Address)); NlsPutMsg(STDOUT, IPV6_MESSAGE_24, FormatLifetimes(ADE->ValidLifetime, ADE->PreferredLifetime)); // printf("life %s", // FormatLifetimes(ADE->ValidLifetime, ADE->PreferredLifetime)); PrintAddrOrigin(ADE->PrefixConf, ADE->InterfaceIdConf); NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); break; case ADE_ANYCAST: NlsPutMsg(STDOUT, IPV6_MESSAGE_37, FormatScopeAdj(ADE->Scope), FormatIPv6Address(&ADE->This.Address)); // printf(" anycast %s %s\n", // FormatScopeAdj(ADE->Scope), // FormatIPv6Address(&ADE->This.Address)); break; case ADE_MULTICAST: NlsPutMsg(STDOUT, IPV6_MESSAGE_38, FormatScopeAdj(ADE->Scope), FormatIPv6Address(&ADE->This.Address), ADE->MCastRefCount); // printf(" multicast %s %s, %u refs", // FormatScopeAdj(ADE->Scope), // FormatIPv6Address(&ADE->This.Address), // ADE->MCastRefCount); if (!(ADE->MCastFlags & 0x01)) NlsPutMsg(STDOUT, IPV6_MESSAGE_39); // printf(", not reportable"); if (ADE->MCastFlags & 0x02) NlsPutMsg(STDOUT, IPV6_MESSAGE_40); // printf(", last reporter"); if (ADE->MCastTimer != 0) NlsPutMsg(STDOUT, IPV6_MESSAGE_41, ADE->MCastTimer); // printf(", %u seconds until report", ADE->MCastTimer); NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); break; default: NlsPutMsg(STDOUT, IPV6_MESSAGE_42, FormatScopeAdj(ADE->Scope), ADE->Type); // printf(" unknown %s address type %u\n", // FormatScopeAdj(ADE->Scope), ADE->Type); break; } } u_int AddressScope(IPv6Addr *Address) { if (IN6_IS_ADDR_LINKLOCAL(Address)) return ADE_LINK_LOCAL; else if (IN6_IS_ADDR_SITELOCAL(Address)) return ADE_SITE_LOCAL; else if (IN6_IS_ADDR_LOOPBACK(Address)) return ADE_LINK_LOCAL; else return ADE_GLOBAL; } void PrintPersistentAddress(IPV6_INFO_INTERFACE *IF, IPV6_UPDATE_ADDRESS *ADE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_23, ((ADE->Type == ADE_ANYCAST) ? "anycast" : FormatDADState((ADE->PreferredLifetime == 0) ? DAD_STATE_DEPRECATED : DAD_STATE_PREFERRED)), FormatScopeAdj(AddressScope(&ADE->This.Address)), FormatIPv6Address(&ADE->This.Address)); // printf(" %s %s %s, ", NlsPutMsg(STDOUT, IPV6_MESSAGE_24, FormatLifetimes(ADE->ValidLifetime, ADE->PreferredLifetime)); // printf("life %s", PrintAddrOrigin(ADE->PrefixConf, ADE->InterfaceIdConf); NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); } IPV6_INFO_INTERFACE * GetInterfaceInfo(IPV6_QUERY_INTERFACE *Query) { IPV6_INFO_INTERFACE *IF; u_int InfoSize, BytesReturned; InfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH; IF = malloc(InfoSize); if (IF == NULL) { NlsPutMsg(STDOUT, IPV6_MESSAGE_43); // printf("malloc failed\n"); exit(1); } if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_INTERFACE, Query, sizeof *Query, IF, InfoSize, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_44, Query->Index); // printf("bad index %u\n", Query->Index); exit(1); } if ((BytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (BytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) { NlsPutMsg(STDOUT, IPV6_MESSAGE_45); // printf("inconsistent interface info length\n"); exit(1); } return IF; } IPV6_INFO_INTERFACE * GetPersistentInterfaceInfo(IPV6_PERSISTENT_QUERY_INTERFACE *Query) { IPV6_INFO_INTERFACE *IF; u_int InfoSize, BytesReturned; InfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH; IF = malloc(InfoSize); if (IF == NULL) { NlsPutMsg(STDOUT, IPV6_MESSAGE_43); // printf("malloc failed\n"); exit(1); } if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_QUERY_INTERFACE, Query, sizeof *Query, IF, InfoSize, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_44, Query->RegistryIndex); // printf("bad index %u\n", Query->RegistryIndex); exit(1); } if ((BytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (BytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) { NlsPutMsg(STDOUT, IPV6_MESSAGE_45); // printf("inconsistent interface info length\n"); exit(1); } return IF; } void ForEachInterface(void (*func)(IPV6_INFO_INTERFACE *)) { IPV6_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; u_int InfoSize, BytesReturned; InfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH; IF = malloc(InfoSize); if (IF == NULL) { NlsPutMsg(STDOUT, IPV6_MESSAGE_43); // printf("malloc failed\n"); exit(1); } Query.Index = (u_int) -1; for (;;) { if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_INTERFACE, &Query, sizeof Query, IF, InfoSize, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_46, Query.Index); // printf("bad index %u\n", Query.Index); exit(1); } if (Query.Index != (u_int) -1) { if ((BytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (BytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) { NlsPutMsg(STDOUT, IPV6_MESSAGE_45); // printf("inconsistent interface info length\n"); exit(1); } (*func)(IF); } else { if (BytesReturned != sizeof IF->Next) { NlsPutMsg(STDOUT, IPV6_MESSAGE_45); // printf("inconsistent interface info length\n"); exit(1); } } if (IF->Next.Index == (u_int) -1) break; Query = IF->Next; } free(IF); } void ForEachPersistentInterface(void (*func)(IPV6_INFO_INTERFACE *)) { IPV6_PERSISTENT_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; u_int InfoSize, BytesReturned; InfoSize = sizeof *IF + 2 * MAX_LINK_LAYER_ADDRESS_LENGTH; IF = malloc(InfoSize); if (IF == NULL) { NlsPutMsg(STDOUT, IPV6_MESSAGE_43); // printf("malloc failed\n"); exit(1); } for (Query.RegistryIndex = 0;; Query.RegistryIndex++) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_QUERY_INTERFACE, &Query, sizeof Query, IF, InfoSize, &BytesReturned, NULL)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) break; NlsPutMsg(STDOUT, IPV6_MESSAGE_46, Query.RegistryIndex); // printf("bad index %u\n", Query.RegistryIndex); exit(1); } if ((BytesReturned < sizeof *IF) || (IF->Length < sizeof *IF) || (BytesReturned != IF->Length + ((IF->LocalLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0) + ((IF->RemoteLinkLayerAddress != 0) ? IF->LinkLayerAddressLength : 0))) { NlsPutMsg(STDOUT, IPV6_MESSAGE_45); // printf("inconsistent interface info length\n"); exit(1); } (*func)(IF); } free(IF); } #ifndef IP_TYPES_INCLUDED // // The real version of this structure in iptypes.h // has more fields, but these are all we need here. // #define MAX_ADAPTER_DESCRIPTION_LENGTH 128 // arb. #define MAX_ADAPTER_NAME_LENGTH 256 // arb. #define MAX_ADAPTER_ADDRESS_LENGTH 8 // arb. typedef struct _IP_ADAPTER_INFO { struct _IP_ADAPTER_INFO* Next; DWORD ComboIndex; char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4]; char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4]; UINT AddressLength; BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH]; DWORD Index; } IP_ADAPTER_INFO; #endif // IP_TYPES_INCLUDED DWORD (WINAPI *pGetAdaptersInfo)(IP_ADAPTER_INFO *pAdapterInfo, ULONG *pOutBufLen); IP_ADAPTER_INFO *pAdapterInfo; HRESULT (WINAPI *pHrLanConnectionNameFromGuidOrPath)( const GUID *pGuid, LPCWSTR pszwPath, LPWSTR pszwName, LPDWORD pcchMax); #define IPHLPAPI_LIBRARY_NAME "iphlpapi.dll" #define NETMAN_LIBRARY_NAME "netman.dll" void InitializeAdaptersInfo(void) { HMODULE hModule; CHAR SystemDir[MAX_PATH + 1]; CHAR Path[MAX_PATH + sizeof(IPHLPAPI_LIBRARY_NAME) + 2]; pAdapterInfo = NULL; if (GetSystemDirectory(SystemDir, MAX_PATH) == 0) { return; } // // Check if the GetAdaptersInfo API is available on this system. // lstrcpy(Path, SystemDir); lstrcat(Path, "\\" IPHLPAPI_LIBRARY_NAME); hModule = LoadLibrary(Path); if (hModule != NULL) { pGetAdaptersInfo = (DWORD (WINAPI *)(IP_ADAPTER_INFO *, ULONG *)) GetProcAddress(hModule, "GetAdaptersInfo"); // // We don't release hModule, to keep the module loaded. // if (pGetAdaptersInfo != NULL) { ULONG BufLen = 0; DWORD error; // // If this returns something other than buffer-overflow, // it probably means that GetAdaptersInfo is not supported. // error = (*pGetAdaptersInfo)(NULL, &BufLen); if (error == ERROR_BUFFER_OVERFLOW) { pAdapterInfo = (IP_ADAPTER_INFO *) malloc(BufLen); if (pAdapterInfo != NULL) { error = (*pGetAdaptersInfo)(pAdapterInfo, &BufLen); if (error != 0) { free(pAdapterInfo); pAdapterInfo = NULL; } } } } } // // Only bother with HrLanConnectionNameFromGuidOrPath // if we could get pAdapterInfo. // if (pAdapterInfo != NULL) { lstrcpy(Path, SystemDir); lstrcat(Path, "\\" NETMAN_LIBRARY_NAME); hModule = LoadLibrary(Path); if (hModule != NULL) { pHrLanConnectionNameFromGuidOrPath = (HRESULT (WINAPI *)(const GUID *, LPCWSTR, LPWSTR, LPDWORD)) GetProcAddress(hModule, "HrLanConnectionNameFromGuidOrPath"); // // We don't release hModule, to keep the module loaded. // } if (pHrLanConnectionNameFromGuidOrPath == NULL) { free(pAdapterInfo); pAdapterInfo = NULL; } } } #define MAX_FRIENDLY_NAME_LENGTH 2000 LPSTR MapAdapterNameToFriendly(LPSTR AdapterName) { WCHAR wszAdapterName[MAX_ADAPTER_NAME_LENGTH]; WCHAR wszFriendlyName[MAX_FRIENDLY_NAME_LENGTH]; DWORD cchFriendlyName = MAX_FRIENDLY_NAME_LENGTH; static CHAR FriendlyName[MAX_FRIENDLY_NAME_LENGTH]; MultiByteToWideChar(CP_ACP, 0, AdapterName, -1, wszAdapterName, MAX_ADAPTER_NAME_LENGTH); if((*pHrLanConnectionNameFromGuidOrPath)( NULL, wszAdapterName, wszFriendlyName, &cchFriendlyName)) return NULL; WideCharToMultiByte(CP_ACP, 0, wszFriendlyName, -1, FriendlyName, MAX_FRIENDLY_NAME_LENGTH, NULL, NULL); return FriendlyName; } LPSTR MapAdapterAddressToFriendly(u_char *Address, u_int AddressLength) { IP_ADAPTER_INFO *pAdapter; for (pAdapter = pAdapterInfo; pAdapter != NULL; pAdapter = pAdapter->Next) { if ((AddressLength == pAdapter->AddressLength) && ! memcmp(Address, pAdapter->Address, AddressLength)) return MapAdapterNameToFriendly(pAdapter->AdapterName); } return NULL; } int ShouldPrintZones(IPV6_INFO_INTERFACE *IF) { u_int Scope; for (Scope = ADE_SMALLEST_SCOPE; Scope <= ADE_LINK_LOCAL; Scope++) if (IF->ZoneIndices[Scope] != IF->This.Index) return TRUE; for (; Scope <= ADE_LARGEST_SCOPE; Scope++) if (IF->ZoneIndices[Scope] != 1) return TRUE; return FALSE; } void PrintInterface(IPV6_INFO_INTERFACE *IF) { LPSTR FriendlyName; u_int Scope; if (IF->LocalLinkLayerAddress == 0) FriendlyName = NULL; else FriendlyName = MapAdapterAddressToFriendly( (u_char *)IF + IF->LocalLinkLayerAddress, IF->LinkLayerAddressLength); NlsPutMsg(STDOUT, IPV6_MESSAGE_47, IF->This.Index); // printf("Interface %u:", IF->This.Index); switch (IF->Type) { case IPV6_IF_TYPE_LOOPBACK: NlsPutMsg(STDOUT, IPV6_MESSAGE_48); // printf(" Loopback Pseudo-Interface"); break; case IPV6_IF_TYPE_ETHERNET: NlsPutMsg(STDOUT, IPV6_MESSAGE_49); // printf(" Ethernet"); break; case IPV6_IF_TYPE_FDDI: NlsPutMsg(STDOUT, IPV6_MESSAGE_50); // printf(" FDDI"); break; case IPV6_IF_TYPE_TUNNEL_AUTO: NlsPutMsg(STDOUT, IPV6_MESSAGE_51); // printf(" Automatic Tunneling Pseudo-Interface"); break; case IPV6_IF_TYPE_TUNNEL_6OVER4: NlsPutMsg(STDOUT, IPV6_MESSAGE_52); // printf(" 6-over-4 Virtual Interface"); break; case IPV6_IF_TYPE_TUNNEL_V6V4: NlsPutMsg(STDOUT, IPV6_MESSAGE_53); // printf(" Configured Tunnel Interface"); break; case IPV6_IF_TYPE_TUNNEL_6TO4: NlsPutMsg(STDOUT, IPV6_6TO4_INTERFACE); // printf(" 6to4 Tunneling Pseudo-Interface"); break; case IPV6_IF_TYPE_TUNNEL_TEREDO: NlsPutMsg(STDOUT, IPV6_TEREDO_INTERFACE); // printf(" Teredo Tunneling Pseudo-Interface"); break; } if (FriendlyName != NULL) NlsPutMsg(STDOUT, IPV6_MESSAGE_54, FriendlyName); // printf(": %s", FriendlyName); NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); NlsPutMsg(STDOUT, IPV6_MESSAGE_GUID, FormatGuid(&IF->This.Guid)); // printf(" Guid %s\n", FormatGuid(&IF->This.Guid)); if (Verbose || ShouldPrintZones(IF)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_55); // printf(" zones:"); for (Scope = ADE_LINK_LOCAL; Scope < ADE_GLOBAL; Scope++) { u_int Expected; if ((Scope == ADE_LINK_LOCAL) || (Scope == ADE_SITE_LOCAL)) Expected = 0; // Always print link & site. else Expected = IF->ZoneIndices[Scope + 1]; if (IF->ZoneIndices[Scope] != Expected) NlsPutMsg(STDOUT, IPV6_MESSAGE_56, FormatScopeNoun(Scope), IF->ZoneIndices[Scope]); // printf(" %s %u", // FormatScopeNoun(Scope), // IF->ZoneIndices[Scope]); } NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); } switch (IF->MediaStatus) { case IPV6_IF_MEDIA_STATUS_DISCONNECTED: NlsPutMsg(STDOUT, IPV6_MESSAGE_57); // printf(" cable unplugged\n"); break; case IPV6_IF_MEDIA_STATUS_RECONNECTED: NlsPutMsg(STDOUT, IPV6_MESSAGE_58); // printf(" cable reconnected\n"); break; case IPV6_IF_MEDIA_STATUS_CONNECTED: break; } if (IF->NeighborDiscovers) NlsPutMsg(STDOUT, IPV6_MESSAGE_USES_ND); // printf(" uses Neighbor Discovery\n"); else NlsPutMsg(STDOUT, IPV6_MESSAGE_DOESNT_USE_ND); // printf(" does not use Neighbor Discovery\n"); if (IF->RouterDiscovers) NlsPutMsg(STDOUT, IPV6_MESSAGE_USES_RD); else NlsPutMsg(STDOUT, IPV6_MESSAGE_DOESNT_USE_RD); if (IF->Advertises) NlsPutMsg(STDOUT, IPV6_MESSAGE_SENDS_RAs); // printf(" sends Router Advertisements\n"); if (IF->Forwards) NlsPutMsg(STDOUT, IPV6_MESSAGE_FORWARDS); // printf(" forwards packets\n"); if (IF->PeriodicMLD) NlsPutMsg(STDOUT, IPV6_MESSAGE_SENDS_PERIODIC_MLD); // printf(" periodically sends MLD Reports\n"); if (IF->Preference != 0) NlsPutMsg(STDOUT, IPV6_MESSAGE_64, IF->Preference); // printf(" routing preference %u\n", IF->Preference); if (IF->Type == IPV6_IF_TYPE_TUNNEL_AUTO) { if (IF->LocalLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_TOKEN_ADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->LocalLinkLayerAddress)); // printf(" EUI-64 embedded IPv4 address: %s\n", } if (IF->RemoteLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_ROUTER_LL_ADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->RemoteLinkLayerAddress)); // printf(" router link-layer address: %s\n", } } else { if (IF->LocalLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_65, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->LocalLinkLayerAddress)); // printf(" link-layer address: %s\n", } if (IF->RemoteLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_66, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->RemoteLinkLayerAddress)); // printf(" remote link-layer address: %s\n", } } ForEachAddress(IF, PrintAddress); NlsPutMsg(STDOUT, IPV6_MESSAGE_67, IF->LinkMTU, IF->TrueLinkMTU); // printf(" link MTU %u (true link MTU %u)\n", // IF->LinkMTU, IF->TrueLinkMTU); NlsPutMsg(STDOUT, IPV6_MESSAGE_68, IF->CurHopLimit); // printf(" current hop limit %u\n", IF->CurHopLimit); NlsPutMsg(STDOUT, IPV6_MESSAGE_69, IF->ReachableTime, IF->BaseReachableTime); // printf(" reachable time %ums (base %ums)\n", // IF->ReachableTime, IF->BaseReachableTime); NlsPutMsg(STDOUT, IPV6_MESSAGE_70, IF->RetransTimer); // printf(" retransmission interval %ums\n", IF->RetransTimer); NlsPutMsg(STDOUT, IPV6_MESSAGE_71, IF->DupAddrDetectTransmits); // printf(" DAD transmits %u\n", IF->DupAddrDetectTransmits); NlsPutMsg(STDOUT, IPV6_MESSAGE_DEFAULT_SITE_PREFIX_LENGTH, IF->DefSitePrefixLength); // printf(" default site prefix length %u\n", } void PrintPersistentInterface(IPV6_INFO_INTERFACE *IF) { u_int Scope; NlsPutMsg(STDOUT, IPV6_MESSAGE_INTERFACE); // printf("Interface:" switch (IF->Type) { case IPV6_IF_TYPE_LOOPBACK: NlsPutMsg(STDOUT, IPV6_MESSAGE_48); // printf(" Loopback Pseudo-Interface"); break; case IPV6_IF_TYPE_ETHERNET: NlsPutMsg(STDOUT, IPV6_MESSAGE_49); // printf(" Ethernet"); break; case IPV6_IF_TYPE_FDDI: NlsPutMsg(STDOUT, IPV6_MESSAGE_50); // printf(" FDDI"); break; case IPV6_IF_TYPE_TUNNEL_AUTO: NlsPutMsg(STDOUT, IPV6_MESSAGE_51); // printf(" Automatic Tunneling Pseudo-Interface"); break; case IPV6_IF_TYPE_TUNNEL_6OVER4: NlsPutMsg(STDOUT, IPV6_MESSAGE_52); // printf(" 6-over-4 Virtual Interface"); break; case IPV6_IF_TYPE_TUNNEL_V6V4: NlsPutMsg(STDOUT, IPV6_MESSAGE_53); // printf(" Configured Tunnel Interface"); break; case IPV6_IF_TYPE_TUNNEL_6TO4: NlsPutMsg(STDOUT, IPV6_6TO4_INTERFACE); // printf(" 6to4 Tunneling Pseudo-Interface"); break; } NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); NlsPutMsg(STDOUT, IPV6_MESSAGE_GUID, FormatGuid(&IF->This.Guid)); // printf(" Guid %s\n", FormatGuid(&IF->This.Guid)); if (IF->NeighborDiscovers == TRUE) NlsPutMsg(STDOUT, IPV6_MESSAGE_USES_ND); // printf(" uses Neighbor Discovery\n"); else if (IF->NeighborDiscovers == FALSE) NlsPutMsg(STDOUT, IPV6_MESSAGE_DOESNT_USE_ND); // printf(" does not use Neighbor Discovery\n"); if (IF->RouterDiscovers == TRUE) NlsPutMsg(STDOUT, IPV6_MESSAGE_USES_RD); else if (IF->RouterDiscovers == FALSE) NlsPutMsg(STDOUT, IPV6_MESSAGE_DOESNT_USE_RD); if (IF->Advertises == TRUE) NlsPutMsg(STDOUT, IPV6_MESSAGE_SENDS_RAs); // printf(" sends Router Advertisements\n"); else if (IF->Advertises == FALSE) NlsPutMsg(STDOUT, IPV6_MESSAGE_DOESNT_SEND_RAs); // printf(" does not send Router Advertisements\n"); if (IF->Forwards == TRUE) NlsPutMsg(STDOUT, IPV6_MESSAGE_FORWARDS); // printf(" forwards packets\n"); else if (IF->Forwards == FALSE) NlsPutMsg(STDOUT, IPV6_MESSAGE_DOESNT_FORWARD); // printf(" does not forward packets\n"); if (IF->PeriodicMLD == TRUE) NlsPutMsg(STDOUT, IPV6_MESSAGE_SENDS_PERIODIC_MLD); // printf(" periodically sends MLD Reports\n"); else if (IF->PeriodicMLD == FALSE) NlsPutMsg(STDOUT, IPV6_MESSAGE_DOESNT_SEND_PERIODIC_MLD); // printf(" does not periodically send MLD Reports\n"); if (IF->Preference != (u_int)-1) NlsPutMsg(STDOUT, IPV6_MESSAGE_64, IF->Preference); // printf(" routing preference %u\n", IF->Preference); if (IF->Type == IPV6_IF_TYPE_TUNNEL_AUTO) { if (IF->LocalLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_TOKEN_ADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->LocalLinkLayerAddress)); // printf(" EUI-64 embedded IPv4 address: %s\n", } if (IF->RemoteLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_ROUTER_LL_ADDRESS, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->RemoteLinkLayerAddress)); // printf(" router link-layer address: %s\n", } } else { if (IF->LocalLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_65, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->LocalLinkLayerAddress)); // printf(" link-layer address: %s\n", } if (IF->RemoteLinkLayerAddress != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_66, FormatLinkLayerAddress(IF->LinkLayerAddressLength, (u_char *)IF + IF->RemoteLinkLayerAddress)); // printf(" remote link-layer address: %s\n", } } ForEachPersistentAddress(IF, PrintPersistentAddress); if (IF->LinkMTU != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_LINK_MTU, IF->LinkMTU); // printf(" link MTU %u\n", } if (IF->CurHopLimit != (u_int)-1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_68, IF->CurHopLimit); // printf(" current hop limit %u\n", IF->CurHopLimit); } if (IF->BaseReachableTime != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_BASE_REACHABLE_TIME, IF->BaseReachableTime); // printf(" base reachable time %ums\n", } if (IF->RetransTimer != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_70, IF->RetransTimer); // printf(" retransmission interval %ums\n", IF->RetransTimer); } if (IF->DupAddrDetectTransmits != (u_int)-1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_71, IF->DupAddrDetectTransmits); // printf(" DAD transmits %u\n", IF->DupAddrDetectTransmits); } if (IF->DefSitePrefixLength != (u_int)-1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_DEFAULT_SITE_PREFIX_LENGTH, IF->DefSitePrefixLength); // printf(" default site prefix length %u\n", } } IPV6_INFO_NEIGHBOR_CACHE * GetNeighborCacheEntry(IPV6_QUERY_NEIGHBOR_CACHE *Query) { IPV6_INFO_NEIGHBOR_CACHE *NCE; u_int InfoSize, BytesReturned; InfoSize = sizeof *NCE + MAX_LINK_LAYER_ADDRESS_LENGTH; NCE = (IPV6_INFO_NEIGHBOR_CACHE *) malloc(InfoSize); if (NCE == NULL) { NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("malloc failed\n"); exit(1); } if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_NEIGHBOR_CACHE, Query, sizeof *Query, NCE, InfoSize, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_72, FormatIPv6Address(&Query->Address)); // printf("bad address %s\n", FormatIPv6Address(&Query->Address)); exit(1); } if ((BytesReturned < sizeof *NCE) || (BytesReturned != sizeof *NCE + NCE->LinkLayerAddressLength)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_73); // printf("inconsistent neighbor cache info length\n"); exit(1); } NCE->Query = *Query; return NCE; } void ForEachNeighborCacheEntry(IPV6_QUERY_INTERFACE *IF, void (*func)(IPV6_INFO_NEIGHBOR_CACHE *)) { IPV6_QUERY_NEIGHBOR_CACHE Query, NextQuery; IPV6_INFO_NEIGHBOR_CACHE *NCE; u_int InfoSize, BytesReturned; InfoSize = sizeof *NCE + MAX_LINK_LAYER_ADDRESS_LENGTH; NCE = (IPV6_INFO_NEIGHBOR_CACHE *) malloc(InfoSize); if (NCE == NULL) { NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("malloc failed\n"); exit(1); } NextQuery.IF = *IF; NextQuery.Address = in6addr_any; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_NEIGHBOR_CACHE, &Query, sizeof Query, NCE, InfoSize, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_72, FormatIPv6Address(&Query.Address)); // printf("bad address %s\n", FormatIPv6Address(&Query.Address)); exit(1); } NextQuery = NCE->Query; if (!IN6_ADDR_EQUAL(&Query.Address, &in6addr_any)) { if ((BytesReturned < sizeof *NCE) || (BytesReturned != sizeof *NCE + NCE->LinkLayerAddressLength)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_73); // printf("inconsistent neighbor cache info length\n"); exit(1); } NCE->Query = Query; (*func)(NCE); } if (IN6_ADDR_EQUAL(&NextQuery.Address, &in6addr_any)) break; } free(NCE); } void PrintNeighborCacheEntry(IPV6_INFO_NEIGHBOR_CACHE *NCE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_74, NCE->Query.IF.Index, FormatIPv6Address(&NCE->Query.Address)); // printf("%u: %18s", NCE->Query.IF.Index, // FormatIPv6Address(&NCE->Query.Address)); if (NCE->NDState != 0) NlsPutMsg(STDOUT, IPV6_MESSAGE_75, FormatLinkLayerAddress( NCE->LinkLayerAddressLength, (u_char *)(NCE + 1))); // printf(" %-17s", FormatLinkLayerAddress(NCE->LinkLayerAddressLength, // (u_char *)(NCE + 1))); else NlsPutMsg(STDOUT, IPV6_MESSAGE_75, ""); // printf(" %-17s", ""); switch (NCE->NDState) { case ND_STATE_INCOMPLETE: NlsPutMsg(STDOUT, IPV6_MESSAGE_76); // printf(" incomplete"); break; case ND_STATE_PROBE: NlsPutMsg(STDOUT, IPV6_MESSAGE_77); // printf(" probe"); break; case ND_STATE_DELAY: NlsPutMsg(STDOUT, IPV6_MESSAGE_78); // printf(" delay"); break; case ND_STATE_STALE: NlsPutMsg(STDOUT, IPV6_MESSAGE_79); // printf(" stale"); break; case ND_STATE_REACHABLE: NlsPutMsg(STDOUT, IPV6_MESSAGE_80, NCE->ReachableTimer); // printf(" reachable (%ums)", NCE->ReachableTimer); break; case ND_STATE_PERMANENT: NlsPutMsg(STDOUT, IPV6_MESSAGE_81); // printf(" permanent"); break; default: NlsPutMsg(STDOUT, IPV6_MESSAGE_82, NCE->NDState); // printf(" unknown ND state %u", NCE->NDState); break; } if (NCE->IsRouter) NlsPutMsg(STDOUT, IPV6_MESSAGE_83); // printf(" (router)"); if (NCE->IsUnreachable) NlsPutMsg(STDOUT, IPV6_MESSAGE_84); // printf(" (unreachable)"); NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); } void QueryInterface(int argc, char *argv[]) { InitializeAdaptersInfo(); if (argc == 0) { if (Persistent) ForEachPersistentInterface(PrintPersistentInterface); else ForEachInterface(PrintInterface); } else if (argc == 1) { IPV6_INFO_INTERFACE *IF; if (Persistent) { IPV6_PERSISTENT_QUERY_INTERFACE Query; Query.RegistryIndex = (u_int)-1; if (! GetGuid(argv[0], &Query.Guid)) usage(); IF = GetPersistentInterfaceInfo(&Query); PrintPersistentInterface(IF); free(IF); } else { IPV6_QUERY_INTERFACE Query; if (! GetInterface(argv[0], &Query)) usage(); IF = GetInterfaceInfo(&Query); PrintInterface(IF); free(IF); } } else { usage(); } } void RenewViaReconnect(IPV6_INFO_INTERFACE *IF) { u_int BytesReturned; if (!DeviceIoControl(Handle, IOCTL_IPV6_RENEW_INTERFACE, &IF->This, sizeof IF->This, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_RENEW_INTERFACE, GetLastError()); // printf("renew interface error: %x\n", GetLastError()); exit(1); } } VOID Poke6to4Service() { SC_HANDLE Service, SCManager; SERVICE_STATUS Status; SCManager = OpenSCManager(NULL, NULL, GENERIC_READ); if (SCManager == NULL) { return; } Service = OpenService(SCManager, "6to4", SERVICE_ALL_ACCESS); if (Service != NULL) { // // Tell the 6to4 service to re-read its configuration information. // (VOID) ControlService(Service, SERVICE_CONTROL_PARAMCHANGE, &Status); CloseServiceHandle(Service); } CloseServiceHandle(SCManager); } void RenewInterface(int argc, char *argv[]) { BOOL PokeService = FALSE; if (argc == 0) { ForEachInterface(RenewViaReconnect); PokeService = TRUE; } else if (argc == 1) { IPV6_QUERY_INTERFACE Query; IPV6_INFO_INTERFACE *IF; if (! GetInterface(argv[0], &Query)) usage(); IF = GetInterfaceInfo(&Query); RenewViaReconnect(IF); // // 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 { usage(); } if (PokeService) { Poke6to4Service(); } } int GetV4Address(char *astr, struct in_addr *address) { struct addrinfo hints; struct addrinfo *result; memset(&hints, 0, sizeof hints); hints.ai_family = PF_INET; if (getaddrinfo(astr, NULL, &hints, &result)) return FALSE; *address = ((struct sockaddr_in *)result->ai_addr)->sin_addr; freeaddrinfo(result); return TRUE; } void CreateInterface(int argc, char *argv[]) { struct { IPV6_INFO_INTERFACE Info; struct in_addr SrcAddr; struct in_addr DstAddr; } Create; IPV6_QUERY_INTERFACE Result; u_int BytesReturned; u_int FlagsOn, FlagsOff; int i; IPV6_INIT_INFO_INTERFACE(&Create.Info); if (argc < 1) usage(); if (!strcmp(argv[0], "v6v4")) { i = 3; if (argc < i) usage(); if (! GetV4Address(argv[1], &Create.SrcAddr)) usage(); if (! GetV4Address(argv[2], &Create.DstAddr)) usage(); Create.Info.Type = IPV6_IF_TYPE_TUNNEL_V6V4; Create.Info.LinkLayerAddressLength = sizeof(struct in_addr); Create.Info.LocalLinkLayerAddress = (u_int) ((char *)&Create.SrcAddr - (char *)&Create.Info); Create.Info.RemoteLinkLayerAddress = (u_int) ((char *)&Create.DstAddr - (char *)&Create.Info); } else if (!strcmp(argv[0], "6over4")) { i = 2; if (argc < i) usage(); if (! GetV4Address(argv[1], &Create.SrcAddr)) usage(); Create.Info.Type = IPV6_IF_TYPE_TUNNEL_6OVER4; Create.Info.LinkLayerAddressLength = sizeof(struct in_addr); Create.Info.LocalLinkLayerAddress = (u_int) ((char *)&Create.SrcAddr - (char *)&Create.Info); } else usage(); for (; i < argc; i++) { if (!strcmp(argv[i], "nd")) { Create.Info.NeighborDiscovers = TRUE; Create.Info.RouterDiscovers = TRUE; } else if (!strcmp(argv[i], "pmld")) { Create.Info.PeriodicMLD = TRUE; } else if (!strcmp(argv[i], "nond")) { Create.Info.NeighborDiscovers = FALSE; Create.Info.RouterDiscovers = FALSE; } else usage(); } if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_CREATE_INTERFACE : IOCTL_IPV6_CREATE_INTERFACE), &Create, sizeof Create, &Result, sizeof Result, &BytesReturned, NULL) || (BytesReturned != sizeof Result)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_85, GetLastError()); // printf("control interface error: %x\n", GetLastError()); exit(1); } NlsPutMsg(STDOUT, IPV6_MESSAGE_86, Result.Index); // printf("Created interface %u.\n", Result.Index); } void UpdateInterface(int argc, char *argv[]) { IPV6_INFO_INTERFACE Update; u_int BytesReturned; int i; IPV6_INIT_INFO_INTERFACE(&Update); if (argc < 1) usage(); if (! GetInterface(argv[0], &Update.This)) usage(); for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "advertises", strlen(argv[i]))) Update.Advertises = TRUE; else if (!strncmp(argv[i], "-advertises", strlen(argv[i]))) Update.Advertises = FALSE; else if (!strncmp(argv[i], "forwards", strlen(argv[i]))) Update.Forwards = TRUE; else if (!strncmp(argv[i], "-forwards", strlen(argv[i]))) Update.Forwards = FALSE; else if (!strcmp(argv[i], "mtu") && (i+1 < argc)) { if (! GetNumber(argv[i+1], &Update.LinkMTU)) usage(); i++; } else if (!strncmp(argv[i], "preference", strlen(argv[i])) && (i+1 < argc)) { if (! GetNumber(argv[++i], &Update.Preference)) usage(); } else if (!strncmp(argv[i], "basereachabletime", strlen(argv[i])) && (i+1 < argc)) { if (! GetNumber(argv[++i], &Update.BaseReachableTime)) usage(); } else if (!strncmp(argv[i], "retranstimer", strlen(argv[i])) && (i+1 < argc)) { if (! GetNumber(argv[++i], &Update.RetransTimer)) usage(); } else if (!strncmp(argv[i], "dupaddrdetecttransmits", strlen(argv[i])) && (i+1 < argc)) { if (! GetNumber(argv[++i], &Update.DupAddrDetectTransmits)) usage(); } else if (!strncmp(argv[i], "curhoplimit", strlen(argv[i])) && (i+1 < argc)) { if (! GetNumber(argv[++i], &Update.CurHopLimit)) usage(); } else if ((!strncmp(argv[i], "defsiteprefixlength", strlen(argv[i])) || !strcmp(argv[i], "spl")) && (i+1 < argc)) { if (! GetNumber(argv[++i], &Update.DefSitePrefixLength)) usage(); } else if (!strcmp(argv[i], "link") && (i+1 < argc)) { if (! GetNumber(argv[i+1], &Update.ZoneIndices[ADE_LINK_LOCAL])) usage(); i++; } else if (!strcmp(argv[i], "subnet") && (i+1 < argc)) { if (! GetNumber(argv[i+1], &Update.ZoneIndices[ADE_SUBNET_LOCAL])) usage(); i++; } else if (!strcmp(argv[i], "admin") && (i+1 < argc)) { if (! GetNumber(argv[i+1], &Update.ZoneIndices[ADE_ADMIN_LOCAL])) usage(); i++; } else if (!strcmp(argv[i], "site") && (i+1 < argc)) { if (! GetNumber(argv[i+1], &Update.ZoneIndices[ADE_SITE_LOCAL])) usage(); i++; } else if (!strcmp(argv[i], "org") && (i+1 < argc)) { if (! GetNumber(argv[i+1], &Update.ZoneIndices[ADE_ORG_LOCAL])) usage(); i++; } else usage(); } if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_UPDATE_INTERFACE : IOCTL_IPV6_UPDATE_INTERFACE), &Update, sizeof Update, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_85, GetLastError()); // printf("control interface error: %x\n", GetLastError()); exit(1); } } void UpdateRouterLinkAddress(int argc, char *argv[]) { char Buffer[sizeof(IPV6_UPDATE_ROUTER_LL_ADDRESS) + 2 * sizeof(IN_ADDR)]; IPV6_UPDATE_ROUTER_LL_ADDRESS *Update = (IPV6_UPDATE_ROUTER_LL_ADDRESS *)Buffer; IN_ADDR *Addr = (IN_ADDR *)(Update + 1); u_int BytesReturned; SOCKET s; SOCKADDR_IN sinRemote, sinLocal; if (argc != 2) usage(); if (! GetInterface(argv[0], &Update->IF)) usage(); if (! GetV4Address(argv[1], &Addr[1])) usage(); s = socket(AF_INET, SOCK_DGRAM, 0); if (s == INVALID_SOCKET) { NlsPutMsg(STDOUT, IPV6_MESSAGE_85, WSAGetLastError()); exit(1); } sinRemote.sin_family = AF_INET; sinRemote.sin_addr = Addr[1]; if (WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY, &sinRemote, sizeof sinRemote, &sinLocal, sizeof sinLocal, &BytesReturned, NULL, NULL) == SOCKET_ERROR) { NlsPutMsg(STDOUT, IPV6_MESSAGE_85, WSAGetLastError()); exit(1); } closesocket(s); Addr[0] = sinLocal.sin_addr; if (Addr[0].s_addr == htonl(INADDR_LOOPBACK)) { // // We're the router. // Addr[0] = Addr[1]; } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_ROUTER_LL_ADDRESS, Buffer, sizeof Buffer, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_85, GetLastError()); // printf("control interface error: %x\n", GetLastError()); exit(1); } } void DeleteInterface(int argc, char *argv[]) { IPV6_QUERY_INTERFACE Query; u_int BytesReturned; if (argc != 1) usage(); if (! GetInterface(argv[0], &Query)) usage(); if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_DELETE_INTERFACE : IOCTL_IPV6_DELETE_INTERFACE), &Query, sizeof Query, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_87, GetLastError()); // printf("delete interface error: %x\n", GetLastError()); exit(1); } } void PrintNeighborCache(IPV6_INFO_INTERFACE *IF) { ForEachNeighborCacheEntry(&IF->This, PrintNeighborCacheEntry); } void QueryNeighborCache(int argc, char *argv[]) { if (argc == 0) { ForEachInterface(PrintNeighborCache); } else if (argc == 1) { IPV6_QUERY_INTERFACE Query; if (! GetInterface(argv[0], &Query)) usage(); ForEachNeighborCacheEntry(&Query, PrintNeighborCacheEntry); } else if (argc == 2) { IPV6_QUERY_NEIGHBOR_CACHE Query; IPV6_INFO_NEIGHBOR_CACHE *NCE; if (! GetInterface(argv[0], &Query.IF)) usage(); if (! GetAddress(argv[1], &Query.Address)) usage(); NCE = GetNeighborCacheEntry(&Query); PrintNeighborCacheEntry(NCE); free(NCE); } else { usage(); } } IPV6_INFO_ROUTE_CACHE * GetRouteCacheEntry(IPV6_QUERY_ROUTE_CACHE *Query) { IPV6_INFO_ROUTE_CACHE *RCE; u_int BytesReturned; RCE = (IPV6_INFO_ROUTE_CACHE *) malloc(sizeof *RCE); if (RCE == NULL) { NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("malloc failed\n"); exit(1); } if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_ROUTE_CACHE, Query, sizeof *Query, RCE, sizeof *RCE, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_88); // printf("bad index or address\n"); exit(1); } RCE->Query = *Query; return RCE; } void ForEachDestination(void (*func)(IPV6_INFO_ROUTE_CACHE *)) { IPV6_QUERY_ROUTE_CACHE Query, NextQuery; IPV6_INFO_ROUTE_CACHE RCE; u_int BytesReturned; NextQuery.IF.Index = 0; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_ROUTE_CACHE, &Query, sizeof Query, &RCE, sizeof RCE, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_89, Query.IF.Index); // printf("bad index %u\n", Query.IF.Index); exit(1); } NextQuery = RCE.Query; if (Query.IF.Index != 0) { RCE.Query = Query; (*func)(&RCE); } if (NextQuery.IF.Index == 0) break; } } void PrintRouteCacheEntry(IPV6_INFO_ROUTE_CACHE *RCE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_90, FormatIPv6Address(&RCE->Query.Address)); // printf("%s via ", FormatIPv6Address(&RCE->Query.Address)); NlsPutMsg(STDOUT, IPV6_MESSAGE_91, RCE->NextHopInterface, FormatIPv6Address(&RCE->NextHopAddress)); // printf("%u/%s", RCE->NextHopInterface, // FormatIPv6Address(&RCE->NextHopAddress)); if (! RCE->Valid) NlsPutMsg(STDOUT, IPV6_MESSAGE_92); // printf(" (stale)"); switch (RCE->Type) { case RCE_TYPE_COMPUTED: break; case RCE_TYPE_REDIRECT: NlsPutMsg(STDOUT, IPV6_MESSAGE_93); // printf(" (redirect)"); break; default: NlsPutMsg(STDOUT, IPV6_MESSAGE_94, RCE->Type); // printf(" (unknown type %u)", RCE->Type); break; } switch (RCE->Flags) { case RCE_FLAG_CONSTRAINED: NlsPutMsg(STDOUT, IPV6_MESSAGE_95); // printf(" (interface-specific)\n"); break; case RCE_FLAG_CONSTRAINED_SCOPEID: NlsPutMsg(STDOUT, IPV6_MESSAGE_96); // printf(" (zone-specific)\n"); break; case 0: NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); break; default: NlsPutMsg(STDOUT, IPV6_MESSAGE_97, RCE->Flags); // printf(" (flags 0x%x)\n", RCE->Flags); } NlsPutMsg(STDOUT, IPV6_MESSAGE_98, RCE->Query.IF.Index, FormatIPv6Address(&RCE->SourceAddress)); // printf(" src %u/%s\n", // RCE->Query.IF.Index, // FormatIPv6Address(&RCE->SourceAddress)); if (RCE->PathMTU == 0) NlsPutMsg(STDOUT, IPV6_MESSAGE_99, IPv6_MINIMUM_MTU); // printf(" PMTU %u-", IPv6_MINIMUM_MTU); else NlsPutMsg(STDOUT, IPV6_MESSAGE_100, RCE->PathMTU); // printf(" PMTU %u", RCE->PathMTU); if (RCE->PMTUProbeTimer != INFINITE_LIFETIME) NlsPutMsg(STDOUT, IPV6_MESSAGE_101, RCE->PMTUProbeTimer/1000); // printf(" (%u seconds until PMTU probe)\n", RCE->PMTUProbeTimer/1000); else NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); if ((RCE->ICMPLastError != 0) && (RCE->ICMPLastError < 10*60*1000)) NlsPutMsg(STDOUT, IPV6_MESSAGE_102, RCE->ICMPLastError/1000); // printf(" %d seconds since ICMP error\n", RCE->ICMPLastError/1000); if ((RCE->BindingSeqNumber != 0) || (RCE->BindingLifetime != 0) || ! IN6_ADDR_EQUAL(&RCE->CareOfAddress, &in6addr_any)) NlsPutMsg(STDOUT, IPV6_MESSAGE_103, FormatIPv6Address(&RCE->CareOfAddress), RCE->BindingSeqNumber, RCE->BindingLifetime); // printf(" careof %s seq %u life %us\n", // FormatIPv6Address(&RCE->CareOfAddress), // RCE->BindingSeqNumber, // RCE->BindingLifetime); } void QueryRouteCache(int argc, char *argv[]) { if (argc == 0) { ForEachDestination(PrintRouteCacheEntry); } else if (argc == 2) { IPV6_QUERY_ROUTE_CACHE Query; IPV6_INFO_ROUTE_CACHE *RCE; if (! GetInterface(argv[0], &Query.IF)) usage(); if (! GetAddress(argv[1], &Query.Address)) usage(); RCE = GetRouteCacheEntry(&Query); PrintRouteCacheEntry(RCE); free(RCE); } else { usage(); } } void ForEachRoute(void (*func)(IPV6_INFO_ROUTE_TABLE *)) { IPV6_QUERY_ROUTE_TABLE Query, NextQuery; IPV6_INFO_ROUTE_TABLE RTE; u_int BytesReturned; NextQuery.Neighbor.IF.Index = 0; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_ROUTE_TABLE, &Query, sizeof Query, &RTE, sizeof RTE, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_104, Query.Neighbor.IF.Index); // printf("bad index %u\n", Query.Neighbor.IF.Index); exit(1); } NextQuery = RTE.Next; if (Query.Neighbor.IF.Index != 0) { RTE.This = Query; (*func)(&RTE); } if (NextQuery.Neighbor.IF.Index == 0) break; } } void ForEachPersistentRoute(IPV6_INFO_INTERFACE *IF, void (*func)(IPV6_INFO_ROUTE_TABLE *)) { IPV6_PERSISTENT_QUERY_ROUTE_TABLE Query; IPV6_INFO_ROUTE_TABLE RTE; u_int BytesReturned; Query.IF.RegistryIndex = (u_int) -1; Query.IF.Guid = IF->This.Guid; for (Query.RegistryIndex = 0;; Query.RegistryIndex++) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_QUERY_ROUTE_TABLE, &Query, sizeof Query, &RTE, sizeof RTE, &BytesReturned, NULL) || (BytesReturned != sizeof RTE)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) break; NlsPutMsg(STDOUT, IPV6_MESSAGE_104, Query.RegistryIndex); // printf("bad index %u\n", Query.RegistryIndex); exit(1); } (*func)(&RTE); } } void PrintRouteTableEntry(IPV6_INFO_ROUTE_TABLE *RTE) { IPV6_INFO_INTERFACE *IF; if (!Verbose) { // // Suppress system routes (used for loopback). // if (RTE->Type == RTE_TYPE_SYSTEM) return; } NlsPutMsg(STDOUT, IPV6_MESSAGE_105, FormatIPv6Address(&RTE->This.Prefix), RTE->This.PrefixLength, RTE->This.Neighbor.IF.Index); // printf("%s/%u -> %u", if (! IN6_ADDR_EQUAL(&RTE->This.Neighbor.Address, &in6addr_any)) NlsPutMsg(STDOUT, IPV6_MESSAGE_106, FormatIPv6Address(&RTE->This.Neighbor.Address)); // printf("/%s", FormatIPv6Address(&RTE->This.Neighbor.Address)); IF = GetInterfaceInfo(&RTE->This.Neighbor.IF); if (IF != NULL) { if (IF->Preference != 0) { NlsPutMsg(STDOUT, IPV6_MESSAGE_107, IF->Preference, RTE->Preference, IF->Preference + RTE->Preference); // printf(" pref %uif+%u=%u ", // IF->Preference, RTE->Preference, // IF->Preference + RTE->Preference); } else { NlsPutMsg(STDOUT, IPV6_MESSAGE_108, RTE->Preference); // printf(" pref %u ", RTE->Preference); } free(IF); } else { NlsPutMsg(STDOUT, IPV6_MESSAGE_108, RTE->Preference); // printf(" pref %u ", RTE->Preference); } NlsPutMsg(STDOUT, IPV6_MESSAGE_109, FormatLifetimes(RTE->ValidLifetime, RTE->PreferredLifetime)); // printf("life %s", // FormatLifetimes(RTE->ValidLifetime, RTE->PreferredLifetime)); if (RTE->Publish) NlsPutMsg(STDOUT, IPV6_MESSAGE_110); // printf(", publish"); if (RTE->Immortal) NlsPutMsg(STDOUT, IPV6_MESSAGE_111); // printf(", no aging"); if (RTE->SitePrefixLength != 0) NlsPutMsg(STDOUT, IPV6_MESSAGE_112, RTE->SitePrefixLength); // printf(", spl %u", RTE->SitePrefixLength); NlsPutMsg(STDOUT, IPV6_MESSAGE_113); // printf(" ("); switch (RTE->Type) { case RTE_TYPE_SYSTEM: NlsPutMsg(STDOUT, IPV6_MESSAGE_114); // printf("system"); break; case RTE_TYPE_MANUAL: NlsPutMsg(STDOUT, IPV6_MESSAGE_115); // printf("manual"); break; case RTE_TYPE_AUTOCONF: NlsPutMsg(STDOUT, IPV6_MESSAGE_116); // printf("autoconf"); break; case RTE_TYPE_RIP: NlsPutMsg(STDOUT, IPV6_MESSAGE_117); // printf("RIP"); break; case RTE_TYPE_OSPF: NlsPutMsg(STDOUT, IPV6_MESSAGE_118); // printf("OSPF"); break; case RTE_TYPE_BGP: NlsPutMsg(STDOUT, IPV6_MESSAGE_119); // printf("BGP"); break; case RTE_TYPE_IDRP: NlsPutMsg(STDOUT, IPV6_MESSAGE_120); // printf("IDRP"); break; case RTE_TYPE_IGRP: NlsPutMsg(STDOUT, IPV6_MESSAGE_121); // printf("IGRP"); break; default: NlsPutMsg(STDOUT, IPV6_MESSAGE_122, RTE->Type); // printf("type %u", RTE->Type); break; } NlsPutMsg(STDOUT, IPV6_MESSAGE_123); // printf(")\n"); } void PrintPersistentRouteTableEntry(IPV6_INFO_ROUTE_TABLE *RTE) { IPV6_INFO_INTERFACE *IF; NlsPutMsg(STDOUT, IPV6_MESSAGE_PRINT_PERSISTENT_ROUTE, FormatIPv6Address(&RTE->This.Prefix), RTE->This.PrefixLength, FormatGuid(&RTE->This.Neighbor.IF.Guid)); // printf("%s/%u -> %s", if (! IN6_ADDR_EQUAL(&RTE->This.Neighbor.Address, &in6addr_any)) NlsPutMsg(STDOUT, IPV6_MESSAGE_106, FormatIPv6Address(&RTE->This.Neighbor.Address)); // printf("/%s", FormatIPv6Address(&RTE->This.Neighbor.Address)); NlsPutMsg(STDOUT, IPV6_MESSAGE_108, RTE->Preference); // printf(" pref %u ", RTE->Preference); NlsPutMsg(STDOUT, IPV6_MESSAGE_109, FormatLifetimes(RTE->ValidLifetime, RTE->PreferredLifetime)); // printf("life %s", // FormatLifetimes(RTE->ValidLifetime, RTE->PreferredLifetime)); if (RTE->Publish) NlsPutMsg(STDOUT, IPV6_MESSAGE_110); // printf(", publish"); if (RTE->Immortal) NlsPutMsg(STDOUT, IPV6_MESSAGE_111); // printf(", no aging"); if (RTE->SitePrefixLength != 0) NlsPutMsg(STDOUT, IPV6_MESSAGE_112, RTE->SitePrefixLength); // printf(", spl %u", RTE->SitePrefixLength); NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); } void PrintPersistentRoutesOnInterface(IPV6_INFO_INTERFACE *IF) { ForEachPersistentRoute(IF, PrintPersistentRouteTableEntry); } void QueryRouteTable(int argc, char *argv[]) { if (argc == 0) { if (Persistent) ForEachPersistentInterface(PrintPersistentRoutesOnInterface); else ForEachRoute(PrintRouteTableEntry); } else { usage(); } } void UpdateRouteTable(int argc, char *argv[]) { IPV6_INFO_ROUTE_TABLE Route; u_int BytesReturned; int i; Route.SitePrefixLength = 0; Route.ValidLifetime = INFINITE_LIFETIME; Route.PreferredLifetime = INFINITE_LIFETIME; Route.Preference = ROUTE_PREF_HIGHEST; Route.Type = RTE_TYPE_MANUAL; Route.Publish = FALSE; Route.Immortal = -1; if (argc < 2) usage(); if (! GetNeighbor(argv[1], &Route.This.Neighbor.IF, &Route.This.Neighbor.Address)) usage(); if (! GetPrefix(argv[0], &Route.This.Prefix, &Route.This.PrefixLength)) usage(); for (i = 2; i < argc; i++) { if (!strncmp(argv[i], "lifetime", strlen(argv[i])) && (i+1 < argc)) { if (! GetLifetimes(argv[++i], &Route.ValidLifetime, &Route.PreferredLifetime)) usage(); } else if (!strncmp(argv[i], "preference", strlen(argv[i])) && (i+1 < argc)) { i++; if (!strncmp(argv[i], "low", strlen(argv[i]))) Route.Preference = ROUTE_PREF_LOW; else if (!strncmp(argv[i], "medium", strlen(argv[i]))) Route.Preference = ROUTE_PREF_MEDIUM; else if (!strncmp(argv[i], "high", strlen(argv[i]))) Route.Preference = ROUTE_PREF_HIGH; else if (!strncmp(argv[i], "onlink", strlen(argv[i]))) Route.Preference = ROUTE_PREF_ON_LINK; else if (!strncmp(argv[i], "loopback", strlen(argv[i]))) Route.Preference = ROUTE_PREF_LOOPBACK; else if (! GetNumber(argv[i], &Route.Preference)) usage(); } else if (!strcmp(argv[i], "spl") && (i+1 < argc)) { if (! GetNumber(argv[++i], &Route.SitePrefixLength)) usage(); } else if (!strncmp(argv[i], "advertise", strlen(argv[i])) || !strncmp(argv[i], "publish", strlen(argv[i]))) { Route.Publish = TRUE; } else if (!strncmp(argv[i], "immortal", strlen(argv[i])) || !strncmp(argv[i], "noaging", strlen(argv[i])) || !strcmp(argv[i], "noage")) { Route.Immortal = TRUE; } else if (!strncmp(argv[i], "aging", strlen(argv[i])) || !strcmp(argv[i], "age")) { Route.Immortal = FALSE; } else if (!strcmp(argv[i], "system")) { Route.Type = RTE_TYPE_SYSTEM; } else if (!strcmp(argv[i], "manual")) { Route.Type = RTE_TYPE_MANUAL; } else if (!strcmp(argv[i], "autoconf")) { Route.Type = RTE_TYPE_AUTOCONF; } else if (!strcmp(argv[i], "rip")) { Route.Type = RTE_TYPE_RIP; } else if (!strcmp(argv[i], "ospf")) { Route.Type = RTE_TYPE_OSPF; } else if (!strcmp(argv[i], "bgp")) { Route.Type = RTE_TYPE_BGP; } else if (!strcmp(argv[i], "idrp")) { Route.Type = RTE_TYPE_IDRP; } else if (!strcmp(argv[i], "igrp")) { Route.Type = RTE_TYPE_IGRP; } else usage(); } if (Route.Immortal == -1) Route.Immortal = Route.Publish; if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_UPDATE_ROUTE_TABLE : IOCTL_IPV6_UPDATE_ROUTE_TABLE), &Route, sizeof Route, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_124, GetLastError()); // printf("route update error: %x\n", GetLastError()); exit(1); } } void UpdateAddress(int argc, char *argv[]) { IPV6_UPDATE_ADDRESS Update; u_int BytesReturned; int i; int Origin; Update.Type = ADE_UNICAST; Update.PrefixConf = PREFIX_CONF_MANUAL; Update.InterfaceIdConf = IID_CONF_MANUAL; Update.ValidLifetime = INFINITE_LIFETIME; Update.PreferredLifetime = INFINITE_LIFETIME; if (argc < 1) usage(); if ((strchr(argv[0], '/') == NULL) || ! GetNeighbor(argv[0], &Update.This.IF, &Update.This.Address)) usage(); for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "lifetime", strlen(argv[i])) && (i+1 < argc)) { if (! GetLifetimes(argv[++i], &Update.ValidLifetime, &Update.PreferredLifetime)) usage(); } else if (!strcmp(argv[i], "unicast")) Update.Type = ADE_UNICAST; else if (!strcmp(argv[i], "anycast")) Update.Type = ADE_ANYCAST; else if (!strcmp(argv[i], "prefixorigin") && (i+1 < argc)) { if (! GetPrefixOrigin(argv[++i], &Origin)) usage(); Update.PrefixConf = Origin; } else if (!strcmp(argv[i], "ifidorigin") && (i+1 < argc)) { if (! GetInterfaceIdOrigin(argv[++i], &Origin)) usage(); Update.InterfaceIdConf = Origin; } else usage(); } if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_UPDATE_ADDRESS : IOCTL_IPV6_UPDATE_ADDRESS), &Update, sizeof Update, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_125, GetLastError()); // printf("address update error: %x\n", GetLastError()); exit(1); } } void ForEachBinding(void (*func)(IPV6_INFO_BINDING_CACHE *)) { IPV6_QUERY_BINDING_CACHE Query, NextQuery; IPV6_INFO_BINDING_CACHE BCE; u_int BytesReturned; NextQuery.HomeAddress = in6addr_any; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_BINDING_CACHE, &Query, sizeof Query, &BCE, sizeof BCE, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_126, FormatIPv6Address(&Query.HomeAddress)); // printf("bad home address %s\n", // FormatIPv6Address(&Query.HomeAddress)); exit(1); } NextQuery = BCE.Query; if (!IN6_ADDR_EQUAL(&Query.HomeAddress, &in6addr_any)) { BCE.Query = Query; (*func)(&BCE); } if (IN6_ADDR_EQUAL(&NextQuery.HomeAddress, &in6addr_any)) break; } } void PrintBindingCacheEntry(IPV6_INFO_BINDING_CACHE *BCE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_127, FormatIPv6Address(&BCE->HomeAddress)); // printf("home: %s\n", FormatIPv6Address(&BCE->HomeAddress)); NlsPutMsg(STDOUT, IPV6_MESSAGE_128, FormatIPv6Address(&BCE->CareOfAddress)); // printf(" c/o: %s\n", FormatIPv6Address(&BCE->CareOfAddress)); NlsPutMsg(STDOUT, IPV6_MESSAGE_129, BCE->BindingSeqNumber, BCE->BindingLifetime); // printf(" seq: %u Lifetime: %us\n\n", // BCE->BindingSeqNumber, BCE->BindingLifetime); } void QueryBindingCache(int argc, char *argv[]) { if (argc == 0) { ForEachBinding(PrintBindingCacheEntry); } else { usage(); } } void FlushNeighborCacheForInterface(IPV6_INFO_INTERFACE *IF) { IPV6_QUERY_NEIGHBOR_CACHE Query; u_int BytesReturned; Query.IF = IF->This; Query.Address = in6addr_any; if (!DeviceIoControl(Handle, IOCTL_IPV6_FLUSH_NEIGHBOR_CACHE, &Query, sizeof Query, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_130, GetLastError()); // printf("flush neighbor cache error: %x\n", GetLastError()); exit(1); } } void FlushNeighborCache(int argc, char *argv[]) { // // Rather than put code in the kernel ioctl to iterate // over the interfaces, we do it here in user space. // if (argc == 0) { ForEachInterface(FlushNeighborCacheForInterface); } else { IPV6_QUERY_NEIGHBOR_CACHE Query; u_int BytesReturned; Query.IF.Index = 0; Query.Address = in6addr_any; switch (argc) { case 2: if (! GetAddress(argv[1], &Query.Address)) usage(); // fall-through case 1: if (! GetInterface(argv[0], &Query.IF)) usage(); // fall-through case 0: break; default: usage(); } if (!DeviceIoControl(Handle, IOCTL_IPV6_FLUSH_NEIGHBOR_CACHE, &Query, sizeof Query, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_130, GetLastError()); // printf("flush neighbor cache error: %x\n", GetLastError()); exit(1); } } } void FlushRouteCache(int argc, char *argv[]) { IPV6_QUERY_ROUTE_CACHE Query; u_int BytesReturned; Query.IF.Index = (u_int)-1; Query.Address = in6addr_any; switch (argc) { case 2: if (! GetAddress(argv[1], &Query.Address)) usage(); // fall-through case 1: if (! GetInterface(argv[0], &Query.IF)) usage(); // fall-through case 0: break; default: usage(); } if (!DeviceIoControl(Handle, IOCTL_IPV6_FLUSH_ROUTE_CACHE, &Query, sizeof Query, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_131, GetLastError()); // printf("flush route cache error: %x\n", GetLastError()); exit(1); } } void ForEachSitePrefix(void (*func)(IPV6_INFO_SITE_PREFIX *)) { IPV6_QUERY_SITE_PREFIX Query, NextQuery; IPV6_INFO_SITE_PREFIX SPE; u_int BytesReturned; NextQuery.IF.Index = 0; for (;;) { Query = NextQuery; if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_SITE_PREFIX, &Query, sizeof Query, &SPE, sizeof SPE, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_132, Query.IF.Index); // printf("bad index %u\n", Query.IF.Index); exit(1); } NextQuery = SPE.Query; if (Query.IF.Index != 0) { SPE.Query = Query; (*func)(&SPE); } if (NextQuery.IF.Index == 0) break; } } void PrintSitePrefix(IPV6_INFO_SITE_PREFIX *SPE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_133, FormatIPv6Address(&SPE->Query.Prefix), SPE->Query.PrefixLength, SPE->Query.IF.Index, FormatLifetimes(SPE->ValidLifetime, SPE->ValidLifetime)); // printf("%s/%u -> %u (life %s)\n", // FormatIPv6Address(&SPE->Query.Prefix), // SPE->Query.PrefixLength, // SPE->Query.IF.Index, // FormatLifetimes(SPE->ValidLifetime, SPE->ValidLifetime)); } void QuerySitePrefixTable(int argc, char *argv[]) { if (argc == 0) { ForEachSitePrefix(PrintSitePrefix); } else { usage(); } } void UpdateSitePrefixTable(int argc, char *argv[]) { IPV6_INFO_SITE_PREFIX SitePrefix; u_int BytesReturned; int i; SitePrefix.ValidLifetime = INFINITE_LIFETIME; if (argc < 2) usage(); if (! GetInterface(argv[1], &SitePrefix.Query.IF)) usage(); if (! GetPrefix(argv[0], &SitePrefix.Query.Prefix, &SitePrefix.Query.PrefixLength)) usage(); for (i = 2; i < argc; i++) { if (!strncmp(argv[i], "lifetime", strlen(argv[i])) && (i+1 < argc)) { if (! GetLifetimes(argv[++i], &SitePrefix.ValidLifetime, NULL)) usage(); } else usage(); } if (!DeviceIoControl(Handle, IOCTL_IPV6_UPDATE_SITE_PREFIX, &SitePrefix, sizeof SitePrefix, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_134, GetLastError()); // printf("site prefix update error: %x\n", GetLastError()); exit(1); } } void QueryGlobalParameters(int argc, char *argv[]) { IPV6_GLOBAL_PARAMETERS Params; u_int BytesReturned; if (argc != 0) usage(); if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_QUERY_GLOBAL_PARAMETERS : IOCTL_IPV6_QUERY_GLOBAL_PARAMETERS), NULL, 0, &Params, sizeof Params, &BytesReturned, NULL) || (BytesReturned != sizeof Params)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_135, GetLastError()); // printf("query global params error: %x\n", GetLastError()); exit(1); } if (Params.DefaultCurHopLimit != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_136, Params.DefaultCurHopLimit); // printf("DefaultCurHopLimit = %u\n", Params.DefaultCurHopLimit); } if (Params.UseTemporaryAddresses != (u_int) -1) { switch (Params.UseTemporaryAddresses) { case USE_TEMP_NO: NlsPutMsg(STDOUT, IPV6_MESSAGE_137); // printf("UseTemporaryAddresses = no\n"); break; case USE_TEMP_YES: NlsPutMsg(STDOUT, IPV6_MESSAGE_138); // printf("UseTemporaryAddresses = yes\n"); break; case USE_TEMP_ALWAYS: NlsPutMsg(STDOUT, IPV6_MESSAGE_139); // printf("UseTemporaryAddresses = yes, new random interface id for every address\n"); break; case USE_TEMP_COUNTER: NlsPutMsg(STDOUT, IPV6_MESSAGE_140); // printf("UseTemporaryAddresses = yes, incrementing interface ids\n"); break; default: NlsPutMsg(STDOUT, IPV6_MESSAGE_141, Params.UseTemporaryAddresses); // printf("UseTemporaryAddresses = %u\n", Params.UseTemporaryAddresses); break; } } if (Params.MaxTempDADAttempts != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_142, Params.MaxTempDADAttempts); // printf("MaxTempDADAttempts = %u\n", Params.MaxTempDADAttempts); } if ((Params.MaxTempValidLifetime != (u_int) -1) || (Params.MaxTempPreferredLifetime != (u_int) -1)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_143, FormatLifetimes(Params.MaxTempValidLifetime, Params.MaxTempPreferredLifetime)); // printf("MaxTempLifetime = %s\n", // FormatLifetimes(Params.MaxTempValidLifetime, // Params.MaxTempPreferredLifetime)); } if (Params.TempRegenerateTime != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_144, Params.TempRegenerateTime); // printf("TempRegenerateTime = %us\n", Params.TempRegenerateTime); } if (Params.MaxTempRandomTime != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_145, FormatLifetime(Params.MaxTempRandomTime)); // printf("MaxTempRandomTime = %s\n", // FormatLifetime(Params.MaxTempRandomTime)); } if (! Persistent) { NlsPutMsg(STDOUT, IPV6_MESSAGE_146, FormatLifetime(Params.TempRandomTime)); // printf("TempRandomTime = %s\n", // FormatLifetime(Params.TempRandomTime)); } if (Params.NeighborCacheLimit != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_147, Params.NeighborCacheLimit); // printf("NeighborCacheLimit = %u\n", Params.NeighborCacheLimit); } if (Params.RouteCacheLimit != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_148, Params.RouteCacheLimit); // printf("RouteCacheLimit = %u\n", Params.RouteCacheLimit); } if (Params.BindingCacheLimit != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_BCL_DISPLAY, Params.BindingCacheLimit); // printf("BindingCacheLimit = %u\n", Params.BindingCacheLimit); } if (Params.ReassemblyLimit != (u_int) -1) { NlsPutMsg(STDOUT, IPV6_MESSAGE_REASS_LIMIT_DISPLAY, Params.ReassemblyLimit); // printf("ReassemblyLimit = %u\n", Params.ReassemblyLimit); } if (Params.MobilitySecurity != -1) { if (Params.MobilitySecurity) { NlsPutMsg(STDOUT, IPV6_MESSAGE_MOBILITY_SECURITY_ON); // printf("MobilitySecurity = on\n"); } else { NlsPutMsg(STDOUT, IPV6_MESSAGE_MOBILITY_SECURITY_OFF); // printf("MobilitySecurity = off\n"); } } if (Params.MobileIPv6Mode != (u_int) -1) { NlsPutMsg(STDOUT, MIPV6_MESSAGE_MODE); // printf("MobileIPv6Mode ="); if (Params.MobileIPv6Mode & MOBILE_MOBILE_NODE) { NlsPutMsg(STDOUT, MIPV6_MESSAGE_MODE_MN); // printf(" MN"); } if (Params.MobileIPv6Mode & MOBILE_HOME_AGENT) { NlsPutMsg(STDOUT, MIPV6_MESSAGE_MODE_HA); // printf(" HA"); } if (Params.MobileIPv6Mode & MOBILE_CORRESPONDENT) { NlsPutMsg(STDOUT, MIPV6_MESSAGE_MODE_CN); // printf(" CN"); } NlsPutMsg(STDOUT, IPV6_MESSAGE_36); // printf("\n"); } } void UpdateGlobalParameters(int argc, char *argv[]) { IPV6_GLOBAL_PARAMETERS Params; u_int BytesReturned; int i; IPV6_INIT_GLOBAL_PARAMETERS(&Params); for (i = 0; i < argc; i++) { if (!strcmp(argv[i], "DefaultCurHopLimit") && (i+1 < argc)) { if (! GetNumber(argv[++i], &Params.DefaultCurHopLimit)) goto usage; } else if (!strcmp(argv[i], "UseTemporaryAddresses") && (i+1 < argc)) { if (!strncmp(argv[++i], "no", strlen(argv[i]))) Params.UseTemporaryAddresses = USE_TEMP_NO; else if (!strncmp(argv[i], "yes", strlen(argv[i]))) Params.UseTemporaryAddresses = USE_TEMP_YES; else if (!strncmp(argv[i], "always", strlen(argv[i]))) Params.UseTemporaryAddresses = USE_TEMP_ALWAYS; else if (!strncmp(argv[i], "counter", strlen(argv[i]))) Params.UseTemporaryAddresses = USE_TEMP_COUNTER; else goto usage; } else if (!strcmp(argv[i], "MaxTempDADAttempts") && (i+1 < argc)) { if (! GetNumber(argv[++i], &Params.MaxTempDADAttempts)) goto usage; } else if (!strcmp(argv[i], "MaxTempLifetime") && (i+1 < argc)) { if (! GetLifetimes(argv[++i], &Params.MaxTempValidLifetime, &Params.MaxTempPreferredLifetime)) goto usage; } else if (!strcmp(argv[i], "TempRegenerateTime") && (i+1 < argc)) { if (! GetLifetime(argv[++i], &Params.TempRegenerateTime)) goto usage; } else if (!strcmp(argv[i], "MaxTempRandomTime") && (i+1 < argc)) { if (! GetLifetime(argv[++i], &Params.MaxTempRandomTime)) goto usage; } else if (!strcmp(argv[i], "TempRandomTime") && (i+1 < argc)) { if (! GetLifetime(argv[++i], &Params.TempRandomTime)) goto usage; } else if (!strcmp(argv[i], "NeighborCacheLimit") && (i+1 < argc)) { if (! GetNumber(argv[++i], &Params.NeighborCacheLimit)) goto usage; } else if (!strcmp(argv[i], "RouteCacheLimit") && (i+1 < argc)) { if (! GetNumber(argv[++i], &Params.RouteCacheLimit)) goto usage; } else if (!strcmp(argv[i], "BindingCacheLimit") && (i+1 < argc)) { if (! GetNumber(argv[++i], &Params.BindingCacheLimit)) goto usage; } else if (!strcmp(argv[i], "ReassemblyLimit") && (i+1 < argc)) { if (! GetNumber(argv[++i], &Params.ReassemblyLimit)) goto usage; } else if (!strcmp(argv[i], "MobilitySecurity") && (i+1 < argc)) { if (!strncmp(argv[++i], "on", strlen(argv[i]))) Params.MobilitySecurity = TRUE; else if (!strncmp(argv[i], "off", strlen(argv[i]))) Params.MobilitySecurity = FALSE; else if (!strncmp(argv[i], "yes", strlen(argv[i]))) Params.MobilitySecurity = TRUE; else if (!strncmp(argv[i], "no", strlen(argv[i]))) Params.MobilitySecurity = FALSE; else goto usage; } else if (!strcmp(argv[i], "MobileIPv6Mode")) { Params.MobileIPv6Mode = 0; while (++i < argc) { if (!strncmp(argv[i], "CN", strlen(argv[i]))) Params.MobileIPv6Mode |= MOBILE_CORRESPONDENT; else if (!strncmp(argv[i], "MN", strlen(argv[i]))) Params.MobileIPv6Mode |= MOBILE_MOBILE_NODE; else if (!strncmp(argv[i], "HA", strlen(argv[i]))) Params.MobileIPv6Mode |= MOBILE_HOME_AGENT; else break; } i--; // // Until we have full mobility support, only allow CN. // if (Params.MobileIPv6Mode &~ MOBILE_CORRESPONDENT) { // printf("MobileIPv6Modes MN and HA currently unsupported\n"); NlsPutMsg(STDOUT, MIPV6_MESSAGE_UNSUPPORTED_MODE); exit(1); } // // Disallow nonsensical combinations. // if ((Params.MobileIPv6Mode & MOBILE_MOBILE_NODE) && (Params.MobileIPv6Mode & MOBILE_HOME_AGENT)) { // printf("invalid MobileIPv6Mode combination (HA and MN).\n"); NlsPutMsg(STDOUT, MIPV6_MESSAGE_INVALID_MODE_COMBINATION1); exit(1); } if ((Params.MobileIPv6Mode & MOBILE_HOME_AGENT) && !(Params.MobileIPv6Mode & MOBILE_CORRESPONDENT)) { // printf("invalid MobileIPv6Mode combination (HA and not CN).\n"); NlsPutMsg(STDOUT, MIPV6_MESSAGE_INVALID_MODE_COMBINATION2); exit(1); } } else { usage: NlsPutMsg(STDOUT, IPV6_MESSAGE_149); // printf("usage: ipv6 gpu [parameter value] ...\n"); // printf(" ipv6 gpu DefaultCurHopLimit hops\n"); // printf(" ipv6 gpu UseTemporaryAddresses [yes|no|always|counter]\n"); // printf(" ipv6 gpu MaxTempDADAttempts number\n"); // printf(" ipv6 gpu MaxTempLifetime valid[/preferred]\n"); // printf(" ipv6 gpu TempRegenerateTime time\n"); // printf(" ipv6 gpu MaxTempRandomTime time\n"); // printf(" ipv6 gpu TempRandomTime time\n"); // printf(" ipv6 gpu NeighborCacheLimit number\n"); // printf(" ipv6 gpu RouteCacheLimit number\n"); // printf(" ipv6 gpu BindingCacheLimit number\n"); // printf(" ipv6 gpu ReassemblyLimit number\n"); // printf(" ipv6 gpu MobilitySecurity [on|off]\n"); // printf(" ipv6 gpu MobileIPv6Mode [CN|MN|HA]*\n"); // printf("Use ipv6 -p gpu ... to make a persistent change\n"); // printf("in the registry. Many global parameter changes\n"); // printf("only take effect after restarting the stack.\n"); // printf("MobileIPv6Modes MN and HA are currently unsupported.\n"); exit(1); } } if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_UPDATE_GLOBAL_PARAMETERS : IOCTL_IPV6_UPDATE_GLOBAL_PARAMETERS), &Params, sizeof Params, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_150, GetLastError()); // printf("update global params error: %x\n", GetLastError()); exit(1); } } void ForEachPrefixPolicy(void (*func)(IPV6_INFO_PREFIX_POLICY *)) { IPV6_QUERY_PREFIX_POLICY Query; IPV6_INFO_PREFIX_POLICY PPE; u_int BytesReturned; Query.PrefixLength = (u_int) -1; for (;;) { if (!DeviceIoControl(Handle, IOCTL_IPV6_QUERY_PREFIX_POLICY, &Query, sizeof Query, &PPE, sizeof PPE, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_160); // printf("bad prefix\n"); exit(1); } if (Query.PrefixLength != (u_int) -1) { if (BytesReturned != sizeof PPE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_160); // printf("bad prefix\n"); exit(1); } (*func)(&PPE); } else { if (BytesReturned != sizeof PPE.Next) { NlsPutMsg(STDOUT, IPV6_MESSAGE_160); // printf("bad prefix\n"); exit(1); } } if (PPE.Next.PrefixLength == (u_int) -1) break; Query = PPE.Next; } } void ForEachPersistentPrefixPolicy(void (*func)(IPV6_INFO_PREFIX_POLICY *)) { IPV6_PERSISTENT_QUERY_PREFIX_POLICY Query; IPV6_INFO_PREFIX_POLICY PPE; u_int BytesReturned; for (Query.RegistryIndex = 0;; Query.RegistryIndex++) { if (!DeviceIoControl(Handle, IOCTL_IPV6_PERSISTENT_QUERY_PREFIX_POLICY, &Query, sizeof Query, &PPE, sizeof PPE, &BytesReturned, NULL)) { if (GetLastError() == ERROR_NO_MORE_ITEMS) break; NlsPutMsg(STDOUT, IPV6_MESSAGE_160); // printf("bad prefix\n"); exit(1); } if (BytesReturned != sizeof PPE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_160); // printf("bad prefix\n"); exit(1); } (*func)(&PPE); } } void PrintPrefixPolicyEntry(IPV6_INFO_PREFIX_POLICY *PPE) { NlsPutMsg(STDOUT, IPV6_MESSAGE_161, FormatIPv6Address(&PPE->This.Prefix), PPE->This.PrefixLength, PPE->Precedence, PPE->SrcLabel, PPE->DstLabel); // printf("%s/%u -> precedence %u srclabel %u dstlabel %u\n", // FormatIPv6Address(&PPE->This.Prefix), // PPE->This.PrefixLength, // PPE->Precedence, // PPE->SrcLabel, // PPE->DstLabel); } void QueryPrefixPolicy(int argc, char *argv[]) { if (argc == 0) { if (Persistent) ForEachPersistentPrefixPolicy(PrintPrefixPolicyEntry); else ForEachPrefixPolicy(PrintPrefixPolicyEntry); } else { usage(); } } void UpdatePrefixPolicy(int argc, char *argv[]) { IPV6_INFO_PREFIX_POLICY Info; u_int BytesReturned; int i; if (argc < 1) usage(); if (! GetPrefix(argv[0], &Info.This.Prefix, &Info.This.PrefixLength)) usage(); Info.Precedence = (u_int) -1; Info.SrcLabel = (u_int) -1; Info.DstLabel = (u_int) -1; for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "precedence", strlen(argv[i])) && ((i + 1) < argc)) { if (! GetNumber(argv[++i], &Info.Precedence)) usage(); } else if ((!strncmp(argv[i], "srclabel", strlen(argv[i])) || !strcmp(argv[i], "sl") || !strcmp(argv[i], "label")) && ((i + 1) < argc)) { if (! GetNumber(argv[++i], &Info.SrcLabel)) usage(); } else if ((!strncmp(argv[i], "dstlabel", strlen(argv[i])) || !strcmp(argv[i], "dl")) && ((i + 1) < argc)) { if (! GetNumber(argv[++i], &Info.DstLabel)) usage(); } else usage(); } if ((Info.Precedence == (u_int) -1) || (Info.SrcLabel == (u_int) -1)) usage(); if (Info.DstLabel == (u_int) -1) Info.DstLabel = Info.SrcLabel; if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_UPDATE_PREFIX_POLICY : IOCTL_IPV6_UPDATE_PREFIX_POLICY), &Info, sizeof Info, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_162, GetLastError()); // printf("prefix policy create error: %x\n", GetLastError()); exit(1); } } void DeletePrefixPolicy(int argc, char *argv[]) { IPV6_QUERY_PREFIX_POLICY Query; u_int BytesReturned; if (argc == 1) { if (! GetPrefix(argv[0], &Query.Prefix, &Query.PrefixLength)) usage(); } else { usage(); } if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_DELETE_PREFIX_POLICY : IOCTL_IPV6_DELETE_PREFIX_POLICY), &Query, sizeof Query, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_163, GetLastError()); // printf("prefix policy delete error: %x\n", GetLastError()); exit(1); } } void ResetManualConfig(int argc, char *argv[]) { u_int BytesReturned; if (argc != 0) usage(); if (!DeviceIoControl(Handle, (Persistent ? IOCTL_IPV6_PERSISTENT_RESET : IOCTL_IPV6_RESET), NULL, 0, NULL, 0, &BytesReturned, NULL)) { NlsPutMsg(STDOUT, IPV6_MESSAGE_RESET, GetLastError()); // printf("reset error: %x\n", GetLastError()); exit(1); } }