Coding TCP/IP Stack 1: Ethernet dan ARP (2016)
(saminiir.com)- Sebagai langkah pertama dalam seri mempelajari layer jaringan dengan membuat sendiri TCP/IP stack ruang pengguna di Linux, implementasi dimulai dari pemrosesan frame Ethernet Layer 2 dan respons ARP
- Trafik jaringan level rendah dari kernel diterima melalui perangkat TAP, dan buffer Ethernet perangkat virtual dapat di-
read/writemelalui file descriptor yang dikembalikan - Header Ethernet ditangani sebagai
dmac,smac,ethertype,payload; jika nilaiethertype1536 atau lebih, itu berarti tipe payload, sedangkan jika lebih kecil berarti panjang payload - ARP secara dinamis memetakan alamat protokol seperti alamat IPv4 ke alamat MAC 48-bit, dan diimplementasikan sebagai alur yang memperbarui tabel translasi sambil merespons request
- Dalam pengujian
arping, kernel Linux mengenali respons ARP dari stack kustom, sehingga entri10.0.0.4ditambahkan ke cache ARP antarmukatap0
Titik awal TCP/IP stack ruang pengguna
- Tujuannya adalah memahami jaringan dan pemrograman sistem lebih dalam sambil mengimplementasikan TCP/IP stack ruang pengguna minimal di Linux
- TCP menjadi kompleks karena banyak spesifikasi yang terakumulasi selama lebih dari 30 tahun, tetapi elemen implementasi intinya dapat dipersempit menjadi parsing header TCP, state machine, congestion control, dan perhitungan retransmission timeout
- Ethernet dan IP memiliki kompleksitas lebih rendah daripada TCP, sehingga seri ini memulai implementasi dari Layer 2
Menerima trafik Ethernet dengan perangkat TAP
- Untuk mencegat trafik jaringan level rendah dari kernel Linux, digunakan perangkat Linux TAP
- Perangkat TUN/TAP sering dipakai ketika aplikasi networking ruang pengguna memanipulasi trafik L3/L2
- Tunneling adalah cara membungkus paket di dalam payload paket lain
- Program seperti OpenVPN juga menggunakan perangkat TUN/TAP
- Karena network stack dibuat mulai dari Layer 2, yang dibutuhkan adalah perangkat TAP, bukan TUN
- Perangkat TAP dibuat dengan membuka
/dev/net/taplalu memanggilioctl(fd, TUNSETIFF, ...)IFF_TAPmemilih perangkat TAPIFF_NO_PImencegah informasi paket yang tidak diperlukan ditambahkan di depan frame Ethernet
- Setelah dibuat, buffer Ethernet perangkat virtual dibaca dan ditulis melalui file descriptor
fdyang dikembalikan
Format frame Ethernet
- Ethernet adalah teknologi dasar untuk menghubungkan komputer di LAN, dan standar Ethernet pertama diumumkan pada 1980 oleh Digital Equipment Corporation, Intel, dan Xerox
- Versi pertamanya menggunakan kecepatan sekitar 10Mb/s dan komunikasi half-duplex, sehingga diperlukan protokol MAC untuk mengatur aliran data
- Pada antarmuka Ethernet half-duplex, CSMA/CD diperlukan sebagai metode MAC
- 100BASE-T menggunakan kabel twisted-pair untuk memungkinkan komunikasi full-duplex dan throughput lebih tinggi
- Seiring meluasnya penggunaan switch Ethernet, kebutuhan CSMA/CD secara umum berkurang
- Standar Ethernet dikelola oleh kelompok kerja IEEE 802.3
Header Ethernet yang digunakan dalam implementasi
- Implementasi menyertakan
if_ether.hdari Linux untuk menggunakan pemetaan antara ethertype dan nilai heksadesimal - Header Ethernet direpresentasikan dalam struct C dengan field berikut
dmac: alamat MAC tujuansmac: alamat MAC sumberethertype: panjang atau tipe payloadpayload: pointer payload yang berisi paket ARP atau IPv4
ethertypeadalah field 2 oktet dan maknanya berbeda tergantung nilainya- Jika nilainya 1536 atau lebih, itu menunjukkan tipe payload seperti IPv4 atau ARP
- Jika nilainya lebih kecil dari itu, itu menunjukkan panjang payload
- Frame Ethernet dapat memiliki tag yang menunjukkan VLAN atau QoS, tetapi implementasi ini mengecualikan tag frame
- Jika panjang payload tanpa tag lebih kecil dari ukuran minimum yang disyaratkan, yaitu 48 byte, byte padding ditambahkan di akhir
- Di akhir Ethernet Frame Format terdapat field Frame Check Sequence yang memeriksa integritas dengan CRC, tetapi implementasi ini tidak menanganinya
Cara parsing frame Ethernet
- Atribut
packedpada deklarasi struct mencegah compiler GNU C mengoptimalkan tata letak memori struct dengan byte padding untuk alignment data - Parsing dalam implementasi dilakukan dengan type casting buffer ke struct protokol yang sesuai
- Contoh:
struct eth_hdr *hdr = (struct eth_hdr *) buf;
- Contoh:
- Cara yang lebih portabel adalah menserialisasi data protokol secara manual
- Dalam kasus ini, compiler dapat menambahkan byte padding sesuai kebutuhan alignment data per prosesor
- Pemrosesan frame Ethernet yang diterima mengikuti alur sederhana
- Membaca buffer dari perangkat TAP
- Menginisialisasi header Ethernet dengan
init_eth_hdr(buf) handle_frame(&netdev, hdr)melihat nilaiethertypedan menentukan tindakan berikutnya
Struktur dan peran paket ARP
- ARP(Address Resolution Protocol) secara dinamis memetakan alamat protokol seperti alamat IPv4 ke alamat MAC, yaitu alamat Ethernet 48-bit
- ARP tidak terbatas hanya pada IPv4 dan dapat digunakan bersama berbagai protokol L3
- Sebagai contoh, CHAOS mendeklarasikan alamat protokol 16-bit
- Dalam komunikasi LAN umum, meski alamat IP layanan sudah diketahui, alamat MAC tetap diperlukan untuk transmisi sebenarnya
- ARP mengirim query broadcast ke jaringan agar pemilik alamat IP tersebut memberitahukan alamat hardwarenya
Header ARP dan payload untuk IPv4
- Header ARP terdiri dari field berikut
hwtype: field 2 oktet yang menunjukkan tipe link layer; nilai untuk Ethernet adalah0x0001protype: field 2 oktet yang menunjukkan tipe protokol; nilai untuk IPv4 adalah0x0800hwsize: field 1 oktet yang menunjukkan ukuran alamat hardware; alamat MAC adalah 6 byteprosize: field 1 oktet yang menunjukkan ukuran alamat protokol; alamat IPv4 adalah 4 byteopcode: field 2 oktet yang menunjukkan tipe pesan ARP
- Nilai
opcodedibagi menjadi empat- ARP request:
1 - ARP reply:
2 - RARP request:
3 - RARP reply:
4
- ARP request:
- Data ARP untuk IPv4 ditangani dengan struct
arp_ipv4smac: alamat MAC pengirimsip: alamat IP pengirimdmac: alamat MAC penerimadip: alamat IP penerima
Algoritma resolusi alamat dan cache
- Algoritma resolusi alamat dalam RFC 826 mengikuti alur memeriksa tipe hardware dan tipe protokol, lalu memperbarui tabel translasi, dan jika alamat target adalah dirinya sendiri, membuat respons
- translation table menyimpan hasil ARP agar host dapat mencari entri yang sudah dimilikinya di cache
- Cache ini mengurangi jaringan dipenuhi request ARP duplikat yang tidak perlu
- Kode implementasinya ada di
arp.c
Pengujian respons ARP dan langkah berikutnya
- Pengujian akhir implementasi ARP adalah memastikan apakah ia merespons request dengan benar
- Hasil menjalankan
arping -I tap0 10.0.0.4menunjukkan respons unicast kembali dari10.0.0.4dengan alamat MAC00:0C:29:6D:50:25 - Setelah itu, output
arpmenunjukkan entri10.0.0.4 ether 00:0c:29:6d:50:25 tap0muncul di cache ARP kernel Linux - Dengan hanya pemrosesan frame Ethernet minimal dan implementasi ARP, dapat dipastikan bahwa perangkat Ethernet kustom mengisi cache ARP host Linux
- Source code proyek tersedia di GitHub, dan langkah berikutnya adalah mengimplementasikan ping, yaitu ICMP echo/reply, serta parsing paket IPv4
1 komentar
Opini Hacker News
Beberapa tahun lalu saya pernah membuat network stack ruang pengguna dengan C, memproses paket mentah lewat antarmuka TUN, dan berhasil membuatnya cukup berfungsi
Sekarang di dalamnya ada shell sederhana untuk mengatur alamat IP, route, dan sebagainya, sementara paket jaringan dimasukkan ke struktur hibrida yang terasa seperti campuran mbuf dan sk_buf
Namun setelah menyelesaikan implementasi UDP, saya tidak punya waktu atau motivasi untuk mengimplementasikan TCP, dan kodenya ada di sini: https://github.com/cakturk/unet
Tentu saja hasilnya mungkin termasuk salah satu benda paling lambat dan rapuh dalam sejarah, tetapi benar-benar berjalan dan cukup menyenangkan. Semoga kodenya masih tersisa di suatu tempat
“Port POSIX” lwip juga mengambil byte Ethernet mentah dari perangkat TUN/TAP dengan cara yang sama
https://github.com/lwip-tcpip/lwip/blob/master/contrib/ports...
Jika kernel Linux minimal dikompilasi tanpa stack TCP/IP, ukurannya 400KB; jika stack TCP/IP dimasukkan, ukurannya menjadi 800KB
Pada proyek yang hanya perlu mengirim suhu, kami memasukkan nilai ke dalam pesan UDP buatan sendiri lewat program C kecil di ruang pengguna, sehingga bisa banyak mengurangi ruang dan kompleksitas
Jika ARP dinonaktifkan, Anda bisa mengatur IP yang sama pada beberapa server di jaringan yang sama
Jika server yang berperan sebagai frontend routing dapat meneruskan paket ke antarmuka jaringan server backend berdasarkan alamat MAC, backend itu akan menganggap dirinya sebagai tujuan, lalu mengubah IP sumber/tujuan dan merespons klien secara langsung. Saat itu paket tidak melewati frontend routing lagi
Atau, tanpa mematikan ARP, menambahkan alamat IP bersama sebagai alias pada antarmuka loopback juga bisa memberi efek yang sama, sehingga backend mengenali dirinya sebagai tujuan sekaligus menghindari konflik ARP. Ini trik yang digunakan software load balancer IBM WebSphere pada era 90-an hingga 2000-an
Kelebihannya dibanding load balancing L3 yang lebih umum dipakai adalah tidak perlu menulis ulang header paket IP
Karena itu, jika memakai cara ini, sebaiknya buat VLAN khusus
Saya pernah melakukan hal serupa dengan Python: https://github.com/georgek/notebooks/blob/master/internet.ip...
Mungkin kualitas kodenya kurang bagus, dan jujur saja algoritma resolusi alamatnya juga saya karang begitu saja. Saya berhasil sampai mengirim ping ke host internet dengan ICMP
Saya suka karena semuanya muat sepenuhnya dalam satu notebook pendek. Artikel asli menghilangkan banyak detail dari kode sumber yang lebih besar yang dirujuk
Saya membuatnya hanya dengan melihat Wikipedia, tanpa melihat artikel ini. Namun mulai dari TCP, kompleksitasnya melonjak besar sehingga minat saya agak turun. Karena bagian 3 katanya membahas itu, mungkin suatu hari saya akan membacanya dan menyelesaikannya. Menurut saya, jika tertarik pada networking, ini pekerjaan yang layak dicoba dan memuaskan untuk programmer level apa pun
Beberapa tahun lalu saya bekerja pada instrumentasi pembangkit listrik tenaga nuklir. Pengembangan sisi klien dilakukan di workstation Sun, dan saya sebenarnya direkrut berkat pengalaman TCP/IP, yang saya peroleh dari kelas “sistem operasi” di CMU
Sebaliknya, komputer pembangkit adalah minikomputer tanpa stack TCP/IP, jadi tim itu harus membuat stack sendiri
Sekitar satu menit setelah artikel dimulai, tertulis “dmac dan smac adalah field yang cukup jelas”, tetapi pembaca yang tidak tahu apa itu bisa langsung tersingkir
Mereka akan berpikir, “Artikel ini untuk orang-orang yang menganggap field ini jelas. Ini bukan untuk saya, jadi saya sebaiknya berhenti membaca”
Selain itu, jika ini artikel tentang membuat network stack, cukup aman untuk mengasumsikan pembaca punya sedikit pengetahuan tentang networking
Tulisan terkait:
Let’s code a TCP/IP stack (2016) - https://news.ycombinator.com/item?id=27654182 - Juni 2021, 49 komentar
Let’s code a TCP/IP stack, 1: Ethernet & ARP (2016) - https://news.ycombinator.com/item?id=17316487 - Juni 2018, 47 komentar
Let’s Code a TCP/IP Stack: TCP Retransmission - https://news.ycombinator.com/item?id=14701199 - Juli 2017, 30 komentar
Let’s code a TCP/IP stack, 1: Ethernet and ARP - https://news.ycombinator.com/item?id=11234229 - Maret 2016, 49 komentar
Tidak tahu dari mana penulis mengambil alamat IP 10.0.0.4 yang dipakai untuk pengujian resolusi ARP
Itu alamat apa? Apakah perangkat palsu yang dapat diakses dari perangkat Ethernet palsu yang dibuat di sini, atau perangkat yang benar-benar ada di jaringan penulis?
Perangkat TAP itu semacam link Ethernet yang diemulasi dengan software. Jika paket dikirim ke sana, paket itu langsung diteruskan ke program level pengguna, dan program tersebut yang menentukan alamat IP apa yang dimilikinya serta bagaimana merespons ARP
Biasanya hal seperti ini ditangani oleh sistem operasi, dan untuk menambahkan alamat IP ke antarmuka diperlukan hak akses root. Membuka perangkat TAP juga sama. Networking pada umumnya berjalan secara kooperatif, dan aktor jahat yang memiliki hak root di jaringan bisa melakukan hal-hal buruk
Seingat saya, ARP hanya bekerja di segmen lokal. Router mengisi alamatnya sendiri lalu meneruskan paket
Ada juga rarp, salah satu cara untuk menanyakan alamat IP diri sendiri ke “jaringan”. Saya tidak tahu apakah rarp masih berfungsi di lingkungan nyata saat ini