IPFW در FreeBSD

تاریخچه FreeBSD

پیکربندی در هسته

البته نیازی به پیکر‌بندی هسته نیست. چون IPFW در هسته پیش فرض به صورت ماژول در دسترس است. اگر می‌خواهید IPFW را به صورت ثابت در هسته قرار دهید، خط زیر را به فایل پیکربندی هسته اضافه کنید و سپس آن را کامپایل نمایید:

options    IPFIREWALL

این خط پشتیبانی از IPFW را در هسته فعال می‌کند.

IPFW می تواند از عبور و مرور بسته‌ها گزارش تهیه کند. این گزارش‌ها در فایل /var/log/security ذخیره می‌شوند. البته برای فعال کردن این قابلیت باید خطوط زیر در فایل پیکربندی هسته وجود داشته باشد:

options    IPFIREWALL_VERBOSE
options    IPFIREWALL_VERBOSE_LIMIT

به صورت پیش فرض IPFW مانع عبور تمامی بسته‌ها می‌شود. اگر می‌خواهید این رفتار را تغییر دهید، خط زیر را به فایل پیکربندی هسته اضافه کنید:

options    IPFIREWALL_DEFAULT_TO_ACCEPT

افزودن خط زیربه فایل پیکربندی هسته، قابلیت NAT را فعال می‌کند.

options    IPDIVERT

فایل ‎ /etc/rc.conf

IPFW به صورت پیش فرض غیرفعال است. برای فعال کردن فایروال خط زیر را فایل /etc/rc.conf اضافه کنید:

firewall_enable="YES"

بعد از اینکه سیستم خود را راه اندازی کردید، خط زیر را خواهید دید:

ipfw2 initialized, divert disabled, rule-based forwarding disabled, default to deny, logging disabled

تبریک می‌گوییم! IPFW فعال شده است! حالا باید قوانین مورد نظر خود را برای عبور و مرور بسته‌ها وضع کرده و تعیین کنید که چه بسته‌‌هایی اجازه عبور دارند و یا از عبور چه بسته‌هایی باید جلوگیری شود.

در نصب پیش فرض، تعدادی ruleset در FreeBSD تعبیه شده که می‌توانید یکی از آنها را بعد از خواندن فایل /etc/rc.firewall انتخاب کنید. بعد از انتخاب ruleset دلخواه خود، آن را به صورت زیر فعال کنید:

firewall_type="open"

مقادیر قابل قبول برای این گزینه عبارتند از:

open به تمام بسته‌ها اجازه عبور داده می‌شود.

client تنها از این ماشین محافظت خواهد کرد.

simple از کل شبکه محافظت خواهد کرد.

closed مانع از عبور تمام ترافیک خواهد شد (بجز کارت شبکه loopback)

UNKNOWN این گزینه هیچ rule ای را بارگذاری نخواهد کرد.

filename اگر خودتان یک مجموعه rule نوشته‌اید، می توانید آنها را در فایلی ذخیره کرده و آدرس کامل این فایل را وارد کنید تا rule ها از آن فایل بارگذاری شوند.

شما مجبور نیستید از ruleset های پیش فرض استفاده کنید. خودتان هم می‌توانید یکی بنویسید. برای بارگذاری کردن rule هایی که نوشته‌اید، دو راه پیش رو دارید. یکی اینکه rule های مورد نظر خود را بدون دستور ipfw در فایلی نوشته و سپس آن فایل را با گزینه firewall_type معرفی کنید. یک نمونه از این فایل را در زیر می‌بینید:

add deny in
add deny out

روش دوم هم تقریبا مشابه روش اول است. ابتدا rule های خود را در داخل یک شل‌اسکریپت نوشته و سپس آدرس کامل این شل‌اسکریپت را با گزینه firewall_script معرفی کنید. یک نمونه از این شل اسکریپت را در زیر می‌بینید:

#!/bin/sh
ipfw -q flush
ipfw add deny in
ipfw add deny out

برای فعال کردن logging هم خط زیر را اضافه کنید:

firewall_logging="YES"

دستور ipfw

به کمک دستور ipfw می‌توانید rule های مورد نظر خود را اضافه یا حذف کنید. مشکلی که این روش دارد این است که با راه‌اندازی مجدد رایانه، تمام rule ها از بین خواهند رفت. برای رفع این مشکل می‌توانید rule ها مورد نظر خود را در فایلی نوشته و آن فایل را به فایروال معرفی کرده تا در هنگام بوت سیستم خوانده شود. روش‌های انجام این کار توضیح داده شد. به تمام ruleها یک شماره از ۱ تا ۶۵۵۳۴ اختصاص می‌یابد. شماره ۶۵۵۳۵ یک rule ويژه است که تمام بسته‌‌ها را مسدود می‌کند.

