windows-nt/Source/XPSP1/NT/net/tcpip/tpipv6/6to4svc/teredo.h

838 lines
18 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 2001-2002 Microsoft Corporation
Module Name:
teredo.h
Abstract:
This module contains the teredo client and server (cum relay) state.
Author:
Mohit Talwar (mohitt) Mon Oct 22 15:17:48 2001
Environment:
User mode only.
--*/
#ifndef _TEREDO_
#define _TEREDO_
#pragma once
//
// IP6_HDR
//
// Define the RFC 2292 structure for an IPv6 header.
//
typedef struct _IP6_HDR {
union {
struct ip6_hdrctl {
UINT32 ip6_un1_flow; // 20 bits of flow-ID
UINT16 ip6_un1_plen; // payload length
UINT8 ip6_un1_nxt; // next header
UINT8 ip6_un1_hlim; // hop limit
} ip6_un1;
UINT8 ip6_un2_vfc; // 4 bits version, 4 bits priority
} ip6_ctlun;
IN6_ADDR ip6_src; // source address
IN6_ADDR ip6_dest; // destination address
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
} IP6_HDR, *PIP6_HDR;
#define IPV6_VERSION 0x60 // This is 6 << 4
#define IPV6_TEREDOMTU 1280
#define IPV6_INFINITE_LIFETIME 0xffffffff
#define IPPROTO_NONE 59
//
// HASHTABLE
//
// Define a simple, statically sized, locked hash table.
// Each bucket is a doubly linked LRU list.
//
#define BUCKET_COUNT 29 // # buckets in the hash table
typedef struct _HASHTABLE {
CRITICAL_SECTION Lock; // Protects the table and entries.
ULONG Size; // # entries in the hash table
LIST_ENTRY Bucket[BUCKET_COUNT];
} HASHTABLE, *PHASHTABLE;
//
// TEREDO_TYPE
//
// Define the type of the teredo service.
//
typedef enum {
TEREDO_DEFAULT = 0,
TEREDO_CLIENT,
TEREDO_SERVER,
TEREDO_DISABLE,
TEREDO_MAXIMUM,
} TEREDO_TYPE, *PTEREDO_TYPE;
//
// TEREDO_PACKET_TYPE
//
// Define the type of a teredo packet.
//
typedef enum {
TEREDO_PACKET_READ, // Data read from TUN device.
TEREDO_PACKET_WRITE, // Data written to TUN device.
TEREDO_PACKET_BUBBLE, // Bubble transmitted on UDP socket.
TEREDO_PACKET_BOUNCE, // Packet bounced on UDP socket.
TEREDO_PACKET_RECEIVE, // Packet received on UDP socket.
TEREDO_PACKET_TRANSMIT, // Packet transmitted on UDP socket.
TEREDO_PACKET_MULTICAST, // Multicast bubble transmitted on UDP socket.
TEREDO_PACKET_MAX,
} TEREDO_PACKET_TYPE, *PTEREDO_PACKET_TYPE;
//
// TEREDO_PACKET
//
// Define a teredo packet.
// The packet structure is followed in memory by the packet's data buffer.
//
typedef struct _TEREDO_PACKET {
#if DBG
ULONG Signature; // TEREDO_PACKET_SIGNATURE
#endif // DBG
OVERLAPPED Overlapped; // For asynchronous completion.
TEREDO_PACKET_TYPE Type; // Packet type.
SOCKADDR_IN SocketAddress; // Peer we are in communication with.
UINT SocketAddressLength; // Length of the peer's socket address.
WSABUF Buffer; // Packet buffer and length.
DWORD Flags; // Flags required during sends and receives.
} TEREDO_PACKET, *PTEREDO_PACKET;
#define TEREDO_PACKET_BUFFER(Packet) \
((PUCHAR) (((PTEREDO_PACKET) (Packet)) + 1))
typedef
VOID
(TEREDO_REFERENCE)(
VOID
);
typedef TEREDO_REFERENCE *PTEREDO_REFERENCE;
typedef
VOID
(TEREDO_DEREFERENCE)(
VOID
);
typedef TEREDO_DEREFERENCE *PTEREDO_DEREFERENCE;
typedef
VOID
(TEREDO_PACKET_IO_COMPLETE)(
IN DWORD Error,
IN ULONG Bytes,
IN PTEREDO_PACKET Packet
);
typedef TEREDO_PACKET_IO_COMPLETE *PTEREDO_PACKET_IO_COMPLETE;
//
// TEREDO_STATE_TYPE
//
// Define the protocol state values of the teredo client service.
//
typedef enum {
TEREDO_STATE_OFFLINE,
TEREDO_STATE_PROBE,
TEREDO_STATE_QUALIFIED,
TEREDO_STATE_ONLINE,
} TEREDO_STATE_TYPE, *PTEREDO_STATE_TYPE;
//
// TEREDO_IO
//
// Define teredo I/O state.
// NOTE: All addresses and ports are stored in network byte order.
//
typedef struct _TEREDO_IO {
#if DBG
ULONG Signature; // TEREDO_PACKET_SIGNATURE
#endif // DBG
HANDLE PacketHeap; // Head for allocating teredo packets.
ULONG PostedReceives; // Count of posted receives.
HANDLE ReceiveEvent; // Event signalled upon a receive notification.
HANDLE ReceiveEventWait; // Wait registered for ReceiveEvent.
IN_ADDR Group; // Group joined on the native interface.
SOCKADDR_IN ServerAddress; // Teredo server IPv4 address and UDP port.
SOCKADDR_IN SourceAddress; // Preferred source address to teredo server.
SOCKET Socket; // Socket bound to SourceAddress on a UDP port.
HANDLE TunnelDevice; // Interface to the TUNNEL driver.
WCHAR TunnelInterface[MAX_ADAPTER_NAME_LENGTH];
//
// Function handlers.
//
PTEREDO_REFERENCE Reference;
PTEREDO_DEREFERENCE Dereference;
LPOVERLAPPED_COMPLETION_ROUTINE IoCompletionCallback;
} TEREDO_IO, *PTEREDO_IO;
//
// TEREDO_CLIENT_STATE
//
// Define the global state of the teredo client service.
//
// References:
// - One for initialization.
// - One for any running timer.
// - One for each teredo peer.
// - One for each teredo packet
// - One for "the" multicast bubble. At most one outstanding bubble allowed.
// (reads, writes posted on TunDevice & receives, transmits posted on Socket).
//
typedef struct _TEREDO_CLIENT_STATE {
ULONG ReferenceCount; // Number of outstanding references.
TEREDO_IO Io; // I/O state. TUN device and UDP socket.
HANDLE PeerHeap; // Heap for allocating teredo peers.
HANDLE Timer; // One shot timer active in Probe & Qualified.
HANDLE TimerEvent; // Event signalled upon timer deletion.
HANDLE TimerEventWait; // Wait registered for TimerEvent.
BOOL RestartQualifiedTimer; // When NAT mapping is created or refreshed.
LONG Time; // Current time (in seconds).
TEREDO_STATE_TYPE State; // Teredo client service protocol state.
IN6_ADDR Ipv6Prefix; // Teredo IPv6 prefix advertised by server.
ULONG RefreshInterval; // Expected lifetime of client's NAT mapping.
HASHTABLE PeerSet; // Locked set of recent teredo peers.
ULONG BubbleTicks; // "RefreshInterval" ticks until next bubble.
BOOL BubblePosted; // Whether there is any outstanding bubble.
TEREDO_PACKET Packet; // Teredo multicast bubble packet.
IP6_HDR Bubble; // Teredo multicast bubble packet buffer.
} TEREDO_CLIENT_STATE, *PTEREDO_CLIENT_STATE;
//
// TEREDO_SERVER_STATE
//
// Define the global state of the teredo server service.
//
// References:
// - One for initialization.
// - One for each teredo packet
// (reads, writes posted on TunDevice & receives, transmits posted on Socket).
//
typedef struct _TEREDO_SERVER_STATE {
ULONG ReferenceCount; // Number of outstanding references.
TEREDO_IO Io; // I/O state. TUN device and UDP socket.
TEREDO_STATE_TYPE State; // Teredo server service protocol state.
} TEREDO_SERVER_STATE, *PTEREDO_SERVER_STATE;
//
// TEREDO_PEER
//
// Define a teredo peer's state.
//
// References:
// - One for initialization.
// - One for "the" posted bubble. At most one outstanding bubble is allowed.
//
// Synchronization:
// - Link: Protected by PeerSet::Lock.
// - ReferenceCount: InterlockedIncrement, InterlockedDecrement.
// - LastReceive, LastTransmit: Atomic reads and writes.
// - BubbleCount: Single writer! Atomic reads.
// - BubblePosted: InterlockedExchange.
// - Remaining Fields: Read only.
//
typedef struct _TEREDO_PEER {
#if DBG
ULONG Signature; // TEREDO_PEER_SIGNATURE
#endif // DBG
LIST_ENTRY Link; // Linkage within the PeerSet.
ULONG ReferenceCount; // Number of outstanding references.
LONG LastReceive; // Time of last reception from the peer.
LONG LastTransmit; // Time of last transmission to the peer.
IN6_ADDR Address; // Teredo IPv6 address of the peer.
ULONG BubbleCount; // Number of bubbles transmitted to the peer.
BOOL BubblePosted; // Whether there is any outstanding bubble.
TEREDO_PACKET Packet; // Teredo bubble packet.
IP6_HDR Bubble; // Teredo bubble packet buffer.
} TEREDO_PEER, *PTEREDO_PEER;
//
// Cast and Signature Verification
//
#define TEREDO_IO_SIGNATURE 'oIhS' // 'ShIo'
#define TEREDO_PEER_SIGNATURE 'ePhS' // 'ShPe'
#define TEREDO_PACKET_SIGNATURE 'aPhS' // 'ShPa'
//
// A NULL handle is considered a valid structure.
//
#define Cast(Pointer, TYPE) \
((TYPE *) (Pointer)); \
ASSERT(!(Pointer) || \
(((TYPE *) (Pointer))->Signature == TYPE##_SIGNATURE))
//
// Lower and upper limits on number of posted reads or receives.
//
#define TEREDO_LOW_WATER_MARK 5 // Receives or Reads.
#define TEREDO_HIGH_WATER_MARK 256 // Receives. Reads are fixed.
//
// Intervals used by the protocol.
//
#define INFINITE_INTERVAL 0x7fffffff
#define TEREDO_RESOLVE_INTERVAL 15 * MINUTES
#define TEREDO_PROBE_INTERVAL 15 * SECONDS
#define TEREDO_REFRESH_INTERVAL 30 * SECONDS
#define TEREDO_MULTICAST_BUBBLE_TICKS 0 // In RefreshInterval units.
#define TEREDO_BUBBLE_INTERVAL 10 * SECONDS
#define TEREDO_SLOW_BUBBLE_INTERVAL 5 * MINUTES
#define TEREDO_BUBBLE_THRESHHOLD 2 * MINUTES
#define TEREDO_ROUTER_LIFETIME 5 * HOURS
//
// Teredo multicast bubbles are sent to group 224.0.0.252 on port 337.
//
#define TEREDO_MULTICAST_PREFIX \
{ 0x20, 0x03, 0xe0, 0x00, 0x00, 0xfc, 0x01, 0x51, }
#define TEREDO_DEFAULT_TYPE TEREDO_DISABLE
#define TEREDO_PORT htons(337)
#define TEREDO_SERVER_NAME L"teredo.ipv6.microsoft.com"
#define TEREDO_SERVICE_PREFIX { 0x20, 0x03, }
#define KEY_TEREDO_REFRESH_INTERVAL L"RefreshInterval"
#define KEY_TEREDO_TYPE L"Type"
#define KEY_TEREDO_SERVER_NAME L"ServerName"
#define KEY_TEREDO L"System\\CurrentControlSet\\Services\\Teredo"
//
// Configured parameters.
//
extern ULONG TeredoClientRefreshInterval;
extern BOOL TeredoClientEnabled;
extern BOOL TeredoServerEnabled;
extern WCHAR TeredoServerName[NI_MAXHOST];
extern WCHAR TeredoServiceName[NI_MAXSERV];
extern CONST IN6_ADDR TeredoIpv6ServicePrefix;
extern CONST IN6_ADDR TeredoIpv6MulticastPrefix;
extern TEREDO_CLIENT_STATE TeredoClient;
extern TEREDO_SERVER_STATE TeredoServer;
//
// Time.
//
__inline
LONG
TeredoGetTime(
VOID
)
{
//
// GetTickCount retrieves time in milliseconds.
//
return (GetTickCount() / 1000);
}
#define TIME_GREATER(a, b) (((a) - (b)) > 0)
//
// Address validation and parsing.
//
__inline
BOOL
IN4_MULTICAST(IN_ADDR a)
{
return ((a.s_addr & 0x0000000f) == 0x0000000e);
}
_inline
BOOL
IN4_ADDR_EQUAL(IN_ADDR a, IN_ADDR b)
{
return (a.s_addr == b.s_addr);
}
_inline
BOOL
IN4_SOCKADDR_EQUAL(CONST SOCKADDR_IN *a, CONST SOCKADDR_IN *b)
{
ASSERT((a->sin_family == AF_INET) && (b->sin_family == AF_INET));
return (IN4_ADDR_EQUAL(a->sin_addr, b->sin_addr) &&
(a->sin_port == b->sin_port));
}
__inline
BOOL
TeredoIpv6GlobalAddress(
IN CONST IN6_ADDR *Address
)
/*++
Routine Description:
Determine whether the supplied IPv6 address is of global unicast scope.
--*/
{
//
// This can be coded quite a bit more efficiently!
//
if (IN6_IS_ADDR_UNSPECIFIED(Address) ||
IN6_IS_ADDR_LOOPBACK(Address) ||
IN6_IS_ADDR_MULTICAST(Address) ||
IN6_IS_ADDR_LINKLOCAL(Address) ||
IN6_IS_ADDR_SITELOCAL(Address)) {
return FALSE;
}
return TRUE;
}
__inline
BOOL
TeredoIpv4GlobalAddress(
IN CONST UCHAR *Address
)
/*++
Routine Description:
Determine whether the supplied IPv4 address is of global unicast scope.
--*/
{
if ((Address[0] > 223) || // ~Unicast
(Address[0] == 0) || // 0/8
(Address[0] == 127) || // 127/8
(Address[0] == 10) || // 10/8
((Address[0] == 169) && (Address[1] == 254)) || // 169.254/16
((Address[0] == 172) && ((Address[1] & 0xf0) == 16)) || // 172.16/12
((Address[0] == 192) && (Address[1] == 168))) { // 192.168/16
return FALSE;
}
return TRUE;
}
__inline
BOOL
TeredoServicePrefix(
IN CONST IN6_ADDR *Address
)
{
return (Address->s6_words[0] == TeredoIpv6ServicePrefix.s6_words[0]);
}
__inline
BOOL
TeredoValidAdvertisedPrefix(
IN CONST IN6_ADDR *Address,
IN UCHAR Length
)
{
if (Length != 64) {
return FALSE;
}
if (!TeredoServicePrefix(Address)) {
return FALSE;
}
if (!TeredoIpv4GlobalAddress((PUCHAR) (Address->s6_words + 1))) {
return FALSE;
}
return TRUE;
}
__inline
VOID
TeredoParseAddress(
IN CONST IN6_ADDR *Address,
OUT PIN_ADDR Ipv4Address,
OUT PUSHORT Ipv4Port
)
{
ASSERT(TeredoServicePrefix(Address));
//
// These are returned in network byte order.
//
((PUSHORT) Ipv4Address)[0] = Address->s6_words[1];
((PUSHORT) Ipv4Address)[1] = Address->s6_words[2];
*Ipv4Port = Address->s6_words[3];
}
__inline
BOOL
TeredoEqualPrefix(
IN CONST IN6_ADDR *Address1,
IN CONST IN6_ADDR *Address2
)
{
//
// Compare Teredo IPv6 Service Prefix, Mapped IPv4 Address and Port.
//
return ((Address1->s6_words[0] == Address2->s6_words[0]) &&
(Address1->s6_words[1] == Address2->s6_words[1]) &&
(Address1->s6_words[2] == Address2->s6_words[2]) &&
(Address1->s6_words[3] == Address2->s6_words[3]));
}
//
// Client API
//
DWORD
TeredoInitializeClient(
VOID
);
VOID
TeredoUninitializeClient(
VOID
);
VOID
TeredoCleanupClient(
VOID
);
__inline
VOID
TeredoReferenceClient(
VOID
)
{
ASSERT(TeredoClient.ReferenceCount > 0);
InterlockedIncrement(&(TeredoClient.ReferenceCount));
}
__inline
VOID
TeredoDereferenceClient(
VOID
)
{
ASSERT(TeredoClient.ReferenceCount > 0);
if (InterlockedDecrement(&(TeredoClient.ReferenceCount)) == 0) {
TeredoCleanupClient();
}
}
VOID
TeredoStartClient(
VOID
);
VOID
TeredoStopClient(
VOID
);
VOID
TeredoProbeClient(
VOID
);
VOID
TeredoQualifyClient(
VOID
);
VOID
TeredoClientAddressDeletionNotification(
IN IN_ADDR Address
);
VOID
TeredoClientRefreshIntervalChangeNotification(
VOID
);
//
// Server API
//
DWORD
TeredoInitializeServer(
VOID
);
VOID
TeredoUninitializeServer(
VOID
);
VOID
TeredoCleanupServer(
VOID
);
__inline
VOID
TeredoReferenceServer(
VOID
)
{
ASSERT(TeredoServer.ReferenceCount > 0);
InterlockedIncrement(&(TeredoServer.ReferenceCount));
}
__inline
VOID
TeredoDereferenceServer(
VOID
)
{
ASSERT(TeredoServer.ReferenceCount > 0);
if (InterlockedDecrement(&(TeredoServer.ReferenceCount)) == 0) {
TeredoCleanupServer();
}
}
VOID
TeredoStartServer(
VOID
);
VOID
TeredoStopServer(
VOID
);
VOID
TeredoServerAddressDeletionNotification(
IN IN_ADDR Address
);
//
// Common API
//
DWORD
TeredoInitializeGlobals(
VOID
);
VOID
TeredoUninitializeGlobals(
VOID
);
VOID
TeredoAddressChangeNotification(
IN BOOL Delete,
IN IN_ADDR Address
);
VOID
TeredoConfigurationChangeNotification(
VOID
);
VOID
WINAPI
TeredoWmiEventNotification(
IN PWNODE_HEADER Event,
IN UINT_PTR Context
);
//
// Peer API.
//
DWORD
TeredoInitializePeerSet(
VOID
);
VOID
TeredoUninitializePeerSet(
VOID
);
VOID
TeredoCleanupPeerSet(
VOID
);
PTEREDO_PEER
TeredoFindOrCreatePeer(
IN CONST IN6_ADDR *Address
);
VOID
TeredoDestroyPeer(
IN PTEREDO_PEER Peer
);
__inline
VOID
TeredoReferencePeer(
IN PTEREDO_PEER Peer
)
{
ASSERT(Peer->ReferenceCount > 0);
InterlockedIncrement(&(Peer->ReferenceCount));
}
__inline
VOID
TeredoDereferencePeer(
IN PTEREDO_PEER Peer
)
{
ASSERT(Peer->ReferenceCount > 0);
if (InterlockedDecrement(&(Peer->ReferenceCount)) == 0) {
TeredoDestroyPeer(Peer);
}
}
//
// I/O API.
//
DWORD
TeredoInitializeIo(
IN PTEREDO_IO TeredoIo,
IN IN_ADDR Group,
IN PTEREDO_REFERENCE Reference,
IN PTEREDO_DEREFERENCE Dereference,
IN LPOVERLAPPED_COMPLETION_ROUTINE IoCompletionCallback
);
VOID
TeredoCleanupIo(
IN PTEREDO_IO TeredoIo
);
DWORD
TeredoStartIo(
IN PTEREDO_IO TeredoIo
);
DWORD
TeredoRefreshSocket(
IN PTEREDO_IO TeredoIo
);
VOID
TeredoStopIo(
IN PTEREDO_IO TeredoIo
);
__inline
VOID
TeredoInitializePacket(
IN PTEREDO_PACKET Packet
)
{
#if DBG
Packet->Signature = TEREDO_PACKET_SIGNATURE;
#endif // DBG
ZeroMemory(&(Packet->SocketAddress), sizeof(SOCKADDR_IN));
Packet->SocketAddress.sin_family = AF_INET;
Packet->SocketAddressLength = sizeof(SOCKADDR_IN);
Packet->Flags = 0;
Packet->Buffer.buf = TEREDO_PACKET_BUFFER(Packet);
}
ULONG
TeredoPostReceives(
IN PTEREDO_IO TeredoIo,
IN PTEREDO_PACKET Packet
);
PTEREDO_PACKET
TeredoTransmitPacket(
IN PTEREDO_IO TeredoIo,
IN PTEREDO_PACKET Packet
);
BOOL
TeredoPostRead(
IN PTEREDO_IO TeredoIo,
IN PTEREDO_PACKET Packet OPTIONAL
);
PTEREDO_PACKET
TeredoWritePacket(
IN PTEREDO_IO TeredoIo,
IN PTEREDO_PACKET Packet
);
//
// Utility Functions.
//
ICMPv6Header *
TeredoParseIpv6Headers(
IN PUCHAR Buffer,
IN ULONG Bytes
);
#endif // _TEREDO_