Preloader Icon

استفاده از tcpdump در لینوکس

0 دیدگاه
22 اردیبهشت 1404

استفاده از tcpdump در لینوکس

tcpdump یک ابزار خط فرمان بسیار قدرتمند و انعطاف‌پذیر است که برای ضبط و تحلیل ترافیک شبکه به‌کار می‌رود. این برنامه اغلب در عیب‌یابی مشکلات شبکه و حتی به‌عنوان یک ابزار امنیتی استفاده می‌شود. در این مقاله برخی از کاربردها و ویژگی‌های رایج tcpdump در لینوکس را بررسی می‌کنیم.

مدیران شبکه هنگام رفع ایرادهای اتصال شبکه با چالش‌های متعددی روبه‌رو می‌شوند؛ در چنین مواردی tcpdump به‌عنوان یک دوست و همراه مطمئن به کمک ما می‌آید. این ابزار خط فرمان امکان ضبط (Capture) ترافیک عبوری از شبکه روی سیستم را فراهم کرده و تحلیل آن را میسر می‌سازد.

tcpdump گزینه‌ها و فیلترهای متعددی دارد که آن را به ابزاری همه‌کاره تبدیل کرده‌اند و در سناریوهای گوناگون قابل استفاده است. از آنجا که tcpdump یک ابزار متنی (CLI) است، می‌توان آن را در سرورها یا دستگاه‌های راه‌دوری که واسط گرافیکی (GUI) ندارند برای جمع‌آوری داده جهت تحلیل‌های بعدی به کار گرفت. همچنین می‌توان tcpdump را در پس‌زمینه یا به‌صورت زمان‌بندی‌شده (مثلاً با cron) اجرا کرد.

نصب tcpdump در لینوکس

tcpdump روی بسیاری از توزیع‌های لینوکس به‌صورت پیش‌فرض موجود است؛ پس ابتدا بررسی می‌کنیم که آیا از قبل نصب شده است یا خیر. برای این کار از دستور which استفاده می‌کنیم تا مسیر برنامه tcpdump را بیابیم:

which tcpdump
/usr/sbin/tcpdump

اگر مسیر بالا نمایش داده شود، به این معناست که tcpdump روی سیستم نصب است. در غیر این صورت، می‌توانیم آن را با استفاده از مدیر بسته توزیع خود نصب کنیم. برای مثال، در توزیع‌های CentOS یا RHEL (رد هت) از دستور زیر استفاده می‌کنیم:

sudo dnf install -y tcpdump

هنگام نصب، توجه کنید که tcpdump به کتابخانه‌ی libpcap وابسته است. این کتابخانه مخصوص Capturing Packet‌های شبکه است و اگر از قبل نصب نباشد، مدیر بسته به طور خودکار آن را به‌عنوان وابستگی لازم (Dependency) نصب خواهد کرد.

پس از اطمینان از نصب بودن tcpdump، اکنون آماده‌ایم که عملیات ضبط بسته‌ها را آغاز کنیم.

گرفتن پکت‌ها با tcpdump

برای ضبط (Capture) بسته‌های شبکه جهت عیب‌یابی یا تحلیل، tcpdump نیاز به دسترسی سطح بالا (کاربر ریشه) دارد. بنابراین در بیشتر مثال‌های این بخش دستورات را با sudo اجرا می‌کنیم.

نخست، می‌توانیم با دستور tcpdump --list-interfaces (یا به‌اختصار -D) فهرست تمامی رابط‌های شبکه‌ی موجود را برای عملیات کپچر مشاهده کنیم:

sudo tcpdump -D
1.eth0
2.virbr0
3.eth1
4.any (Pseudo-device that captures on all interfaces)
5.lo [Loopback]

در خروجی بالا، فهرست تمامی رابط‌های شبکه (interfaces) روی سیستم را مشاهده می‌کنیم. رابط ویژه‌ی any این امکان را فراهم می‌کند که tcpdump همه‌ی اینترفیس‌های فعال را به‌طور هم‌زمان پایش و ترافیک آن‌ها را ضبط کند.

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

sudo tcpdump --interface any
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
09:56:18.293641 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 3770820720:3770820916, ack 3503648727, win 309, options [nop,nop,TS val 76577898 ecr 510770929], length 196
09:56:18.293794 IP 192.168.64.1.56322 > rhel75.localdomain.ssh: Flags [.], ack 196, win 391, options [nop,nop,TS val 510771017 ecr 76577898], length 0
09:56:18.295058 IP rhel75.59883 > gateway.domain: 2486+ PTR? 1.64.168.192.in-addr.arpa. (43)
...
^C
9003 packets captured
9010 packets received by filter
7 packets dropped by kernel

همان‌طور که مشاهده می‌کنید، tcpdump تمامی ترافیک شبکه را ضبط می‌کند و تا زمانی که سیگنال توقف نگیرد (مانند فشردن Ctrl+C) به کپچر کردن ادامه می‌دهد. در مثال بالا با فشردن ترکیب کلید ^C کپچر را متوقف کرده‌ایم؛ tcpdump گزارش می‌دهد که بیش از ۹۰۰۰ بسته را ضبط کرده است. دلیل این تعداد زیاد بسته آن است که در این سناریو از طریق SSH به سرور متصل بوده‌ایم و tcpdump تمامی ترافیک SSH (شامل هر بسته‌ی مربوط به اتصال SSH ما) را نیز ضبط کرده است.

در بسیاری از مواقع برای محدود کردن حجم خروجی و کنترل بهتر، می‌توانیم تعداد بسته‌هایی را که tcpdump ضبط می‌کند محدود کنیم تا پس از رسیدن به آن تعداد، tcpdump به‌طور خودکار متوقف شود. برای این منظور از گزینه‌ی -c (count) استفاده می‌کنیم. به عنوان نمونه، دستور زیر را اجرا می‌کنیم تا حداکثر ۵ پکت ضبط شود و سپس tcpdump متوقف گردد:

sudo tcpdump -i any -c 5
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
11:21:30.242740 IP rhel75.localdomain.ssh > 192.168.64.1.56322: Flags [P.], seq 3772575680:3772575876, ack 3503651743, win 309, options [nop,nop,TS val 81689848 ecr 515883153], length 196
...
5 packets captured
12 packets received by filter
0 packets dropped by kernel

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

به‌طور پیش‌فرض، tcpdump تلاش می‌کند آدرس‌های IP و پورت‌ها را به نام میزبان و نام سرویس مربوطه Resolve کند (تبدیل آدرس به نام انجام می‌دهد)؛ همان‌طور که در نمونه‌خروجی‌های قبلی می‌بینید، مثلاً آدرس 192.168.64.28.22 را به rhel75.localdomain.ssh تبدیل کرده است. در هنگام عیب‌یابی شبکه، معمولاً مشاهده‌ی خود آدرس‌های IP و شماره پورت‌ها ساده‌تر و مفیدتر است. برای غیرفعال کردن تبدیل نام میزبان و سرویس‌ها می‌توانیم از گزینه‌های -n و -nn استفاده کنیم. سوئیچ -n جلوی تبدیل آدرس‌های شبکه به نام میزبان را می‌گیرد و -nn علاوه بر آن نام سرویس‌ها (پورت‌ها) را نیز به عدد نشان می‌دهد. به عبارت دیگر -nn به طور کامل رزولوشن نام‌ها را غیرفعال می‌کند.

در ادامه همان دستور را با گزینه -nn اجرا می‌کنیم تا تفاوت را ببینیم:

sudo tcpdump -i any -c5 -nn
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
23:56:24.292206 IP 192.168.64.28.22 > 192.168.64.1.35110: Flags [P.], seq 166198580:166198776, ack 2414541257, win 309, options [nop,nop,TS val 615664 ecr 540031155], length 196
23:56:24.292357 IP 192.168.64.1.35110 > 192.168.64.28.22: Flags [.], ack 196, win 1377, options [nop,nop,TS val 540031229 ecr 615664], length 0
...
5 packets captured
6 packets received by filter
0 packets dropped by kernel

همان‌طور که مشاهده می‌کنید، خروجی tcpdump اکنون آدرس‌های IP و شماره پورت‌ها را به صورت عددی نمایش می‌دهد (به جای نام میزبان یا سرویس). غیرفعال کردن تبدیل نام علاوه بر خواناتر کردن خروجی برای ما، جلوی ارسال درخواست‌های DNS توسط خود tcpdump را نیز می‌گیرد و در نتیجه ترافیک اضافی حین عیب‌یابی تولید نخواهد شد.

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

تحلیل خروجی tcpdump

