Back to Blog
Tech Sharing 2026-06-14 7 min read

Navigasi Network Adapter di Windows: Membangun Multi-Interface Proxy dengan Go

Golang Windows API Network Routing Proxy Server

Ketika bekerja dengan sistem jaringan yang kompleks atau melakukan web scraping tingkat lanjut, salah satu tantangan terbesar adalah mengontrol jalur lalu lintas keluar (outbound traffic). Secara default, sistem operasi Windows menentukan rute keluar secara otomatis berdasarkan nilai metric (routing metric) dari network adapter terkoneksi. Adapter dengan metric terendah (biasanya Ethernet atau Wi-Fi tercepat) akan melayani seluruh traffic keluar.

Namun, bagaimana jika kita ingin mengarahkan traffic dari program tertentu melewati koneksi seluler (USB tethering), sementara program lainnya tetap menggunakan jaringan kantor atau Wi-Fi lokal? Di sinilah konsep Multi-Interface Proxy bermain. Di artikel sharing ini, kita akan bedah bagaimana membangun proxy server lokal dengan Go yang mampu melakukan navigasi network adapter secara dinamis di Windows.

Mengapa Menggunakan Go?

Go memiliki pustaka standar net yang sangat kuat dan efisien untuk pemrograman jaringan tingkat rendah. Konkurensi melalui goroutine juga memungkinkan proxy server menangani ratusan koneksi secara bersamaan dengan memori yang sangat minim. Ini sangat cocok untuk utilitas desktop ringan yang berjalan di latar belakang (seperti yang gue terapkan pada proyek Proxymon).

Langkah 1: Mendeteksi Network Adapter Aktif

Langkah awal yang harus dilakukan adalah memetakan seluruh network adapter (interfaces) yang terpasang di sistem operasi beserta alamat IP lokal masing-masing. Di Go, kita bisa menggunakan fungsi bawaan net.Interfaces():

package main

import (
	"fmt"
	"net"
)

func listAdapters() {
	interfaces, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	for _, iface := range interfaces {
		// Lewati interface yang mati atau loopback
		if iface.Flags&net.FlagUp == 0 || iface.Flags&net.FlagLoopback != 0 {
			continue
		}

		addrs, err := iface.Addrs()
		if err != nil {
			continue
		}

		for _, addr := range addrs {
			var ip net.IP
			switch v := addr.(type) {
			case *net.IPNet:
				ip = v.IP
			case *net.IPAddr:
				ip = v.IP
			}

			// Kita hanya memetakan IPv4 untuk kemudahan
			if ip != nil && ip.To4() != nil {
				fmt.Printf("Adapter: %s | IP: %s\n", iface.Name, ip.String())
			}
		}
	}
}

Langkah 2: Melakukan Bind Socket ke IP Adapter Terpilih

Secara default, saat kita membuat koneksi TCP keluar menggunakan net.Dial(), OS akan memilih IP lokal asal secara otomatis. Untuk membelokkan traffic ke adapter tertentu, kita harus memaksa socket untuk melakukan bind ke alamat IP lokal milik adapter tersebut sebelum melakukan dial keluar.

Di Go, kita bisa melakukan bind ini dengan menyetel properti LocalAddr pada struct net.Dialer:

func dialViaAdapter(targetAddr string, localIP string) (net.Conn, error) {
	localTCPAddr, err := net.ResolveTCPAddr("tcp", localIP+":0") // Port 0 membiarkan OS memilih port asal yang kosong
	if err != nil {
		return nil, err
	}

	dialer := net.Dialer{
		LocalAddr: localTCPAddr, // Kunci utama pembelokan interface
		Timeout:   30 * time.Second,
	}

	return dialer.Dial("tcp", targetAddr)
}

Langkah 3: Mengintegrasikan ke dalam Proxy Server (HTTP CONNECT)

Kini kita memiliki dialer yang bisa memilih jalur keluar. Langkah selanjutnya adalah menyematkan dialer ini ke dalam server proxy HTTP lokal. Ketika client (misalnya browser) mengirimkan permintaan CONNECT, proxy server kita akan membajak koneksi tersebut dan menghubungkannya ke target internet melalui adapter pilihan kita:

func handleTunnel(clientConn net.Conn, targetHost string, localIP string) {
	// Koneksi ke server tujuan menggunakan adapter spesifik
	targetConn, err := dialViaAdapter(targetHost, localIP)
	if err != nil {
		clientConn.Write([]byte("HTTP/1.1 502 Bad Gateway\r\n\r\n"))
		return
	}
	defer targetConn.Close()

	// Kirim respon sukses ke client
	clientConn.Write([]byte("HTTP/1.1 200 Connection Established\r\n\r\n"))

	// Lakukan copy data secara bidirectional (goroutine bridge)
	go io.Copy(targetConn, clientConn)
	io.Copy(clientConn, targetConn)
}

Mengatasi Tantangan di Windows

Di Windows, ada beberapa kendala unik yang perlu diperhatikan saat bermain dengan multiple network interfaces:

  • IP Dinamis (DHCP): Jika koneksi terputus dan tersambung kembali, alamat IP adapter bisa berubah. Kita harus mengimplementasikan pemantau (watcher) atau melakuan polling berkala untuk mengupdate daftar IP aktif.
  • Metric Konflik: Dalam kasus ekstrem, Windows mungkin memblokir outbound bind jika gateway dari adapter terpilih tidak memiliki rute aktif. Mengonfigurasi routing table Windows menggunakan perintah CLI route add secara terprogram kadang diperlukan untuk kasus lanjutan.

Kesimpulan

Membangun multi-interface proxy dengan Go memberikan kontrol penuh atas bagaimana paket data berjalan meninggalkan komputer kita. Logika dasar di atas sangat fleksibel dan dapat dikembangkan lebih lanjut dengan menambahkan protokol SOCKS5, enkripsi lalu lintas, atau sistem statistik bandwidth per adapter.

Dengan memadukan dialer kustom ini ke dalam GUI ringan menggunakan WebView2 atau sistem tray, kita bisa menciptakan aplikasi utility tangguh seperti Proxymon untuk membantu produktivitas operasional harian.

Commit. Push. Repeat.

More Tech Sharing Articles