Exceptions de pare-feu requises pour Teredo
Pour qu’une application reçoive le trafic Teredo, l’application doit être autorisée à recevoir le trafic IPv6 dans le pare-feu hôte, et l’application doit définir l’option de socket IPV6_PROTECTION_LEVEL sur « PROTECTION_LEVEL_UNRESTRICTED ». Pour activer ce type de scénario, les exceptions de pare-feu détaillées dans ce document doivent être implémentées.
Les configurations de pare-feu suivantes sont requises pour garantir une interopérabilité fluide entre un pare-feu et Teredo :
Le pare-feu client doit autoriser la résolution de teredo.ipv6.microsoft.com.
Le port UDP 3544 doit être ouvert pour garantir que les clients Teredo peuvent communiquer avec le serveur Teredo.
Le pare-feu doit récupérer les ports UDP dynamiques utilisés par le service Teredo sur l’ordinateur local en appelant la fonction FwpmSystemPortsGet0 ; les ports pertinents sont de type FWPM_SYSTEM_PORT_TEREDO. La fonction FwpmSystemPortsGet0 doit être implémentée à la place des fonctions GetTeredoPort ou NotifyTeredoPortChange désormais dépréciées.
Le pare-feu permet au système d’envoyer et de recevoir des paquets UDP/IPv4 vers le port UDP 1900 sur le sous-réseau local, car cela permet au trafic de découverte UPnP de circuler et a le potentiel d’améliorer les taux de connectivité.
Notes
Si cette condition n’est pas remplie, la possibilité pour les scénarios de rencontrer des problèmes de compatibilité impliquant la communication entre certains types NAT est introduite ; spécifiquement entre les NAT symétriques et les NAT restreints. Bien que les NNA symétriques soient populaires dans les points d’accès privilégiés et que les NAT restreints soient populaires dans les foyers, la communication entre les deux peut être défaillante du côté du NAT restreint.
Les exceptions « Echo Request » et « Echo Reply » entrantes et sortantes ICMPv6 doivent être activées. Ces exceptions sont nécessaires pour garantir qu’un client Teredo peut agir en tant que relais spécifique à l’hôte Teredo. Un relais spécifique à l’hôte Teredo peut être identifié par l’adresse IPv6 native supplémentaire ou une adresse 6to4 fournie avec l’adresse Teredo.
Les pare-feu clients doivent prendre en charge les messages d’erreur ICMPv6 et les fonctions de découverte suivants selon RFC 4443 :
Code | Description |
---|---|
135/136 | Sollicitation et publicité des voisins ICMPV6 |
133/134 | Sollicitation de routeur et publicité |
128/129 | Demande et réponse D’écho ICMPV6 |
1 | Destination inaccessible |
2 | Paquet trop volumineux |
3 | Temps dépassé |
4 | Paramètre non valide |
Si ces messages ne peuvent pas être spécifiquement autorisés, l’exemption de tous les messages ICMPv6 doit être activée sur le pare-feu. En outre, le pare-feu hôte peut remarquer que les paquets classés par les codes 135/136 ou 133/134 proviennent du service de mode utilisateur iphlpsvc ou sont ciblés vers, et non de la pile. Ces paquets ne doivent pas être supprimés par le pare-feu hôte. Le service Teredo est implémenté principalement dans le service d’assistance IP « mode utilisateur ».
À l’aide de l’API de pare-feu Windows INetFwPolicy2 pour énumérer toutes les règles avec l’ensemble d’indicateurs Edge Traversal, toutes les applications qui souhaitent écouter le trafic non sollicité sont énumérées pour l’exception de pare-feu. Des informations spécifiques sur l’utilisation de l’option Edge Traversal sont détaillées dans Réception de trafic non sollicité sur Teredo.
Les rappels ne sont pas associés à l’exemple de code d’énumération suivant ; il est vivement recommandé que des pare-feu tiers effectuent l’énumération régulièrement, ou chaque fois que le pare-feu détecte une nouvelle application qui tente de passer par le pare-feu.
#include <windows.h>
#include <objbase.h>
#include <stdio.h>
#include <atlcomcli.h>
#include <strsafe.h>
#include <netfw.h>
#define NET_FW_IP_PROTOCOL_TCP_NAME L"TCP"
#define NET_FW_IP_PROTOCOL_UDP_NAME L"UDP"
#define NET_FW_RULE_DIR_IN_NAME L"In"
#define NET_FW_RULE_DIR_OUT_NAME L"Out"
#define NET_FW_RULE_ACTION_BLOCK_NAME L"Block"
#define NET_FW_RULE_ACTION_ALLOW_NAME L"Allow"
#define NET_FW_RULE_ENABLE_IN_NAME L"TRUE"
#define NET_FW_RULE_DISABLE_IN_NAME L"FALSE"
#import "netfw.tlb"
void DumpFWRulesInCollection(long Allprofiletypes, NetFwPublicTypeLib::INetFwRulePtr FwRule)
{
variant_t InterfaceArray;
variant_t InterfaceString;
if(FwRule->Profiles == Allprofiletypes)
{
wprintf(L"---------------------------------------------\n");
wprintf(L"Name: %s\n", (BSTR)FwRule->Name);
wprintf(L"Description: %s\n", (BSTR)FwRule->Description);
wprintf(L"Application Name: %s\n", (BSTR)FwRule->ApplicationName);
wprintf(L"Service Name: %s\n", (BSTR)FwRule->serviceName);
switch(FwRule->Protocol)
{
case NET_FW_IP_PROTOCOL_TCP: wprintf(L"IP Protocol: %s\n", NET_FW_IP_PROTOCOL_TCP_NAME);
break;
case NET_FW_IP_PROTOCOL_UDP: wprintf(L"IP Protocol: %s\n", NET_FW_IP_PROTOCOL_UDP_NAME);
break;
default:
break;
}
if(FwRule->Protocol != NET_FW_IP_VERSION_V4 && FwRule->Protocol != NET_FW_IP_VERSION_V6)
{
wprintf(L"Local Ports: %s\n", (BSTR)FwRule->LocalPorts);
wprintf(L"Remote Ports: %s\n", (BSTR)FwRule->RemotePorts);
}
wprintf(L"LocalAddresses: %s\n", (BSTR)FwRule->LocalAddresses);
wprintf(L"RemoteAddresses: %s\n", (BSTR)FwRule->RemoteAddresses);
wprintf(L"Profile: %d\n", Allprofiletypes);
if(FwRule->Protocol == NET_FW_IP_VERSION_V4 || FwRule->Protocol == NET_FW_IP_VERSION_V6)
{
wprintf(L"ICMP TypeCode: %s\n", (BSTR)FwRule->IcmpTypesAndCodes);
}
switch(FwRule->Direction)
{
case NET_FW_RULE_DIR_IN:
wprintf(L"Direction: %s\n", NET_FW_RULE_DIR_IN_NAME);
break;
case NET_FW_RULE_DIR_OUT:
wprintf(L"Direction: %s\n", NET_FW_RULE_DIR_OUT_NAME);
break;
default:
break;
}
switch(FwRule->Action)
{
case NET_FW_ACTION_BLOCK:
wprintf(L"Action: %s\n", NET_FW_RULE_ACTION_BLOCK_NAME);
break;
case NET_FW_ACTION_ALLOW:
wprintf(L"Action: %s\n", NET_FW_RULE_ACTION_ALLOW_NAME);
break;
default:
break;
}
InterfaceArray = FwRule->Interfaces;
if(InterfaceArray.vt != VT_EMPTY)
{
SAFEARRAY *pSa = NULL;
long index = 0;
pSa = InterfaceArray.parray;
for(long index= pSa->rgsabound->lLbound; index < (long)pSa->rgsabound->cElements; index++)
{
SafeArrayGetElement(pSa, &index, &InterfaceString);
wprintf(L"Interfaces: %s\n", (BSTR)InterfaceString.bstrVal);
}
}
wprintf(L"Interface Types: %s\n", (BSTR)FwRule->InterfaceTypes);
if(FwRule->Enabled)
{
wprintf(L"Enabled: %s\n", NET_FW_RULE_ENABLE_IN_NAME);
}
else
{
wprintf(L"Enabled: %s\n", NET_FW_RULE_DISABLE_IN_NAME);
}
wprintf(L"Grouping: %s\n", (BSTR)FwRule->Grouping);
wprintf(L"Edge: %s\n", (BSTR)FwRule->EdgeTraversal);
}
}
int __cdecl main()
{
HRESULT hr;
BOOL fComInitialized = FALSE;
ULONG cFetched = 0;
CComVariant var;
long Allprofiletypes = 0;
try
{
IUnknownPtr pEnumerator = NULL;
IEnumVARIANT* pVariant = NULL;
NetFwPublicTypeLib::INetFwPolicy2Ptr sipFwPolicy2;
//
// Initialize the COM library on the current thread.
//
hr = CoInitialize(NULL);
if (FAILED(hr))
{
_com_issue_error(hr);
}
fComInitialized = TRUE;
hr = sipFwPolicy2.CreateInstance("HNetCfg.FwPolicy2");
if (FAILED(hr))
{
_com_issue_error(hr);
}
Allprofiletypes = NET_FW_PROFILE2_ALL; // 0x7FFFFFFF
printf("The number of rules in the Windows Firewall are %d\n", sipFwPolicy2->Rules->Count);
pEnumerator = sipFwPolicy2->Rules->Get_NewEnum();
if(pEnumerator)
{
hr = pEnumerator->QueryInterface(__uuidof(IEnumVARIANT), (void **) &pVariant);
}
while(SUCCEEDED(hr) && hr != S_FALSE)
{
NetFwPublicTypeLib::INetFwRulePtr sipFwRule;
var.Clear();
hr = pVariant->Next(1, &var, &cFetched);
if (S_FALSE != hr)
{
if (SUCCEEDED(hr))
{
hr = var.ChangeType(VT_DISPATCH);
}
if (SUCCEEDED(hr))
{
hr = (V_DISPATCH(&var))->QueryInterface(__uuidof(INetFwRule), reinterpret_cast<void**>(&sipFwRule));
}
if (SUCCEEDED(hr))
{
DumpFWRulesInCollection(Allprofiletypes, sipFwRule);
}
}
}
}
catch(_com_error& e)
{
printf ("Error. HRESULT message is: %s (0x%08lx)\n", e.ErrorMessage(), e.Error());
if (e.ErrorInfo())
{
printf ("Description: %s\n", (char *)e.Description());
}
}
if (fComInitialized)
{
CoUninitialize();
}
return 0;
}