Sejarah antarmuka terprogram ke iptables, ipchains, dan ipfw

Sep 04 2020

Saya harus melakukan beberapa mengutak-atik iptablesaturan dari Go baru-baru ini, dan saya perhatikan baik library wrapper buruh pelabuhan dan coreosexec() keluar ke iptablesperintah dan layar mengikis output standar. Ini tampak mengejutkan saya.

Di Python-land, ada python-iptables :

Interoperabilitas dengan iptables dicapai melalui penggunaan pustaka C iptables (libiptc, libxtables, dan ekstensi iptables), tidak memanggil biner iptables dan mengurai keluarannya.

Saya kira pustaka Python diizinkan untuk memuat pustaka C saat runtime, dan Go tidak bisa [edit: Saya salah], tapi tidak bisakah Go secara statis menautkan ke pustaka tersebut? Karena perpustakaan Go harus mendapatkan libxtables.adll dari suatu tempat? (Saya sedang dpkg -Lmencari -devpaket yang relevan di Debian, dan saya hanya melihat .sos.)

Bagaimanapun, menurut FAQ Netfilter :

4.5 Apakah ada C / C ++ API untuk menambahkan / menghapus aturan?

Sayangnya, jawabannya adalah: Tidak.

Sekarang Anda mungkin berpikir 'tapi bagaimana dengan libiptc?'. Seperti yang telah ditunjukkan berkali-kali di milis, libiptc TIDAK PERNAH dimaksudkan untuk digunakan sebagai antarmuka publik. Kami tidak menjamin antarmuka yang stabil, dan direncanakan untuk menghapusnya pada paket linux inkarnasi berikutnya

Kami sangat menyadari bahwa ada kekurangan mendasar untuk API semacam itu, dan kami sedang berupaya memperbaiki situasi itu. Sampai saat itu, disarankan untuk menggunakan system () atau membuka pipa ke stdin dari iptables-restore. Yang terakhir akan memberi Anda kinerja yang jauh lebih baik. Pemfilteran. libiptc adalah lapisan yang terlalu rendah untuk digunakan secara wajar.

Oke, jadi mungkin Anda tidak seharusnya memperlakukan pustaka C itu sebagai stabil. Lalu saya berpikir "mengapa tidak berbicara /procatau apapun secara langsung?" Ternyata, iptablessebagian besar tidak digunakan /procuntuk berbicara dengan kernel (hanya untuk membaca nama tabel?), Dan antarmuka utama sebenarnya getsockopt()dan setsockopt()pada soket tidak terikat.

Ini adalah kejutan lain! (Tapi mungkin hanya karena saya tidak terbiasa dengan kode semacam ini sehingga sepertinya cara yang lucu untuk berinteraksi dengan kernel.)

Saya melakukan sedikit mundur arkeologi dari iptableske ipchainske ipfwdan menemukan halaman manual ipfw dari tahun 1997 yang membuat saya merasa sedikit lebih baik:

BUGS
       The  setsockopt(2)  interface  is a crock.  This should be
       put under /proc/sys/net/ipv4 and the world would be a bet-
       ter place.

Anda dapat menemukan di tempat lain bahwa "Utilitas ipfw pertama kali muncul di FreeBSD 2.0" dan

HISTORY
      Initially this utility was written for BSDI by:
       Daniel Boulet    <[email protected]>
      The FreeBSD version is written completely by:
       Ugen J.S.Antsilevich <[email protected]>
      while synopsis partially compatible with old one.

Ini adalah versi FreeBSD 2.0 ipfwdari tahun 1994 . Masih menggunakan setsockopt(), tetapi tampaknya menggunakan kvm_read()bukan getsockopt().

Pertanyaan saya

  • Harap perbaiki semua kesalahan yang saya katakan di atas :)
  • Mengapa mereka memilih {get,set}sockopt()di tempat pertama? Apakah ini tidak biasa, atau baru bagi saya?
  • Mengapa tidak diubah di beberapa titik? Suka sesuatu di bawah /procseperti yang disarankan halaman manual 1997.
  • Mengapa mereka tidak pernah menemukan antarmuka C yang stabil / publik iptables?

Pertanyaan Tindak Lanjut Saya

"Kurang tepat, antarmuka utamanya adalah keluarga NETLINK_NETFILTER netlink"

Terima kasih untuk petunjuk ini!

Saya melihat https://git.netfilter.org/iptables/treedan libipqsepertinya hanya menggunakan soket netlink, kecuali jika saya melewatkan sesuatu.

$ ick "socket\("
include/libiptc/libiptc.h
158:int iptc_get_raw_socket(void);

include/libiptc/libip6tc.h
152:int ip6tc_get_raw_socket(void);

utils/nfsynproxy.c
129:    fd = socket(AF_INET, SOCK_STREAM, 0);

