문제

SIP 통화를 설정하려면 UDP 패킷을 보내야하는 SIP 응용 프로그램이 있습니다. SIP에는 전달 실패에 대처할 시간 초과 메커니즘이 있습니다. 내가 할 수있는 추가 작업은 32S Retransmit Interval SIP 사용을 기다리기 위해 UDP 소켓이 닫혀 있는지 여부를 감지하는 것입니다.

내가 언급 한 사례는 UDP 소켓으로 보내려고 시도하면 ICMP 대상이 원격 호스트가 생성 할 수없는 패킷이 생성됩니다. 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());

다음은 UDP 패킷을 10.0.0.100 (내 PC)에서 10.0.0.138 (내 라우터)로 보내는 시도에서 ICMP 응답이 내 PC에 들어오는 ICMP 응답을 보여주는 것을 보여주는 Wireshark 추적입니다. 내 문제는 임의의 기간 이후에 신청서를 타임 아웃으로 기다리는 것보다 UDP 보내기가 실패했다는 것을 깨닫기 위해 ICMP 패킷을 사용하는 방법입니다.

ICMP responses to UDP send

도움이 되었습니까?

해결책

거의 3 년 후, 나는 걸려 넘어졌다 http://www.codeproject.com/articles/17031/a-network-sniffer-in-c Windows 7에서 ICMP 패킷을 수신 할 수있는 솔루션을 찾는 데 도움이되는 힌트를 충분히주었습니다 (원래 질문은 Vista에 대해 알지 못하지만이 솔루션이 작동 할 것 같아요).

두 가지 핵심 사항은 소켓이 iPaddress가 아닌 단일 특정 IP 주소에 바인딩되어야한다는 것입니다.

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

다른 팁

ICMP는 An을 사용하고 있습니다 식별자 모든 ICMP "세션"(모든 ICMP 소켓에 대해)마다 다른 것 같습니다. 그래서 동일한 소켓으로 보내지 않은 ICMP 패킷에 답장 도움이됩니다 필터링 당신을 위한. 이것이 해당 코드가 작동하지 않는 이유입니다. (나는 이것에 대해 잘 모르겠습니다. 그것은 ICMP 트래픽을보고 한 후에 단지 가정 일뿐입니다.)

당신은 단순히 호스트를 핑하고 접근 할 수 있는지 여부를 확인한 다음 한 모금을 시도 할 수 있습니다. 그러나 다른 호스트가 ICMP를 필터링하는 경우에는 작동하지 않습니다.

못생긴 (그러나 작동) 솔루션이 사용 중입니다 winpcap. (이것을 유일하게 작동하는 솔루션으로 사용하는 것은 사실 이기에는 너무 나빠 보입니다.)

winpcap을 사용한다는 것은 당신이 할 수있는 것입니다. ICMP 트래픽을 캡처합니다 그리고 캡처 된 패킷이 UDP 패킷에 관한 것인지 확인할 수 없는지 확인하십시오..

다음은 TCP 패킷을 캡처하기위한 예입니다.http://www.tamirgal.com/home/sourceview.aspx?item=sharppcap&file=example6.dumptcp.cs(ICMP와 똑같이하는 것은 너무 어렵지 않아야합니다.)

업데이트 : 내가 미쳤다고 생각합니다 .... 당신이 게시 한 코드도 저에게도 효과가 있습니다 ...

다음 코드는 나에게 잘 작동합니다 (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");
                }
            }

        }
    }
}

연결된 UDP 소켓을 사용하면 OS가 ICMP와 일치하지 않고 UDP 소켓에서 오류를 반환합니다.

연결된 UDP 소켓 용 Google.

웹에 ICMP 포트에 대한 문제가 더 이상 Vista에서 액세스 할 수없는 문제를 언급하는 여러 게시물이 있습니다.

스택은 ICMP를받을 때 예외를 돌려 주어야합니다. 그러나 적어도 Vista에서는 그렇지 않습니다. 따라서 해결 방법을 시도하고 있습니다.

