2009-03-09 3 views
7

SIP 호출을 설정하기 위해 UDP 패킷을 보내야하는 SIP 응용 프로그램이 있습니다. SIP에는 전달 실패에 대처할 수있는 시간 초과 메커니즘이 있습니다. 추가적으로 제가 할 수있는 일은 SIP가 사용하는 32s 재전송 간격을 기다리기 위해 UDP 소켓이 닫혔는지 여부를 감지하는 것입니다.C#에서 ICMP 패킷 수신

내가 언급 한 경우는 UDP 소켓으로 보내려는 시도가 원격 호스트에서 ICMP Destination Unreachable 패킷을 생성하는 경우입니다. UDP 패킷을 호스트에 보내려고 시도하지만 포트가 수신 대기하지 않는다면 패킷 추적기로 다시 도착하는 ICMP 메시지를 볼 수는 있지만 질문은 어떻게하면 C# 코드에서 액세스 할 수 있습니까?

나는 원시 소켓으로 놀고 있지만 아직 ICMP 패킷을 내 프로그램에서 수신하지 못했습니다. 아래 예제는 ICMP 메시지가 내 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()); 

내가 그것을 알고 포트에 (내 라우터) 10.0.0.138에 10.0.0.100 (내 PC)에서 UDP 패킷을 보낼 시도에서 내 PC로 오는 ICMP 응답을 보여주는 Wireshark를 추적하다 듣지 않았다. 내 문제는 그 ICMP 패킷을 사용하여 임의의 시간이 지난 후 응용 프로그램이 대기하는 것을 기다리는 대신 UDP 전송이 실패했다는 것을 깨닫는 것입니다.

ICMP responses to UDP send

답변

13

