در این بخش از آموزش Embedded Ethernet، به یکی از پروتکلهای حیاتی در شبکههای کامپیوتری، یعنی پروتکل ICMP (Internet Control Message Protocol) میپردازیم. این پروتکل نقشی کلیدی در مدیریت و کنترل جریان دادهها و همچنین گزارش خطاها در شبکه ایفا میکند. شناخت دقیق و پیادهسازی صحیح ICMP، به ویژه در دستگاههای امبدد، کمک میکند تا ارتباطات شبکهای پایدارتر و قابل اطمینانتر باشند. در این قسمت، علاوه بر بررسی ساختار و عملکرد هدر ICMP، به کاربردهای مهمی همچون عملیات پینگ (Ping) و نحوه پاسخدهی به آن، و همچنین روشهای گزارش خطا در شبکه خواهیم پرداخت. با درک این مفاهیم، توانایی شما در طراحی سیستمهای شبکهای هوشمند و مقاوم افزایش خواهد یافت.
پروتکل ICMP پروتکلیست برای مدیریت، کنترل و همچنین گزارش خطاهایی که احتمالاً در یک ارتباط به وجود خواهند آمد. در نتیجه این پروتکل، کاربردهای زیادی داره. یکی از پرکاربردترین وظایف، بررسی برقراری ارتباط با یک هاست دیگه در شبکه است.
به این عملیات اصطلاحاً پینگ (ping) گفته میشه. در عملیات پینگ، دادههایی (عموماً با طول و مقدار ثابت که وابسته به پیادهسازی است) برای هاست موردنظر ارسال میشه و انتظار میره همان دادهها، به ما برگردانده (echo) بشه. در این فرایند، اطلاعاتی مثل زمان تقریبی دسترسی به هاست موردنظر، محاسبه و گزارش میشود. ما پروتکل ICMP رو فقط جهت پردازش عملیات ping؛ اون هم تنها در حالت پاسخدهی پیادهسازی میکنیم. براي همين، برد ما قادر به ارسال دستور پينگ نيست و فقط ميتونه به درخواست پينگ جواب بده. بيشتر از اين هم در حال حاضر نياز نيست.
یکی دیگر از دستوراتی که از ICMP استفاده میکنه تا اطلاعات روترهای بین دو هاست رو به دست بیاره؛ Treace Route هست که در ضمیمهها معرفی خواهیم کرد.
همچنین در صفحات قبلی این نوشتار گفتیم که بعضی مواقع در صورت رخداد خطا یا بهوجودآمدن وضعیت خاصی در شبکه، پیغامی برای فرستنده یا ادمین مدیر، Admin شبکه ارسال میشه؛
مثلاً هنگامی که یک روتر با TTL=0 مواجه میشه؛ گفتیم که عموماً بسته دور ریخته میشه؛ ولی به فرستنده اطلاع داده میشه. اینگونه گزارشات، توسط پروتکل ICMP انجام میشه. دو وضعیت دیگه وقتیه که هنگام مسیریابی توسط روترها، مسیری برای رسیدن به زيرشبكه مقصد نیست یا اینکه پکت به زیرشبکه مقصد رسیده؛ اما هاست موردنظر در اون زیرشبکه وجود نداره.
دو وضعیت دیگر نیز هنگام مسیریابی توسط روترها ممکن است رخ دهد:
Destination Network Unreachable: مسیر برای رسیدن به زیرشبکه مقصد وجود ندارد.
Destination Host Unreachable: پکت به زیرشبکه مقصد رسیده، اما هاست موردنظر در آن زیرشبکه یافت نشده است.
در این دو حالت نیز پیغامهایی از طرف روتر نهایی به فرستنده ارسال میشود که این پیامها نیز از طریق ICMP صورت میگیرند.
وقتی هم كه پیغام به دلیل TTL=0 دور ریخته میشه؛ پیغامی با کد Time exceeded به فرستنده برمیگرده. جهت مشاهده مابقی پیغامها به سند RFC 792 رجوع کنید. یادتون باشه که ICMP قابلیت پیادهسازی این پیامها رو در اختیار میذاره، ولی کد مربوطه، باید در پردازنده پیادهسازی (Implementatio) شده باشه. بهعنوانمثال اگر در میکروکنترلرتون عملیات ping رو ننوشته باشید، بالطبع درخواست یا پاسخ پینگ رو نمیتونید اجرا کنید و برد شما به پينگ جواب نخواهد داد.
ابتدا ببینیم هدر (Header) در پروتکل ICMP چه شکلی هست :
Octet Offset | 0 | 1 | 2 | 3 |
0 | Type | Code (sybtype) | CheckSum | |
4 | Rest of Header |
دادههای پس از هدر ICMP
بعد از بخش هدر، دادههای این پروتکل قرار میگیرند. البته تعداد و مقدار این دادهها، وابسته به عملیاتیست که در حال استفاده از ICMP است؛ پس ممکنه این پروتکل دادهای نداشته باشه یا دارای دادههایی با مقادیر خاص باشه.
یک روش ساده برای اطلاع از اینکه ارتباط بین دو هاست بهدرستی برقرار هست؛ استفاده از عملیات (یا دستور) ping هست. این پیغام بهصورت درخواست/پاسخ (Request/Reply) پیادهسازی میشه. فرستنده از گیرنده درخواست میکنه، اطلاعاتی که برای گیرنده ارسال میشه رو به فرستنده برگردونه (echo). اين عمليات با استفاده از پروتكل ICMP اجرا ميشه.
اینکه نامگذاری ping از کجا اومده؛ در بعضی جاها ازجمله دانشنامه ویکیپدیا گفته شده که این نام از عملیات بازتاب امواج سونار در زیردریاییها یا اژدرها گرفته شده ( نام echo نشون دهنده اين وضعيت هست). توصیف ديگه ای که دیدم و به نظرم جهت آشنایی با مفهوم پینگ به ذهن آشناتر هست، گفته بود این اسم از ورزش پینگپنگ (نام قدیمی ورزش تنیسرویمیز که به نظر اصطلاحی به زبان چینی است) گرفته شده، همونطور که در این ورزش مشخصه؛ توپ بهدفعات بین دو بازیکن رفتوبرگشت داره! در عملیات پینگ در ویندوز هم، چهار بار؛ و هر بار تعداد 32 بایت با مقدار ثابت؛ به مقصد فرستاده میشه و انتظار میره که همونا برگرده. البته این فرایند با استفاده از تنظیمات دستور پینگ، قابلتغییر هست و در سیستمعاملهای دیگه مثل لینوکس هم ممکنه به طور دیگه ای پیادهسازی شده باشه.
در عملیات پینگ، بخش 4 بایتی rest of header به دو بخش دو بایتی با نام های ID,Sequence Number تقسیم میشه.
از طرفی بخش Type برای فرستنده (درخواستکننده) برابر با 0x08 و برای گیرنده (پاسخدهنده) عدد 0x00 هست که بهصورت زیر در کد میاد :
1 2 3 | #define ICMP_FRAME_TYPE_ECHO_REQUEST 0x08 #define ICMP_FRAME_TYPE_ECHO_REPLY 0x00 |
بخش Code در هر دو حالت، 0x00 است.
بریم سر وقت کدنویسی؛ ابتدا ساختار مناسبي برای هدر ICMP تعریف میکنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | typedef struct ICMP_EchoFrame { uint8_t type; uint8_t code; uint16_t checkSum; uint16_t id; uint16_t seqNum; uint8_t data []; } ICMP_EchoFrame; |
در تابع پردازشگر پکت های IP ( یعنی در تابع IP_Process ) ابتدا بررسی میکنیم که آیا محتویات پکت دریافتی متعلق به پروتکل ICMP هست؟ و اگر جواب مثبت بود؛ تابعی که برای پروتکل ICMP در نظر گرفتیم (و فعلاً فقط درخواستهای پینگ رو جواب میده) رو فراخوانی میکنیم:
1 2 3 4 5 | if (ipFrame->protocol == IP_FRAME_PROTOCOL_ICMP) //==0x01 { newDataLen = ICMP_Process((ICMP_EchoFrame*)ipFrame->data, dataLen); |
گفتیم که در عملیات پینگ؛ دادههایی که از طرف درخواستکننده ارسال میشن، عیناً برگشت داده میشن (echo) فقط در این بخش مقدار type از 0x08 به 0x00 تغییر میکنه و از اونجاییکه دادههای بخش مربوط به چک سام تغییر کرده؛ بالطبع در پاسخ؛ مقدار چک سام تغییر می کنه و باید دوباره محاسبه بشه.
بریم ببینیم تابع ICMP_Process چطور پیادهسازی شده :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | uint16_t ICMP_Process ( ICMP_EchoFrame* icmpFrame, uint16_t frameLen ) { uint16_t newFrameLen = 0; uint16_t rxCheckSum = icmpFrame-> checkSum; icmpFrame->checkSum = 0; uint16_t calcCheckSum = IP_CalcCheckSum (( uint8_t* ) icmpFrame, frameLen ) ; if ( rxCheckSum == calcCheckSum ) { if ( icmpFrame->type == ICMP_FRAME_TYPE_ECHO_REQUEST ) //=0x08 { icmpFrame->type = ICMP_FRAME_TYPE_ECHO_REPLY; //=0x00 icmpFrame->checkSum = IP_CalcCheckSum (( uint8_t * ) icmpFrame, frameLen ) ; newFrameLen = frameLen; } } return newFrameLen; } |
طبق معمول صحت چک سام بررسی شده، و بعد بررسی کردیم که آیا در قسمت type در هدر، درخواست پینگ داریم؟ ( بالطبع اگه بخوایم درخواستهای دیگه رو بررسی کنیم؛ باید زیر این if اضافه کنیم ) اگر نتیجه مثبت باشه؛ فقط بخش نوع فریم فعلی رو تغییر میدیم؛ چک سام جدید رو در جای خودش مینویسیم و از تابع خارج میشیم؛ و همونطور که از قبل پیادهسازی شده، لایه سوم این نتیجه رو می گیره، IP فرستنده گیرنده رو تغییر میده، چک سام خودش رو به وجود میاره و اونو به لایه دو میده؛ در این لایه هم جای مک آدرسها تغییر میکنه و فریم ارسال میشه.
در دو شکل زیر نتیجه درخواست و پاسخ پینگ برد ما که توسط ویندوز فرستاده شده؛ رو میبینیم:
شکل 1: اجرای دستور پینگ در ویندوز
شکل 2: شنود پروتکل ICMP با نرم افزار wireshark
همونطور که در تصویر معلومه؛ با یکبار اجرای دستور پینگ، چهار مرتبه درخواست پینگ ارسال و پاسخ دریافت شده است. اطلاعات موجود در آخرین پاسخ شکل بالا (انتخاب شده با رنگ آبی) بهصورت در شکل زیر ثبت شده :
همونطور که در شکل دیده میشه؛ تنها بخش type از مقدار 0x08 به 0x00 تغییر کرده؛ لذا چک سام هم بهناچار تغییر داشته و این تغییر تنها در بایت پرارزش چک سام هست در واقع از چک سام اولیه 0x0800 یا از بایت پرارزش 0x08 تا کم شده! این جواب سؤالی است که کمی قبلتر پرسیدیم. محل قرارگیری بایت type در بخش پرارزش کلمه 16 بیتی (word) بوده؛ از type هشت تا کم شده که نتیجه این کاهش، شده تغییر 0x55 در بایت پرارزش چک سام به 0x47 ؛ پس سادهتر اینه که هنگام محاسبه چک سام، بهجای محاسبه تمام چک سام؛ فقط مقدار بایت پرارزش رو 8 تا؛ (یا از کل چک سام، 0x0800 تا) کم کنیم.
نویسنده شو !
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.