یافتن دستگاه سانسور کننده ی DNS

یافتن دستگاه دستکاری کننده ی DNS #

به دلیل عدم شفافیت ISP ها و حکومت در اعمال سانسور و نبود حد و مرز در آن، نیاز است تا دریابیم که چه کسی مسئول یک اختلال و سانسور است. همچنین این بخش مقدمه ای برای بررسی بیشتر و اثبات رفتار سیستم سانسور در مسدود کردن برخی ارتباطات است که در بخش «سانسور random» آن را بررسی خواهیم کرد.

اگر از DNS ارایه شده توسط ISP استفاده می کنید احتمالا به صورت پیشفرض این خود ISP است که دارد جواب DNS را دستکاری می کند. اما در مورد DNS های دیگر و بخصوص موارد خارج از ایران، بررسی هایی می توان انجام داد.

شیوه ی کار به این صورت است که یک سری درخواست DNS ارسال کنیم که هر بار یک مرتبه مقدار TTL در لایه ی IP ی آن افزایش می یابد. با توجه به هدف فعلی بهترین ابزار برای این کار scapy است. ابزاری که این امکان را فراهم می کند تا یک packet جدید بسازید و یا یک packet قبلی را با کمی تغییرات دوباره ارسال کنید.

در ادامه دو روش را بررسی می کنیم:

  • ساختن یک packet ساده
  • کپی یک packet واقعی و تغییر جزئی آن.

در واقع نباید بین این دو روش تفاوتی باشد، اما شواهد در بعضی شبکه ها، خلاف آن را ثابت می کند. همچنین در مطالب بعدی وجود cache برای درخواست های DNS نیز بررسی می شوند.

طی بررسی این تحقیق، یک ابزار هم ساخته شده به اسم TraceVis که علاوه بر امکان انجام هر دو روش گفته شده به صورت راحت تر، یک گراف هم از کل مسیر می سازد. به همراه چند قابلیت دیگر.

tracevis dns over udp mci

اما برگردیم به اصل مطلب و بررسی جزئیات.

ساختن یک packet ساده ی DNS over UDP : #

ما میتوانیم این یک فایل با پسوند .py بسازیم و این کد را در آن قرار دهیم و یا درون برنامه ی Scapy این کد را اجرا کنیم.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#!/usr/bin/env python3
from scapy.all import *
for myttl in range(30):
       dns_request = IP(dst="8.8.8.8", id=RandShort(), ttl=myttl)/UDP(dport=53)/DNS(rd=1, id=RandShort(), qd=DNSQR(qname="www.google.com"))
       print(">>>request:" + "   ip.dst: " + dns_request[IP].dst + "   ip.ttl: " + str(myttl))
       req_answer = sr1(dns_request, verbose=0, timeout=3)
       if req_answer is not None:
               print("   <<< answer:" + "   ip.src: " + req_answer[IP].src + "   ip.ttl: " + str(req_answer[IP].ttl))
               print("   " + req_answer.summary())
       print(" · · · − − − · · ·     · · · − − − · · ·     · · · − − − · · · ")
  1. (اگر در خود scapy از این کد استفاده می کنید، این خط را وارد نکنید.)

  2. (اگر در خود scapy از این کد استفاده می کنید، این خط را نیز وارد نکنید.)

  3. بازه ی مقدار TTL را مشخص می کردیم. از 0 تا 30.

  4. یک packet ساده ی DNS over UDP ساختیم (بدون لایه ی Ether) . همچنین برای جلوگیری از ignore شدن packet، از ID های random استفاده کردیم.

  5. در جواب دریافتی، مقدار IP ی مقصد و همچنین TTL ای که تنظیم کردیم را چاپ می کنیم.

  6. packet ساخته شده را بدون نمایش log و حداکثر زمان انتظار سه ثانیه ارسال کردیم.

  7. بررسی می کنیم که جواب دریافتی پوچ نباشد.

  8. مقدار IP ی مبدا ای که در حال جواب دادن به ما هست را به همراه TTL ای که در زمان دریافت packet مشاهده کردیم را چاپ می کنیم.

  9. یک خلاصه از جواب دریافتی هر چه که هست (DNS یا ICMP) را چاپ می کنیم.

  10. فقط خطی جدا کننده را چاپ می کنیم.

scapy dns over udp 8.8.8.8 googledotcom

از سرور مورد تست (AS48147-امین داده) تا Hop یازدهم، به جای DNS جواب از نوع ICMP دریافت کردیم که به معنای این است که TTL صفر شده است و آن hop نیز مقصد مورد نظر ما نیست. بعد از آن، تمام جواب هایی که دریافت کردیم مقدار 56 در TTL داشتند و همراه با پاسخ DNS.

>>>request:   ip.dst: 8.8.8.8   ip.ttl: 0
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 1
   <<< answer:   ip.src: 172.22.8.3   ip.ttl: 255
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 2
   <<< answer:   ip.src: 172.22.6.2   ip.ttl: 254
      IP / ICMP 172.22.6.2 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 3
   <<< answer:   ip.src: 172.22.9.2   ip.ttl: 62
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 4
   <<< answer:   ip.src: 10.202.5.49   ip.ttl: 252
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'"  / Padding
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 5
   <<< answer:   ip.src: 10.202.4.83   ip.ttl: 251
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'"  / Padding
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 6
   <<< answer:   ip.src: 85.185.45.133   ip.ttl: 250
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'"  / Padding
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 7
   <<< answer:   ip.src: 10.202.4.206   ip.ttl: 251
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'"  / Padding
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 8
   <<< answer:   ip.src: 213.202.4.172   ip.ttl: 249
      IP / ICMP 213.202.4.172 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 9
   <<< answer:   ip.src: 213.202.5.239   ip.ttl: 238
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'"  / Padding
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 10
   <<< answer:   ip.src: 216.239.48.133   ip.ttl: 50
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 11
   <<< answer:   ip.src: 216.239.51.115   ip.ttl: 52
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 12
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 13
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 14
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 15
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 16
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 17
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 18
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 19
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 20
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 21
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 22
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 23
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 24
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 25
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 26
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 27
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 28
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 29
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · ·

همچنین به نظر می رسد که در این تست تا Hop سوم، که با آدرس 172.22 شروع می شود، همچنان در شبکه ی امین داده قرار دارد. بعد از آن تا Hop هفتم، در شبکه ی شرکت ارتباطات زیرساخت (AS12880). علاوه بر آن، مسیر برگشت در Hop های 7 و 8 یکسان است. که می تواند یا ناشی از تغییرات routing در شبکه باشد و یا نشان از جایی که firewall برای ایزوله کردن شبکه قرار دارد.

AS12880 ITC Iran gateway

در ادامه، hob های 8 و 9 به در عمان‌تل (AS8529) قرار دارد. اما نکته ای وجود دارد و آن این است که در جواب ICMP درون این شبکه، بین hop های 8 و 9، حدود 11 واحد مقدار TTL تفاوت دارد. بدین صورت که اگر 255 را منهای 238 کنیم می شود 17. یعنی ما با 9 تا Hop به آن میرسیم اما پاسخ با 17 تا Hop به ما می رسد. این می تواند به این دلیل باشد که hop نهم، مسیر متفاوتی برای پاسخ دادن انتخاب می کند که با routing اصلی متفاوت است.

AS8529 OmanTel transit to Iran

در ادامه Hop های 10 و 11 در در زیرساخت گوگل قرار دارند. اما هنوز درخواست ما به مقصد نرسیده است. اگر 64 را منهای 50 کنیم، می شود 14. یعنی ما با 10 تا Hop به زیرساخت گوگل می رسیم و 14 واحد مسیر برگشت پیام ICMP است.

در انتها بعد از hop دوازدهم و دریافت جواب از مقصد مورد نظر، TTL های دریافتی همیشه 56 هستند. که یعنی جواب، 8 تا Hop مسیر را طی می کند تا به ما برسد! (این را نیز در مطالب بعدی بیشتر بررسی خواهیم کرد.)

ما آدرس درخواستی را از www.google.com به www.twitter.com تغییر می دهیم تا ببینیم در کجای مسیر، DNS Hijacking انجام می شود:

scapy dns over udp 8888 twitter.com

بعد از Hop چهارم به بعد، یعنی در شبکه ی شرکت ارتباطات زیرساخت، از ارسال Packet ها DNS ما که حاوی آدرس Twitter است جلوگیری می شود. لاگ کامل:

>>>request:   ip.dst: 8.8.8.8   ip.ttl: 0
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 1
   <<< answer:   ip.src: 172.22.8.3   ip.ttl: 255
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.twitter.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 2
   <<< answer:   ip.src: 172.22.6.2   ip.ttl: 254
      IP / ICMP 172.22.6.2 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 3
   <<< answer:   ip.src: 172.22.9.2   ip.ttl: 62
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.twitter.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 4
   <<< answer:   ip.src: 10.202.5.49   ip.ttl: 252
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.twitter.com.'"  / Padding
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 5
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 6
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 7
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 8
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 9
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 10
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 11
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 12
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 13
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 14
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 15
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 16
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 17
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 18
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 19
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 20
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 21
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 22
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 23
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 24
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 25
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 26
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 27
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 28
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 29
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 

(شبکه های مختلف، رفتار متفاوتی دارند و ممکن است این درخواست در شبکه ی شما بدون مشکل عبور کند.)

اما سوالی به وجود می آید که آیا این یک سانسور عادی است و یا یک لیست سفید از Packet های DNS است؟ برای تست آن باید یک packet واقعی را کپی و دوباره ارسال کنیم.

کپی یک packet واقعی ی DNS over UDP و تغییر جزئی آن: #

یکی از قابلیت های مهم در برنامه ی Scapy امکان کپی کردن یک packet واقعی به صورت Hex و تغییر و ارسال مجدد آن است.

راه های مختلفی برای دریافت Hex یک Packet دارد که در در بخش «آنالیز packet ها» بیشتر توضیح داده خواهد شد.

در اینجا برای سادگی کار، از tcpdump استفاده کردیم.

ابتدا این دستور را اجرا می کنیم:

$ sudo tcpdump -s 0 -x 'port 53'

به معنای اینکه مقدار hex از لایه ی IP به بعد و فقط ترافیک پورت 53.

بعد در یک پنجره ی دیگر، دستور مورد نظرمان را اجرا می کنیم:

$ dig www.google.com @8.8.8.8

dig google.com 8.8.8.8

به صورتی که در تصویر مشخص شده بخشی از Packet مورد نظرمان که به صورت Hex است را کپی می کنیم:

tcpdump x port 53 hex

برنامه ی scapy را اجرا می کنیم:

scapy start

ابتدا دستور زیر را وارد می کنیم و enter می زنیم:

>>> mypacket = IP(import_hexcap())

scapy import hex

بعد محتوای کپی شده را paste می کنیم و enter میزنیم تا دوباره علامت <‌<‌< ظاهر شود:

scapy show packet details

اگر نام متغیر ساخته شده را به تنهایی وارد کنید، جزئیات کامل این packet نمایش داده خواهد شد. اگر بجز لایه ی IP بقیه فقط Hex نمایش داده شد، کپی را به درستی انجام ندادید.

برای اینکه بتوانیم این packet را دوباره ارسال کنیم و انتظار جواب مثبت داشته باشیم، نیاز داریم که تغییراتی در آن انجام دهیم. کدی که در بالا استفاده کرده بودیم را کمی تغییر می دهیم و enter میزنیم تا دستور اجرا شود:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
>>> for myttl in range(30):
       mypacket[IP].ttl = myttl
       mypacket[IP].id = RandShort()
       mypacket[DNS].id = RandShort()
       mypacket[UDP].sport = RandShort()
       print(">>>request:" + "   ip.dst: " + mypacket[IP].dst + "   ip.ttl: " + str(myttl))
       del(mypacket[IP].chksum)
       del(mypacket[UDP].chksum)
       del(mypacket[IP].len)
       req_answer = sr1(mypacket, verbose=0, timeout=3)
       if req_answer is not None:
               print("   <<< answer:" + "   ip.src: " + req_answer[IP].src + "   ip.ttl: " + str(req_answer[IP].ttl))
               print("   " + req_answer.summary())
       print(" · · · − − − · · ·     · · · − − − · · ·     · · · − − − · · · ")

در این کد، TTL پیشفرض که 64 بود را به مقدار دلخواه خود تغییر دادیم. برای ID ی لایه ی IP ، برای ID ی DNS و برای پورت مبدا در UDP یک مقدار عددی random تعیین می کنیم. Checksum های مربوط به IP و UDP را حذف می کنیم تا هر بار دوباره توسط برنامه ی Scapy محاسبه و تعیین شود.

scapy copy dig packet google.com 8.8.8.8

تا Hop یازدهم تقریبا رفتار شبیه قبل است. (آدرس مورد آزمایش www.google.com است.)

اما بعد از آن، ما رفتاری کاملا متفاوت می بینیم و هر بار با یک TTL متفاوت با فاصله ی 8 Hop تا 14 Hop. به معنای 6 واحد تفاوت در بین پاسخ ها.

لاگ کامل:

>>>request:   ip.dst: 8.8.8.8   ip.ttl: 0
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 1
   <<< answer:   ip.src: 172.22.8.3   ip.ttl: 255
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 2
   <<< answer:   ip.src: 172.22.6.2   ip.ttl: 254
      IP / ICMP 172.22.6.2 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 3
   <<< answer:   ip.src: 172.22.9.2   ip.ttl: 62
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 4
   <<< answer:   ip.src: 10.202.5.49   ip.ttl: 252
      IP / ICMP 10.202.5.49 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror / Raw
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 5
   <<< answer:   ip.src: 10.202.4.83   ip.ttl: 251
      IP / ICMP 10.202.4.83 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror / Raw
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 6
   <<< answer:   ip.src: 85.185.45.133   ip.ttl: 250
      IP / ICMP 85.185.45.133 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror / Raw
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 7
   <<< answer:   ip.src: 10.202.4.206   ip.ttl: 251
      IP / ICMP 10.202.4.206 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror / Raw
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 8
   <<< answer:   ip.src: 213.202.4.172   ip.ttl: 249
      IP / ICMP 213.202.4.172 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 9
   <<< answer:   ip.src: 213.202.5.239   ip.ttl: 238
      IP / ICMP 213.202.5.239 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror / Raw
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 10
   <<< answer:   ip.src: 216.239.48.87   ip.ttl: 49
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.google.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 11
   <<< answer:   ip.src: 108.170.233.243   ip.ttl: 55
      IP / ICMP 108.170.233.243 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror / Raw
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 12
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 115
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 13
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 116
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 14
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 119
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 15
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 119
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 16
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 119
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 17
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 116
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 18
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 55
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 19
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 119
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 20
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 114
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 21
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 120
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 22
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 116
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 23
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 120
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 24
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 119
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 25
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 116
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 26
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 27
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 120
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 28
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 29
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 56
      IP / UDP / DNS Ans "216.58.209.132" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 

حالا همان مسیر قبلیِ کپی کردن Packet را در مورد آدرس www.twitter.com انجام می دهیم که در شیوه ی قبلی بعد از Hop چهارم وارد سیاهچاله می شد.

scapy copy dig packet twitter 8888

در این شرایط می بینیم که دوباره از Hop چهارم وارد سیاهچاله شده است اما از Hop نهم جوابی ارسال می شود که هم آدرس مربوط به صفحه ی سانسور جمهوری اسلامی برگردانده می شود و هم TTL آن بسیار پایین است. این مقدار TTL دریافتی با افزایش TTL ارسالی، افزایش می یابد. لاگ کامل:

>>>request:   ip.dst: 8.8.8.8   ip.ttl: 0
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 1
   <<< answer:   ip.src: 172.22.8.3   ip.ttl: 255
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.twitter.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 2
   <<< answer:   ip.src: 172.22.6.2   ip.ttl: 254
      IP / ICMP 172.22.6.2 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 3
   <<< answer:   ip.src: 172.22.9.2   ip.ttl: 62
      IP / ICMP / IPerror / UDPerror / DNS Qry "b'www.twitter.com.'" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 4
   <<< answer:   ip.src: 10.202.5.49   ip.ttl: 252
      IP / ICMP 10.202.5.49 > 185.*.*.* time-exceeded ttl-zero-during-transit / IPerror / UDPerror / Raw
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 5
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 6
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 7
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 8
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 9
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 1
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 10
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 2
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 11
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 3
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 12
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 4
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 13
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 5
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 14
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 6
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 15
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 7
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 16
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 8
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 17
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 9
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 18
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 10
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 19
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 11
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 20
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 12
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 21
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 13
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 22
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 14
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 23
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 15
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 24
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 16
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 25
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 17
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 26
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 18
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 27
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 19
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 28
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 20
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · · 
>>>request:   ip.dst: 8.8.8.8   ip.ttl: 29
   <<< answer:   ip.src: 8.8.8.8   ip.ttl: 21
      IP / UDP / DNS Ans "10.10.34.35" 
 · · ·    · · ·     · · ·    · · ·     · · ·    · · ·

