windows-nt/Source/XPSP1/NT/net/tcpip/tpipv6/ipv6/ipv6.c
2020-09-26 16:20:57 +08:00

3734 lines
102 KiB
C

// -*- 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 <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ws2ip6.h>
#include <wspiapi.h>
#include <ntddip6.h>
#include <ip6.h>
#include <stdio.h>
#include <stdlib.h>
//
// Localization library and MessageIds.
//
#include <nls.h>
#include <winnlsp.h>
#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, "<invalid>");
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, "<invalid>");
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_10, GetLastError());
// 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_10, GetLastError());
// 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(" (anonymous)");
} 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");
printf("%s\n", FormatGuid(&IF->This.Guid));
// 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_59);
// printf(" uses Neighbor Discovery\n");
else
NlsPutMsg(STDOUT, IPV6_MESSAGE_60);
// 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_61);
// printf(" sends Router Advertisements\n");
if (IF->Forwards)
NlsPutMsg(STDOUT, IPV6_MESSAGE_62);
// printf(" forwards packets\n");
if (IF->PeriodicMLD)
NlsPutMsg(STDOUT, IPV6_MESSAGE_63);
// 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);
}
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");
printf("%s\n", FormatGuid(&IF->This.Guid));
// 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_59);
// printf(" uses Neighbor Discovery\n");
else if (IF->NeighborDiscovers == FALSE)
NlsPutMsg(STDOUT, IPV6_MESSAGE_60);
// 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_61);
// 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_62);
// 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_63);
// 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);
}
}
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_RESET, GetLastError());
// 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 (!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;
printf("%s/%u -> %s",
// NlsPutMsg(STDOUT, IPV6_MESSAGE_PRINT_PERSISTENT_ROUTE,
FormatIPv6Address(&RTE->This.Prefix),
RTE->This.PrefixLength,
FormatGuid(&RTE->This.Neighbor.IF.Guid));
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.UseAnonymousAddresses != (u_int) -1) {
switch (Params.UseAnonymousAddresses) {
case USE_ANON_NO:
NlsPutMsg(STDOUT, IPV6_MESSAGE_137);
// printf("UseAnonymousAddresses = no\n");
break;
case USE_ANON_YES:
NlsPutMsg(STDOUT, IPV6_MESSAGE_138);
// printf("UseAnonymousAddresses = yes\n");
break;
case USE_ANON_ALWAYS:
NlsPutMsg(STDOUT, IPV6_MESSAGE_139);
// printf("UseAnonymousAddresses = yes, new random interface id for every address\n");
break;
case USE_ANON_COUNTER:
NlsPutMsg(STDOUT, IPV6_MESSAGE_140);
// printf("UseAnonymousAddresses = yes, incrementing interface ids\n");
break;
default:
NlsPutMsg(STDOUT, IPV6_MESSAGE_141, Params.UseAnonymousAddresses);
// printf("UseAnonymousAddresses = %u\n", Params.UseAnonymousAddresses);
break;
}
}
if (Params.MaxAnonDADAttempts != (u_int) -1) {
NlsPutMsg(STDOUT, IPV6_MESSAGE_142, Params.MaxAnonDADAttempts);
// printf("MaxAnonDADAttempts = %u\n", Params.MaxAnonDADAttempts);
}
if ((Params.MaxAnonValidLifetime != (u_int) -1) ||
(Params.MaxAnonPreferredLifetime != (u_int) -1)) {
NlsPutMsg(STDOUT, IPV6_MESSAGE_143,
FormatLifetimes(Params.MaxAnonValidLifetime,
Params.MaxAnonPreferredLifetime));
// printf("MaxAnonLifetime = %s\n",
// FormatLifetimes(Params.MaxAnonValidLifetime,
// Params.MaxAnonPreferredLifetime));
}
if (Params.AnonRegenerateTime != (u_int) -1) {
NlsPutMsg(STDOUT, IPV6_MESSAGE_144, Params.AnonRegenerateTime);
// printf("AnonRegenerateTime = %us\n", Params.AnonRegenerateTime);
}
if (Params.MaxAnonRandomTime != (u_int) -1) {
NlsPutMsg(STDOUT, IPV6_MESSAGE_145,
FormatLifetime(Params.MaxAnonRandomTime));
// printf("MaxAnonRandomTime = %s\n",
// FormatLifetime(Params.MaxAnonRandomTime));
}
if (! Persistent) {
NlsPutMsg(STDOUT, IPV6_MESSAGE_146,
FormatLifetime(Params.AnonRandomTime));
// printf("AnonRandomTime = %s\n",
// FormatLifetime(Params.AnonRandomTime));
}
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");
}
}
}
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], "UseAnonymousAddresses") && (i+1 < argc)) {
if (!strncmp(argv[++i], "no", strlen(argv[i])))
Params.UseAnonymousAddresses = USE_ANON_NO;
else if (!strncmp(argv[i], "yes", strlen(argv[i])))
Params.UseAnonymousAddresses = USE_ANON_YES;
else if (!strncmp(argv[i], "always", strlen(argv[i])))
Params.UseAnonymousAddresses = USE_ANON_ALWAYS;
else if (!strncmp(argv[i], "counter", strlen(argv[i])))
Params.UseAnonymousAddresses = USE_ANON_COUNTER;
else
goto usage;
}
else if (!strcmp(argv[i], "MaxAnonDADAttempts") && (i+1 < argc)) {
if (! GetNumber(argv[++i], &Params.MaxAnonDADAttempts))
goto usage;
}
else if (!strcmp(argv[i], "MaxAnonLifetime") && (i+1 < argc)) {
if (! GetLifetimes(argv[++i],
&Params.MaxAnonValidLifetime,
&Params.MaxAnonPreferredLifetime))
goto usage;
}
else if (!strcmp(argv[i], "AnonRegenerateTime") && (i+1 < argc)) {
if (! GetLifetime(argv[++i], &Params.AnonRegenerateTime))
goto usage;
}
else if (!strcmp(argv[i], "MaxAnonRandomTime") && (i+1 < argc)) {
if (! GetLifetime(argv[++i], &Params.MaxAnonRandomTime))
goto usage;
}
else if (!strcmp(argv[i], "AnonRandomTime") && (i+1 < argc)) {
if (! GetLifetime(argv[++i], &Params.AnonRandomTime))
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 {
usage:
NlsPutMsg(STDOUT, IPV6_MESSAGE_149);
// printf("usage: ipv6 gpu [parameter value] ...\n");
// printf(" ipv6 gpu DefaultCurHopLimit hops\n");
// printf(" ipv6 gpu UseAnonymousAddresses [yes|no|always|counter]\n");
// printf(" ipv6 gpu MaxAnonDADAttempts number\n");
// printf(" ipv6 gpu MaxAnonLifetime valid[/preferred]\n");
// printf(" ipv6 gpu AnonRegenerateTime time\n");
// printf(" ipv6 gpu MaxAnonRandomTime time\n");
// printf(" ipv6 gpu AnonRandomTime 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("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");
}
}
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);
}
}