거의 삼년 후에 나는 (원래의 질문에 대해이었다 비스타 모르는 나 Windows 7에서 ICMP 패킷을 수신에 대한 해결책을 찾을 수 있도록 힌트를 충분히 준 http://www.codeproject.com/Articles/17031/A-Network-Sniffer-in-C를 우연히 발견하지만 난 의심 이 해결책이 효과가있다).

두 가지 중요한 점은 소켓이 IPAddress.Any가 아닌 단일 특정 IP 주소와 SIO_RCVALL 플래그를 설정하는 IOControl 호출에 바인딩되어야한다는 것입니다.

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(); 

또한 ICMP 포트 도달 불가능 패킷을 수신 할 수 있도록 방화벽 규칙을 설정해야했습니다.

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

도움이되는지 여부는 알 수 없습니다. 그러나 나는 Socket.BeginReceiveFrom을 사용하고 있으며 때때로 SocketException (10054)의 SocketException과 함께 실패 할 것이다. UDP 프로토콜에서 소켓이 ICMP Port Unreachable 메시지를 수신했다는 통지. – SilverX

+1

소켓에서 수신 한 것과 관계없이 동일한 예외가 발생합니다. 내가 항상 가지고있는 문제는 예외가 ICMP 응답이 어느 원격 호스트에서 왔는지 알려주지 않았다는 것입니다. 이것이 바로 ICMP 리스너가 할 수있는 일입니다. – sipwiz

+8

3 년 후에도 솔루션을 제공하는 데 여전히 신경 쓸 것입니다. –

3

는 ICMP (ICMP 모든 소켓을위한) 모든 ICMP "세션"에 대해 상이 할 것 같은 데 식별자를 사용한다. 따라서 동일한 소켓에서 보내지 않은 icmp 패킷에 답장을 보내면으로 필터링되어이 필터링됩니다. 이것이 그 코드가 작동하지 않는 이유입니다. 는 (나는 이것에 대해 확실하지 않다. 그것은 단지 일부 ICMP 트래픽을보고 한 후 가정입니다.)

당신은 단순히 호스트를 ping하고 당신이 그것을 도달 여부를 한 다음 SIP 일을 시도 할 수 있는지 여부를 볼 수 있었다. 그러나 다른 호스트가 icmp를 필터링하는 경우에는 작동하지 않습니다.

못생긴 (그러나 작동하는) 솔루션은 winpcap을 사용합니다. (유일한 작업 솔루션으로이 갖는는 사실이 너무 나쁜 것 같다.)

은 내가은 WinPcap을 사용하여 의미하는 것은 당신이 캡쳐 된 패킷에 대한 다음 캡처 ICMP 트래픽입니다 볼 수있는 경우입니다 귀하의 UDP 패킷을 배달 할 수 없거나 없습니다.. 여기

캡처 TCP 패킷에 대한 예는 다음과 같습니다 http://www.tamirgal.com/home/SourceView.aspx?Item=SharpPcap&File=Example6.DumpTCP.cs (ICMP와 동일한 작업을 수행하기 위해 너무 열심히해서는 안됩니다.)

+1

동의합니다. 사용할 수있는 것이 없다면 좋은 해결책입니다. 나는 다른 방법이 있다고 생각하는 것을 도울 수 없다. ICMP 메시지가 수신되면 실제로 UDP 보내기가 예외를 throw해야합니다. – sipwiz

+0

UDP는 상태가 저장되지 않아야한다고 생각하지 않습니다. –

+0

적당한 사람이 현상금을 얻는 것을 확신하기 위하여 Upvoting,이 포스트가 그것을 저장하지 않는다. – Joshua

1

세부 사항이 완전히 때문에 내가 별도의 답변으로 이것을 쓰고 있어요 이전에 썼던 것과는 다릅니다.

그래서 Kalmi의 세션 ID에 대한 의견을 토대로 동일한 시스템에서 두 개의 Ping 프로그램을 열 수있는 이유에 대해 생각하게되었습니다. 응답은 교차하지 않습니다. 둘 다 ICMP이기 때문에 둘 다 포트가없는 원시 소켓을 사용합니다. 이것은 IP 스택에있는 어떤 것을 의미하며, 그 응답이 의도 한 소켓을 알아야합니다. ping을 위해 ECHO REQUEST와 ECHO REPLY의 일부로 ICMP 패키지의 데이터에 사용 된 ID가 있습니다.ICMP 메시지는 정상 IP 처리 구별, ICMP 메시지는 일반적으로 특별한 경우로 처리 표준 IP 데이터 그램 내에서 을 포함하고 있지만

:

은 그 때 나는 ICMP에 대해 위키 백과에이 댓글 가로 질러 ( ) 대신 정상 서브 프로토콜 ( IP)으로 처리됩니다. 많은 경우에, 에 ICMP 메시지의 내용을 검사하고 원래의 IP 패킷을 생성 한 응용 프로그램에 적절한 오류 메시지를 전달하여 ICMP 메시지 보내는 메시지가 나타나면 하나 필요하다. (간접적으로)에 here 정교화되었다

:

인터넷 헤더 플러스 원래의 데이터 그램의 처음 64 비트 . 이 데이터는 호스트에서 메시지와 해당 프로세스를 일치시키는 데 사용됩니다. 상위 레벨 프로토콜 포트 번호를 사용하는 경우, 그들은 원래의 데이터 그램의 처음 64 데이터 비트 일 수 가정한다.

포트를 사용하는 UDP를 사용 중이므로 네트워크 스택이 ICMP 메시지를 원래 소켓으로 다시 라우팅 할 수 있습니다. 이것이 새롭고 분리 된 소켓이 절대로 이러한 메시지를 수신하지 않는 이유입니다. 나는 UDP가 ICMP 메시지를 먹는다 고 생각한다.

맞다면 해결 방법 중 하나는 원시 소켓을 열고 수동으로 UDP 패킷을 만들고 되돌아 오는 것을 수신하고 적절하게 UDP 및 ICMP 메시지를 처리하는 것입니다. 코드에서 어떻게 보이는지 확신 할 수 없지만, 너무 어려울 것이라고 상상하지 못하고 winpcap 솔루션보다 더 "우아한"것으로 간주 될 수 있습니다.

또한이 링크 (http://www.networksorcery.com/enp/default1003.htm)는 낮은 수준의 네트워크 프로토콜을위한 훌륭한 리소스 인 것으로 보입니다.

이 정보가 도움이되기를 바랍니다.

+0

ICMP 세션 ID에 대한 요점은 나에게 완벽합니다. 이것이 실제로 문제의 핵심입니다. 왜 전달할 수없는 UDP 패킷이 내 신청서에 전달되었음을 나타내는 ICMP 메시지가 아닌가? 그들은 UDP 패킷에 대한 것이기 때문에 어떤 이유로 Windows는 응용 프로그램과 일치하지 않는 것 같습니다. – sipwiz

+1

같은 원시 소켓을 통해 UDP와 ICMP를 멀티 플렉스하려고 생각했지만 모든 UDP 처리를해야 할 것입니다.하지만 윈도우와 함께 원시 소켓을 만들 때는 IP인지 아니면 IP인지를 선택해야합니다. ICMP, 둘 다 가질 수는 없습니다. – sipwiz

+0

예 원시 IP 소켓으로 만들고 모든 ICMP 메시지를 처리해야한다고 생각합니다. 이것은 가치가있는 것보다 더 복잡 할 수도 있지만, IP와 ICMP에 관해 읽을 수있는 것은 winpcap 스타일이 아닌 유일한 대답 일 수 있습니다. – grieve

1

그래서 당신은 프로그래밍의 최종 도착 도달 할 수없는 반환 ICMP 패킷을 데리러하고 싶어? 힘든 일. 나는 당신이 그 근처의 어느 곳이라도 갈 수 있기 전에 네트워크 스택이 흡수되었다고 말할 것이다.

나는 순수한 C#을 접근 여기서 일 것입니다 생각하지 않습니다. 당신은 윈도우 기반의 ipfiltdrv.sys를 사용하여 패킷 (icmp, tcp, udp 등)을 트랩하고 관리 코드를 사용하여 읽기/재생하는이 응용 프로그램을 살펴보십시오. 기음#).

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

  • Oisin
3

UPDATE : 나는 .... 당신이 게시 코드의 조각이 또한 나를 위해 노력하고 내가 미친 것 같네요 ...

다음 코드 조각이 날 (XP SP3)에 대한 잘 작동 :

더 이상 ICMP 포트 도달 할 수없는 패킷의 문제를 언급 비스타에 접근 할 수있는 웹 게시물의 숫자가 있습니다
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"); 
       } 
      } 

     } 
    } 
} 
+0

