1 poin oleh GN⁺ 2025-03-05 | 1 komentar | Bagikan ke WhatsApp
  • 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/write melalui file descriptor yang dikembalikan
  • Header Ethernet ditangani sebagai dmac, smac, ethertype, payload; jika nilai ethertype 1536 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 entri 10.0.0.4 ditambahkan ke cache ARP antarmuka tap0

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/tap lalu memanggil ioctl(fd, TUNSETIFF, ...)
    • IFF_TAP memilih perangkat TAP
    • IFF_NO_PI mencegah informasi paket yang tidak diperlukan ditambahkan di depan frame Ethernet
  • Setelah dibuat, buffer Ethernet perangkat virtual dibaca dan ditulis melalui file descriptor fd yang 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.h dari Linux untuk menggunakan pemetaan antara ethertype dan nilai heksadesimal
  • Header Ethernet direpresentasikan dalam struct C dengan field berikut
    • dmac: alamat MAC tujuan
    • smac: alamat MAC sumber
    • ethertype: panjang atau tipe payload
    • payload: pointer payload yang berisi paket ARP atau IPv4
  • ethertype adalah 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 packed pada 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;
  • 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 nilai ethertype dan 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 adalah 0x0001
    • protype: field 2 oktet yang menunjukkan tipe protokol; nilai untuk IPv4 adalah 0x0800
    • hwsize: field 1 oktet yang menunjukkan ukuran alamat hardware; alamat MAC adalah 6 byte
    • prosize: field 1 oktet yang menunjukkan ukuran alamat protokol; alamat IPv4 adalah 4 byte
    • opcode: field 2 oktet yang menunjukkan tipe pesan ARP
  • Nilai opcode dibagi menjadi empat
    • ARP request: 1
    • ARP reply: 2
    • RARP request: 3
    • RARP reply: 4
  • Data ARP untuk IPv4 ditangani dengan struct arp_ipv4
    • smac: alamat MAC pengirim
    • sip: alamat IP pengirim
    • dmac: alamat MAC penerima
    • dip: 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.4 menunjukkan respons unicast kembali dari 10.0.0.4 dengan alamat MAC 00:0C:29:6D:50:25
  • Setelah itu, output arp menunjukkan entri 10.0.0.4 ether 00:0c:29:6d:50:25 tap0 muncul 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

 
GN⁺ 2025-03-05
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

    • Dulu sekali saya pernah menulis parser pcap/tcpdump dalam bash murni, karena saat itu hanya itu alat yang saya tahu bisa dipakai untuk menulis “program”
      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
    • Banyak perangkat embedded menggunakan lwip sebagai implementasi TCP/IP
      “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

    • Dari sudut pandang orang yang tidak tahu apa-apa, ini cukup mengejutkan, tetapi saya penasaran apakah itu bukan berarti bagian TCP/IP adalah setengah dari seluruh kode sumber kernel
    • Saya penasaran kenapa stack IP sebesar itu. Biner 400KB berarti cukup banyak kode; apakah karena sangat dioptimalkan untuk kebutuhan server besar?
  • 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

    • Cisco IOS SLB juga bisa bekerja dengan cara serupa. Caranya adalah menambahkan IP virtual sebagai alias pada loopback tiap server di server farm
      Kelebihannya dibanding load balancing L3 yang lebih umum dipakai adalah tidak perlu menulis ulang header paket IP
    • Ini juga dikenal sebagai DSR (Direct Server Return): https://www.haproxy.com/blog/layer-4-load-balancing-direct-s...
    • Jika ARP dinonaktifkan dan IP yang sama diatur pada beberapa server di jaringan yang sama, switch/bridge tidak dapat mempelajari alamat MAC, sehingga paket akan terus di-flood/broadcast ke semua port pada segmen tersebut
      Karena itu, jika memakai cara ini, sebaiknya buat VLAN khusus
    • F5 punya pengaturan proxy ARP, jadi tidak perlu melakukan ini. Kekurangannya, ini sering merusak DHCP
    • Untuk eksperimen level rendah seperti ini, DPDK juga bisa dicoba. ARP pada dasarnya dinonaktifkan secara default
  • 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”

    • Kalimat lengkapnya adalah “dmac dan smac adalah field yang cukup jelas. Keduanya berisi alamat MAC pihak yang berkomunikasi (masing-masing tujuan dan sumber)”, jadi sebenarnya sudah dijelaskan
      Selain itu, jika ini artikel tentang membuat network stack, cukup aman untuk mengasumsikan pembaca punya sedikit pengetahuan tentang networking
    • Jika bukan baru saja diperbarui, tepat di kalimat berikutnya dijelaskan “Keduanya berisi alamat MAC pihak yang berkomunikasi (masing-masing tujuan dan sumber)”
  • 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?

    • Tidak disebutkan di tulisan, tetapi itu adalah nilai yang di-hardcode penulis saat inisialisasi antarmuka: https://github.com/saminiir/level-ip/blob/e9ceb08f01a5499b85...
      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