libiptc/libiptc.c
1312:   sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);

extensions/libxt_set.h
14: int res, sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

libipq/libipq.c
223:                h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_FIREWALL);
225:                h->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_IP6_FW);

libxtables/xtables.c
881:    sockfd = socket(afinfo->family, SOCK_RAW, IPPROTO_RAW);

The libipqhal terlihat "normal" dengan saya: membuat socket, mengikat dengan sockaddr sebuah, sendto(), recvfrom(), dll

Juga xtables-monitortampaknya menggunakan beberapa mnl_socket_*pembungkus yang melakukan hal-hal netlink.

Tapi saya tidak tahu libiptcdan xtables- tidak menyebutkan netlink, dan mereka bahkan tidak mengikat soketnya.

https://git.netfilter.org/iptables/tree/libxtables/xtables.c#n881

https://git.netfilter.org/iptables/tree/libiptc/libiptc.c#n1312

Ada contoh lain yang tidak (sepertinya?) Menggunakan netlink, seperti kode dari debugger rr mozilla ini: https://github.com/mozilla/rr/blob/master/src/test/netfilter.c

Dan netlink hanya untuk Linux, dari tahun 2000 (2.2), sementara {get,set}sockopt()hal ini (setidaknya) ipfwlebih tua, dan di BSD-land.

Saya tidak begitu yakin lagi dengan pertanyaan saya :) Bagaimana soket non-netlink dapat berkomunikasi dengan sisi kernel yang benar tanpa bahkan bind()dan sockaddr?

Jawaban

StephenKitt Sep 04 2020 at 20:22

Saya kira pustaka Python diizinkan untuk memuat pustaka C saat runtime, dan Go tidak bisa

Go dapat menggunakan pustaka C bersama.

Ternyata, iptablessebagian besar tidak digunakan /procuntuk berbicara dengan kernel (hanya untuk membaca nama tabel?), Dan antarmuka utamanya sebenarnya getsockopt()dan setsockopt().

Mengapa mereka memilih {get,set}sockopt()di tempat pertama? Apakah ini tidak biasa, atau baru bagi saya?

(Jawaban ini sebelumnya menyatakan, tidak benar, bahwa antarmuka utama adalah netlink's NETLINK_NETFILTERkeluarga.)

Anda benar, iptablesmenggunakan panggilan ke getsockoptsoket tak terikat dari jenis yang sesuai untuk berinteraksi dengan kernel, yang akhirnya memanggil kode kernelnetfilter . Saya menduga ini karena alasan sejarah ...

Secara kebetulan, getsockoptdan setsockoptbekerja pada soket di berbagai negara bagian, termasuk tidak terikat, dan mereka harus melakukannya karena digunakan untuk mengatur opsi sebelum menghubungkan. The netfilter-via- sockoptkoneksi efektif sisi-channel.

Mengapa tidak diubah di beberapa titik? Suka sesuatu di bawah /procseperti yang disarankan halaman manual 1997.

Mungkin ada beberapa alasan, tetapi tidak diragukan lagi kompatibilitas ke belakang - di Linux, antarmuka ruang pengguna tidak pernah seharusnya rusak. Jadi, meskipun antarmuka baru dapat disediakan, antarmuka yang sudah ada akan tetap ada, yang mengurangi insentif untuk memperbaikinya atau menulis ulang program yang sudah berfungsi.

Selama iptablesalat baris perintah dapat digunakan dengan tidak terlalu banyak usaha, dan menyediakan antarmuka yang lebih baik melibatkan lebih banyak usaha, perubahan akan sulit. libiptcPustaka bergaya yang terawat dengan baik akan menjadi kemungkinan juga, tetapi tidak pernah ada banyak insentif bagi iptablespengembang untuk melakukan itu.

Mengapa mereka tidak pernah menemukan antarmuka C yang stabil / publik iptables?

Karena "mereka" tidak pernah bisa melakukannya. Sekarang iptablessedang dihapus mendukung nftables, yang mencakup sejumlah perpustakaan yang menyediakan akses pada berbagai tingkat abstraksi ( libnftables, libnftnl, libnfnetlink). Penggunaan ini netlink, yang dirancang sebagai antarmuka berbasis soket untuk mentransfer informasi antara kernel dan ruang pengguna, dan secara alami cocok untuk alat seperti nftables(dan iptables). The netlinkdokumentasi daftar keluarga lain yang tersedia; ini mencakup cukup banyak fungsionalitas yang dihosting kernel. netlink.

Anda mungkin menemukan https://github.com/vishvananda/netlinkberguna untuk mulai mengemudi iptablesdari Go. (Diperlukan kerja keras untuk itu, tetapi lebih baik daripada memulai dari awal.)