Pergunta

Eu tenho um aplicativo SIP que as necessidades para enviar pacotes UDP para configurar as chamadas SIP. SIP tem um mecanismo de tempo limite para lidar com falhas na entrega. Uma coisa adicional que eu gostaria de ser capaz de fazer é detectar se um socket UDP está fechado, a fim de ter que esperar os 32s retransmitir os usos SIP intervalo.

Os casos a que me refiro é quando uma tentativa de enviar a um soquete UDP resulta em um destino do pacote inacessível ICMP sendo gerado pelo host remoto. Se eu tentar enviar um pacote UDP para um host que está acontecendo, mas que a porta não está escutando Eu posso ver a mensagem ICMP chegar de volta com um traçador de pacotes, mas a questão é como faço para obter acesso ao que a partir de meu código C #?

Eu estou brincando com soquetes brutos, mas como ainda não ter sido capaz de obter os pacotes ICMP a ser recebido pelo meu programa. O exemplo abaixo nunca recebe um pacote mesmo que as mensagens ICMP são entrar no meu PC.

Socket icmpListener = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
icmpListener.Bind(new IPEndPoint(IPAddress.Any, 0));

byte[] buffer = new byte[4096];
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
int bytesRead = icmpListener.ReceiveFrom(buffer, ref remoteEndPoint);
logger.Debug("ICMPListener received " + bytesRead + " from " + remoteEndPoint.ToString());

Abaixo está um traço Wireshark mostrando as respostas ICMP que entram em meu PC a partir de uma tentativa de enviar um pacote UDP de 10.0.0.100 (meu PC) para 10.0.0.138 (meu roteador) em uma porta que eu sei que não é escutando. Meu problema é como fazer uso desses pacotes ICMP para realizar o envio UDP falhou em vez de apenas esperando para que o aplicativo de tempo limite após um período arbitrário?

respostas ICMP para UDP enviar

Foi útil?

Solução

Quase 3 anos depois e eu metida http://www.codeproject.com / artigos / 17031 / a-Network-Sniffer-in-C que me deu o suficiente de uma dica para me ajudar a encontrar uma solução para receber pacotes ICMP no Windows 7 (não sei sobre o Vista, que a pergunta original foi sobre, mas eu suspeito que esta solução iria trabalhar).

Os dois pontos-chave são de que a tomada tem de ser vinculado a um único endereço IP específico em vez de IPAddress.Any ea chamada IOControl que define o sinalizador SIO_RCVALL.

Socket icmpListener = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
icmpListener.Bind(new IPEndPoint(IPAddress.Parse("10.1.1.2"), 0));
icmpListener.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 });

byte[] buffer = new byte[4096];
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
int bytesRead = icmpListener.ReceiveFrom(buffer, ref remoteEndPoint);
Console.WriteLine("ICMPListener received " + bytesRead + " from " + remoteEndPoint);
Console.ReadLine();

Eu também tive que definir uma regra de firewall para permitir pacotes ICMP Porta inacessível a ser recebido.

netsh advfirewall firewall add rule name="All ICMP v4" dir=in action=allow protocol=icmpv4:any,any

Outras dicas

Icmp está usando um identificador que parece ser diferente para cada icmp "sessão" (para cada soquete icmp). Assim, o responder a um pacote ICMP não enviado pelo mesmo soquete é prestativamente filtrados para você. É por isso que esse pedaço de código não vai funcionar. (não tenho certeza sobre isso. É apenas uma suposição depois de olhar para algum tráfego ICMP.)

Você poderia simplesmente ping no host e veja se você pode alcançá-lo ou não e, em seguida, tentar a sua coisa SIP. No entanto isso não vai funcionar se o outro host está filtrando icmp.

Uma solução feia (mas de trabalho) está usando winpcap . (Tendo isso como as soluções única de trabalho apenas parece ser muito ruim para ser verdade.)

O que quero dizer usando winpcap é o que você poderia captura o tráfego ICMP e depois ver se o pacote capturado é sobre o seu pacote UDP sendo não entregues ou não .

Aqui está um exemplo para capturar pacotes TCP: http://www.tamirgal.com/home/ SourceView.aspx? item = SharpPcap & File = Example6.DumpTCP.cs (Não deve ser muito difícil de fazer o mesmo com ICMP).

UPDATE: Eu acho que eu estou ficando louco .... Aquele pedaço de código que você postou também está trabalhando para mim ...

O seguinte trecho de código funciona bem para mim (XP SP3):

using System;
using System.Net;
using System.Net.Sockets;