나는 그것이 불가능하다고 말하는 대답을 좋아하지 않지만 그렇게 보인다. 그래서 나는 당신이 원래의 문제로 돌아가는 것이 좋습니다.

  • 사용자가 타임 아웃을 구성하도록 할 수 있습니다 (따라서 사양을 준수하는 일종).
  • 시간 초과가 끝나기 전에 다른 프록시를 확인하는 것과 같은 다른 일을 시작할 수 있습니다.
  • 알려진 나쁜 목적지를 캐시 할 수 있습니다 (그러나 캐시 관리가 필요합니다.
  • ICMP 및 UDP가 올바른 오류 메시지를 제공하지 않으면 TCP 또는 다른 프로토콜을 사용해보십시오. 원하는 정보를 이끌어 내기 위해.

(가능한 모든 것이 가능하면 많은 자원이 필요할 수 있습니다.)

세부 사항은 이전에 쓴 것과 완전히 다르기 때문에 이것을 별도의 답변으로 작성하고 있습니다.

따라서 세션 ID에 대한 Kalmi의 의견을 바탕으로 동일한 기계에서 두 개의 핑 프로그램을 열 수있는 이유에 대해 생각하게되었고 응답이 교차하지 않습니다. 둘 다 ICMP이므로 포트리스 원시 소켓을 사용합니다. 즉, IP 스택에있는 것이 의미가 있으며 해당 응답이 어떤 소켓에 의도했는지 알아야합니다. Ping의 경우 Echo Request 및 Echo Reply의 일부로 ICMP 패키지의 데이터에 사용 된 ID가 있음이 밝혀졌습니다.

그런 다음 Wikipedia에 대한이 의견을 다루었습니다 ICMP:

ICMP 메시지는 표준 IP 데이터 그램 내에 포함되어 있지만 ICMP 메시지는 일반적으로 IP의 일반적인 하위 프로토콜로 처리되지 않고 일반적인 IP 처리와 구별되는 특별한 경우로 처리됩니다. 대부분의 경우 ICMP 메시지의 내용을 검사하고 원래 IP 패킷을 생성 한 응용 프로그램에 적절한 오류 메시지를 전달해야합니다.

(간접적으로) 정교한 여기:

인터넷 헤더는 원래 데이터 그램 데이터의 처음 64 비트를 추가했습니다. 이 데이터는 호스트가 메시지를 적절한 프로세스에 맞추기 위해 사용됩니다. 더 높은 레벨 프로토콜이 포트 번호를 사용하는 경우 원래 데이터 그램 데이터의 처음 64 개의 데이터 비트에 있다고 가정합니다.

포트를 사용하는 UDP를 사용하고 있으므로 네트워크 스택이 ICMP 메시지를 원래 소켓으로 다시 라우팅 할 수 있습니다. 그렇기 때문에 새롭고 별도의 소켓이 해당 메시지를받지 못하는 이유입니다. UDP가 ICMP 메시지를 먹는다 고 생각합니다.

내가 올바른 경우, 이에 대한 한 가지 해결책은 원시 소켓을 열고 수동으로 UDP 패킷을 만들고, 돌아 오는 모든 것을 듣고, UDP 및 ICMP 메시지를 적절하게 처리하는 것입니다. 코드에서 어떻게 보일지 확실하지 않지만, 그것이 너무 어려울 것이라고 생각하지 않으며 WinPCAP 솔루션보다 더 "우아한"것으로 간주 될 수 있습니다.

또한이 링크, http://www.networksorcery.com/enp/default1003.htm, 낮은 레벨 네트워크 프로토콜에 대한 훌륭한 리소스 인 것으로 보입니다.

이게 도움이 되길 바란다.

그래서 당신은 프로그래밍 방식으로 도달 할 수없는 반환 ICMP 패킷을 집어 들고 싶습니까? 힘든 것. 네트워크 스택이 근처에 어디로도 얻기 전에 스택을 담그고 있다고 말하고 싶습니다.

나는 순수한 C# 접근법이 여기서 효과가 있다고 생각하지 않습니다. 드라이버 레벨 인터셉트를 사용하여 훅을 가져와야합니다. Windows의 ipfiltdrv.sys를 사용하여 패킷 (ICMP, TCP, UDP 등)을 사용하고 관리되는 코드로 읽기/재생하는이 앱을 살펴보십시오. 씨#).

http://www.codeproject.com/kb/ip/firewall_sniffer.aspx?display=print

  • 오이신
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top