tcpdump قادر است طیف وسیعی از پروتکل‌ها (TCP, UDP, ICMP و …) را رمزگشایی و نمایش دهد. پرداختن به تمام جزئیات خروجی برای همه‌ی پروتکل‌ها در این مجال ممکن نیست. بنابراین برای شروع، ساختار خروجی یک بسته‌ی TCP معمولی را با هم بررسی می‌کنیم. به عنوان نمونه، یک خط خروجی tcpdump مربوط به یک بسته‌ی TCP ممکن است به شکل زیر باشد:

08:41:13.729687 IP 192.168.64.28.22 > 192.168.64.1.41916: Flags [P.], seq 196:568, ack 1, win 309, options [nop,nop,TS val 117964079 ecr 816509256], length 372

اجزای این خط بسته به نوع بسته‌ی ضبط‌شده می‌تواند متفاوت باشد، اما به طور کلی این قالب را داریم:

    • زمان: بخش ابتدایی (08:41:13.729687) نشان‌دهنده‌ی زمان دریافت بسته بر حسب ساعت/دقیقه/ثانیه (و کسری از ثانیه) در ساعت محلی سیستم است.

    • پروتکل لایه شبکه: عبارت IP بعد از زمان، نشان می‌دهد که این بسته مربوط به پروتکل IPv4 است (در صورتی که IPv6 بود، به صورت IP6 نمایش داده می‌شد).

    • آدرس مبدأ و مقصد: بخش بعدی 192.168.64.28.22 > 192.168.64.1.41916 شامل آدرس IP و شماره پورت مبدأ، و سپس آدرس IP و شماره پورت مقصد است. در این مثال، بسته از آدرس 192.168.64.28 و پورت 22 (SSH) به آدرس 192.168.64.1 و پورت مقصد 41916 ارسال شده است.

    • پرچم‌ها (Flags): پس از آدرس‌ها، بخش Flags [P.] را مشاهده می‌کنیم. این قسمت نشان‌دهنده‌ی فلگ‌های TCP برای آن بسته است. هر کاراکتر معرف یک وضعیت خاص در پروتکل TCP است. مقادیر متداول این فیلد عبارت‌اند از: S (شروع ارتباط SYN)، F (پایان ارتباط FIN)، P (فشار داده PUSH)، R (بازنشانی اتصال RST) و . (تأیید ACK).

      این حروف می‌توانند به صورت ترکیبی نیز ظاهر شوند، مانند [S.] که نشان‌دهنده‌ی بسته‌ی SYN+ACK است.

    • شماره توالی (Sequence Number): عدد یا بازه‌ی بعد از seq، شماره‌ی توالی داده‌های موجود در بسته را مشخص می‌کند. در اولین بسته از یک جریان، این شماره یک مقدار مطلق است؛ اما در بسته‌های بعدی معمولاً tcpdump برای سهولت خواندن از شماره‌گذاری نسبی استفاده می‌کند. در مثال بالا seq 196:568 بدین معناست که این بسته حاوی بایت‌های شماره 196 تا 568 از جریان داده است.

    • شماره تأییدیه (Ack Number): بخش بعدی با ack مشخص شده (ack 1 در مثال) شماره تأییدیه را نشان می‌دهد. در بسته‌های ارسالی از فرستنده‌ی داده اولیه (مثل بسته‌ی اول در ابتدای ارتباط) معمولاً مقدار ACK برابر 1 است چون هنوز داده‌ای از سمت مقابل دریافت نکرده است. در طرف مقابل، این شماره نشان‌دهنده‌ی شماره‌ی بایت بعدی است که گیرنده در جریان انتظار دارد دریافت کند. به عنوان مثال، اگر بسته‌ی بعدی در این جریان حاوی 372 بایت داده باشد، شماره‌ی ACK آن 568 خواهد بود (یعنی تأیید دریافت تا بایت 567 و انتظار دریافت از 568 به بعد).

    • اندازه پنجره (Window Size): مقدار بعدی که با win مشخص شده (win 309 در مثال) اندازه پنجره‌ی TCP را نشان می‌دهد؛ یعنی تعداد بایتی که گیرنده در بافر دریافت خود جا دارد.

    • گزینه‌های TCP: پس از اندازه پنجره، ممکن است گزینه‌های اختیاری TCP آمده باشد که داخل کروشه نمایش داده می‌شود (در مثال بالا: options [nop,nop,TS val 117964079 ecr 816509256]). این گزینه‌ها می‌توانند شامل MSS (حداکثر اندازه سگمنت)، Window Scale، Timestamp و موارد دیگر باشند. در اینجا nop ها صرفاً پرکننده هستند و TS val و ecr به گزینه‌های Timestamp مربوط می‌شوند.

    • طول داده: در انتها length 372 طول بخش داده‌ی بسته (به بایت) را نشان می‌دهد. این مقدار در واقع اختلاف بین آخرین و اولین شماره توالی این بسته است (568 – 196 = 372 بایت داده).

    اکنون که ساختار کلی یک خط خروجی tcpdump را درک کردیم، می‌توانیم با استفاده از فیلترها خروجی را محدود کرده و روی بسته‌های مربوط به مسأله‌ی موردنظر تمرکز کنیم.

 

