package main
import (
"fmt"
"net"
"strconv"
"time"
"github.com/pion/stun"
log "github.com/sirupsen/logrus"
)
const (
stunServer1 = "stun1.l.google.com:19302"
stunServer2 = "stun2.l.google.com:19302"
WgListenPort = 51820
)
func main() {
isSymmetric, err := IsSymmetricNAT()
if err != nil {
log.Error(err)
}
log.Infof("Symmetric NAT is -> %t", isSymmetric)
}
// IsSymmetricNAT attempts to infer if the node is behind a symmetric
// nat device by querying two STUN servers. If the requests return
// different ports, then it is likely the node is behind a symmetric nat.
func IsSymmetricNAT() (bool, error) {
firstStun, err := StunRequest(stunServer1, WgListenPort)
if err != nil {
return false, fmt.Errorf("failed to queury the STUN server %s", stunServer1)
}
secondStun, err := StunRequest(stunServer2, WgListenPort)
if err != nil {
return false, fmt.Errorf("failed to queury the STUN server %s", stunServer1)
}
if firstStun != secondStun {
return true, nil
}
return false, nil
}
// StunRequest initiate a connection to a STUN server sourced from the wg src port
func StunRequest(stunServer string, srcPort int) (string, error) {
lAddr := &net.UDPAddr{
Port: srcPort,
}
d := &net.Dialer{
Timeout: 3 * time.Second,
LocalAddr: lAddr,
}
log.Debugf("dialing stun server %s", stunServer)
conn, err := d.Dial("udp4", stunServer)
if err != nil {
log.Errorf("%v", err)
return "", fmt.Errorf("failed to dial stun server %s: %v", stunServer, err)
}
stunResults, err := stunDialer(&conn)
if err != nil {
return "", err
}
return stunResults, nil
}
func stunDialer(conn *net.Conn) (string, error) {
c, err := stun.NewClient(*conn)
if err != nil {
log.Errorf("%v", err)
}
var xorAddr stun.XORMappedAddress
if err = c.Do(stun.MustBuild(stun.TransactionID, stun.BindingRequest), func(res stun.Event) {
if res.Error != nil {
log.Println(res.Error)
return
}
if getErr := xorAddr.GetFrom(res.Message); getErr != nil {
log.Println(getErr)
if err := c.Close(); err != nil {
log.Println(err)
return
}
return
}
log.Infof("Stun address and port is: %s:%d", xorAddr.IP, xorAddr.Port)
}); err != nil {
return "", err
}
if err := c.Close(); err != nil {
return "", err
}
stunAddress := net.JoinHostPort(xorAddr.IP.String(), strconv.Itoa(xorAddr.Port))
if err != nil {
return "", err
}
return stunAddress, nil
}
Created
November 22, 2022 16:16
-
-
Save nerdalert/9e36c87b6caae027219262015c5e1699 to your computer and use it in GitHub Desktop.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment