Compartilhar via


Exceções de firewall necessárias para Teredo

Para que um aplicativo receba o tráfego teredo, o aplicativo deve ter permissão para receber tráfego IPv6 no firewall do host e o aplicativo é necessário para definir a opção de soquete IPV6_PROTECTION_LEVEL como "PROTECTION_LEVEL_UNRESTRICTED". Para habilitar esse tipo de cenário, as exceções de firewall detalhadas neste documento devem ser implementadas.

As seguintes configurações de firewall são necessárias para garantir uma interoperação suave entre um firewall e o Teredo:

  • O firewall do cliente deve permitir a resolução de teredo.ipv6.microsoft.com.

  • A porta UDP 3544 deve estar aberta para garantir que os clientes teredo possam se comunicar com êxito com o servidor Teredo.

  • O firewall deve recuperar portas UDP dinâmicas usadas pelo serviço Teredo no computador local chamando a função FwpmSystemPortsGet0 ; as portas relevantes são do tipo FWPM_SYSTEM_PORT_TEREDO. A função FwpmSystemPortsGet0 deve ser implementada no lugar das funções GetTeredoPort ou NotifyTeredoPortChange preteridas.

  • O firewall permite que o sistema envie e receba pacotes UDP/IPv4 para a porta UDP 1900 na sub-rede local, pois isso permite que o tráfego de descoberta UPnP flua e tenha o potencial de melhorar as taxas de conectividade.

    Observação

    Se essa condição não for atendida, será introduzido o potencial de cenários encontrarem problemas de compatibilidade envolvendo a comunicação entre determinados tipos NAT; especificamente entre NATs simétricas e NATs restritas. Embora NATs simétricas sejam populares em hotspots e NATs restritos sejam populares em casas, a comunicação entre os dois tem o potencial de falhar na lateral da NAT Restrita.

     

  • As exceções de entrada e saída do ICMPv6 "Solicitação de Eco" e "Resposta de Eco" devem ser habilitadas. Essas exceções são necessárias para garantir que um cliente Teredo possa atuar como uma retransmissão específica do host teredo. Uma retransmissão específica do host teredo pode ser identificada pelo endereço IPv6 nativo adicional ou um endereço 6to4 fornecido com o endereço Teredo.

Os firewalls do cliente devem dar suporte às seguintes mensagens de erro ICMPv6 e funções de descoberta por RFC 4443:

Código Descrição
135/136 Solicitação e anúncio do vizinho ICMPV6
133/134 Solicitação e Anúncio do Roteador
128/129 Solicitação e resposta de eco ICMPV6
1 Destino Inacessível
2 Pacote muito grande
3 Tempo Excedido
4 Parâmetro inválido

 

Se essas mensagens não puderem ser permitidas especificamente, a isenção de todas as mensagens ICMPv6 deverá ser habilitada no firewall. Além disso, o firewall do host pode observar que os pacotes classificados pelos códigos 135/136 ou 133/134 se originam ou são direcionados para o iphlpsvc do serviço de modo de usuário e não da pilha. Esses pacotes não devem ser descartados pelo firewall do host. O serviço Teredo é implementado principalmente no serviço auxiliar de IP do "modo de usuário".

Usando a API de Firewall do Windows INetFwPolicy2 para enumerar todas as regras com o conjunto de sinalizadores do Edge Traversal, todos os aplicativos que desejam escutar o tráfego não solicitado são enumerados para a exceção de firewall. Informações específicas sobre o uso da opção Passagem de Borda são detalhadas em Recebendo tráfego não solicitado sobre Teredo.

Os retornos de chamada não estão associados ao código de enumeração de exemplo a seguir; É altamente recomendável que firewalls de terceiros executem a enumeração periodicamente ou sempre que o firewall detecta um novo aplicativo tentando passar pelo 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;
}