Bagikan melalui


Pengecualian Firewall yang Diperlukan untuk Teredo

Agar aplikasi menerima lalu lintas Teredo, aplikasi harus diizinkan untuk menerima lalu lintas IPv6 di firewall host, dan aplikasi diperlukan untuk mengatur opsi soket IPV6_PROTECTION_LEVEL ke 'PROTECTION_LEVEL_UNRESTRICTED'. Untuk mengaktifkan jenis skenario ini, pengecualian firewall yang dirinci dalam dokumen ini harus diimplementasikan.

Konfigurasi firewall berikut diperlukan untuk memastikan interoperatasi yang lancar antara firewall dan Teredo:

  • Firewall klien harus mengizinkan resolusi teredo.ipv6.microsoft.com.

  • Port UDP 3544 harus terbuka untuk memastikan bahwa klien Teredo dapat berhasil berkomunikasi dengan server Teredo.

  • Firewall harus mengambil port UDP dinamis yang digunakan oleh layanan Teredo pada komputer lokal dengan memanggil fungsiFwpmSystemPortsGet0; port yang relevan berjenis FWPM_SYSTEM_PORT_TEREDO. Fungsi FwpmSystemPortsGet0 harus diimplementasikan sebagai ganti fungsiGetTeredoPortGetTeredoPort yang sekarang tidak digunakan lagi atauNotifyTeredoPortChange.

  • Firewall mengizinkan sistem untuk mengirim dan menerima paket UDP/IPv4 ke port UDP 1900 pada subnet lokal karena ini memungkinkan lalu lintas penemuan UPnP mengalir dan berpotensi meningkatkan tingkat konektivitas.

    Nota

    Jika kondisi ini tidak terpenuhi, potensi skenario untuk mengalami masalah kompatibilitas yang melibatkan komunikasi antara jenis NAT tertentu diperkenalkan; khususnya antara NAT Simetris dan NAT Terbatas. Meskipun NAT Simetris populer di hotspot dan NAT Terbatas populer di rumah, komunikasi antara keduanya berpotensi kesalahan di sisi NAT Terbatas.

     

  • Pengecualian "Permintaan Echo" dan "Balasan Echo" ICMPv6 masuk dan keluar harus diaktifkan. Pengecualian ini diperlukan untuk memastikan bahwa klien Teredo dapat bertindak sebagai relai khusus host Teredo. Relai khusus host Teredo dapat diidentifikasi oleh alamat IPv6 asli tambahan atau alamat 6to4 yang disediakan dengan alamat Teredo.

Firewall klien harus mendukung pesan kesalahan ICMPv6 berikut dan fungsi penemuan per RFC 4443:

Kode Deskripsi
135/136 Ajakan dan Iklan Tetangga ICMPV6
133/134 Ajakan dan Iklan Router
128/129 Permintaan dan Balasan ICMPV6 Echo
1 Tujuan Tidak Dapat Dijangkau
2 Paket Terlalu Besar
3 Waktu Terlampaui
4 Parameter Tidak Valid

 

Jika pesan ini tidak dapat diizinkan secara khusus, maka pengecualian semua pesan ICMPv6 harus diaktifkan pada firewall. Selain itu, firewall host mungkin melihat bahwa paket yang diklasifikasikan oleh kode 135/136 atau 133/134 berasal, atau ditargetkan ke, layanan mode pengguna iphlpsvc dan bukan dari tumpukan. Paket ini tidak boleh dihilangkan oleh firewall host. Layanan Teredo diimplementasikan terutama dalam layanan Pembantu IP 'mode pengguna'.

Menggunakan INetFwPolicy2 Windows Firewall API untuk menghitung semua aturan dengan set bendera Edge Traversal, semua aplikasi yang ingin mendengarkan lalu lintas yang tidak diminta dijumlahkan untuk pengecualian firewall. Informasi spesifik mengenai penggunaan opsi Edge Traversal dirinci dalam Menerima Lalu Lintas yang Tidak Diminta Melalui Teredo.

Panggilan balik tidak terkait dengan kode enumerasi sampel berikut; sangat disarankan agar firewall pihak ketiga melakukan enumerasi secara berkala, atau setiap kali firewall mendeteksi aplikasi baru yang mencoba melalui firewall.

#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;
}