باز کردن کارت شبکه و دریافت پاکت ها
اکنون که دیدیم چگونه می توانی کارت شبکه ای را که می خواهیم با آن کار کنیم را بدست آوریم ، بیاید کار اصلی را شروع کنیم، باز کردن کارت شبکه و دریافت بخشی از ترافیک شبکه. در این درس ما برنامه ای خواهیم نوشت که برخی از اطلاعات موجود در باره پاکت هایی که از کارت شبکه عبور می کنند را چاپ کند.
تابعی که درستگاه دریافت کننده پاکت ها (کارت شبکه) را باز می کند تابع Open() است. پارامتر های این تابع مانند، اندازه تصویر، مشخصه ها و حداکثر زمان خواندن ، نیازمند کمی توضیح است.
اندازه تصویر (SnapshotLenght): بخشی از پاکت را که می خواهیم ضبط کنیم را مشخص می کند. دربرخی از سیستم عامل ها مانند xBSD و Win32 ، درایور پاکت می تواند طوری پیکربندی شود تا تنها بخش آغازین هر پاکت را ضبط کند. این ویژگی باعث کاهش داده ای می شود که به برنامه کپی می شود. از این رو کارایی عملیات ضبط بالا می رود. در این برنامه ها از مقدار 65536 که از بیشترین مقدار MTU ای که میتوانیم با آن مواجه شویم بیشتر است، استفاده می کنیم. در این حالت مطمئن ایم که برنامه ما همیشه تمامی بسته ها را دریافت خواهد کرد.
ویژگی ها: مهم ترین پرچم ، نشان دهنده قرارگرفتن کارت شبکه (آداپتور) در حالت بی قاعده[1] است. در عملیات عادی، یک آداپتور فقط پاکت هایی را دریافت می کند که مقصد آن هاست. پاکت ها توسط سایر میزبان ها رد و بدل می شود، سپس قبول می شوند. در صورتی که در حالت بی قاعده ، کارت شبکه تمامی پاکت هایی را که چه مقصد آنهاست و یا نه را دریافت می کند.این بدین معناست که در رسانه های مشترک (مانند اترنت بدون سوئیچ) ، Pcap.Net قدر به دریافت پاکت های سایر میزبان ها است. حالت بی قاعده ، حالت پیش فرض در اکثر برنامه های ضبط است ، پس ما در مثال بعدی آن را فعال می کنیم.
زمان خواندن (readTimeout) : زمان خواندن را به میلی ثاتیه مشخص می کند.خواندن از یک کارت شبکه (برای مثال با ReciveSomePackets() یا RecivePacket()) ، همواره بعد از زمان خواندن مقدار برمی گردانند ، حتی اگر هیچ پاکتی در شبکه موجود نباشد. زمان خواندن همچنین فاصله بین گزارش های ایستا را تعیین می کند. اگر کارت شبکه در حالت ایستا باشد (برای کسب اطلاعات بیشتر در باره حالت ایستا بخش گردآوری آمار در ترافیک شبکه را ملاحضه کیند). قرار دادن مقدار 0 به readTimeout به معنی عدم محدودیت زمانی است، در این حالت تازمانی که بسته ای نرسیده باشد مقداری برگشت داده نمی شود. در نقطه مقابل با قرار دادن مقدار -1 به این پارامتر باعث می شود آداپتور سریعاٌ مقدار برگرداند.
using System;
using System.Collections.Generic;
using PcapDotNet.Core;
using PcapDotNet.Packets;
namespace OpeningAnAdapterAndCapturingThePackets
{
class Program
{
static void Main(string[] args)
{
// Retrieve the device list from the local machine
IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;
if (allDevices.Count == 0)
{
Console.WriteLine("No interfaces found! Make sure WinPcap is installed.");
return;
}
// Print the list
for (int i = 0; i != allDevices.Count; ++i)
{
LivePacketDevice device = allDevices[i];
Console.Write((i + 1) + ". " + device.Name);
if (device.Description != null)
Console.WriteLine(" (" + device.Description + ")");
else
Console.WriteLine(" (No description available)");
}
int deviceIndex = 0;
do
{
Console.WriteLine("Enter the interface number (1-" + allDevices.Count + "):");
string deviceIndexString = Console.ReadLine();
if (!int.TryParse(deviceIndexString, out deviceIndex) ||
deviceIndex < 1 || deviceIndex > allDevices.Count)
{
deviceIndex = 0;
}
} while (deviceIndex == 0);
// Take the selected adapter
PacketDevice selectedDevice = allDevices[deviceIndex - 1];
// Open the device
using (PacketCommunicator communicator =
selectedDevice.Open(65536, // portion of the packet to capture
// 65536 guarantees that the whole packet will be captured on all the link layers
PacketDeviceOpenAttributes.Promiscuous, // promiscuous mode
1000)) // read timeout
{
Console.WriteLine("Listening on " + selectedDevice.Description + "...");
// start the capture
communicator.ReceivePackets(0, PacketHandler);
}
}
// Callback function invoked by Pcap.Net for every incoming packet
private static void PacketHandler(Packet packet)
{
Console.WriteLine(packet.Timestamp.ToString("yyyy-MM-dd hh:mm:ss.fff") + " length:" + packet.Length);
}
}
}
یکبار که آداپتور باز می شود، عملیات ضبط می توان با استفاده از ReciveSomePackets() یا RecivePacket() آغاز شود. این دو تابع بسیار شبیه هم هستند ، تفاوت آنها در این است که ReciveSomePackets() در هنگان پایان زمان خواندن مقدار برمی گرداند (البته تضمین نمی کند) ولی RecivePacket() تا زمانی که تعداد تعیین شده پاکت ها را دریافت نکند مقداری بر نمی گرداند. از این رو می تواند برای بازه دلخواه در شبکه های مورد استفاده بلوکه شود. RecivePacket() برای مثال جاری کافی است ، در حالی که ReciveSomePackets() معمولاً در برنامه های پیچیده تر استفاده می شود.
هر دوی این توابع دارای پارامتر CallBack از نوع HandlePacket هستند که تابعی را که پارامتر ها را دریافت خواهند کرد را معرفی می کند. این تابع هنگام رسیدن یک بسته تازه از شبکه توسط Pcap.Net فراخوانی می شود. و یک بسته با برخی از اطلاعات مانند برچسب زمان[2] ، طول و داده اصلی بسته که شامل همه سرآیند های پروتکل می باشد دریافت می شود.توجه داشته باشید که فریم CRC در حالت معمولی نمایش داده نمی شود، زیرا توسط آداپتور شبکه بعد از بررسی فریم حذف می شود.همچینین توجه داشته باشید که آداپتور شبکه بسته های با CRC اشتباه را حذف می کند از این رو Pcap.Net در حالت معمولی قادر به دریافت آنها نمی باشد.مثال بالا مقادیر برچسب زمان و طول تمامی بسته ها را استخراج و چاپ می کند.
لطفا توجه داشته باشید که ممکن است، اشکالاتی در استفاده از Pcap.Net رخ دهد که عمدتاً مربوط به این واقعیت است که اجرا کننده توسط درایور ضبط پاکت فراخوانی می شود و از این رو برنامه کاربر کنترل مستقیم روی آن ندارد.یک روش دیگر (برای داشتن برنامه های خواناتر) استفاده از تابع RecivePacket() است که در درس بعدی نشان داده شده است.