فیلتر کردن پکت‌ها

همان‌طور که اشاره شد، tcpdump ممکن است حجم بسیار زیادی از ترافیک را ضبط کند که همه‌ی آن برای مشکل موردنظر ما مفید نیست. به عنوان نمونه، اگر در حال عیب‌یابی مشکل اتصال به یک وب‌سرور هستیم و ترافیک SSH ارتباطی به موضوع ما ندارد، حذف بسته‌های مربوط به SSH از خروجی به ما کمک می‌کند روی مشکل اصلی متمرکز شویم.

یکی از قدرتمندترین قابلیت‌های tcpdump توانایی فیلتر کردن بسته‌های ضبط‌شده بر اساس معیارهای مختلف از جمله آدرس IP مبدأ یا مقصد، شماره پورت، نوع پروتکل و … است. در ادامه به برخی از رایج‌ترین فیلترها و نحوه‌ی استفاده از آن‌ها می‌پردازیم.

فیلتر بر اساس پروتکل

برای فیلتر کردن بسته‌ها بر مبنای نوع پروتکل کافی است نام پروتکل مربوطه را در فرمان tcpdump ذکر کنیم. به‌عنوان مثال، برای اینکه فقط بسته‌های ICMP را ضبط کنیم (که معمولاً برای پینگ استفاده می‌شود) می‌توانیم چنین دستوری اجرا کنیم:

sudo tcpdump -i any -c5 icmp

پس از اجرای دستور بالا، در یک ترمینال دیگر یک مقصد را پینگ می‌کنیم تا ترافیک ICMP ایجاد شود:

ping opensource.com
PING opensource.com (54.204.39.132) 56(84) bytes of data.
64 bytes from ec2-54-204-39-132.compute-1.amazonaws.com (54.204.39.132): icmp_seq=1 ttl=47 time=39.6 ms

حالا دوباره به خروجی tcpdump نگاه می‌کنیم. طبق انتظار، tcpdump تنها بسته‌های ICMP مربوط به پینگ را ضبط و نمایش داده است و بسته‌های دیگری (نظیر بسته‌های DNS مربوط به Resolving نام opensource.com) در خروجی دیده نمی‌شوند:

09:34:20.136766 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 1, length 64
09:34:20.176402 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply, id 20361, seq 1, length 64
09:34:21.140230 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 2, length 64
09:34:21.180020 IP ec2-54-204-39-132.compute-1.amazonaws.com > rhel75: ICMP echo reply, id 20361, seq 2, length 64
09:34:22.141777 IP rhel75 > ec2-54-204-39-132.compute-1.amazonaws.com: ICMP echo request, id 20361, seq 3, length 64
5 packets captured
5 packets received by filter
0 packets dropped by kernel

در مثال بالا، مشاهده می‌کنید که فقط درخواست‌ها و پاسخ‌های ICMP (پینگ) بین دو هاست نمایش داده شده و خبری از بسته‌های دیگر (مثلاً بسته‌های DNS مربوط به name resolution) نیست.

فیلتر بر اساس میزبان (Host)

با استفاده از فیلتر host می‌توانیم ترافیک را تنها به یک میزبان مشخص محدود کنیم. این میزبان می‌تواند مبدأ یا مقصد بسته‌ها باشد. به عنوان مثال، دستور زیر را اجرا می‌کنیم تا فقط بسته‌هایی که از یا به آدرس IP مشخصی (مثلاً 54.204.39.132) مرتبط هستند گرفته شوند:

sudo tcpdump -i any -c5 -nn host 54.204.39.132

و خروجی نمونه‌ی آن به صورت زیر خواهد بود:

