Teredo に必要なファイアウォール例外

アプリケーションが Teredo トラフィックを受信するには、アプリケーションがホスト ファイアウォールで IPv6 トラフィックを受信することを許可する必要があり、アプリケーションはソケット オプション IPV6_PROTECTION_LEVEL を "PROTECTION_LEVEL_UNRESTRICTED" に設定する必要があります。 この種のシナリオを有効にするには、このドキュメントで詳しく説明されているファイアウォール例外を実装する必要があります。

ファイアウォールと Teredo の間の円滑な相互運用を確保するには、次のファイアウォール構成が必要です。

  • クライアント ファイアウォールは、teredo.ipv6.microsoft.com の解決を許可する必要があります。

  • Teredo クライアントが Teredo サーバーと正常に通信できるようにするには、UDP ポート 3544 を開く必要があります。

  • ファイアウォールは 、FwpmSystemPortsGet0 関数を呼び出して、ローカル コンピューター上の Teredo サービスによって使用される動的 UDP ポートを取得する必要があります。関連するポートの種類は FWPM_SYSTEM_PORT_TEREDO です。 FwpmSystemPortsGet0 関数は、非推奨になった GetTeredoPort 関数または NotifyTeredoPortChange 関数の代わりに実装する必要があります。

  • ファイアウォールにより、システムはローカル サブネット上の UDP ポート 1900 に UDP/IPv4 パケットを送受信できます。これにより、UPnP 検出トラフィックのフローが可能になり、接続速度が向上する可能性があります。

    Note

    この条件が満たされない場合、特定の 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 Firewall API を使用して、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;
}