작품을 발표 할 때 핑 (ping) 또는 뭔가를 보내면 ICMP 패킷을 받는다는 것을 의미합니까? 나는 그것이 UDP가 unreachbale 포트로 보내고 ICMP를받을 수 없었을 때 내가 사용하고 있었던 것이라고 확신한다. 다시 확인해야 겠어. – sipwiz

+0

나는 접근 할 수없는 호스트와 tcp로만 테스트를했다 ... 나는 포트 –

+0

을 시도 할 것이다 ... UDP와 기존의 호스트로 잘 작동한다 ... 테스트를 위해 주석 처리 된 부분을 추가했다 .. –

2

. 는 ICMP를받을 때 http://www.eggheadcafe.com/software/aspnet/31961998/icmp-port-unreachable-and.aspx

  • http://social.msdn.microsoft.com/Forums/en-US/Offtopic/thread/5bd8b275-cc6f-43cd-949d-7c411973b2f3/
  • 스택

    • 다시 예외를 제공해야합니다. 그러나 적어도 Vista에서는 그렇지 않습니다. 따라서 해결 방법을 시도하고 있습니다.

      나는 불가능하다고 말하는 대답을 좋아하지 않지만 그런 식으로 보입니다. 그래서 저는 SIP에서 오랫동안 타임 아웃했던 원래의 문제로 한발 더 나아갈 것을 제안합니다.

      • 당신은 사용자가 (따라서 종류의 사양 준수)를 시간 제한을 구성 할 수 있습니다.
      • 제한 시간이 끝나기 전에 다른 프록시 (예 : 다른 프록시 확인)를 시작할 수 있습니다.
      • 는 당신은 나쁜 목적지를 알려 캐시 할 수있다 (하지만 캐시 좋은 관리가 필요합니다.
      • ICMP 및 UDP는 적절한 오류 메시지를 제공 TCP 또는 다른 프로토콜을 시도하지 마십시오. 그냥 원하는 정보를 유도 할 수 있습니다.

    3

    그냥 연결된 UDP 소켓을 사용하고 OS에 연결할 수는 ICMP 일치와 UDP 소켓에서 오류를 반환합니다 (뭐든지, 그냥. 많은 자원이 걸릴 수있다).

    Google은 연결된 udp 소켓 용입니다.

    +0

    UDP 클라이언트는 ICMP 포트에 연결할 수 없지만 ICMP 호스트에 연결할 수 없거나 다른 ICMP "연결할 수없는"메시지에 대해 소켓 예외를 throw합니다. – trampster