ورود

View Full Version : سوال: بررسی گلوگاه ارتباط یک کامپیوتر با دنیای خارج (اینترنت) !



jlover
سه شنبه 24 فروردین 1389, 15:03 عصر
با سلام؛
چندی پیش قصد داشتم از تجربه ی اندکی که در خصوص برنامه نویسی سوکتها بدست آوردم، برنامه ای بنویسم که در این صفحه (http://barnamenevis.org/forum/showthread.php?t=210546) توضیح دادم. اما اون کار، صرفنظر از پیچیدگیهای طراحی و پیاده سازیش، احتیاج به یه سرور داشت و البته به اون مسئله بعدن به طریق دیگه ای میخام بپردازم...

اما صورت جدید مسئله :

من میخام یه برنامه بنویسم که روی سیستمم وقتی اجرا میشه بیاد ترافیک مصرفی مربوط به ارتباطم با اینترنت رو محاسبه کنه.
همین !
و چون یه دو جین نرم افزار سراغ دارم که این کار رو انجام میدن، مطمئنم باید با جاوا هم بشه این کار رو انجام داد.

گیر کارم کجاست ؟!
ببینید من تا حالا هر چی کار روی سوکتها انجام دادم، همش محدود میشد به ساختن یک (یا چند نخ) سرورسوکت و یک(یا چند) کلاینت سوکت که با هم ارتباط برقرار میکردند ...(البته از udp و دیتاگرام هم در حد demo میدونم)
خب با این حساب هم آدرس رو داشتم و هم پورت !
اما اگه فرضن بخام یه سرور بسازم و وصلش کنم به آدرس Default Gateway کامپیوترم (که همون آی پی ادرس روتر ای دی اس ال هست) روی کدوم پورت باید گوش بدم (حالا بماند اینکه برقراری چنین ارتباطی از سوی مودم مجاز شمرده میشه یا نه) و اصلن این نگاه من به قضیه درست هست یا نه !؟ یا شاید هم پورت صفر !؟ یا ...
من یکی دو روزه چند تا مقاله تو ویکیپدیا میگردم مطلبی که به دردم بخوره پیدا کنم، اما...
در ضمن دارم java tutorials رو دنبال میکنم (بخش مربوطه) و شاید هم بشه از کلاس NetworkInterface بهره ای برد یا شایدم نه ...)

همه ی این شاید ها بخاطر عدم آگاهیم از شبکه هست و به خاطر همین سپردم پسرداییم چند تا کتاب شبکه از تهران بخره (حالا دیگه فرصت نشد راهنمایی بگیرم چی خوبه برام) و از دوستانی که سررشته دارند تقاضا میکنم اطلاعاتی که حداقل برای شروع و در این مورد خاص احتیاج دارم رو راهنمایی کنند

با سپاس

javanerd
سه شنبه 24 فروردین 1389, 17:03 عصر
اما اگه فرضن بخام یه سرور بسازم و وصلش کنم به آدرس Default Gateway کامپیوترم (که همون آی پی ادرس روتر ای دی اس ال هست) روی کدوم پورت باید گوش بدم (حالا بماند اینکه برقراری چنین ارتباطی از سوی مودم مجاز شمرده میشه یا نه) و اصلن این نگاه من به قضیه درست هست یا نه !؟ یا شاید هم پورت صفر !؟ یا ...


با این روشی که شما در نظر دارید شدنی نیست. روتر ای‌دی‌اس‌ال به هیچ پورتی گوش نمیده که شما بتونید بهش وصل بشید. (احتمالا فقط به یک سری پورت پیش‌فرض گوش میده که برای تنظیم کردن مودم میشه به اونها وصل شد و طبق پروتکل تعریف شده برای روتر با دستگاه ارتباط برقرار کرد.)

من پیشنهاد می‌کنم که از کتابخانه‌ی jpcap استفاده کنید. این کتابخانه به شما اجازه میده که هر چیزی که روی کارت شبکه‌ی شما رد و بدل میشه رو ببینید.

