github.com/MetalBlockchain/metalgo@v1.11.9/nat/no_router.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package nat
     5  
     6  import (
     7  	"errors"
     8  	"net"
     9  	"net/netip"
    10  	"time"
    11  )
    12  
    13  var (
    14  	_ Router = (*noRouter)(nil)
    15  
    16  	errNoRouterCantMapPorts = errors.New("can't map ports without a known router")
    17  	errFetchingIP           = errors.New("getting outbound IP failed")
    18  )
    19  
    20  const googleDNSServer = "8.8.8.8:80"
    21  
    22  type noRouter struct {
    23  	ip    netip.Addr
    24  	ipErr error
    25  }
    26  
    27  func (noRouter) SupportsNAT() bool {
    28  	return false
    29  }
    30  
    31  func (noRouter) MapPort(uint16, uint16, string, time.Duration) error {
    32  	return errNoRouterCantMapPorts
    33  }
    34  
    35  func (noRouter) UnmapPort(uint16, uint16) error {
    36  	return nil
    37  }
    38  
    39  func (r noRouter) ExternalIP() (netip.Addr, error) {
    40  	return r.ip, r.ipErr
    41  }
    42  
    43  func getOutboundIP() (netip.Addr, error) {
    44  	conn, err := net.Dial("udp", googleDNSServer)
    45  	if err != nil {
    46  		return netip.Addr{}, err
    47  	}
    48  
    49  	localAddr := conn.LocalAddr()
    50  	if err := conn.Close(); err != nil {
    51  		return netip.Addr{}, err
    52  	}
    53  
    54  	udpAddr, ok := localAddr.(*net.UDPAddr)
    55  	if !ok {
    56  		return netip.Addr{}, errFetchingIP
    57  	}
    58  	addr := udpAddr.AddrPort().Addr()
    59  	if addr.Is4In6() {
    60  		addr = addr.Unmap()
    61  	}
    62  	return addr, nil
    63  }
    64  
    65  // NewNoRouter returns a router that assumes the network is public
    66  func NewNoRouter() Router {
    67  	ip, err := getOutboundIP()
    68  	return &noRouter{
    69  		ip:    ip,
    70  		ipErr: err,
    71  	}
    72  }