Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
UDP firewall holepunching / NAT traversal demo in Go
/* UDP firewall holepunching / NAT traversal demo in Go
* Very simple, send a UDP packet out to a server and await a response. Should
* work even if you are behind a NAT as many home routers will open a firewall
* "hole" for egress datagrams; this way we can connect directly to a server
* without port-forwarding (we cannot do this over TCP, a connection-oriented
* protocol).
* Usage (server): go build && ./udp-nat-traversal
* Usage (client): go build && ./udp-nat-traversal
* ~ Wesley Coakley
package main
import (
// Send a UDP packet out
func doClient(remote string, port int) {
msgBuf := make([]byte, 1024)
// Resolve the passed address as UDP4
toAddr, err := net.ResolveUDPAddr("udp4", remote + ":" + strconv.Itoa(port))
if err != nil {
fmt.Printf("Could not resolve %s:%d\n", remote, port)
fmt.Printf("Trying to punch a hole to %s:%d\n", remote, port)
// Initiate the transaction (force IPv4 to demo firewall punch)
conn, err := net.DialUDP("udp4", nil, toAddr)
defer conn.Close()
if err != nil {
fmt.Printf("Unable to connect to %s:%d\n", remote, port)
// Initiate the transaction, creating the hole
msg := "ただいま~"
fmt.Fprintf(conn, msg)
fmt.Printf("Sent a UDP packet to %s:%d\n\tSent: %s\n", remote, port, msg)
// Await a response through our firewall hole
msgLen, fromAddr, err := conn.ReadFromUDP(msgBuf)
if err != nil {
fmt.Printf("Error reading UDP response!\n")
fmt.Printf("Received a UDP packet back from %s:%d\n\tResponse: %s\n",
fromAddr.IP, fromAddr.Port, msgBuf[:msgLen])
fmt.Println("Success: NAT traversed! ^-^")
func doServer(port int) {
msgBuf := make([]byte, 1024)
// Initiatlize a UDP listener
ln, err := net.ListenUDP("udp4", &net.UDPAddr{Port: port})
if err != nil {
fmt.Printf("Unable to listen on :%d\n", port)
fmt.Printf("Listening on :%d\n", port)
for {
// Await incoming packets
rcvLen, addr, err := ln.ReadFrom(msgBuf)
if err != nil {
fmt.Println("Transaction was initiated but encountered an error!")
fmt.Printf("Received a packet from: %s\n\tSays: %s\n",
addr.String(), msgBuf[:rcvLen])
// Let the client confirm a hole was punched through to us
reply := "お帰り~"
copy(msgBuf, []byte(reply))
_, err = ln.WriteTo(msgBuf[:len(reply)], addr)
if err != nil {
fmt.Println("Socket closed unexpectedly!")
fmt.Printf("Sent reply to %s\n\tReply: %s\n",
addr.String(), msgBuf[:len(reply)])
func main() {
port := 9199
if len(os.Args) > 1 {
// Act as a client and initiate the transaction
remoteServer := os.Args[1]
doClient(remoteServer, port)
// Act as a server and respond to incoming UDP messages
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.