نکته:
به صورت پیش فرض، IPFW تمام ترافیک را مسدود کرده و اجازه عبور به هیچ بسته‌ای را نخواهد داد.

ipfw برای هر rule یک شمارنده یا کنتور در نظر می‌گیرد. هر بار که بسته‌ای با یک rule تطابق (match) پیدا کرد، این شمارنده یک واحد افزایش می‌یابد. وقتی که در حال آزمودن rule های خود هستید، می توانید با نگاه کردن به این شمارنده متوجه شوید که آیا تطابق رخ داده یا نه.

برای دیدن لیستی از rule های در حال استفاده دستور زیر را اجرا کنید:

# ipfw list

برای اینکه بدانید یک rule آخرین بار کی تطبیق پیدا کرده، دستور زیر را اجرا کنید.

# ipfw -t list

دستور زیر rule های پویا را هم به همراه rule های ایستا نمایش می‌دهد:

# ipfw -d list

دستور زیر شمارنده‌ها را صفر می‌کند:

# ipfw zero

دستور زیر شمارنده یک rule خاص را صفر می‌کند. NUM همان شماره rule مورد نظر است:

# ipfw zero NUM

یک ruleset به مجموعه چند rule گفته می‌شود. این rule ها با توجه به مشخصاتی یک بسته دارد در مورد عبور آن تصمیم گیری می‌کنند.

وقتی که یک بسته وارد فایروال می‌شود، با اولین rule موجود در ruleset مقایسه می‌شود. اگر تطبیقی رخ نداد، rule بعدی بر روی بسته آزمایش می‌شود و به همین ترتیب. به محض اینکه بسته‌ای با یکی از rule ها تطبیق پیدا کرد، پردازش بسته متوقف شده و با توجه به عملیات تعریف شده برای آن rule، درباره سرنوشت آن بسته تصمیم گیری می‌شود. این روش به «اولین تطبیق برنده است» معرف است. اگر بسته مورد نظر با هیچ rule ای منطبق نشد، بالاجبار گرفتار آخرین rule می‌شود. آخرین rule به صورت پیش فرض، بسته مورد نظر را بدون هیچ قید و شرطی نابود خواهد کرد و به آن اجازه عبور نخواهد داد. البته این رفتار قابل تغییر است.

هنگامی که این متن را می‌خوانید، به این نکته توجه داشته باشید که در شبکه ارتباطات دوطرفه هستند. وقتی که شما در‌خواستی را برای کسی ارسال می‌کنید، او هم یک پاسخ برایتان ارسال خواهد کرد. در هنگام نوشتن rule ها توجه داشته باشید که ruleها ی خود را هم برای درخواست ها و هم برای پاسخ‌ها بنویسید. اگر به درخواستی اجازه عبور دهید اما به پاسخ آن اجازه عبور ندهید، نتیجه‌ای دریافت نخواهید کرد. برای رفع این مشکل کافی است در آخر rule خود از کلید‌واژه keep-state استفاده کنید تا اجازه ارتباط دو طرفه بین مبدا و مقصد صادر شود.

نحوه نوشته ruleها

Rule ها از یکسری کلید‌واژه تشکیل می‌شوند. این کلید واژه ها را باید با یک ترتیب خاصی از چپ به راست بنویسید. کلید‌واژه ها به حروف کوچک و بزرگ حساس هستند. شکل کلی هر rule به صورت زیر است:

CMD RULE_NUMBER ACTION LOGGING SELECTION STATEFUL

فیلد CMD

در ابتدای تمام ruleها کلیدواژه add قرار می‌گیرد که برای اضافه کردن یک rule به کار می‌رود. از کلیدواژه delete هم برای پاک کردن یک rule استفاده می‌شود.

فیلد RULE_NUMBER

هر rule یک شماره منحصر به فرد دارد. این شماره باید بین ۱ تا ۶۵۵۳۵ باشد. می‌توانید این شماره را در هنگام نوشتن rule مشخص کنید. البته انجام این کار اختیاری است. اگر این کار را انجام ندهید، ipfw اولین شماره قابل استفاده را انتخاب کرده و آن را هر ۱۰۰ تا ۱۰۰ تا افزایش می‌دهد.

فیلد ACTION

این فیلد سرنوشت بسته را تعیین می‌کند. می توانید بر اساس مشخصاتی که یک بسته دارد به آن اجازه عبور دهید یا این اجازه را از او بگیرید. برای اینکه به یک بسته اجازه عبور دهید، از کلید‌واژه های زیر استفاده کنید:

allow | accept | pass | permit

تمام کلید‌واژه های بالا معادل یکدیگر بوده و با هم هیچ فرقی ندارند. از هر کدام که دوست داشتید استفاده کنید. تمام این کلید‌واژه‌ها به بسته مورد نظر اجازه عبور می‌دهند. پردازش بسته بلافاصله متوقف می‌شود.

deny | drop

این کلید‌واژه ها هم مانع از عبور یک بسته می‌شوند و عملکردی یکسان دارند.

reset

این کلید واژه، ابتدا بسته مورد نظر را drop کرده و سپس یک پیغام TCP reset برای مبدا ارسال می‌کند.

count

این کلید‌واژه باعث می‌شود تا شمارنده rule یک واحد افزایش یابد. بقیه rule ها بر روی بسته آزمایش می‌شوند و پردازش بسته متوقف نخواهد شد.

skipto RULNUM

این کلید واژه باعث می‌شود تا پردازش بسته از rule شماره RULNUM ادامه یابد.

فیلد LOGGING

این گزینه به فایروال می‌گوید که از مشخصات این بسته گزارش تهیه کن. این گزارش برای ثبت به syslog ارسال می‌شود. انجام این کار می‌تواند شما را در خطایابی یاری دهد. اگر ruleها مطابق میل شما رفتار نمی‌کنند، می توانید با ثبت گزارش از بسته‌ها اقدام به خطایابی کنید.

فواید گزارش گیری آشکار است. اینکه بدانید چه بسته‌هایی وارد فایروال شده‌اند، چه کسی آنها را ارسال کرده، چه کسی آنها را باید دریافت کند، فایروال به کدام یک اجازه عبور داده و کدام یک را drop کرده و … می‌تواند بسیار مفید باشد. این گزارش‌ها در فایل‌هایی ذخیره می‌شوند و شما می‌توانید این فایل‌ها را بخوانید.

البته عمل گزارش‌گیری یک چاقوی دو لبه است. اگر در انجام این کار دقت نکنید، ممکن است فایل‌های ثبت رخداد بسیار حجیم شوند و دیسک سخت شما را پر کنند. بنابراین باید در دیسک سخت خود به اندازه کافی فضای خالی داشته باشید.

فیلد SELECTION

کلید واژه ‌هایی که در این قسمت تشریح می‌شوند، برای مشخص کردن ویژگی‌های بسته مورد نظر به کار می‌روند. این کلید‌واژه‌ها را باید با ترتیب خاصی وارد کنید.

udp | tcp | icmp | ip

پروتکل مربوط به بسته مورد نظر را مشخص می‌کنند. می‌توانید از هر پروتکل دیگری که خواستید استفاده کنید؛ به شرطی که در فایل /etc/protocols تعریف شده باشد. مشخص کردن این فیلد اجباری است.

from src to dst

کلید‌واژه‌های from و to برای مشخص کردن فرستنده و گیرنده استفاده می‌شوند. می‌توانید از آدرس IP یا نام دامنه استفاده کنید. from مشخص می‌کند که بسته توسط چه کسی ارسال شده و to هم مشخص می‌کند که بسته توسط چه کسی دریافت خواهد شد. باید هم مبدا و هم مقصد را مشخص کنید. کلید‌واژه‌ای به نام any وجود دارد که ‘’همه‌جا’’ معنی می‌دهد و با تمام آدرس‌های IP تطابق دارد. Any همان آدرس ۰٫۰٫۰٫۰/۰ را مشخص می‌کند. me هم کلید‌واژه دیگری است که مشخص کننده تمام آدرس‌های IP متعلق به فایروال است. (یعنی همین ماشینی که قرار است ipfw بر روی آن پیکربندی شود)

مثال:

from me to any بسته‌هایی را مشخص می‌کند که مبدا آنها فایروال است.

from any to me بسته‌هایی را مشخص می‌کند که مقصد آنها فایروال است.

from any to any مبدا و مقصد اهمیتی ندارد. تمام بسته ها از هر مبدائی به هر مقصدی را شامل می‌شود.

آدرسهای IP را باید به روش CIDR بنویسید.

port number

بعضی از پروتکل‌ها با پورت ها سروکار دارند (مثل TCP و UDP) برای این پروتکل‌‌ها باید بالاجبار شماره پورت را هم مشخص کنید. هم می‌توانیم شماره پورت را بنویسید و هم می‌توانید از نامی که در فایل /etc/protocols به پورت مورد نظر اختصاص داده شده استفاده کنید.

in | out

جهت حرکت بسته را مشخص می‌کند. یعنی اینکه بسته مورد نظر قرار است به فایروال وارد شده یا اینکه از آن خارج شود.

