سؤال

لدي تطبيق SIP يحتاج إلى إرسال حزم UDP لإعداد مكالمات SIP.لدى SIP آلية مهلة للتعامل مع فشل التسليم.الشيء الإضافي الذي أود أن أكون قادرًا على القيام به هو اكتشاف ما إذا كان مقبس UDP مغلقًا من أجل الاضطرار إلى انتظار الفاصل الزمني لإعادة الإرسال لمدة 32 ثانية الذي يستخدمه SIP.

الحالات التي أشير إليها هي عندما تؤدي محاولة الإرسال إلى مقبس UDP إلى إنشاء حزمة ICMP Destination Unreachable بواسطة المضيف البعيد.إذا حاولت إرسال حزمة UDP إلى مضيف قيد التشغيل ولكن المنفذ لا يستمع، فيمكنني رؤية رسالة ICMP تصل مرة أخرى مع متتبع الحزمة ولكن السؤال هو كيف يمكنني الوصول إلى ذلك من كود C# الخاص بي؟

أنا أتلاعب بالمآخذ الخام ولكن حتى الآن لم أتمكن من الحصول على حزم ICMP ليتم استقبالها بواسطة برنامجي.لا يتلقى النموذج أدناه أي حزمة مطلقًا على الرغم من وصول رسائل ICMP إلى جهاز الكمبيوتر الخاص بي.

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

يوجد أدناه تتبع لـ wireshark يُظهر استجابات ICMP القادمة إلى جهاز الكمبيوتر الخاص بي من محاولة إرسال حزمة UDP من 10.0.0.100 (جهاز الكمبيوتر الخاص بي) إلى 10.0.0.138 (جهاز التوجيه الخاص بي) على منفذ أعلم أنه لا يستمع إليه.مشكلتي هي كيفية الاستفادة من حزم ICMP لإدراك فشل إرسال UDP بدلاً من مجرد انتظار انتهاء مهلة التطبيق بعد فترة عشوائية؟

ICMP responses to UDP send

هل كانت مفيدة؟

المحلول

وبعد ما يقرب من 3 سنوات وأنا تعثرت عبر http://www.codeproject.com / مقالات / 17031 / A-شبكة-الشم في-C الذي أعطاني ما يكفي من تلميح لمساعدتي في إيجاد حل لتلقي الحزم ICMP على ويندوز 7 (لا أعرف عن ويندوز فيستا، والتي السؤال الأصلي وحول ولكن أظن أن هذا الحل).

والنقاط الرئيسية هما أن مأخذ لابد منضما إلى عنوان IP معين واحد بدلا من IPAddress.Any والدعوة IOControl الذي يحدد العلم 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();

وكان لي أيضا لتعيين قاعدة جدار الحماية للسماح حزم ICMP منفذ تصل إلى أن تصل.

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

نصائح أخرى

يستخدم Icmp ملف معرف والذي يبدو أنه مختلف بالنسبة لكل "جلسة" icmp (لكل مقبس icmp).لذلك الرد على حزمة ICMP التي لم يتم إرسالها بواسطة نفس المقبس هو مفيد تخرج لك.وهذا هو السبب في أن هذا الجزء من التعليمات البرمجية لن يعمل. (لست متأكدا بشأن هذا.إنه مجرد افتراض بعد النظر في بعض حركة مرور ICMP.)

يمكنك ببساطة اختبار اتصال المضيف ومعرفة ما إذا كان يمكنك الوصول إليه أم لا ثم تجربة شيء SIP الخاص بك.ومع ذلك، لن ينجح ذلك إذا كان المضيف الآخر يقوم بتصفية icmp.

يتم استخدام حل قبيح (لكنه فعال). com.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.

وGoogle للمآخذ UDP المتصلة.

هناك عدد من المنشورات على الويب تشير إلى مشكلة عدم إمكانية الوصول إلى الحزم التي يتعذر الوصول إليها في منفذ ICMP على نظام التشغيل Vista.

يجب أن يعطيك المكدس استثناءً عندما يستقبل ICMP.ولكن هذا لا يحدث، على الأقل في نظام التشغيل Vista.ومن ثم فأنت تحاول إيجاد حل بديل.

