Bind program unix ke antarmuka jaringan tertentu

40

Pertanyaan: Bagaimana saya menjalankan program sambil memastikan bahwa akses jaringannya terikat melalui antarmuka jaringan tertentu?

Kasus: Saya ingin mengakses dua mesin berbeda dengan IP yang sama (192.168.1.1), tetapi dapat diakses melalui dua antarmuka jaringan yang berbeda (eth1 dan eth2).

Contoh:

net-bind -D eth1 -exec {Program 192.168.1.1}
net-bind -D eth2 -exec {Program 192.168.1.1}

Di atas adalah perkiraan dari apa yang saya suka, terinspirasi oleh pengikatan hardware yang dilakukan melalui primusrun dan optirun .

Tantangan: Seperti yang disarankan dalam utas terkait , antarmuka yang digunakan tidak dipilih oleh program, melainkan oleh kernel (Oleh karena itu sintaks pra-mengikat dalam contoh di atas).

Saya telah menemukan beberapa solusi terkait, yang tidak memuaskan. Mereka didasarkan pada antarmuka jaringan yang mengikat melalui daftar hitam jaringan khusus pengguna; yaitu, menjalankan proses sebagai pengguna yang hanya dapat mengakses satu antarmuka jaringan tertentu.

Skeen
sumber
Apakah Anda menyiratkan bahwa mesin Anda terhubung ke dua jaringan yang berbeda, keduanya 192.168.1.0? Seperti apa tabel perutean Anda? Jika Anda ingin membatasi antarmuka yang terlihat dari suatu proses, solusi paling ringan adalah cgroup, yang lebih berat satu wadah.
lgeorget
Ya, dua jaringan berbeda, keduanya pada rentang IP yang sama. Saya tidak yakin saya tidak ingin membatasi antarmuka yang terlihat, hanya menentukan mana yang akan digunakan sebagai default? :)
Skeen
3
Apa yang Anda minta sulit karena satu alasan: memiliki dua jaringan yang saling terhubung menggunakan domain IP yang sama seperti memiliki lift di gedung dengan dua lantai dengan nomor yang sama. Rentang IP adalah apa yang mengidentifikasi domain bukan antarmuka output. Namun demikian harus ada cara untuk mengatasi desain jaringan Anda yang cacat dengan iptables.
lgeorget
Saya menghubungkan sistem saya ke dua infrastruktur di tempat yang berbeda, karena infrastruktur seperti itu tidak pernah dirancang untuk berinteraksi, dan karenanya desain jaringan cacat dalam hal itu.
Skeen
1
Argumen saya terhadap NAT adalah bahwa seluruh ruang alamat biasanya tersembunyi di belakang NAT, dan ketika saya menghubungkan dua infrastruktur NAT'ted tabrakan terjadi. - Saya tidak dalam posisi apa pun untuk memodifikasi infrastruktur. - Saya mencoba menggunakan namespace jaringan dengan pasangan antarmuka jaringan virtual (satu di namespace, satu di namespace root) menjembatani root namespace satu ke antarmuka fisik, dan menjalankan program dalam namespace jaringan. - Ini sepertinya berfungsi, tapi saya tidak mendapatkan akses di luar root namespace (yaitu tidak ada akses di luar mesin itu sendiri).
Skeen

Jawaban:

35

Untuk Linux, ini sudah dijawab pada Superuser - Bagaimana cara menggunakan antarmuka jaringan yang berbeda untuk proses yang berbeda? .

Jawaban yang paling populer menggunakan LD_PRELOADtrik untuk mengubah pengikatan jaringan untuk suatu program, tetapi kernel modern mendukung fitur yang jauh lebih fleksibel yang disebut 'ruang nama jaringan' yang diekspos melalui ipprogram. Jawaban ini menunjukkan cara menggunakan ini. Dari percobaan saya sendiri, saya telah melakukan yang berikut (sebagai root):

# Add a new namespace called test_ns
ip netns add test_ns

# Set test to use eth0, after this point eth0 is not usable by programs
# outside the namespace
ip link set eth0 netns test_ns

# Bring up eth0 inside test_ns
ip netns exec test_ns ip link set eth0 up