09:54:20.042023 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [S], seq 1375157070, win 29200, options [mss 1460,sackOK,TS val 122350391 ecr 0,nop,wscale 7], length 0
09:54:20.088127 IP 54.204.39.132.80 > 192.168.122.98.39326: Flags [S.], seq 1935542841, ack 1375157071, win 28960, options [mss 1460,sackOK,TS val 522713542 ecr 122350391,nop,wscale 9], length 0
09:54:20.088204 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 122350437 ecr 522713542], length 0
09:54:20.088734 IP 192.168.122.98.39326 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122350438 ecr 522713542], length 112: HTTP: GET / HTTP/1.1
09:54:20.129733 IP 54.204.39.132.80 > 192.168.122.98.39326: Flags [.], ack 113, win 57, options [nop,nop,TS val 522713552 ecr 122350438], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

در این مثال، tcpdump تنها بسته‌هایی را که مبدأ یا مقصد آن‌ها آدرس 54.204.39.132 بوده ضبط و نمایش داده است (هر پنج بسته مربوط به ارتباط بین کلاینت 192.168.122.98 و سرور 54.204.39.132 هستند).

فیلتر بر اساس پورت

به‌منظور فیلتر کردن بسته‌ها بر اساس یک سرویس یا پورت مشخص از فیلتر port استفاده می‌کنیم. برای مثال، برای ضبط بسته‌های مربوط به سرویس وب (HTTP که پورت 80 است) دستور زیر را اجرا می‌کنیم:

sudo tcpdump -i any -c5 -nn port 80

نمونه خروجی این دستور می‌تواند مشابه زیر باشد:

09:58:28.790548 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [S], seq 1745665159, win 29200, options [mss 1460,sackOK,TS val 122599140 ecr 0,nop,wscale 7], length 0
09:58:28.834026 IP 54.204.39.132.80 > 192.168.122.98.39330: Flags [S.], seq 4063583040, ack 1745665160, win 28960, options [mss 1460,sackOK,TS val 522775728 ecr 122599140,nop,wscale 9], length 0
09:58:28.834093 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 122599183 ecr 522775728], length 0
09:58:28.834588 IP 192.168.122.98.39330 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 122599184 ecr 522775728], length 112: HTTP: GET / HTTP/1.1
09:58:28.878445 IP 54.204.39.132.80 > 192.168.122.98.39330: Flags [.], ack 113, win 57, options [nop,nop,TS val 522775739 ecr 122599184], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

همان‌طور که مشاهده می‌شود، در این خروجی پنج بسته‌ی مربوط به ارتباط HTTP (شروع اتصال TCP و تبادل HTTP GET) ضبط شده‌اند.

فیلتر بر اساس IP مبدأ یا مقصد

همچنین می‌توانیم بسته‌ها را بر اساس آدرس IP (یا نام میزبان) مبدأ یا مقصد فیلتر کنیم. فیلترهای src و dst به ترتیب برای این منظور استفاده می‌شوند. به عنوان مثال، برای گرفتن بسته‌هایی که از میزبان 192.168.122.98 ارسال می‌شوند، از فیلتر src استفاده می‌کنیم:

sudo tcpdump -i any -c5 -nn src 192.168.122.98

و نمونه خروجی مربوطه:

10:02:15.220824 IP 192.168.122.98.39436 > 192.168.122.1.53: 59332+ A? opensource.com. (32)
10:02:15.220862 IP 192.168.122.98.39436 > 192.168.122.1.53: 20749+ AAAA? opensource.com. (32)
10:02:15.364062 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [S], seq 1108640533, win 29200, options [mss 1460,sackOK,TS val 122825713 ecr 0,nop,wscale 7], length 0
10:02:15.409229 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [.], ack 268723504, win 229, options [nop,nop,TS val 122825758 ecr 522832372], length 0
10:02:15.409667 IP 192.168.122.98.39334 > 54.204.39.132.80: Flags [P.], seq 0:112, ack 1, win 229, options [nop,nop,TS val 122825759 ecr 522832372], length 112: HTTP: GET / HTTP/1.1
5 packets captured
5 packets received by filter
0 packets dropped by kernel

در خروجی بالا مشاهده می‌کنید که tcpdump تمامی بسته‌های ارسالی از آدرس 192.168.122.98 را گرفته است. این بسته‌ها شامل درخواست‌های DNS (پورت 53) و HTTP (پورت 80) بوده‌اند. بسته‌های پاسخ مربوطه نمایش داده نشده‌اند چون آدرس مبدأ آن‌ها 192.168.122.98 نبوده است.

برعکس حالت فوق، می‌توانیم از فیلتر dst برای فیلتر کردن بسته‌ها بر اساس آدرس IP/هاست مقصد استفاده کنیم. برای نمونه، برای گرفتن بسته‌هایی که به میزبان 192.168.122.98 ختم می‌شوند:

