New Upstream Release - golang-github-ccding-go-stun

Ready changes

Summary

Merged new upstream version: 0.1.4 (was: 0.1.3).

Resulting package

Built on 2022-12-14T03:35 (took 3m15s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases golang-github-ccding-go-stun-dev

Lintian Result

Diff

diff --git a/debian/changelog b/debian/changelog
index 75cd5c1..e0bec0f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-ccding-go-stun (0.1.4-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 14 Dec 2022 03:32:45 -0000
+
 golang-github-ccding-go-stun (0.1.3-1) unstable; urgency=medium
 
   * New upstream version.
diff --git a/main.go b/main.go
index a6a25c2..574e74b 100644
--- a/main.go
+++ b/main.go
@@ -23,6 +23,7 @@ import (
 
 func main() {
 	var serverAddr = flag.String("s", stun.DefaultServerAddr, "STUN server address")
+	var b = flag.Bool("b", false, "NAT behavior test mode")
 	var v = flag.Bool("v", false, "verbose mode")
 	var vv = flag.Bool("vv", false, "double verbose mode (includes -v)")
 	var vvv = flag.Bool("vvv", false, "triple verbose mode (includes -v and -vv)")
@@ -35,6 +36,12 @@ func main() {
 	// Non verbose mode will be used by default unless we call SetVerbose(true) or SetVVerbose(true).
 	client.SetVerbose(*v || *vv || *vvv)
 	client.SetVVerbose(*vv || *vvv)
+
+	if *b {
+		behaviorTest(client)
+		return
+	}
+
 	// Discover the NAT and return the result.
 	nat, host, err := client.Discover()
 	if err != nil {
@@ -49,3 +56,17 @@ func main() {
 		fmt.Println("External Port:", host.Port())
 	}
 }
+
+func behaviorTest(c *stun.Client) {
+	natBehavior, err := c.BehaviorTest()
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	if natBehavior != nil {
+		fmt.Println("  Mapping Behavior:", natBehavior.MappingType)
+		fmt.Println("Filtering Behavior:", natBehavior.FilteringType)
+		fmt.Println("   Normal NAT Type:", natBehavior.NormalType())
+	}
+	return
+}
diff --git a/stun/client.go b/stun/client.go
index e7baf09..d661ee0 100644
--- a/stun/client.go
+++ b/stun/client.go
@@ -99,6 +99,27 @@ func (c *Client) Discover() (NATType, *Host, error) {
 	return c.discover(conn, serverUDPAddr)
 }
 
+func (c *Client) BehaviorTest() (*NATBehavior, error) {
+	if c.serverAddr == "" {
+		c.SetServerAddr(DefaultServerAddr)
+	}
+	serverUDPAddr, err := net.ResolveUDPAddr("udp", c.serverAddr)
+	if err != nil {
+		return nil, err
+	}
+	// Use the connection passed to the client if it is not nil, otherwise
+	// create a connection and close it at the end.
+	conn := c.conn
+	if conn == nil {
+		conn, err = net.ListenUDP("udp", nil)
+		if err != nil {
+			return nil, err
+		}
+		defer conn.Close()
+	}
+	return c.behaviorTest(conn, serverUDPAddr)
+}
+
 // Keepalive sends and receives a bind request, which ensures the mapping stays open
 // Only applicable when client was created with a connection.
 func (c *Client) Keepalive() (*Host, error) {
diff --git a/stun/const.go b/stun/const.go
index e335dce..e1faa9f 100644
--- a/stun/const.go
+++ b/stun/const.go
@@ -28,6 +28,14 @@ const (
 // NATType is the type of NAT described by int.
 type NATType int
 
+// NAT behavior type
+type BehaviorType int
+
+type NATBehavior struct {
+	MappingType   BehaviorType
+	FilteringType BehaviorType
+}
+
 // NAT types.
 const (
 	NATError NATType = iota
@@ -46,7 +54,16 @@ const (
 	NATSymmetricUDPFirewall = SymmetricUDPFirewall
 )
 
+const (
+	BehaviorTypeUnknown BehaviorType = iota
+	BehaviorTypeEndpoint
+	BehaviorTypeAddr
+	BehaviorTypeAddrAndPort
+)
+
 var natStr map[NATType]string
+var natBehaviorTypeStr map[BehaviorType]string
+var natNormalTypeStr map[NATBehavior]string
 
 func init() {
 	natStr = map[NATType]string{
@@ -60,6 +77,20 @@ func init() {
 		NATNone:              "Not behind a NAT",
 		SymmetricUDPFirewall: "Symmetric UDP firewall",
 	}
+
+	natBehaviorTypeStr = map[BehaviorType]string{
+		BehaviorTypeEndpoint:    "EndpointIndependent",
+		BehaviorTypeAddr:        "AddressDependent",
+		BehaviorTypeAddrAndPort: "AddressAndPortDependent",
+	}
+
+	// Defined in RFC 3489
+	natNormalTypeStr = map[NATBehavior]string{
+		NATBehavior{BehaviorTypeEndpoint, BehaviorTypeEndpoint}:       "Full cone NAT",
+		NATBehavior{BehaviorTypeEndpoint, BehaviorTypeAddr}:           "Restricted cone NAT",
+		NATBehavior{BehaviorTypeEndpoint, BehaviorTypeAddrAndPort}:    "Port Restricted cone NAT",
+		NATBehavior{BehaviorTypeAddrAndPort, BehaviorTypeAddrAndPort}: "Symmetric NAT",
+	}
 }
 
 func (nat NATType) String() string {
@@ -69,6 +100,20 @@ func (nat NATType) String() string {
 	return "Unknown"
 }
 
+func (natBhType BehaviorType) String() string {
+	if s, ok := natBehaviorTypeStr[natBhType]; ok {
+		return s
+	}
+	return "Unknown"
+}
+
+func (natBehavior NATBehavior) NormalType() string {
+	if s, ok := natNormalTypeStr[natBehavior]; ok {
+		return s
+	}
+	return "Undefined"
+}
+
 const (
 	errorTryAlternate                 = 300
 	errorBadRequest                   = 400
diff --git a/stun/discover.go b/stun/discover.go
index a8910d8..b37bbb7 100644
--- a/stun/discover.go
+++ b/stun/discover.go
@@ -164,3 +164,90 @@ func (c *Client) discover(conn net.PacketConn, addr *net.UDPAddr) (NATType, *Hos
 	}
 	return NATSymmetric, mappedAddr, nil
 }
+
+func (c *Client) behaviorTest(conn net.PacketConn, addr *net.UDPAddr) (*NATBehavior, error) {
+	natBehavior := &NATBehavior{}
+
+	// Test1   ->(IP1,port1)
+	// Perform test to check if it is under NAT.
+	c.logger.Debugln("Do Test1")
+	resp1, err := c.test(conn, addr)
+	if err != nil {
+		return nil, err
+	}
+	// identical used to check if it is open Internet or not.
+	if resp1.identical {
+		return nil, errors.New("Not behind a NAT.")
+	}
+	// use otherAddr or changedAddr
+	otherAddr := resp1.otherAddr
+	if otherAddr == nil {
+		if resp1.changedAddr != nil {
+			otherAddr = resp1.changedAddr
+		} else {
+			return nil, errors.New("Server error: no other address and changed address.")
+		}
+	}
+
+	// Test2   ->(IP2,port1)
+	// Perform test to see if mapping to the same IP and port when
+	// send to another IP.
+	c.logger.Debugln("Do Test2")
+	tmpAddr := &net.UDPAddr{IP: net.ParseIP(otherAddr.IP()), Port: addr.Port}
+	resp2, err := c.test(conn, tmpAddr)
+	if err != nil {
+		return nil, err
+	}
+	if resp2.mappedAddr.IP() == resp1.mappedAddr.IP() &&
+		resp2.mappedAddr.Port() == resp1.mappedAddr.Port() {
+		natBehavior.MappingType = BehaviorTypeEndpoint
+	}
+
+	// Test3   ->(IP2,port2)
+	// Perform test to see if mapping to the same IP and port when
+	// send to another port.
+	if natBehavior.MappingType == BehaviorTypeUnknown {
+		c.logger.Debugln("Do Test3")
+		tmpAddr.Port = int(otherAddr.Port())
+		resp3, err := c.test(conn, tmpAddr)
+		if err != nil {
+			return nil, err
+		}
+		if resp3.mappedAddr.IP() == resp2.mappedAddr.IP() &&
+			resp3.mappedAddr.Port() == resp2.mappedAddr.Port() {
+			natBehavior.MappingType = BehaviorTypeAddr
+		} else {
+			natBehavior.MappingType = BehaviorTypeAddrAndPort
+		}
+	}
+
+	// Test4   ->(IP1,port1)   (IP2,port2)->
+	// Perform test to see if the client can receive packet sent from
+	// another IP and port.
+	c.logger.Debugln("Do Test4")
+	resp4, err := c.testChangeBoth(conn, addr)
+	if err != nil {
+		return natBehavior, err
+	}
+	if resp4 != nil {
+		natBehavior.FilteringType = BehaviorTypeEndpoint
+	}
+
+	// Test5   ->(IP1,port1)   (IP1,port2)->
+	// Perform test to see if the client can receive packet sent from
+	// another port.
+	if natBehavior.FilteringType == BehaviorTypeUnknown {
+		c.logger.Debugln("Do Test5")
+		resp5, err := c.testChangePort(conn, addr)
+		if err != nil {
+			return natBehavior, err
+		}
+		if resp5 != nil {
+			natBehavior.FilteringType = BehaviorTypeAddr
+		} else {
+			natBehavior.FilteringType = BehaviorTypeAddrAndPort
+		}
+	}
+
+	return natBehavior, nil
+}
diff --git a/stun/tests.go b/stun/tests.go
index e504da7..bfd92ae 100644
--- a/stun/tests.go
+++ b/stun/tests.go
@@ -15,9 +15,45 @@
 package stun
 
 import (
+	"errors"
 	"net"
 )
 
+func (c *Client) sendWithLog(conn net.PacketConn, addr *net.UDPAddr, changeIP bool, changePort bool) (*response, error) {
+	c.logger.Debugln("Send To:", addr)
+	resp, err := c.sendBindingReq(conn, addr, changeIP, changePort)
+	if err != nil {
+		return nil, err
+	}
+	c.logger.Debugln("Received:", resp)
+	if resp == nil && changeIP == false && changePort == false {
+		return nil, errors.New("NAT blocked.")
+	}
+	if resp != nil && !addrCompare(resp.serverAddr, addr, changeIP, changePort) {
+		return nil, errors.New("Server error: response IP/port")
+	}
+	return resp, err
+}
+
+// Make sure IP and port  have or haven't change
+func addrCompare(host *Host, addr *net.UDPAddr, IPChange, portChange bool) bool {
+	isIPChange := host.IP() != addr.IP.String()
+	isPortChange := host.Port() != uint16(addr.Port)
+	return isIPChange == IPChange && isPortChange == portChange
+}
+
+func (c *Client) test(conn net.PacketConn, addr *net.UDPAddr) (*response, error) {
+	return c.sendWithLog(conn, addr, false, false)
+}
+
+func (c *Client) testChangePort(conn net.PacketConn, addr *net.UDPAddr) (*response, error) {
+	return c.sendWithLog(conn, addr, false, true)
+}
+
+func (c *Client) testChangeBoth(conn net.PacketConn, addr *net.UDPAddr) (*response, error) {
+	return c.sendWithLog(conn, addr, true, true)
+}
+
 func (c *Client) test1(conn net.PacketConn, addr net.Addr) (*response, error) {
 	return c.sendBindingReq(conn, addr, false, false)
 }

Debdiff

File lists identical (after any substitutions)

No differences were encountered in the control files

More details

Full run details