Teredo 的必要防火牆例外狀況
若要讓應用程式接收 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 「Echo Request」 和 「Echo Reply」 例外狀況。 這些例外狀況是確保 Teredo 用戶端可以做為 Teredo 主機特定轉送的必要條件。 Teredo 主機特定轉寄可由其他原生 IPv6 位址或 Teredo 位址提供的 6to4 位址來識別。
用戶端防火牆必須支援下列 ICMPv6 錯誤訊息和每個 RFC 4443 的探索函式:
程式碼 | 描述 |
---|---|
135/136 | ICMPV6 芳鄰要求和廣告 |
133/134 | 路由器要求和公告 |
128/129 | ICMPV6 回應要求和回復 |
1 | 目的地無法連線 |
2 | 封包太大 |
3 | 超過時間 |
4 | 不正確參數 |
如果無法特別允許這些訊息,則應在防火牆上啟用所有 ICMPv6 訊息的豁免。 此外,主機防火牆可能會注意到由代碼 135/136 或 133/134 所分類的封包源自使用者模式服務 iphlpsvc ,而不是來自堆疊。 主機防火牆不得卸載這些封包。 Teredo 服務主要是在「使用者模式」IP 協助程式服務內實作。
使用 INetFwPolicy2 Windows 防火牆 API 列舉所有規則並設定 Edge 周遊旗標,則會列舉所有想要接聽未經要求流量的應用程式,以取得防火牆例外狀況。 有關使用 Edge 周遊選項的特定資訊詳述于 接收透過 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;
}