via

مشخص کننده نام کارت شبکه‌ای است که بسته از طریق آن وارد/خارج می‌شود. اگر چند کارت شبکه دارید، می‌توانید بر اساس آنها بسته‌ها را فیلتر کنید. مثلا بسته‌هایی را شناسایی کنید که از طریق رابط em0 وارد سیستم می‌شوند یا همچنین بسته‌هایی که از طریق رابط em0 از سیستم خارج می‌شوند.

setup

این کلیدواژه بسته‌های TCP که بیت SYN دارند، اما بیت ACK ندارند را شناسایی می‌کند. مخفف tcpflags syn,!ack است. معنی این حرف این است که این کلیدواژه برای شناسایی بسته‌های TCP که قرار است ارتباطی را آغاز کنند، به کار می‌رود.

 keep-state

وقتی که تطبیقی رخ داد، یک rule پویا ایجاد شده و اجازه ارتباط دو طرفه بین مبدا و مقصد صادر می‌شود. یعنی باعث می‌شود فایروال رفتاری stateful داشته باشد. همین جا متذکر می‌شوم که rule های پویا عمر محدودی دارند و بعد از مدت مشخصی از بین خواهند رفت. این مدت زمان را می‌توانید با تغییر گزینه net.inet.ip.fw توسط sysctl تنظیم کنید.

// this is a comment.

متن مورد نظر را به عنوان توضیح به rule اضافه می‌کند. هر چیزی که بعد از // قرار گیرد، به عنوان توضیح تفسیر شده و در rule ذخیره می‌شود.

جداول

جداول برای دسته‌بندی آدرس‌های IP استفاده می‌شوند. اگر می‌خواهید عملیات یکسانی را بر روی تعداد زیادی آدرس IP انجام دهید، می توانید آدرس‌های مورد نظر خود را در داخل جدولی وارد کرده و سپس عملیات مورد نظر خود را بر روی ان جدول انجام دهید. بدون انجام این کار مجبور هستید تا آن عملیات را به ازای تمام آدرس‌ها تکرار کنید.

به هر جدول یک شماره از ۰ تا ۱۲۷ اختصاص می‌یابد. آدرس‌های IP باید به روش CIDR وارد جداول شوند. برای اضافه کردن یک آدرس به جدول از قالب زیر استفاده کنید:

ipfw table NUM add ADDRESS/MASK

همین طور برای حذف یک آدرس:

ipfw table NUM delete ADDRESS/MASK

برای پاک کردن کلیه آدرس‌های موجود در جدول:

ipfw table NUM flush

و برای دیدن لیست آدرس های موجود در جدول:

ipfw table NUM list

در تمام مثال‌های بالا، NUM شماره جدول مورد نظر و ADDRESS/MASK همان آدرس مورد نظر می‌باشد.

مثال ها

add 1000 allow all from any to any

مثال بالا، یکی از ساده‌ترین مثال های ممکن است. این مثال به تمام بسته‌ها از هر مبدا‌ئی که باشند و بخواهند به هر مقصدی که بروند اجازه عبور می‌دهد. شماره این rule صد می‌باشد.

add 1300 count all from any to any

به ازای هر بسته‌ای که وارد فایروال می‌شود، یک واحد به شمارنده این rule اضافه خواهد شد.

add 1400 skipto 1800 all from any to any

پردازش تمام بسته‌هایی که با این rule تطابق پیدا می‌کنند از rule شماره ۱۸۰۰ ادامه خواهد یافت. چون شماره خودِ این rule هزارو چهارصد است، عملا rule های شماره ۱۴۰۱ تا ۱۷۹۹ جا انداخته می‌شوند و بسته بر روی آنها آزمایش نمی‌شود.

add 1000 allow all from myhost to hishost

مثال بالا اجازه عبور را برای تمامی بسته‌هایی که از مبدا myhost به مقصد hishost ارسال می‌شوند را صادر می‌کند. به جای myhost و hishost می توانید از آدرس های IP آنها هم استفاده کنید. مانند زیر:

add 1100 deny all from 10.0.0.5 to any

همان طور که می بینید در قسمت from از یک آدرس IP استفاده شده.

add 1000 allow all from any to any in

تمام بسته‌های وارده به فایروال، از هر مبدائی که باشند و به هر مقصدی که بخواهند بروند را شناسایی کرده و به آنها اجازه عبور می‌دهد.

add 1100 allow all from any to any in via xl0

به تمامی بسته هایی که از طریق کارت شبکه x10 وارد فایروال می‌شوند، بدون توجه به مبدا و مقصد آنها اجازه عبور می‌دهد.