# Use dhcp to get an ipv4 address for eth0
ip netns exec test_ns dhclient eth0

# Ping google from inside the namespace
ip netns exec test_ns ping www.google.co.uk

Dimungkinkan juga untuk mengelola ruang nama jaringan sampai batas tertentu dengan unsharedan nsenterperintah. Ini memungkinkan Anda juga membuat ruang terpisah untuk PID, pengguna, dan titik pemasangan. Untuk informasi lebih lanjut, lihat:

Graeme
sumber
"setelah titik ini eth0 tidak dapat digunakan oleh program di luar namespace" - Jadi saya menarik koneksi untuk semua masalah lain dalam melakukan ini?
Skeen
1
@Skeen, ya, jadi mungkin Anda akan mendorong antarmuka yang tidak ada program lain yang menggunakan namespace dan menggunakan yang utama secara normal.
Graeme
1
@ Galena; Kedua antarmuka sedang digunakan secara aktif; Saya tidak mampu menghapus antarmuka.
Skeen
dan apa dengan gateway default? wvdialmisalnya sepertinya tidak mengaturnya sama sekali ... jadi harus didefinisikan dalam namespace itu sendiri
Flash Thunder
Bisakah Anda memasukkan instruksi tentang cara membatalkannya? Apakah Anda hanya ip netns remove test_nsuntuk kembali normal? Atau apakah Anda harus melakukan sesuatu yang istimewa?
Multihunter
17

Saya menerima jawaban Graeme; ini hanyalah tindak lanjut untuk menjelaskan perubahan yang saya lakukan terhadap sarannya untuk menyelesaikan masalah saya.

Alih-alih mengikat antarmuka fisik di dalam namespace, saya membuat pasangan antarmuka jaringan virtual, dengan satu ujung di namespace jaringan dan satu di root. Paket-paket kemudian dialihkan melalui jaringan virtual ini dari namespace, ke root namespace dan kemudian ke antarmuka fisik. - Karena itu saya dapat menjalankan semua transfer data biasa saya, dan selain itu memulai proses yang hanya dapat mengakses antarmuka tertentu.

# Create the eth0 network namespace
ip netns add eth0_ns

# Create the virtual network pair
ip link add v_eth0a type veth peer name v_eth0b

# Move v_eth0a to the eth0_ns namespace, the virtual pair is now split
# between two network namespaces.
ip link set v_eth0a netns eth0_ns

# Configure the ends of the virtual network pairs
ip netns exec eth0_ns ifconfig v_eth0a up {{NAMESPACE_IP}} netmask {{NAMESPACE_NETMASK}}
ifconfig v_eth0b up {{ROOT_NS_IP}} netmask {{ROOT_NS_NETMASK}}

# Setup routing from namespace to root
ip netns exec eth0_ns route add default gw {{ROOT_NS_IP}} dev v_eth0a

# Setup IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s {{ROUTE_SOURCE}}/24 -o {{NETWORK_INTERFACE}} -j SNAT --to-source {{ROUTE_TARGET}}

Setelah antarmuka telah diatur untuk eth0 dan eth1, dengan masing-masing namespaces eth0_ns dan eth1_ns, program dapat dieksekusi pada antarmuka yang ditentukan melalui;

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish
Skeen
sumber
4
Sudah selesai dilakukan dengan baik! Saya pikir Anda juga dapat membuat perangkat jembatan dan menjembatani namespace default dan pasangan virtual dengan salah satu perangkat fisik. Ini terlihat setara.
Graeme
1
Saya memang mencoba menjembatani perangkat virtual dan fisik; Saya tidak dapat menjangkau jaringan eksternal menggunakan solusi itu.
Skeen
2
Saya lakukan, tetapi hanya dari namespace baru. Saya pikir masalah yang saya alami terkait dengan manajer jaringan, saya tidak mengetahuinya atau saya akan memperbarui jawaban saya.
Graeme
Saya memiliki masalah yang sama, tetapi saya gagal menggunakan solusi itu. Apa tepatnya yang harus saya masukkan di {{ROUTE_SOURCE}} dan {{ROUTE_TARGET}} pada langkah terakhir?
litov
@ Greme, setidaknya di Ubuntu saya bisa mendapatkan konektivitas kembali di namespace maupun namespace global dengan mengeluarkan dhclient <bridge>per di sini .
Chris Hunt
4