لا أحب الإجابات التي تقول أن هذا غير ممكن، لكن الأمر يبدو كذلك.لذا أقترح عليك الرجوع خطوة إلى المشكلة الأصلية، وهي المهلات الطويلة في SIP.

  • يمكنك السماح للمستخدم بتكوين المهلة (وبالتالي نوع الامتثال للمواصفات).
  • يمكنك البدء في القيام بأشياء أخرى (مثل التحقق من الوكلاء الآخرين) قبل انتهاء المهلة.
  • يمكنك التخزين المؤقت للوجهات السيئة المعروفة (ولكن ذلك سيحتاج إلى إدارة جيدة من ذاكرة التخزين المؤقت.
  • إذا لم يقدم icmp وudp رسائل خطأ مناسبة، فحاول استخدام بروتوكول tcp أو بروتوكول آخر.فقط للحصول على المعلومات المطلوبة.

(كل شيء ممكن، لكنه قد يتطلب الكثير من الموارد.)

أكتب هذا كإجابة منفصلة، ​​لأن التفاصيل مختلفة تماما عن تلك التي كتبتها سابقا.

لذا، بناءً على تعليق Kalmi حول معرف الجلسة، جعلني أفكر في سبب قدرتي على فتح برنامجين ping على نفس الجهاز، وعدم تقاطع الاستجابات.كلاهما ICMP، وبالتالي يستخدم كلاهما مآخذ توصيل أولية بدون منافذ.وهذا يعني أن شيئًا ما في مكدس IP يجب أن يعرف ما هو المقبس المقصود من هذه الاستجابات.بالنسبة لـ ping، اتضح أن هناك معرفًا مستخدمًا في بيانات حزمة ICMP كجزء من طلب ECHO ورد ECHO.

ثم صادفت هذا التعليق على ويكيبيديا عنه ICMP:

على الرغم من أن رسائل ICMP موجودة في بيانات بيانات IP قياسية ، إلا أن رسائل ICMP تتم معالجتها عادةً كحالة خاصة ، تتميز عن معالجة IP العادية ، بدلاً من معالجتها كبروتوكول فرعي عادي لـ IP.في كثير من الحالات ، من الضروري فحص محتويات رسالة ICMP وتسليم رسالة الخطأ المناسبة إلى التطبيق الذي أنشأ حزمة IP الأصلية ، التي دفعت إلى إرسال رسالة ICMP.

والذي تم تفصيله (بشكل غير مباشر) هنا:

رأس الإنترنت بالإضافة إلى أول 64 بت من بيانات بيانات البيانات الأصلية.يتم استخدام هذه البيانات من قبل المضيف لمطابقة الرسالة مع العملية المناسبة.إذا كان بروتوكول المستوى الأعلى يستخدم أرقام المنافذ ، فمن المفترض أن يكون في أول 64 بت بيانات من بيانات بيانات البيانات الأصلية.

نظرًا لأنك تستخدم UDP، الذي يستخدم المنافذ، فمن الممكن أن يقوم مكدس الشبكة بتوجيه رسالة ICMP مرة أخرى إلى المقبس الأصلي.هذا هو السبب في أن المقبس الجديد والمنفصل الخاص بك لا يتلقى هذه الرسائل مطلقًا.أتخيل أن UDP يأكل رسالة ICMP.

إذا كنت على صواب، فإن أحد الحلول لذلك هو فتح مأخذ توصيل خام وإنشاء حزم UDP يدويًا، والاستماع إلى أي شيء يعود، والتعامل مع رسائل UDP وICMP بالشكل المناسب.لست متأكدًا من الشكل الذي سيبدو عليه ذلك في الكود، لكنني لا أتخيل أنه سيكون صعبًا للغاية، ويمكن اعتباره أكثر "أناقة" من حل winpcap.

بالإضافة إلى هذا الرابط، http://www.networksorcery.com/enp/default1003.htm, ، يبدو أنه مصدر رائع لبروتوكولات الشبكة ذات المستوى المنخفض.

آمل أن يساعد هذا.

هل ترغب في التقاط حزمة icmp المرتجعة التي لا يمكن الوصول إليها برمجيًا؟صعبة.أود أن أقول إن مكدس الشبكة يمتص ذلك قبل أن تتمكن من الاقتراب منه.

لا أعتقد أن نهج C# النقي سيعمل هنا.ستحتاج إلى استخدام اعتراض على مستوى السائق للحصول على خطاف.ألقِ نظرة على هذا التطبيق الذي يستخدم ipfiltdrv.sys الخاص بنظام Windows لاصطياد الحزم (icmp وtcp وudp وما إلى ذلك) وقراءتها/تشغيلها باستخدام التعليمات البرمجية المُدارة (c#).

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

  • أويسين
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top