add count log tcp from me to any dst-port 80

مثال بالا از تمام بسته‌هایی که برای یک وب‌سرور ارسال می‌شوند گزارش تهیه می‌کند. این گزارش در فایل /var/log/security ذخیره می‌شود. برای rule بالا ما شماره‌ای را مشخص نکردیم. بنابراین ipfw آن را به انتهای لیست اضافه خواهد کرد.

حالا فرض کنید که قوانین زیر را برای عبور و مرور بسته‌ها وضع کرده‌ایم:

# ipfw l 
	۰۰۱۰۰ allow ip from any to any via lo0
	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

فرض کنید که فایروال ما یک IP با آدرس ۲۰۵٫۲۳۸٫۱۲۹٫۲۲۱ دارد و یک بسته telnet از اینترنت دریافت می‌کند. یعنی شخصی (مثلا با آدرس ۱٫۲٫۳٫۴) سعی می‌کند از طریق telnet به فایروال ما دسترسی پیدا کند. بنابراین بسته ارسالی توسط او مشخصات زیر را دارد:

Source_IP     Source_PORT     Destination_IP     Destination_PORT     Protocol
۱٫۲٫۳٫۴          ۳۳۳۳         ۲۰۵٫۲۳۸٫۱۲۹٫۲۲۱           ۲۳               TCP

مراحل زیر برای پردازش این بسته در فایروال انجام می‌شود:

۱) کرنل بسته را از کارت شبکه xl0 دریافت می‌کند.

۲) کرنل بسته را با rule شماره ۱۰۰ آزمایش می‌کند.

=====> 00100 allow ip from any to any via lo0
	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۳) بسته تطبیق داده نشد. بنابراین بسته با rule بعدی آزمایش می‌شود:

	۰۰۱۰۰ allow ip from any to any via lo0
======>	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۴) بسته تطبیق داده نشد. بنابراین بسته با rule بعدی آزمایش می‌شود:

	۰۰۱۰۰ allow ip from any to any via lo0
	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
======>	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۵) بسته تطبیق داده نشد. بنابراین بسته با rule بعدی آزمایش می‌شود:

	۰۰۱۰۰ allow ip from any to any via lo0
	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
======>	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۶) بسته تطبیق داده شد! سرنوشت بسته بر اساس rule تعیین خواهد شد که در اینجا بسته اجازه عبور دارد.

۷) بسته به دایمن telnet بر روی پورت ۲۳ تحویل داده می‌شود تا مورد پردازش قرار گیرد.

۸) دایمن telnet بسته مورد نظر را پردازش کرده و پاسخ آن را ارسال می‌کند.

همان طور که قبلا گفتم، در شبکه ارتباطات دو طرفه است و هر درخواستی یک پاسخ به همراه دارد. بیشتر افراد این موضوع را فراموش می‌کنند و به همین دلیل از ruleهای خود نتیجه دلخواه را نمی‌گیرند. مشخصات پاسخی که دایمن telnet ارسال کرده به شرح زیر است:

Source_IP        Source_PORT     Destination_IP   Destination_PORT   Protocol
۲۰۵٫۲۳۸٫۱۲۹٫۲۲۱     ۲۳              ۱٫۲٫۳٫۴             ۳۳۳۳           TCP

بنابراین، ما مراحل بالا را برای این بسته هم تکرار می‌کنیم:

۱) کرنل بسته را با rule شماره ۱۰۰ آزمایش می‌کند.

=====> 00100 allow ip from any to any via lo0
	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۲) بسته تطبیق داده نشد. بنابراین بسته با rule بعدی آزمایش می‌شود:

	۰۰۱۰۰ allow ip from any to any via lo0
======>	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۳) بسته تطبیق داده نشد. بنابراین بسته با rule بعدی آزمایش می‌شود:

	۰۰۱۰۰ allow ip from any to any via lo0
	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
======>	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۴) بسته تطبیق داده نشد. بنابراین بسته با rule بعدی آزمایش می‌شود:

	۰۰۱۰۰ allow ip from any to any via lo0
	۰۰۲۰۰ deny ip from any to 127.0.0.0/8
	۰۰۳۰۰ deny ip from 127.0.0.0/8 to any
======>	۶۵۰۰۰ allow ip from any to any
	۶۵۵۳۵ deny ip from any to any

۵)مشخصات بسته هم خوانی دارد! بنابراین اجازه خروج برای او صادر خواهد شد.

در مثال بالا، اگر ما rule شماره ۶۵۰۰۰ را نداشتیم، بسته توسط rule شماره ۶۵۵۳۵ نابود می‌شد.