You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
609 lines
12 KiB
609 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 2001-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
isatap.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the ISATAP interface to the IPv6 Helper Service.
|
|
|
|
Author:
|
|
|
|
Mohit Talwar (mohitt) Tue May 07 10:16:49 2002
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define DEFAULT_ISATAP_STATE ENABLED
|
|
#define DEFAULT_ISATAP_ROUTER_NAME L"isatap"
|
|
#define DEFAULT_ISATAP_RESOLUTION_STATE ENABLED
|
|
#define DEFAULT_ISATAP_RESOLUTION_INTERVAL (24 * HOURS)
|
|
|
|
#define KEY_ISATAP_STATE L"IsatapState"
|
|
#define KEY_ISATAP_ROUTER_NAME L"IsatapRouterName"
|
|
#define KEY_ISATAP_RESOLUTION_STATE L"EnableIsatapResolution"
|
|
#define KEY_ISATAP_RESOLUTION_INTERVAL L"IsatapResolutionInterval"
|
|
|
|
STATE IsatapState;
|
|
WCHAR IsatapRouterName[NI_MAXHOST];
|
|
STATE IsatapResolutionState;
|
|
ULONG IsatapResolutionInterval; // in minutes
|
|
|
|
HANDLE IsatapTimer; // Periodic timer started for the service.
|
|
HANDLE IsatapTimerEvent; // Event signalled upon Timer deletion.
|
|
HANDLE IsatapTimerEventWait; // Wait registered for TimerEvent.
|
|
|
|
IN_ADDR IsatapRouter;
|
|
IN_ADDR IsatapToken;
|
|
|
|
BOOL IsatapInitialized = FALSE;
|
|
|
|
DWORD
|
|
GetPreferredSource(
|
|
IN IN_ADDR Destination,
|
|
OUT PIN_ADDR Source
|
|
)
|
|
{
|
|
SOCKADDR_IN DestinationAddress, SourceAddress;
|
|
int BytesReturned;
|
|
|
|
memset(&DestinationAddress, 0, sizeof(SOCKADDR_IN));
|
|
DestinationAddress.sin_family = AF_INET;
|
|
DestinationAddress.sin_addr = Destination;
|
|
|
|
if (WSAIoctl(
|
|
g_sIPv4Socket, SIO_ROUTING_INTERFACE_QUERY,
|
|
&DestinationAddress, sizeof(SOCKADDR_IN),
|
|
&SourceAddress, sizeof(SOCKADDR_IN),
|
|
&BytesReturned, NULL, NULL) == SOCKET_ERROR) {
|
|
return WSAGetLastError();
|
|
}
|
|
|
|
*Source = SourceAddress.sin_addr;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapUpdateRouterAddress(
|
|
VOID
|
|
)
|
|
{
|
|
DWORD Error = NO_ERROR;
|
|
ADDRINFOW Hints;
|
|
PADDRINFOW Addresses;
|
|
IN_ADDR NewRouter = { INADDR_ANY }, NewToken = { INADDR_ANY };
|
|
|
|
//
|
|
// Set the ISATAP router address if ISATAP resolution is enabled.
|
|
//
|
|
if (IsatapResolutionState == ENABLED) {
|
|
//
|
|
// Resolve IsatapRouterName to an IPv4 address.
|
|
//
|
|
ZeroMemory(&Hints, sizeof(Hints));
|
|
Hints.ai_family = PF_INET;
|
|
Error = GetAddrInfoW(IsatapRouterName, NULL, &Hints, &Addresses);
|
|
if (Error == NO_ERROR) {
|
|
NewRouter = ((LPSOCKADDR_IN) Addresses->ai_addr)->sin_addr;
|
|
FreeAddrInfoW(Addresses);
|
|
|
|
//
|
|
// Determine the preferred source address.
|
|
//
|
|
if (GetPreferredSource(NewRouter, &NewToken) != NO_ERROR) {
|
|
//
|
|
// What use is the IsatapRouter that cannot be reached?
|
|
//
|
|
NewRouter.s_addr = INADDR_ANY;
|
|
}
|
|
} else {
|
|
Trace2(ERR, _T("GetAddrInfoW(%s): %x"), IsatapRouterName, Error);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Update the stack with the new addresses.
|
|
//
|
|
IsatapRouter = NewRouter;
|
|
IsatapToken = NewToken;
|
|
UpdateRouterLinkAddress(V4_COMPAT_IFINDEX, IsatapToken, IsatapRouter);
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapConfigureAddress(
|
|
IN BOOL Delete,
|
|
IN IN_ADDR Ipv4
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates an ISATAP link-scoped address from an IPv4 address.
|
|
|
|
--*/
|
|
{
|
|
SOCKADDR_IN6 IsatapAddress;
|
|
|
|
memset(&IsatapAddress, 0, sizeof(SOCKADDR_IN6));
|
|
IsatapAddress.sin6_family = AF_INET6;
|
|
IsatapAddress.sin6_addr.s6_addr[0] = 0xfe;
|
|
IsatapAddress.sin6_addr.s6_addr[1] = 0x80;
|
|
IsatapAddress.sin6_addr.s6_addr[10] = 0x5e;
|
|
IsatapAddress.sin6_addr.s6_addr[11] = 0xfe;
|
|
memcpy(&IsatapAddress.sin6_addr.s6_addr[12], &Ipv4, sizeof(IN_ADDR));
|
|
|
|
(VOID) ConfigureAddressUpdate(
|
|
V4_COMPAT_IFINDEX,
|
|
&IsatapAddress,
|
|
Delete ? 0 : INFINITE_LIFETIME,
|
|
ADE_UNICAST, PREFIX_CONF_WELLKNOWN, IID_CONF_LL_ADDRESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapConfigureAddressList(
|
|
IN BOOL Delete
|
|
)
|
|
{
|
|
int i;
|
|
|
|
//
|
|
// Configure the lifetime of link-local ISATAP addresses.
|
|
// This will cause them to be either added or deleted.
|
|
//
|
|
for (i = 0; i < g_pIpv4AddressList->iAddressCount; i++) {
|
|
IsatapConfigureAddress(
|
|
Delete,
|
|
((PSOCKADDR_IN)
|
|
g_pIpv4AddressList->Address[i].lpSockaddr)->sin_addr);
|
|
}
|
|
}
|
|
|
|
|
|
__inline
|
|
VOID
|
|
IsatapRestartTimer(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG ResolveInterval = (IsatapResolutionState == ENABLED)
|
|
? IsatapResolutionInterval * MINUTES * 1000 // minutes to milliseconds
|
|
: INFINITE_INTERVAL;
|
|
|
|
(VOID) ChangeTimerQueueTimer(NULL, IsatapTimer, 0, ResolveInterval);
|
|
}
|
|
|
|
|
|
__inline
|
|
VOID
|
|
IsatapStart(
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT(IsatapState != ENABLED);
|
|
IsatapState = ENABLED;
|
|
|
|
IsatapConfigureAddressList(FALSE);
|
|
|
|
IsatapRestartTimer();
|
|
}
|
|
|
|
|
|
__inline
|
|
VOID
|
|
IsatapStop(
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT(IsatapState == ENABLED);
|
|
IsatapState = DISABLED;
|
|
|
|
IsatapConfigureAddressList(TRUE);
|
|
|
|
IsatapRestartTimer();
|
|
}
|
|
|
|
|
|
__inline
|
|
VOID
|
|
IsatapRefresh(
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT(IsatapState == ENABLED);
|
|
|
|
IsatapRestartTimer();
|
|
}
|
|
|
|
|
|
VOID
|
|
CALLBACK
|
|
IsatapTimerCallback(
|
|
IN PVOID Parameter,
|
|
IN BOOLEAN TimerOrWaitFired
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine for IsatapTimer expiration.
|
|
The timer is always active.
|
|
|
|
Arguments:
|
|
|
|
Parameter, TimerOrWaitFired - Ignored.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ENTER_API();
|
|
|
|
TraceEnter("IsatapTimerCallback");
|
|
|
|
IsatapUpdateRouterAddress();
|
|
|
|
TraceLeave("IsatapTimerCallback");
|
|
|
|
LEAVE_API();
|
|
}
|
|
|
|
|
|
VOID
|
|
CALLBACK
|
|
IsatapTimerCleanup(
|
|
IN PVOID Parameter,
|
|
IN BOOLEAN TimerOrWaitFired
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Callback routine for IsatapTimer deletion.
|
|
|
|
Deletion is performed asynchronously since we acquire a lock in
|
|
the callback function that we hold when deleting the timer.
|
|
|
|
Arguments:
|
|
|
|
Parameter, TimerOrWaitFired - Ignored.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
UnregisterWait(IsatapTimerEventWait);
|
|
IsatapTimerEventWait = NULL;
|
|
|
|
CloseHandle(IsatapTimerEvent);
|
|
IsatapTimerEvent = NULL;
|
|
|
|
IsatapState = IsatapResolutionState = DISABLED;
|
|
IsatapUpdateRouterAddress();
|
|
|
|
DecEventCount("IsatapCleanupTimer");
|
|
}
|
|
|
|
|
|
DWORD
|
|
IsatapInitializeTimer(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes the timer.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or failure code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
ULONG ResolveInterval;
|
|
|
|
IsatapTimerEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (IsatapTimerEvent == NULL) {
|
|
Error = GetLastError();
|
|
return Error;
|
|
}
|
|
|
|
if (!RegisterWaitForSingleObject(
|
|
&(IsatapTimerEventWait),
|
|
IsatapTimerEvent,
|
|
IsatapTimerCleanup,
|
|
NULL,
|
|
INFINITE,
|
|
0)) {
|
|
Error = GetLastError();
|
|
CloseHandle(IsatapTimerEvent);
|
|
return Error;
|
|
}
|
|
|
|
ResolveInterval = (IsatapResolutionState == ENABLED)
|
|
? (IsatapResolutionInterval * MINUTES * 1000)
|
|
: INFINITE_INTERVAL;
|
|
|
|
if (!CreateTimerQueueTimer(
|
|
&(IsatapTimer),
|
|
NULL,
|
|
IsatapTimerCallback,
|
|
NULL,
|
|
0,
|
|
ResolveInterval,
|
|
0)) {
|
|
Error = GetLastError();
|
|
UnregisterWait(IsatapTimerEventWait);
|
|
CloseHandle(IsatapTimerEvent);
|
|
return Error;
|
|
}
|
|
|
|
IncEventCount("IsatapInitializeTimer");
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapUninitializeTimer(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Uninitializes the timer. Typically invoked upon service stop.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DeleteTimerQueueTimer(NULL, IsatapTimer, IsatapTimerEvent);
|
|
IsatapTimer = NULL;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IsatapInitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initializes ISATAP and attempts to start it.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NO_ERROR or failure code.
|
|
|
|
--*/
|
|
{
|
|
DWORD Error;
|
|
|
|
IsatapState = DEFAULT_ISATAP_STATE;
|
|
wcscpy(IsatapRouterName, DEFAULT_ISATAP_ROUTER_NAME);
|
|
IsatapResolutionState = DEFAULT_ISATAP_RESOLUTION_STATE;
|
|
IsatapResolutionInterval = DEFAULT_ISATAP_RESOLUTION_INTERVAL;
|
|
|
|
IsatapRouter.s_addr = INADDR_ANY;
|
|
IsatapToken.s_addr = INADDR_ANY;
|
|
|
|
IsatapUpdateRouterAddress();
|
|
|
|
Error = IsatapInitializeTimer();
|
|
if (Error != NO_ERROR) {
|
|
return Error;
|
|
}
|
|
|
|
IsatapInitialized = TRUE;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapUninitialize(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Uninitializes ISATAP.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
if (!IsatapInitialized) {
|
|
return;
|
|
}
|
|
|
|
IsatapUninitializeTimer();
|
|
|
|
IsatapInitialized = FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapAddressChangeNotification(
|
|
IN BOOL Delete,
|
|
IN IN_ADDR Address
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an address deletion or addition request.
|
|
|
|
Arguments:
|
|
|
|
Delete - Supplies a boolean. TRUE if the address was deleted, FALSE o/w.
|
|
|
|
Address - Supplies the IPv4 address that was deleted or added.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Caller LOCK: API.
|
|
|
|
--*/
|
|
{
|
|
IsatapConfigureAddress(Delete, Address);
|
|
|
|
if (IsatapResolutionState == ENABLED) {
|
|
//
|
|
// Preferred source address deleted -or- Any address added.
|
|
//
|
|
if (Delete
|
|
? (IsatapToken.s_addr == Address.s_addr)
|
|
: (IsatapToken.s_addr == INADDR_ANY)) {
|
|
Sleep(1000); // Wait a second to ensure DNS is alerted.
|
|
IsatapUpdateRouterAddress();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapRouteChangeNotification(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process a route change notification.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Caller LOCK: API.
|
|
|
|
--*/
|
|
{
|
|
if (IsatapResolutionState == ENABLED) {
|
|
IsatapRefresh();
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
IsatapConfigurationChangeNotification(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process an configuration change request.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Caller LOCK: API.
|
|
|
|
--*/
|
|
{
|
|
HKEY Key = INVALID_HANDLE_VALUE;
|
|
STATE State;
|
|
|
|
(VOID) RegOpenKeyExW(
|
|
HKEY_LOCAL_MACHINE, KEY_GLOBAL, 0, KEY_QUERY_VALUE, &Key);
|
|
//
|
|
// Continue despite errors, reverting to default values.
|
|
//
|
|
|
|
State = GetInteger(
|
|
Key,
|
|
KEY_ISATAP_STATE,
|
|
DEFAULT_ISATAP_STATE);
|
|
|
|
IsatapResolutionState = GetInteger(
|
|
Key,
|
|
KEY_ISATAP_RESOLUTION_STATE,
|
|
DEFAULT_ISATAP_RESOLUTION_STATE);
|
|
|
|
IsatapResolutionInterval= GetInteger(
|
|
Key,
|
|
KEY_ISATAP_RESOLUTION_INTERVAL,
|
|
DEFAULT_ISATAP_RESOLUTION_INTERVAL);
|
|
|
|
GetString(
|
|
Key,
|
|
KEY_ISATAP_ROUTER_NAME,
|
|
IsatapRouterName,
|
|
NI_MAXHOST,
|
|
DEFAULT_ISATAP_ROUTER_NAME);
|
|
|
|
if (Key != INVALID_HANDLE_VALUE) {
|
|
RegCloseKey(Key);
|
|
}
|
|
|
|
if (State == DISABLED) {
|
|
IsatapResolutionState = DISABLED;
|
|
}
|
|
|
|
//
|
|
// Start / Reconfigure / Stop.
|
|
//
|
|
if (State == ENABLED) {
|
|
if (IsatapState == ENABLED) {
|
|
IsatapRefresh();
|
|
} else {
|
|
IsatapStart();
|
|
}
|
|
} else {
|
|
if (IsatapState == ENABLED) {
|
|
IsatapStop();
|
|
}
|
|
}
|
|
}
|