jlover
یک شنبه 29 فروردین 1389, 17:32 عصر
با سلامی دوباره؛
ابتدا که صدر نتایج جستجوی گوگل رو دنبال کردم، با مزایا و امکانات کتابخونه هایی مثل jpcap که برپایه ی کتابخونه های libpcap/winpcap (http://winpcap.polito.it/)هستند آشنا شدم و چندین پیاده سازی مختلف هم بر این اساس پیدا کردم که چندتاشون برای جاوا بودند و باقی هم زبونهای دیگه رو در بر میگرفتند.

این همون در صدر نتایج حستجو برای jpcap قرار داشت و در نتیجه ی تحقیق و اظهار نظر دیگران و قدری هم بررسی خودم، یکی از سرراست ترین هاست. (http://netresearch.ics.uci.edu/kfujii/jpcap/doc/index.html)
این در SF قرار داره و همنام قبلیه، ولی به اندازه ی قبلی اقبال نداشته ! (http://jpcap.sourceforge.net/)
این مورد آخر بوده که با نگاهی اجمالی به مستنداتش و خوندن چند صفحه از معرفی و طرز استفاده ش متوجه شدم که بسیار پربار تر از باقی موارد هست و امکانات خیلی زیادی ارایه میده و جدید هم هست و همچنان فعالانه در حال توسعه...
(http://jnetpcap.com/)

در ضمن متوجه شدم که کتابخونه ی استاندارد جاوا، امکانات دسترسی و دستکاری لایه های پایینتر از لایه ی کاربردی رو در اختیار برنامه نویس قرار نمیده (به استثنای بحث دیتاگرام و بسته های UDP و در این مسئله ما در لایه ی انتقال و شبکه فعالیت میکنیم) و تمام این کتابخانه های برپایه ی libpcap/winpcap با تنها جاوا پیاده سازی نشدنه اند و C/C++‎ هم در پیاده سازیشون دخیل هست و مثلن در محیط ویندوز احتیاج به یک درایور (فک میکنم فقط همون یه DLL باشه) هست و دارم به صحت گفته های دوست عزیزمون آقا سعید (http://barnamenevis.org/forum/member.php?u=8702) پی میبرم که در تاپیک مربوطه ی قبلی عنوان کردند. و البته پرسشی هم دارم و اون اینه که واقعن جاوای خالص چنین امکانی رو ارایه نمیده و یا من اطلاعی ندارم !؟
تمام این کتابخونه ها هم (البته برای نظر دادن در مورد اخری باید مطالعه ی بیشتری روش داشته باشم) متدها و متغیرهایی ارایه میدن که کار یکسانی انجام میدن و فقط تفاوتهای جزیی در نامگذاریها میبینیم، مثلن برای شروع کار (بعد از مشخص کردن یک NIC ) متدی هست که در jpcap اول به این صورت تعریف میشه :

openDevice(NetworkInterface intrface, int snaplen, boolean promics, int to_ms)
و در یکجای دیگه فقط اسمش میشه openLive ! یا حتی به یه زبون اسکریپتی هم برخوردم که اون هم پارامترهای یکسانی داره و حتی توضیحات یکسان !

خب، تا اینجا خاستم نتیجه ی این دو روز جستجوم رو با دیگران هم تقسیم کنم (البته به طور اجمالی)
اما برگردیم سر مسئله ی خودم :
با در دست داشتن این کتابخونه ها باید بشه در یک چشم به هم زدن برنامه ای که میخاستم رو نوشت! اما امان از این فقر اطلاعات شبکه :
شوربختانه مستندات این کتابخونه ها درست در قسمتی که من احتیاج به دونستن تمایز دو تا فیلد دارم، در خلاصه ترین حد ممکن توضیح دادند :
در کلاس Packet که ارایه دهنده ی یک بسته ی capture شده هست دو تا فیلد داریم که نمیدونم برای حل مسئله م باید از کدومشون استفاده کنم:
len----packet length
caplen----captured length
من به چندین صورت مقدار این دو تا فیلد رو امتحان کردم و سعی کردم با اجرای برنامه ی نمونه ی JpcapDumper به تفاوتشون پی ببرم، اما چندان موفقیتی نداشتم، مثلن همیشه بسته های UDP مقدار caplen شون بیشتر از packet length شون بوده و یا در بسته های TCP که ظاهرن هر دو مقدار یکی هستند (البته این موضوع رو از قسمتهای دیگه ی تحقیقم برداشت کردم) و بماند چند ده صفحه ای از گوگل که با انواع کلیدواژه هایی که به نظرم میرسید و حتی اواخر بدون ارتباط به برنامه نویسی و با این سوال what is actual packet length + captured length جستجوم رو ادامه دادم و در کمال ناباوری انگار حتی یک نفر هم قبلن این سوال براش پیش نیومده بوده (شاید به این خاطر که همه دنبال توسعه ی برنامه های مهمتری مثل NIDSها و فایروالها و... بودند ! )
تنها جملاتی که از صفحه های کاملن متفاوت (مربوز به زبانهای متفاوت، اما با اشتراک در کتابخونه ی سطح پایین) قدری این موضوع رو روشنتر کردند اینها بودند :
caplen - the captured length of the packet; this corresponds to the $snaplen argument passed to the Net::Pcap::open_live method

snaplen : specify the maximum number of bytes to capture from each packet
البته این دو مورد به پارامتر دوم تابعی که کار capture رو انجام میده میپردازند، ولی بقیه :
len (required) : The content of the value attribute is the total length (in bytes) of the packet.
caplen (required) : The content of the value attribute is the captured length (in bytes), i.e. the length of portion of the packet that has been captured.


پس دو تا مسئله هست که باید رسیدگی کنم و به کمکتون احتیاج دارم :

1_ برای محاسبه ی میزان ترافیک گذرنده از روی کارت شبکه، کدوم پارامتر Packet رو باید بشمارم ؟ packet length یا captured length

2_ چه نوع از بسته ها رو باید برای محاسبه ی ترافیک اینترنتی در نظر بگیرم و اصلن انواع بسته ها چیه؟ البته در این مورد خودم یه حدسهایی میزنم و در مورد انواع بسته ها هم خب تا حدودی اطلاع دارم و همینطور مستندات این کتابخونه هام بهم کمک زیادی کرده، حالا نمیئونم اطلاعاتم کامل هست یا نه.
من باید برای بسته ها IPPacket شامل بسته های TCP/UDP/ICMP و بسته های دیگه ای که آدرس منبع و مقصد دارند، بررسی کنم آدرس منبعشون اگه سیستم خودم بود و آدرس مقصدشون هم روتر یا کلاینت دیگه ای در لن بود (یا بعکس)، نشمرمشون!

jlover
شنبه 04 اردیبهشت 1389, 21:31 عصر
من همون روز اول اسکلت برنامه رو نوشتم و فقط گیر دو تا مفهوم بودم که در به در دنبالشون گشتم...
به هر حال فکر میکنم درستش برای برنامه ی من به همین صورت باشه که اینجا قرار میدم و حالا که سرگرم تکمیل کردن ر.ک.گ نرم افزارم هستم، گفتم کلاسی که پاکتها رو پردازش میکنه (همون شمردن اندازه شون) رو اینجا قرار بدم، شاید کسی دوست داشت ببینه و شاید هم شانس بیارم و کسی تستش کنه (گرچه خودم تست گرفتم و میگیرم) و شاید هم خیلی بیشتر شانس بیارم و کسی محبت کنه و جواب سوال اولی که در پست قبل بصورت پررنگ نوشتم رو به من بگه !



import java.io.*;
import java.net.UnknownHostException;
import jpcap.*;
import jpcap.packet.*;

public class InternetMeter {

final java.net.InetAddress PRIVATE_ADDRESS ;
public InternetMeter() throws UnknownHostException {
// set your NIC IP address in your LAN, assumming the router IP address as 192.168.1.1
PRIVATE_ADDRESS = java.net.InetAddress.getByName("192.168.1.2");
}


int trafficCount = 0 ;
public static void main(String args[]) throws UnknownHostException, IOException {
new InternetMeter().run();
}

void run() throws UnknownHostException, IOException {
// finding NIC with IP address corresponds to one specified by constabt PRIVATE_ADDRESS
NetworkInterface targetInterface = null;
NetworkInterface devices[] = JpcapCaptor.getDeviceList();
for (NetworkInterface nic : devices) {
for (NetworkInterfaceAddress address : nic.addresses)
if (address.address.equals(PRIVATE_ADDRESS)){
targetInterface = nic ;
break;
}
}
// starting to capture packets passing on NIC already specified
final JpcapCaptor captor = JpcapCaptor.openDevice(targetInterface,65535, false, 0);
captor.setFilter("not src and dst net 192.168.1", true);
System.out.println(captor.loopPacket( -1, new PacketReceiver() {

public void receivePacket(Packet packet) {
// System.out.println(packet);
// System.out.println("captured length : "+packet.caplen);
// System.out.println("packet length : "+packet.len);
if( (trafficCount+=packet.len) >= 1000000 ){
System.out.println(trafficCount +"bytes to/from Internet");
captor.breakLoop();
}
}
}));
}
}


مهمترین قسمت کار (البته بعد از اینکه تصمیم گرفتم مطمئن باشم که packet length رو برای شمارش باید در نظر بگیرم و نه captured length ! ) مربوط میشه به عبارت فیلترینگ، یعنی :
"not src and dst net 192.168.1" و به نظرم این میتونه تضمین کنه که فقط بسته های ارسالی/دریافتی به/از اینترنت برای پردازش در نظر گرفته میشن
نحو این عبارت در کتابخونه ی winpcap و به آدرس زیر تعریف و تشریح شده و هر چقدر ترکیب پیچیده تری مورد نظر باشه، کار ساخت عبارت سختتر میشه (برای خود من که بار اولم بود، تا بفهمم و حدس بزنم و آزمون و خطا کنم، یه شب تا صبح طول کشید :خجالت: )
Filtering expression syntax (http://www.winpcap.org/docs/docs_40_2/html/group__language.html)
البته برای نرم افزار مورد نظر این کلاس دستخوش تغییرات زیادی میشه و فقط خاستم یک SSCCE قرار بدم.
نرم افزار رو هم یه نسخه عمومی و مقاوم ازش درست میکنم و به صورت باز منبع در کتابخونه ی سایت میگذارم...

سوالی که با تمام جستجوم پاسخ کاملی براش نگرفتم و حسابی ملول شدم (!) :

captured length در یک Packet یعنی چی؟ فرقش با packet length چیه ؟ امتحان کردم، دیدم همه ی بسته های UDP انتقالی بین سیتم خودم و روترم captured lengthشون بیشتر از packet lengthشونه ولی برای بسته های TCP هر دو یکسانه ...