Solusi I: Preloading perpustakaan tertentu

  • App-Route-Jail : gunakan ld_preload untuk memaksa gateway antarmuka (ide bagus tetapi membutuhkan kemampuan root atau tanda) penggunaan dirinci pada catatan di bawah

  • Proxybound : gunakan ld_preload untuk memaksa proxy ke aplikasi tertentu (ini menggunakan proxy bukan antarmuka)

  • Force-Bind : memiliki banyak fitur tetapi bind bocoran (tidak dapat diandalkan)

  • Bind-Interface-IP : koneksi terlalu sederhana dan bocor (tidak dapat diandalkan)

  • Bind-IP : terlalu sederhana dan koneksi bocor (tidak dapat diandalkan)

Solusi II: ruang pengguna Linux

  • Ruang pengguna linux klasik ip-netns : solusi hebat tetapi membutuhkan root dan antarmuka hanya dapat ada pada satu ruang pengguna tunggal

  • Firejail : Firejail dapat memaksa aplikasi untuk menggunakan jaringan tertentu, tetapi kompatibilitasnya terbatas (contohnya tidak kompatibel dengan antarmuka tun). firejail tidak membutuhkan rootfirejail --dns=8.8.8.8 --noprofile --net=eth0 --ip=192.168.1.1 app-command

  • Firejail dengan jaring : Firejail dapat memaksa aplikasi untuk menggunakan ruang pengguna tertentu yang dibuat secara terpisah, ini mari kita beri nama spasi tanpa rootfirejail --dns=8.8.8.8 --noprofile --netns=nameOfyourNS app-command

  • Firejail dengan masquerade dan bridge : Firejail dapat memaksa aplikasi untuk menggunakan antarmuka spesifik dengan iptables masquerade , ini hebat dan tidak memerlukan root tetapi ini memerlukan ip_forward dan dapat menyiratkan dampak keamananfirejail --net=br0 firefox

Solusi III: iptables Linux

Iptables dapat digunakan untuk tujuan ini tetapi ini memerlukan ip_forward dan dapat menyiratkan dampak keamanan jika tidak dikonfigurasi dengan benar, contoh 1 , contoh 2 , contoh 3 , contoh 4

Catatan Solusi (I, II & III):

Wireguard

Jika Anda menggunakan VPN (terutama wireguard) dan Anda ingin menerapkan solusi ini ke antarmuka wireguard ( wireguard dengan ruang pengguna ), Anda dapat mengikuti tautan yang diinstruksikan untuk membuat ruang pengguna yang berisi antarmuka wg (dan dengan demikian terbatas pada antarmuka vpn ) juga ini dapat dikombinasikan dengan firejail --netns=containeruntuk dapat menggunakan ruang pengguna tanpa root.

Cara menemukan antarmuka gateway

Ada banyak solusi untuk menemukan gateway di sini adalah beberapa perintah yang memungkinkan untuk menemukan gateway yang digunakan

$ route
$ route -n
$ ip rule list
$ ip route show
$ netstat -rn
$ cat /etc/network/interfaces
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0
$ traceroute www.google.com
$ ip route show 0.0.0.0/0 dev eth0

Cara menggunakan App-Route-Jail

  • Bangun App-Route-Jail
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Utils
chown 755 make.sh
./make.sh
  • Tambahkan rute untuk paket yang ditandai di masa depan (untuk aplikasi yang dipenjara) dalam contoh 192.168.1.1ini digunakan sebagai gateway paksa, aturan rute ini tidak akan mempengaruhi aplikasi lain, manipulasi ini harus dilakukan hanya sekali pada boot sistem misalnya jika Anda ingin gunakan solusi ini setiap hari
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
  • Mulai aplikasi yang ingin dipenjara
MARK=10 LD_PRELOAD=./mark.so firefox
  • Menguji alamat IP lemah
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me
intika
sumber