Apa Itu Protokol Session Traversal Utilities for NAT (STUN)?
Salah satu istilah yang sering saya jumpai saat membuat kode program yang berhubungan dengan WebRTC adalah STUN. Session Traversal Utilities for NAT (STUN) adalah protokol yang didefinisikan di RFC 5389. STUN membantu mempermudah komunikasi dengan perangkat yang berada dibalik NAT yang tidak dapat dihubungi secara langsung dari IP publik. Komponen STUN disebut sebagai STUN Agent yang terdiri atas STUN Client dan STUN Server.
STUN Lewat Program Go
Sebagai latihan, saya akan membuat kode program Go yang berperan sebagai STUN Client dan mengirim pesan Binding Request ke
STUN Server publik milik Google di stun.l.google.com
. Biasanya port yang dipakai untuk STUN adalah UDP/3478
, namun
STUN Server gratis tersebut menggunakan port UDP/19302
. Saya akan mulai dengan mendefinisikan struktur packet STUN seperti
pada kode program berikut ini:
MessageHeader
adalah sebuah struktur statis yang terdiri atas 20 bytes pertama dari packet STUN. Nilai MessageType
menunjukkan jenis pesan STUN yang diterima. Pada kode program sederhana ini, saya hanya akan menggunakan jenis pesan BindingRequest
dan BindingResponse
:
Nilai MessageLength
menunjukkan isi dari pesan STUN (kosong atau beberapa MessageAttribute
) dalam jumlah byte tidak
termasuk 20 bytes pertama (untuk header). Khusus untuk pesan BindingRequest
, karena saya tidak perlu memakai
atribut, nilai dari MessageLength
selalu 0
.
Nilai MagicCookie
selalu berupa 0x2112A442
. Nilai ini dapat dipakai untuk memeriksa apakah packet STUN yang diterima
adalah bener packet STUN atau bukan.
Nilai TransactionId
adalah sebuah angka pengenal unik dalam ukuran 12 bytes (96 bit). Pada saat mengirim pesan BindingRequest
,
saya perlu mengisi nilai ini dengan sebuah nilai acak. Pada saat menerima pesan BindingResponse
, saya perlu membandingkan
nilai TransactionId
yang dterima apakah sama dengan nilai TranscationId
saat dikirim. Ini untuk memastikan bahwa jawaban
yang diterima adalah jawaban untuk request yang saya berikan.
Untuk membuat sebuah pesan BindingRequest
, saya dapat menggunakan kode program seperti berikut ini:
Saya kemudian dapat mengirim pesan ini ke STUN server melalui koneksi UDP seperti pada packet lainnya, misalnya dengan kode program seperti berikut ini:
Setelah mengirim packet STUN ke STUN Server, kode program di atas akan menunggu hingga maksimal 5 detik untuk mendapatkan
respon. STUN Server akan mengirim pesan BindingResponse
yang berisi alamat NAT atau IP publik terakhir yang dilihat
oleh STUN server saat menerima pesan BindingRequest
. Karena respon yang diterima berada dalam bentuk []byte
, saya dapat
menggunakan kode program seperti berikut ini untuk menerjemahkannya menjadi sebuah struktur Message
:
Pada kode program di atas, saya perlu menggunakan looping for
karena sebuah packet STUN dapat berisi lebih dari satu
MessageAttribute
dimana masing-masing MessageAttribute
memiliki ukuran yang bervariasi tergantung pada nilai Length
-nya. Setiap
MessageAttribute
memiliki nilai MessageType
yang menunjukkan jenis atribut (dan juga mendefinisikan struktur nilai dari
atribut tersebut). Khusus untuk BindingResponse
, saya perlu mendapatkan nilai dari atribut MappedAddressAttribute
dengan
nilai 0x0001
atau XorMappedAddressAttributeType
dengan nilai 0x0020
:
Untuk mengubah nilai MessageAttribute.Value
menjadi sebuah MappedAddressAttribute
, saya dapat menggunakan kode program
seperti berikut ini:
Untuk MappedAddressAttribute
, byte pertama selalu kosong. Saya dapat menggunakan fakta ini untuk memeriksa apakah atribut ini
valid atau tidak. Setelah itu, saya mulai dengan byte kedua yang berisi nilai untuk Family
. Nilai Family
berupa 0x01
menunjukkan bawah ini adalah alamat IPv4 dan 0x02
untuk alamat IPv6. Berikutnya, byte ketiga dan keempat menjukkan nilai
Port
. Sisanya adalah nilai alamat IP. Karena Go memiliki struktur net.IP
untuk []byte
, saya menggunakan struktur
tersebut untuk nilai IP.
STUN server dari Google tidak mengembalikan atribut MappedAddressAttribute
melainkan XorMappedAddressAttribute
. Jenis
atribut ini hampir sama dengan nilai MappedAddressAttribute
, hanya saja nilai port dan IP disamarkan melalui operasi
XOR terhadap magic cookie dan transaction id. Tujuan menyamarkan nilai tersebut adalah untuk mencegah perangkat jaringan
tertentu dalam memproses NAT secara tidak sengaja menulis ulang IP dan port yang hanya berupa informasi di packet STUN.
Untuk mendapatkan nilai XorMappedAddressAttribute
, saya dapat menggunakan kode program seperti berikut ini:
Saya dapat memanggil function di atas dengan menyertakan nilai byte magic cookie hingga transaction id seperti berikut ini:
Sampai disini, saya sudah berhasil mendapatkan IP publik melalui protokol STUN.
STUN Lewat Web
Selain dengan pemograman low level melalui Go, saya juga dapat menghubungi STUN Server melalui JavaScript di web browser. Hampir semua browser modern mendukung WebRTC yang menggunakan protokol Interactive Connectivity Establishment (ICE). Protokol ICE menggunakan STUN di tahap client negotiation. Dengan demikian, saya dapat memanfaatkan fase tersebut untuk mengetahui IP publik dan menampilkannya di halaman web. Sebagai contoh, saya dapat membuat kode program seperti berikut ini:
Kode program di atas akan melakukan binding request ke STUN Server stun.l.google.com:19302
untuk setiap perangkat jaringan lokal yang
dijumpai oleh web browser. Untuk mendapatkan informasi alamat IP publik, saya dapat menggunakan event onicecandidate
seperti berikut ini:
Sebagai contoh, berikut ini adalah contoh hasil eksekusi JavaScript yang berusaha mendapatkan IP publik melalui WebRTC: