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 请求”和“回显回复”异常。 这些异常是必需的,以确保 Teredo 客户端可以充当 Teredo 主机特定的中继。 可通过附加本机 IPv6 地址或 Teredo 地址提供的 6to4 地址来标识 Teredo 主机特定的中继。
客户端防火墙必须支持每个 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 遍历标志,所有想要侦听未请求流量的应用程序都会枚举防火墙例外。 有关使用边缘遍历选项的具体信息,请参阅 在 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;
}