namespace icmp_capture
{
    class Program
    {
        static void Main(string[] args)
        {            
            IPEndPoint ipMyEndPoint = new IPEndPoint(IPAddress.Any, 0);
            EndPoint myEndPoint = (ipMyEndPoint);
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);            
            socket.Bind(myEndPoint);
            while (true)
            {

                /*                
                //SEND SOME BS (you will get a nice infinite loop if you uncomment this)
                var udpClient = new UdpClient("192.168.2.199", 666);   //**host must exist if it's in the same subnet (if not routed)**              
                Byte[] messagebyte = Encoding.Default.GetBytes("hi".ToCharArray());                
                int s = udpClient.Send(messagebyte, messagebyte.Length);
                */

                Byte[] ReceiveBuffer = new Byte[256];
                var nBytes = socket.ReceiveFrom(ReceiveBuffer, 256, 0, ref myEndPoint);
                if (ReceiveBuffer[20] == 3)// ICMP type = Delivery failed
                {
                    Console.WriteLine("Delivery failed");
                    Console.WriteLine("Returned by: " + myEndPoint.ToString());
                    Console.WriteLine("Destination: " + ReceiveBuffer[44] + "." + ReceiveBuffer[45] + "." + ReceiveBuffer[46] + "." + ReceiveBuffer[47]);
                    Console.WriteLine("---------------");
                }
                else {
                    Console.WriteLine("Some (not delivery failed) ICMP packet ignored");
                }
            }

        }
    }
}

Apenas uso conectado udp soquetes e o sistema operacional irá coincidir com o ICMP inacessível e retornar um erro no soquete udp.

O Google para sockets UDP conectados.

Há uma série de posts sobre a web mencionar o problema de pacotes ICMP Porta inacessível não ser mais acessível no Vista.

A pilha deve lhe dar de volta uma exceção quando recebe o ICMP. Mas isso não acontece, pelo menos no Vista. E, portanto, você está tentando uma solução alternativa.

Eu não gosto de respostas que dizem que não é possível, mas parece que maneira. Então eu sugiro que você volte um passo para o problema original, que era longos tempos de espera em SIP.

  • Você poderia permitir que o usuário configure o tempo limite (daí tipo de cumprimento a especificação).
  • Você pode começar a fazer outras coisas (como a verificação de outros proxies) antes as extremidades tempo de espera.
  • Você pode armazenar em cache conhecidos destinos ruins (mas que seria necessário boa gestão do cache.
  • Se icmp, e udp não dão mensagens de erro adequadas, tente tcp ou outro protocolo. Apenas para obter a informação desejada.

(Tudo é possível, ele só pode ter um monte de recursos.)

Estou escrevendo isso como uma resposta em separado, uma vez que os detalhes são completamente diferentes da que eu escrevi anteriormente.

Assim, com base no comentário de Kalmi sobre o ID da sessão, ele me levou a pensar sobre por que eu pode abrir dois programas de ping na mesma máquina, e as respostas não atravessar. Eles são ambos ICMP, por conseguinte, tanto usando bases de porta-menos em bruto. Isso significa algo na pilha IP, tem que saber o soquete essas respostas foram destinados. Para pingue verifica-se há um ID usado nos dados do pacote ICMP como parte do Echo Request e Echo Reply.

Então eu corri através deste comentário na wikipedia sobre ICMP :

Embora as mensagens ICMP são contidos em datagramas IP padrão, ICMP mensagens são normalmente processados ??como um caso especial, que se distingue de normal de IP de processamento, em vez de processados ??tal como uma sub-protocolo normal IP. Em muitos casos, é necessário inspeccionar o conteúdo do ICMP mensagem e entregar o apropriado mensagem de erro para o aplicativo que gerou o pacote IP original, o aquele que for solicitado o envio do ICMP mensagem.

Qual foi elaborado com (indiretamente) aqui :

A Internet cabeçalho mais o primeiro 64 bits de dados do datagrama original. Esta informação é usada pelo host para corresponder a mensagem para o apropriado processo. Se um protocolo de nível mais elevado utiliza números de porta, que são assumidos estar nos primeiros 64 bits de dados do dados do datagrama original.

Uma vez que você estiver usando UDP, que utiliza as portas, é possível que a pilha de rede está a encaminhar a mensagem de volta ICMP à tomada originais. É por isso que o seu novo e separado, tomada não está recebendo essas mensagens. Imagino come UDP a mensagem ICMP.

Se eu estiver correto, uma solução para isso é abrir um socket raw e criar manualmente seus pacotes UDP, ouça o nada voltando, e lidar com mensagens UDP e ICMP, conforme apropriado. Não tenho a certeza que isso seria semelhante no código, mas eu não imagino que seria muito difícil, e pode ser considerado mais "elegante" do que a solução winpcap.

Além disso, esse link, http://www.networksorcery.com/enp/default1003.htm , parece ser um grande recurso para protocolos de rede de baixo nível.

Espero que isso ajude.

Então você quer pegar o dest pacote ICMP retorno inacessível por meio de programação? Uma pergunta difícil. Eu diria que as imersões pilha de rede que antes que você pode começar em qualquer lugar perto dele.

Eu não acho que um # abordagem C pura vai funcionar aqui. Você vai precisar usar um interceptar nível de driver para obter um gancho no. Dê uma olhada neste app que ipfiltdrv.sys utilizações Windows para pacotes de trap (ICMP, TCP, UDP, etc) e ler / jogar com eles com código gerenciado ( c #).

http://www.codeproject.com/KB/IP /firewall_sniffer.aspx?display=Print

  • Oisin
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top