diff --git a/cmd/main.go b/cmd/main.go index 28e7db0..2b4e9d5 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -17,6 +17,7 @@ func main() { flag.IntVar(&model.Verbose, "verbose", 0, "the verbosity level") flag.IntVar(&model.Timeout, "timeout", 3, "the number of seconds to wait for STUN server's response") flag.StringVar(&model.AddrStr, "server", "stun.voipgate.com:3478", "STUN server address") + flag.BoolVar(&model.EnableLoger, "e", true, "Enable logging") flag.Parse() go func() { http.Get("https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2Foneclickvirt%2Fgostun&count_bg=%2379C83D&title_bg=%23555555&icon=&icon_color=%23E7E7E7&title=hits&edge_flat=false") @@ -26,25 +27,31 @@ func main() { fmt.Println(model.GoStunVersion) return } - var logLevel logging.LogLevel - switch model.Verbose { - case 0: - logLevel = logging.LogLevelWarn // default // my changes - case 1: - logLevel = logging.LogLevelInfo - case 2: - logLevel = logging.LogLevelDebug - case 3: - logLevel = logging.LogLevelTrace + if model.EnableLoger { + var logLevel logging.LogLevel + switch model.Verbose { + case 0: + logLevel = logging.LogLevelWarn // default + case 1: + logLevel = logging.LogLevelInfo + case 2: + logLevel = logging.LogLevelDebug + case 3: + logLevel = logging.LogLevelTrace + } + model.Log = logging.NewDefaultLeveledLoggerForScope("", logLevel, os.Stdout) } - model.Log = logging.NewDefaultLeveledLoggerForScope("", logLevel, os.Stdout) if model.AddrStr != "stun.voipgate.com:3478" { if err := stuncheck.MappingTests(model.AddrStr); err != nil { - model.NatMappingBehavior = "inconclusive" // my changes + if model.EnableLoger { + model.NatMappingBehavior = "inconclusive" + } model.Log.Warn("NAT mapping behavior: inconclusive") } if err := stuncheck.FilteringTests(model.AddrStr); err != nil { - model.NatFilteringBehavior = "inconclusive" // my changes + if model.EnableLoger { + model.NatFilteringBehavior = "inconclusive" + } model.Log.Warn("NAT filtering behavior: inconclusive") } } else { @@ -58,13 +65,17 @@ func main() { err1 := stuncheck.MappingTests(addrStr) if err1 != nil { model.NatMappingBehavior = "inconclusive" - model.Log.Warn("NAT mapping behavior: inconclusive") + if model.EnableLoger { + model.Log.Warn("NAT mapping behavior: inconclusive") + } checkStatus = false } err2 := stuncheck.FilteringTests(addrStr) if err2 != nil { model.NatFilteringBehavior = "inconclusive" - model.Log.Warn("NAT filtering behavior: inconclusive") + if model.EnableLoger { + model.Log.Warn("NAT filtering behavior: inconclusive") + } checkStatus = false } if model.NatMappingBehavior == "inconclusive" || model.NatFilteringBehavior == "inconclusive" { @@ -78,5 +89,5 @@ func main() { } } res := stuncheck.CheckType() - fmt.Printf("NAT Type: %s", res) + fmt.Printf("NAT Type: %s\n", res) } diff --git a/model/model.go b/model/model.go index 72b5d22..b297e31 100644 --- a/model/model.go +++ b/model/model.go @@ -11,4 +11,5 @@ var ( Log logging.LeveledLogger NatMappingBehavior string NatFilteringBehavior string + EnableLoger = true ) diff --git a/stuncheck/stuncheck.go b/stuncheck/stuncheck.go index c82f43c..04d901a 100644 --- a/stuncheck/stuncheck.go +++ b/stuncheck/stuncheck.go @@ -37,12 +37,16 @@ var ( func MappingTests(addrStr string) error { mapTestConn, err := connect(addrStr) if err != nil { - model.Log.Warnf("Error creating STUN connection: %s", err) + if model.EnableLoger { + model.Log.Warnf("Error creating STUN connection: %s", err) + } return err } // Test I: Regular binding request - model.Log.Info("Mapping Test I: Regular binding request") + if model.EnableLoger { + model.Log.Info("Mapping Test I: Regular binding request") + } request := stun.MustBuild(stun.TransactionID, stun.BindingRequest) resp, err := mapTestConn.roundTrip(request, mapTestConn.RemoteAddr) @@ -53,26 +57,36 @@ func MappingTests(addrStr string) error { // Parse response message for XOR-MAPPED-ADDRESS and make sure OTHER-ADDRESS valid resps1 := parse(resp) if resps1.xorAddr == nil || resps1.otherAddr == nil { - model.Log.Info("Error: NAT discovery feature not supported by this server") + if model.EnableLoger { + model.Log.Info("Error: NAT discovery feature not supported by this server") + } return errNoOtherAddress } addr, err := net.ResolveUDPAddr("udp4", resps1.otherAddr.String()) if err != nil { - model.Log.Infof("Failed resolving OTHER-ADDRESS: %v", resps1.otherAddr) + if model.EnableLoger { + model.Log.Infof("Failed resolving OTHER-ADDRESS: %v", resps1.otherAddr) + } return err } mapTestConn.OtherAddr = addr - model.Log.Infof("Received XOR-MAPPED-ADDRESS: %v", resps1.xorAddr) + if model.EnableLoger { + model.Log.Infof("Received XOR-MAPPED-ADDRESS: %v", resps1.xorAddr) + } // Assert mapping behavior if resps1.xorAddr.String() == mapTestConn.LocalAddr.String() { model.NatMappingBehavior = "endpoint independent (no NAT)" // my changes - model.Log.Warn("=> NAT mapping behavior: endpoint independent (no NAT)") + if model.EnableLoger { + model.Log.Warn("=> NAT mapping behavior: endpoint independent (no NAT)") + } return nil } // Test II: Send binding request to the other address but primary port - model.Log.Info("Mapping Test II: Send binding request to the other address but primary port") + if model.EnableLoger { + model.Log.Info("Mapping Test II: Send binding request to the other address but primary port") + } oaddr := *mapTestConn.OtherAddr oaddr.Port = mapTestConn.RemoteAddr.Port resp, err = mapTestConn.roundTrip(request, &oaddr) @@ -82,15 +96,21 @@ func MappingTests(addrStr string) error { // Assert mapping behavior resps2 := parse(resp) - model.Log.Infof("Received XOR-MAPPED-ADDRESS: %v", resps2.xorAddr) + if model.EnableLoger { + model.Log.Infof("Received XOR-MAPPED-ADDRESS: %v", resps2.xorAddr) + } if resps2.xorAddr.String() == resps1.xorAddr.String() { model.NatMappingBehavior = "endpoint independent" // my changes - model.Log.Warn("=> NAT mapping behavior: endpoint independent") + if model.EnableLoger { + model.Log.Warn("=> NAT mapping behavior: endpoint independent") + } return nil } // Test III: Send binding request to the other address and port - model.Log.Info("Mapping Test III: Send binding request to the other address and port") + if model.EnableLoger { + model.Log.Info("Mapping Test III: Send binding request to the other address and port") + } resp, err = mapTestConn.roundTrip(request, mapTestConn.OtherAddr) if err != nil { return err @@ -98,13 +118,19 @@ func MappingTests(addrStr string) error { // Assert mapping behavior resps3 := parse(resp) - model.Log.Infof("Received XOR-MAPPED-ADDRESS: %v", resps3.xorAddr) + if model.EnableLoger { + model.Log.Infof("Received XOR-MAPPED-ADDRESS: %v", resps3.xorAddr) + } if resps3.xorAddr.String() == resps2.xorAddr.String() { model.NatMappingBehavior = "address dependent" // my changes - model.Log.Warn("=> NAT mapping behavior: address dependent") + if model.EnableLoger { + model.Log.Warn("=> NAT mapping behavior: address dependent") + } } else { model.NatMappingBehavior = "address and port dependent" // my changes - model.Log.Warn("=> NAT mapping behavior: address and port dependent") + if model.EnableLoger { + model.Log.Warn("=> NAT mapping behavior: address and port dependent") + } } return mapTestConn.Close() } @@ -113,12 +139,16 @@ func MappingTests(addrStr string) error { func FilteringTests(addrStr string) error { mapTestConn, err := connect(addrStr) if err != nil { - model.Log.Warnf("Error creating STUN connection: %s", err) + if model.EnableLoger { + model.Log.Warnf("Error creating STUN connection: %s", err) + } return err } // Test I: Regular binding request - model.Log.Info("Filtering Test I: Regular binding request") + if model.EnableLoger { + model.Log.Info("Filtering Test I: Regular binding request") + } request := stun.MustBuild(stun.TransactionID, stun.BindingRequest) resp, err := mapTestConn.roundTrip(request, mapTestConn.RemoteAddr) @@ -127,18 +157,24 @@ func FilteringTests(addrStr string) error { } resps := parse(resp) if resps.xorAddr == nil || resps.otherAddr == nil { - model.Log.Warn("Error: NAT discovery feature not supported by this server") + if model.EnableLoger { + model.Log.Warn("Error: NAT discovery feature not supported by this server") + } return errNoOtherAddress } addr, err := net.ResolveUDPAddr("udp4", resps.otherAddr.String()) if err != nil { - model.Log.Infof("Failed resolving OTHER-ADDRESS: %v", resps.otherAddr) + if model.EnableLoger { + model.Log.Infof("Failed resolving OTHER-ADDRESS: %v", resps.otherAddr) + } return err } mapTestConn.OtherAddr = addr // Test II: Request to change both IP and port - model.Log.Info("Filtering Test II: Request to change both IP and port") + if model.EnableLoger { + model.Log.Info("Filtering Test II: Request to change both IP and port") + } request = stun.MustBuild(stun.TransactionID, stun.BindingRequest) request.Add(stun.AttrChangeRequest, []byte{0x00, 0x00, 0x00, 0x06}) @@ -146,14 +182,18 @@ func FilteringTests(addrStr string) error { if err == nil { parse(resp) // just to print out the resp model.NatFilteringBehavior = "endpoint independent" // my changes - model.Log.Warn("=> NAT filtering behavior: endpoint independent") + if model.EnableLoger { + model.Log.Warn("=> NAT filtering behavior: endpoint independent") + } return nil } else if !errors.Is(err, errTimedOut) { return err // something else went wrong } // Test III: Request to change port only - model.Log.Info("Filtering Test III: Request to change port only") + if model.EnableLoger { + model.Log.Info("Filtering Test III: Request to change port only") + } request = stun.MustBuild(stun.TransactionID, stun.BindingRequest) request.Add(stun.AttrChangeRequest, []byte{0x00, 0x00, 0x00, 0x02}) @@ -161,10 +201,14 @@ func FilteringTests(addrStr string) error { if err == nil { parse(resp) // just to print out the resp model.NatFilteringBehavior = "address dependent" // my changes - model.Log.Warn("=> NAT filtering behavior: address dependent") + if model.EnableLoger { + model.Log.Warn("=> NAT filtering behavior: address dependent") + } } else if errors.Is(err, errTimedOut) { model.NatFilteringBehavior = "address and port dependent" // my changes - model.Log.Warn("=> NAT filtering behavior: address and port dependent") + if model.EnableLoger { + model.Log.Warn("=> NAT filtering behavior: address and port dependent") + } } return mapTestConn.Close() @@ -199,12 +243,14 @@ func parse(msg *stun.Message) (ret struct { if ret.software.GetFrom(msg) != nil { ret.software = nil } - model.Log.Debugf("%v", msg) - model.Log.Debugf("\tMAPPED-ADDRESS: %v", ret.mappedAddr) - model.Log.Debugf("\tXOR-MAPPED-ADDRESS: %v", ret.xorAddr) - model.Log.Debugf("\tRESPONSE-ORIGIN: %v", ret.respOrigin) - model.Log.Debugf("\tOTHER-ADDRESS: %v", ret.otherAddr) - model.Log.Debugf("\tSOFTWARE: %v", ret.software) + if model.EnableLoger { + model.Log.Debugf("%v", msg) + model.Log.Debugf("\tMAPPED-ADDRESS: %v", ret.mappedAddr) + model.Log.Debugf("\tXOR-MAPPED-ADDRESS: %v", ret.xorAddr) + model.Log.Debugf("\tRESPONSE-ORIGIN: %v", ret.respOrigin) + model.Log.Debugf("\tOTHER-ADDRESS: %v", ret.otherAddr) + model.Log.Debugf("\tSOFTWARE: %v", ret.software) + } for _, attr := range msg.Attributes { switch attr.Type { case @@ -215,7 +261,9 @@ func parse(msg *stun.Message) (ret struct { stun.AttrSoftware: break //nolint:staticcheck default: - model.Log.Debugf("\t%v (l=%v)", attr, attr.Length) + if model.EnableLoger { + model.Log.Debugf("\t%v (l=%v)", attr, attr.Length) + } } } return ret @@ -223,10 +271,14 @@ func parse(msg *stun.Message) (ret struct { // Given an address string, returns a StunServerConn func connect(addrStr string) (*stunServerConn, error) { - model.Log.Infof("Connecting to STUN server: %s", addrStr) + if model.EnableLoger { + model.Log.Infof("Connecting to STUN server: %s", addrStr) + } addr, err := net.ResolveUDPAddr("udp4", addrStr) if err != nil { - model.Log.Warnf("Error resolving address: %s", err) + if model.EnableLoger { + model.Log.Warnf("Error resolving address: %s", err) + } return nil, err } @@ -234,8 +286,10 @@ func connect(addrStr string) (*stunServerConn, error) { if err != nil { return nil, err } - model.Log.Infof("Local address: %s", c.LocalAddr()) - model.Log.Infof("Remote address: %s", addr.String()) + if model.EnableLoger { + model.Log.Infof("Local address: %s", c.LocalAddr()) + model.Log.Infof("Remote address: %s", addr.String()) + } mChan := listen(c) @@ -250,14 +304,18 @@ func connect(addrStr string) (*stunServerConn, error) { // Send request and wait for response or timeout func (c *stunServerConn) roundTrip(msg *stun.Message, addr net.Addr) (*stun.Message, error) { _ = msg.NewTransactionID() - model.Log.Infof("Sending to %v: (%v bytes)", addr, msg.Length+messageHeaderSize) - model.Log.Debugf("%v", msg) - for _, attr := range msg.Attributes { - model.Log.Debugf("\t%v (l=%v)", attr, attr.Length) + if model.EnableLoger { + model.Log.Infof("Sending to %v: (%v bytes)", addr, msg.Length+messageHeaderSize) + model.Log.Debugf("%v", msg) + for _, attr := range msg.Attributes { + model.Log.Debugf("\t%v (l=%v)", attr, attr.Length) + } } _, err := c.conn.WriteTo(msg.Raw, addr) if err != nil { - model.Log.Warnf("Error sending request to %v", addr) + if model.EnableLoger { + model.Log.Warnf("Error sending request to %v", addr) + } return nil, err } @@ -269,7 +327,9 @@ func (c *stunServerConn) roundTrip(msg *stun.Message, addr net.Addr) (*stun.Mess } return m, nil case <-time.After(time.Duration(model.Timeout) * time.Second): - model.Log.Infof("Timed out waiting for response from server %v", addr) + if model.EnableLoger { + model.Log.Infof("Timed out waiting for response from server %v", addr) + } return nil, errTimedOut } } @@ -286,18 +346,21 @@ func listen(conn *net.UDPConn) (messages chan *stun.Message) { close(messages) return } - model.Log.Infof("Response from %v: (%v bytes)", addr, n) + if model.EnableLoger { + model.Log.Infof("Response from %v: (%v bytes)", addr, n) + } buf = buf[:n] m := new(stun.Message) m.Raw = buf err = m.Decode() if err != nil { - model.Log.Infof("Error decoding message: %v", err) + if model.EnableLoger { + model.Log.Infof("Error decoding message: %v", err) + } close(messages) return } - messages <- m } }()