sudo tcpdump -i any -c5 -nn dst 192.168.122.98

نمونه خروجی این دستور:

10:05:03.572931 IP 192.168.122.1.53 > 192.168.122.98.47049: 2248 1/0/0 A 54.204.39.132 (48)
10:05:03.572944 IP 192.168.122.1.53 > 192.168.122.98.47049: 33770 0/0/0 (32)
10:05:03.621833 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [S.], seq 3474204576, ack 3256851264, win 28960, options [mss 1460,sackOK,TS val 522874425 ecr 122993922,nop,wscale 9], length 0
10:05:03.667767 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [.], ack 113, win 57, options [nop,nop,TS val 522874436 ecr 122993972], length 0
10:05:03.672221 IP 54.204.39.132.80 > 192.168.122.98.39338: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 522874437 ecr 122993972], length 642: HTTP: HTTP/1.1 302 Found
5 packets captured
5 packets received by filter
0 packets dropped by kernel

در اینجا پنج بسته‌ی رسیده به میزبان 192.168.122.98 نمایش داده شده است (دو پاسخ DNS از 192.168.122.1 و سه بسته از سمت سرور وب 54.204.39.132 به کلاینت مذکور).

ترکیب فیلترها

همچنین می‌توان فیلترها را با استفاده از عملگرهای منطقی and و or برای ایجاد عبارات پیچیده‌تر ترکیب کرد. برای مثال، فرض کنید می‌خواهیم فقط بسته‌هایی را ببینیم که از آدرس IP 192.168.122.98 و مرتبط با سرویس HTTP (پورت 80) هستند. ترکیب فیلتر به صورت زیر خواهد بود:

sudo tcpdump -i any -c5 -nn src 192.168.122.98 and port 80

نمونه خروجی این دستور:

10:08:00.472696 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [S], seq 2712685325, win 29200, options [mss 1460,sackOK,TS val 123170822 ecr 0,nop,wscale 7], length 0
10:08:00.516118 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [.], ack 268723504, win 229, options [nop,nop,TS val 123170865 ecr 522918648], length 0
10:08:00.516583 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [P.], seq 0:112, ack 1, win 229, options [nop,nop,TS val 123170866 ecr 522918648], length 112: HTTP: GET / HTTP/1.1
10:08:00.567044 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [.], ack 643, win 239, options [nop,nop,TS val 123170916 ecr 522918661], length 0
10:08:00.788153 IP 192.168.122.98.39342 > 54.204.39.132.80: Flags [F.], seq 112, ack 643, win 239, options [nop,nop,TS val 123171137 ecr 522918661], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

همان‌طور که می‌بینید، فقط بسته‌هایی که از 192.168.122.98 بوده و پورت مرتبطشان 80 بوده (ترافیک HTTP خروجی از .98) گرفته شده است. در این مثال، تنها بسته‌های سمت کلاینت (192.168.122.98) در ارتباط HTTP دیده می‌شوند و پاسخ‌های سرور حضور ندارند.

برای ساخت عبارات فیلتر پیچیده‌تر می‌توانیم از پرانتزگذاری نیز استفاده کنیم. در این حالت بهتر است کل عبارت فیلتر را در نقل‌قول قرار دهیم تا از تداخل با شل جلوگیری شود. برای مثال، برای فیلتر کردن بسته‌های مرتبط با سرویس HTTP (پورت 80) که مبدأ آن‌ها 192.168.122.98 یا 54.204.39.132 است (در واقع هر دو سمت یک ارتباط مشخص را شامل شود)، دستور را به صورت زیر می‌نویسیم:

sudo tcpdump -i any -c5 -nn "port 80 and (src 192.168.122.98 or src 54.204.39.132)"

و خروجی نمونه:

10:10:37.602214 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [S], seq 871108679, win 29200, options [mss 1460,sackOK,TS val 123327951 ecr 0,nop,wscale 7], length 0
10:10:37.650651 IP 54.204.39.132.80 > 192.168.122.98.39346: Flags [S.], seq 854753193, ack 871108680, win 28960, options [mss 1460,sackOK,TS val 522957932 ecr 123327951,nop,wscale 9], length 0
10:10:37.650708 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 123328000 ecr 522957932], length 0
10:10:37.651097 IP 192.168.122.98.39346 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 123328000 ecr 522957932], length 112: HTTP: GET / HTTP/1.1
10:10:37.692900 IP 54.204.39.132.80 > 192.168.122.98.39346: Flags [.], ack 113, win 57, options [nop,nop,TS val 522957942 ecr 123328000], length 0
5 packets captured
5 packets received by filter
0 packets dropped by kernel

در این مثال، ما بسته‌ها را تنها برای سرویس HTTP (پورت 80) و آدرس‌های IP مبدأ 192.168.122.98 یا 54.204.39.132 فیلتر کرده‌ایم. به این ترتیب توانستیم هر دو سمت یک ارتباط را مشاهده کنیم. این یک روش سریع برای بررسی ترافیک بین دو میزبان مشخص (هر دو جهت) در یک سرویس معین است.

بررسی محتوای بسته‌ها

در مثال‌های قبلی، ما عمدتاً سرآیند (Header) بسته‌ها را بررسی می‌کردیم تا اطلاعاتی مانند آدرس مبدأ، مقصد، پورت‌ها و … را استخراج کنیم. گاهی همین اطلاعات برای عیب‌یابی مشکلات اتصال شبکه کافی است. اما در برخی موارد لازم است که محتوای درون بسته‌ها را نیز ببینیم تا مطمئن شویم پیام‌هایی که ارسال می‌شوند حاوی داده‌ی مورد انتظار هستند یا پاسخ دریافتی همان چیزی است که باید باشد.

برای مشاهده‌ی محتوای بسته‌ها، tcpdump دو فلگ مفید دارد: -X که محتویات هر بسته را هم به‌صورت هگزا دسیمال و هم ASCII چاپ می‌کند، و -A که محتوا را فقط به‌صورت متن ASCII (تا حد ممکن خوانا) نمایش می‌دهد. گزینه‌ی -A برای مشاهده محتوای پروتکل‌های متنی مانند HTTP بسیار کاربردی است.

به عنوان مثال، دستور زیر را اجرا می‌کنیم تا محتوای یک ارتباط وب (HTTP روی پورت 80) را در خروجی ببینیم:

sudo tcpdump -i any -c10 -nn -A port 80

در خروجی این دستور، سرآیند و محتوای بسته‌های HTTP مبادله‌شده به شکل متن قابل خواندن نمایش داده می‌شود. برای نمونه، بخش‌هایی از درخواست HTTP و پاسخ HTTP را در خروجی خواهیم دید:

GET / HTTP/1.1
User-Agent: Wget/1.14 (linux-gnu)
Accept: */*
Host: opensource.com
Connection: Keep-Alive

HTTP/1.1 302 Found
Server: nginx
Date: Sun, 23 Sep 2018 17:02:14 GMT
Content-Type: text/html; charset=iso-8859-1
Content-Length: 207
Location: https://opensource.com/
...

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved <a href="https://opensource.com/">here</a>.</p>
</body></html>

همان‌طور که مشاهده می‌کنید، توسط سوئیچ -A توانستیم محتویات بسته‌ها را که شامل متن ارسالی و دریافتی پروتکل HTTP است ببینیم. در قسمت اول، درخواست HTTP (شامل خط GET و سرآیندهای HTTP مثل User-Agent و Host) نمایش داده شده و در قسمت دوم، پاسخ HTTP 302 (شامل سرآیندهایی مانند Location و بخش متن HTML) آمده است. در صورت استفاده از -X، tcpdump هم‌زمان محتوای هر بسته را به صورت کد هگزا نیز در کنار متن ASCII نشان می‌دهد که برای تحلیل‌های بسیار دقیق‌تر یا پروتکل‌های غیرمتنی به‌کار می‌آید.

ذخیره‌سازی کپچرها در فایل

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

برای ذخیره‌ی بسته‌ها در یک فایل (به جای نمایش روی صفحه) از گزینه‌ی -w استفاده می‌کنیم. به عنوان مثال، دستور زیر تمام بسته‌های مرتبط با پورت 80 را ضبط کرده و در فایلی به نام webserver.pcap ذخیره می‌کند:

sudo tcpdump -i any -c10 -nn -w webserver.pcap port 80
[sudo] password for user: ****
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
10 packets captured
10 packets received by filter
0 packets dropped by kernel

دستور بالا خروجی را در فایلی به نام webserver.pcap ذخیره می‌کند. پسوند .pcap مخفف “Packet Capture” است و به‌صورت قراردادی برای این نوع فایل‌ها استفاده می‌شود. همان‌طور که مشاهده می‌شود، در این حالت هیچ چیز روی صفحه نمایش داده نشد و پس از گرفتن ۱۰ بسته (طبق گزینه -c10)، کپچر متوقف گردید.

tcpdump فایل را به فرمت باینری ایجاد می‌کند؛ بنابراین نمی‌توان محتویات آن را به‌سادگی با یک ویرایشگر متن مشاهده کرد. برای خواندن محتویات فایل ضبط‌شده، می‌توانیم tcpdump را با گزینه‌ی -r اجرا کنیم. برای مثال، جهت خواندن فایل ذخیره‌شده در مثال قبل:

tcpdump -nn -r webserver.pcap

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

reading from file webserver.pcap, link-type LINUX_SLL (Linux cooked)
13:36:57.679494 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [S], seq 3709732619, win 29200, options [mss 1460,sackOK,TS val 135708029 ecr 0,nop,wscale 7], length 0
13:36:57.718932 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [S.], seq 1999298316, ack 3709732620, win 28960, options [mss 1460,sackOK,TS val 526052949 ecr 135708029,nop,wscale 9], length 0
13:36:57.719005 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [.], ack 1, win 229, options [nop,nop,TS val 135708068 ecr 526052949], length 0
13:36:57.719186 IP 192.168.122.98.39378 > 54.204.39.132.80: Flags [P.], seq 1:113, ack 1, win 229, options [nop,nop,TS val 135708068 ecr 526052949], length 112: HTTP: GET / HTTP/1.1
...
13:36:58.022089 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 526053025 ecr 135708327], length 0

از آنجا که در حال خواندن بسته‌ها از فایل هستیم (و نه مستقیماً از رابط شبکه)، دیگر نیازی به اجرای tcpdump با sudo نیست.

جالب‌تر اینکه می‌توانیم از همان فیلترهایی که پیش‌تر یاد گرفتیم، هنگام خواندن فایل نیز بهره ببریم. به عبارت دیگر، می‌توان محتویات فایل کپچر را هم بر اساس مبدأ، مقصد، پورت و … فیلتر کرد. برای مثال، برای مشاهده‌ی بسته‌های موجود در فایل کپچر که از آدرس IP منبع 54.204.39.132 هستند، می‌توانیم فرمان زیر را اجرا کنیم:

tcpdump -nn -r webserver.pcap src 54.204.39.132

و بخشی از خروجی فیلترشده‌ی خواندن فایل به شکل زیر خواهد بود:

reading from file webserver.pcap, link-type LINUX_SLL (Linux cooked)
13:36:57.718932 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [S.], seq 1999298316, ack 3709732620, win 28960, options [mss 1460,sackOK,TS val 526052949 ecr 135708029,nop,wscale 9], length 0
13:36:57.756979 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [.], ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 0
13:36:57.760122 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [P.], seq 1:643, ack 113, win 57, options [nop,nop,TS val 526052959 ecr 135708068], length 642: HTTP: HTTP/1.1 302 Found
13:36:58.022089 IP 54.204.39.132.80 > 192.168.122.98.39378: Flags [F.], seq 643, ack 114, win 57, options [nop,nop,TS val 526053025 ecr 135708327], length 0

همان‌طور که ملاحظه می‌کنید، خروجی بالا تنها بسته‌هایی را نشان می‌دهد که آدرس مبدأ آن‌ها 54.204.39.132 بوده (چه در مرحله‌ی Handshake اولیه و چه در پاسخ HTTP).

جمع‌بندی

قابلیت‌های پایه‌ی tcpdump که در این مقاله مرور کردیم، به ما کمک می‌کنند تا کار با این ابزار قدرتمند و همه‌کاره را آغاز کنیم. واسط خط فرمان tcpdump انعطاف زیادی برای ضبط و تحلیل ترافیک شبکه در اختیار ما قرار می‌دهد. اگر برای درک جریان‌های پیچیده‌تر شبکه به یک ابزار گرافیکی نیاز داشته باشیم، می‌توانیم از Wireshark استفاده کنیم. یکی از مزایای Wireshark این است که توانایی خواندن فایل‌های .pcap ضبط‌شده توسط tcpdump را دارد. در عمل می‌توانیم tcpdump را روی یک سیستم راه‌دور (بدون واسط گرافیکی) برای ضبط ترافیک به‌کار بگیریم و سپس فایل نتیجه را در محیط گرافیکی با Wireshark تحلیل کنیم.

دسته بندی‌ها:

دیدگاه شما

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *