کار با فضانام شبکه در لینوکس

Photo by Thomas Jensen on Unsplash
Photo by Thomas Jensen on Unsplash

توی این پست می‌خوام در رابطه با استفاده از ip-netns صحبت کنم که یک ابزار هست برای اجرا کردن برنامه‌ها توی یک فضانام شبکه (Network Namespace).

تو لینوکس لایه‌های مختلف مثل سیستم‌فایل، پروسه‌ها، شبکه و غیره رو می‌تونی جدا کنی. اصلا؛ چیزی مثل داکر یا LXD مجموعه‌ای از همین فضانام‌ها رو ایجاد و مدیریت می‌کنه.

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

کار با فضانام شبکه

داخل یک فضانام شبکه (network namespace) می‌تونید:

  • نوع‌های مختلف از یک اینترفیس رو داخلش بسازید یا مثلا یه اینترفیس رو از داخل سیستم بردارید و اون رو توی فضانام قرار بدید.
  • جدول مسیریابی داخلی رو کاملا از نو تنظیم کنید مثلا دروازه پیشفرض داخل فضانام رو تغییر بدید.
  • قوانین iptables وضع کنید.
  • از یک DNS Server جدا استفاده کنید.

خب برای شروع؛ یک تب ترمینال باز کنید (هشدار دسترسی روت):

sudo su
/bin/bash --rcfile <(echo &quotPS1=\&quotFrom Earth: \&quot&quot)

می‌خوایم یک مریخ نورد بسازیم و از زمین بهش اینترنت بدیم :) پس این شد کنسول ما توی زمین. حالا باید:

  • یک مریخ نورد بسازیم (فضانام شبکه به اسم rover).
  • یه آنتن زمینی بسازیم و وصلش کنیم به آنتن مریخ نورد (veth یه دیوایس مجازی شبکه هست؛ دیوایس‌های دیگه هم هست مثل BRIDGE, MACVLAN, VLAN ...).
  • آنتن مریخ نورد رو داخلش نصب کنیم.
  • یک آدرس بدیم به آنتن زمینی و روشنش کنیم.
ip netns add rover
ip link add earth-antenna type veth peer name rover-antenna
ip link set rover-antenna netns rover
ip addr add 10.10.1.1/24 dev earth-antenna
ip link set earth-antenna up

حالا یه تب جدید ترمینال باز کنید:

وارد کنسول مریخ نورد بشید (هر دستوری بعد از ip netns exec rover بیاد؛ داخل فضانام شبکه rover اجرا می‌شه و در اینجا ما بش رو بالا میاریم) بعدش یه آدرس بدیم به آنتن مریخ نورد و روشنش کنیم:

sudo su
ip netns exec rover /bin/bash --rcfile <(echo &quotPS1=\&quotRover Console: \&quot&quot)
ip netns exec rover ip addr add 10.10.1.2/24 dev rover-antenna
ip netns exec rover ip link set rover-antenna up
ip route add default via 10.10.1.1

حالا بیاید کاری کنیم که مریخ نورد ما به اینترنت دسترسی پیدا کنه؛ برای اینکار باید از سمت زمین این دستورات رو بزنیم (wlan0 رو با اینترفیسی که دروازه پیشفرض شماست عوض کنید):

echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 10.10.1.0/24 -o wlan0 -j MASQUERADE
iptables -A FORWARD -o wlan0 -i earth-antenna -j ACCEPT
iptables -A FORWARD -i wlan0 -o earth-antenna -j ACCEPT

حالا داخل مریخ نورد پینگ بزنیم به گوگل:

Rover Console: ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=46 time=60.8 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=46 time=75.9 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=46 time=76.7 ms

--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 60.827/71.140/76.727/7.301 ms

حالا DNS مریخ نورد رو چطوری عوض کنیم؟

From Earth: mkdir -p /etc/netns/rover && echo &quotnameserver 1.1.1.1&quot > /etc/netns/rover/resolv.conf
Rover Console: exit
ip netns exec rover /bin/bash --rcfile <(echo &quotPS1=\&quotRover Console: \&quot&quot)
Rover Console: cat /etc/resolv.conf

مثال‌های دیگه

من توی خونه یه اینترنت همراه اول دارم و یه TD-LTE ایرانسل؛ نمی‌شه همزمان دوتا دروازه پیشفرض داشته باشم (یه جورایی می‌شه‌ها ولی اون بمونه برای یه پست دیگه). یعنی اگه از ساعت 1 تا 11صبح بخوام چیزی دانلود کنم و همزمان وب گردی کنم سرعتم کم می‌شه. پس چیکار می‌شه کرد؟ برنامه aria2 رو توی یک فضانام جدا اجرا می‌کنم و اینترنت همراه اول رو بهش اختصاص می‌دم بعدش اینترنت ایرانسل رو دروازه پیشفرض بقیه چیزام قرار میدم. اینطوری:

ip link add macv0 link eth1 type macvlan mode bridge
ip netns add dm
ip link set macv0 netns dm
ip netns exec dm ip addr add 192.168.8.101/24 dev macv0
ip netns exec dm ip route add default via 192.168.8.1
ip netns exec dm sudo -u hadi aria2c -x 8 -j 1 -i list.txt

من اینجا از macvlan استفاده کردم چون ساده و سریعه؛ و می‌تونم eth1 رو هم از داخل فضانام و هم بیرون از اون کنترل کنم (مثلا شاید من یهویی نیاز داشتم دروازه پیشفرض سیستم رو تغییر بدم به eth1 بدون اینکه دانلودم رو مختل کنم). به جای این کار می‌تونستم دستور ip link set eth1 netns dm رو بزنم و اینترفیس رو کاملا در اختیار فضانام قرار بدم.

پروژه تورباکس که چند وقت پیش درست کردم؛ از فضانام استفاده می‌کنه تا کارت شبکه بی‌سیم رو کاملا در اختیار کانتینر داکر قرار بده (به جای اینکه از net=host استفاده کنم) و یه Anonymizing Middlebox تور درست می‌کنه.

برنامه از چندتا کانتینر تشکیل شده که همه‌ اونها به busybox وصل می‌شن. بعدش من process id کانتینر busybox رو در میارم؛ و به فضانامش وصل می‌شم و بعدش هم کارت شبکه بی‌سیم رو داخلش قرار می‌دم. من توی اسکریپت به صورت دستی فایل فضانام رو می‌سازم و حذف می‌کنم ولی معادلش می‌تونه این دستور باشه:

ip netns attach torbox &quot$(${Docker} inspect -f '{{.State.Pid}}' torbox)&quot

کانتینر‌های داکر وقتی ساخته می‌شن یه فضانام هم دارن که اسمش برابر با pid اون کانتینر هست حالا این دستور میاد یه برچسب می‌سازه به اسم torbox بعد وصلش می‌کنه به pid کانتینر داکر که اسمش torbox هست. «شبیه» وقتی که با دستور add فضانام می‌سازید. چرا شبیه؟ ببینید دستور attach به فضانام‌هایی که وجود دارن وصل می‌شه. به دستور زیر نگاه کنید:

 ip netns attach tg &quot$(pidof telegram-desktop)&quot
ip netns exec tg ip r
output:
default via 192.168.1.100 dev wlan0 
10.10.1.0/24 dev earth-antenna proto kernel scope link src 10.10.1.1 
192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.101 metric 600

درواقع من می‌خوام از طریق pid برنامه تلگرام به فضانام اون دست پیدا کنم. اما وقتی که ip r رو داخل فضانام تلگرام اجرا کردم؛ دیدم که داره به جدول مسیریابی پیشفرض «کل سیستم» اشاره می‌کنه.

چرا اینطوری شد؟ چون تلگرام فضانام اختصاصی نداره؛ ولی هر پروسه «باید» یک فضانام داشته باشه و فضانام پیشفرض شبکه برای همه پروسه‌ها میشه کل سیستم. در نتیجه tg میشه یک برچسب به default