若要讓應用程式接收 Teredo 流量,應用程式必須能夠接收主機防火牆中的 IPv6 流量,而且應用程式必須將套接字選項 IPV6_PROTECTION_LEVEL 設定為 「PROTECTION_LEVEL_UNRESTRICTED」。 若要啟用這種類型的案例,必須實作本文件中詳述的防火牆例外狀況。
需要下列防火牆設定,以確保防火牆與 Teredo 之間的順暢互通:
用戶端防火牆必須允許解析 teredo.ipv6.microsoft.com。
UDP 埠 3544 必須開啟,以確保 Teredo 用戶端可以成功與 Teredo 伺服器通訊。
防火牆必須藉由呼叫 FwpmSystemPortsGet0 函式來擷取本機計算機上 Teredo 服務所使用的動態 UDP 埠;相關的埠類型為 FWPM_SYSTEM_PORT_TEREDO。 應該實作 FwpmSystemPortsGet0 函式,以取代現在已被取代 的 getTeredoPort 或 NotifyTeredoPortChange 函式。
防火牆允許系統將 UDP/IPv4 封包傳送和接收到本機子網上的 UDP 連接埠 1900,因為這樣可讓 UPnP 探索流量流動,並有可能改善連線率。
注意
如果不符合此條件,就會引入與特定NAT類型之間通訊相關的相容性問題的情況:特別是在對稱 NAT 與受限制的 NAT 之間。 雖然對稱 NAT 在熱點地區很受歡迎,但受限制的 NAT 在家庭中很受歡迎,但兩者之間的通訊有可能在受限制 NAT 的一邊發生錯誤。
必須啟用傳入和傳出ICMPv6「回應要求」和「回應回復」例外狀況。 這些例外狀況是必要的,以確保 Teredo 用戶端可以做為 Teredo 主機特定的轉送。 Teredo 主機特定轉送可由其他原生 IPv6 位址或 Teredo 位址提供的 6to4 位址來識別。
用戶端防火牆必須支援每個 RFC 4443 的下列 ICMPv6 錯誤訊息和探索函式:
| 法典 | 描述 |
|---|---|
| 135/136 | ICMPV6 芳鄰請求和廣告 |
| 133/134 | 路由器請求和公告 |
| 128/129 | ICMPV6 回應要求和回復 |
| 1 | 無法連線到目的地 |
| 2 | 封包太大 |
| 3 | 超過時間 |
| 4 | 無效的參數 |
如果無法特別允許這些訊息,則應在防火牆上啟用所有ICMPv6訊息的豁免。 此外,主機防火牆可能會注意到,依代碼 135/136 或 133/134 分類的封包源自使用者模式服務 iphlpsvc,而不是來自堆疊。 主機防火牆不得捨棄這些封包。 Teredo 服務主要是在「使用者模式」IP 協助程式服務內實作。
使用 INetFwPolicy2 Windows 防火牆 API 列舉已設定 Edge Traversal 旗標的所有規則,會列舉所有想要接聽未經請求流量的應用程式,以列舉防火牆例外狀況。 有關使用 Edge Traversal 選項的特定資訊詳述於 接收透過 Teredo的未請求流量。
回呼與下列範例列舉程式代碼無關;強烈建議第三方防火牆定期執行列舉,或每當防火牆偵測到嘗試通過防火牆的新應用程式時。
#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;
}