برای اطمینان از اینکه این رفتار چطور عمل می کند، که آیا افزایش نسبت به دفعات درخواست است و یا نسبت به TTL ارسالی، یک آزمایش بیشتر انجام می دهیم. برای این کار از همان کد قبلی استفاده می کنیم اما این بار range آن را از 30 تا 128 قرار می دهیم و مرتبه ی افزایش در هر بار را 3 قرار می دهیم.

scapy copy dig packet twitter 8888 ttl 30-128 3-step

با توجه به این آزمایش، به این نتیجه می رسیم که سیستم سانسور جمهوری اسلامی در صورت مواجهه با یک packet مرسوم DNS over UDP اگر آدرس درخواستی ممنوعه است، مقدار TTL دریافتی را در جواب DNS با محتوای آدرس صفحه ی سانسور قرار می دهد و آن را به سمت کاربر ارسال می کند.

دلیل اینکه TTL ارسالی باید بیشتر از 8 باشد، این است که سیستم سانسور در این شبکه، در Hop پنجم قرار دارد. به این صورت که ما با TTL با مقدار 9 را ارسال می کنیم، سیستم سانسور TTL با مقدار 5 را دریافت می کند، آن را کپی کرده و در پاسخ به ما ارسال می کند و مقدار 1 به ما می رسد. و این بدین معنی است که سیستم سانسور در تست های ما از TTL با مقدار 4 در حال دریافت packet های ما است، اما فقط پاسخ آن است که به ما نمی رسد.

routing middlebox diagram

این یافته، وسعت بیشتری دارد که در مطالب بعدی به آن بیشتر خواهیم پرداخت.

استفاده از TraceVis #

برای ساده سازی و درک بهتر این مسئله و وضعیت شبکه و سانسور، اقدام به ساخت ابزاری کردیم به اسم TraceVis که می توانید به راحتی تست های خود را انجام دهید.

ابتدا dependency ها را نصب کنید:

python3 -m pip install -r requirements.txt

و بعد تست را به این صورت اجرا کنید:

python ./tracevis.py --dns

و یا :

python ./tracevis.py --dns -n "test-prefix" -i "1.0.0.1,8.8.4.4,9.9.9.9,5.200.200.200"

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

tracevis log

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

 **********************************************************************
saving measurement data...
saved: ./output/test-prefix-dns-tracevis-20211212-1551.json
· · · - · -     · · · - · -     · · · - · -     · · · - · -
saving measurement graph...

saved: ./output/test-prefix-dns-tracevis-20211212-1551.html
· · · - · -     · · · - · -     · · · - · -     · · · - · -

یک فایل نتیجه ی آزمایش، از نوع json است که سازگار با ساختار RIPE Atlas است و یک فایل HTML که حاوی گراف.

tracevis measurement json file

این سازگاری به ما این امکان را می دهد تا علاوه بر داشتن یک ساختار استاندارد، به سادگی قابلیت ساخت گراف از طریق نتایج تست های traceroute در Probe های RIPE Atlas را نیز داشته باشیم.

در این گراف، به صورت پیشفرض رنگ های سرد برای آدرسی که فیلتر نیست در نظر گرفته شده و رنگ های گرم، برای آدرس فیلتر شده.

در تصویر زیر می بنید که هر دو مسیر به یک نقطه رسیدند و این به آن معنی است که جواب درخواست ها برای هر دو آدرس توسط یک دستگاه داده شده اند.

tracevis graph html file 5.200.200.200

اما این وضعیت برای تمام آدرس ها صدق نمی کند. و اگر مسیر packet از سیستم سانسور بگذرد، شما حالتی متفاوت خواهید دید.

tracevis graph 1.0.0.1 google.com

در این تصویر درخواست به آدرس گوگل از شبکه ی داخلی خارج و به سرور مقصد رسید.

اما در مورد آدرس توییتر، مسیر متفاوت است:

tracevis graph 1.0.0.1 twitter.com middlebox

وقتی در توضیحات علاوه بر اسم Middlebox، مقدار back-TTL عدد 6 قرار گرفت، یعنی Middlebox به اندازه ی 6 Hop فاصله دارد.

یعنی در این موقعیت هایی که با پیکان مشخص شده:

tracevis graph middlebox

این ابزار متن باز، قابلیت ها و امکانات بیشتری دارد. مانند امکان trace route با هر نوع packet از نوع TCP و UDP و ساخت گراف.

tracevis usage

منتظر مشارکت شما در بهبود و توسعه ی این پروژه هستیم.