v0.0.2 - 进一步解耦

This commit is contained in:
spiritlhl
2024-06-25 02:55:02 +00:00
parent 42023a68b2
commit 631eff3feb
3 changed files with 133 additions and 58 deletions

View File

@@ -17,6 +17,7 @@ func main() {
flag.IntVar(&model.Verbose, "verbose", 0, "the verbosity level") 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.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.StringVar(&model.AddrStr, "server", "stun.voipgate.com:3478", "STUN server address")
flag.BoolVar(&model.EnableLoger, "e", true, "Enable logging")
flag.Parse() flag.Parse()
go func() { 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") 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) fmt.Println(model.GoStunVersion)
return return
} }
var logLevel logging.LogLevel if model.EnableLoger {
switch model.Verbose { var logLevel logging.LogLevel
case 0: switch model.Verbose {
logLevel = logging.LogLevelWarn // default // my changes case 0:
case 1: logLevel = logging.LogLevelWarn // default
logLevel = logging.LogLevelInfo case 1:
case 2: logLevel = logging.LogLevelInfo
logLevel = logging.LogLevelDebug case 2:
case 3: logLevel = logging.LogLevelDebug
logLevel = logging.LogLevelTrace 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 model.AddrStr != "stun.voipgate.com:3478" {
if err := stuncheck.MappingTests(model.AddrStr); err != nil { 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") model.Log.Warn("NAT mapping behavior: inconclusive")
} }
if err := stuncheck.FilteringTests(model.AddrStr); err != nil { 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") model.Log.Warn("NAT filtering behavior: inconclusive")
} }
} else { } else {
@@ -58,13 +65,17 @@ func main() {
err1 := stuncheck.MappingTests(addrStr) err1 := stuncheck.MappingTests(addrStr)
if err1 != nil { if err1 != nil {
model.NatMappingBehavior = "inconclusive" model.NatMappingBehavior = "inconclusive"
model.Log.Warn("NAT mapping behavior: inconclusive") if model.EnableLoger {
model.Log.Warn("NAT mapping behavior: inconclusive")
}
checkStatus = false checkStatus = false
} }
err2 := stuncheck.FilteringTests(addrStr) err2 := stuncheck.FilteringTests(addrStr)
if err2 != nil { if err2 != nil {
model.NatFilteringBehavior = "inconclusive" model.NatFilteringBehavior = "inconclusive"
model.Log.Warn("NAT filtering behavior: inconclusive") if model.EnableLoger {
model.Log.Warn("NAT filtering behavior: inconclusive")
}
checkStatus = false checkStatus = false
} }
if model.NatMappingBehavior == "inconclusive" || model.NatFilteringBehavior == "inconclusive" { if model.NatMappingBehavior == "inconclusive" || model.NatFilteringBehavior == "inconclusive" {
@@ -78,5 +89,5 @@ func main() {
} }
} }
res := stuncheck.CheckType() res := stuncheck.CheckType()
fmt.Printf("NAT Type: %s", res) fmt.Printf("NAT Type: %s\n", res)
} }

View File

@@ -11,4 +11,5 @@ var (
Log logging.LeveledLogger Log logging.LeveledLogger
NatMappingBehavior string NatMappingBehavior string
NatFilteringBehavior string NatFilteringBehavior string
EnableLoger = true
) )

View File

@@ -37,12 +37,16 @@ var (
func MappingTests(addrStr string) error { func MappingTests(addrStr string) error {
mapTestConn, err := connect(addrStr) mapTestConn, err := connect(addrStr)
if err != nil { 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 return err
} }
// Test I: Regular binding request // 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) request := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
resp, err := mapTestConn.roundTrip(request, mapTestConn.RemoteAddr) 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 // Parse response message for XOR-MAPPED-ADDRESS and make sure OTHER-ADDRESS valid
resps1 := parse(resp) resps1 := parse(resp)
if resps1.xorAddr == nil || resps1.otherAddr == nil { 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 return errNoOtherAddress
} }
addr, err := net.ResolveUDPAddr("udp4", resps1.otherAddr.String()) addr, err := net.ResolveUDPAddr("udp4", resps1.otherAddr.String())
if err != nil { 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 return err
} }
mapTestConn.OtherAddr = addr 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 // Assert mapping behavior
if resps1.xorAddr.String() == mapTestConn.LocalAddr.String() { if resps1.xorAddr.String() == mapTestConn.LocalAddr.String() {
model.NatMappingBehavior = "endpoint independent (no NAT)" // my changes 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 return nil
} }
// Test II: Send binding request to the other address but primary port // 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 := *mapTestConn.OtherAddr
oaddr.Port = mapTestConn.RemoteAddr.Port oaddr.Port = mapTestConn.RemoteAddr.Port
resp, err = mapTestConn.roundTrip(request, &oaddr) resp, err = mapTestConn.roundTrip(request, &oaddr)
@@ -82,15 +96,21 @@ func MappingTests(addrStr string) error {
// Assert mapping behavior // Assert mapping behavior
resps2 := parse(resp) 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() { if resps2.xorAddr.String() == resps1.xorAddr.String() {
model.NatMappingBehavior = "endpoint independent" // my changes 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 return nil
} }
// Test III: Send binding request to the other address and port // 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) resp, err = mapTestConn.roundTrip(request, mapTestConn.OtherAddr)
if err != nil { if err != nil {
return err return err
@@ -98,13 +118,19 @@ func MappingTests(addrStr string) error {
// Assert mapping behavior // Assert mapping behavior
resps3 := parse(resp) 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() { if resps3.xorAddr.String() == resps2.xorAddr.String() {
model.NatMappingBehavior = "address dependent" // my changes 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 { } else {
model.NatMappingBehavior = "address and port dependent" // my changes 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() return mapTestConn.Close()
} }
@@ -113,12 +139,16 @@ func MappingTests(addrStr string) error {
func FilteringTests(addrStr string) error { func FilteringTests(addrStr string) error {
mapTestConn, err := connect(addrStr) mapTestConn, err := connect(addrStr)
if err != nil { 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 return err
} }
// Test I: Regular binding request // 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) request := stun.MustBuild(stun.TransactionID, stun.BindingRequest)
resp, err := mapTestConn.roundTrip(request, mapTestConn.RemoteAddr) resp, err := mapTestConn.roundTrip(request, mapTestConn.RemoteAddr)
@@ -127,18 +157,24 @@ func FilteringTests(addrStr string) error {
} }
resps := parse(resp) resps := parse(resp)
if resps.xorAddr == nil || resps.otherAddr == nil { 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 return errNoOtherAddress
} }
addr, err := net.ResolveUDPAddr("udp4", resps.otherAddr.String()) addr, err := net.ResolveUDPAddr("udp4", resps.otherAddr.String())
if err != nil { 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 return err
} }
mapTestConn.OtherAddr = addr mapTestConn.OtherAddr = addr
// Test II: Request to change both IP and port // 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 = stun.MustBuild(stun.TransactionID, stun.BindingRequest)
request.Add(stun.AttrChangeRequest, []byte{0x00, 0x00, 0x00, 0x06}) request.Add(stun.AttrChangeRequest, []byte{0x00, 0x00, 0x00, 0x06})
@@ -146,14 +182,18 @@ func FilteringTests(addrStr string) error {
if err == nil { if err == nil {
parse(resp) // just to print out the resp parse(resp) // just to print out the resp
model.NatFilteringBehavior = "endpoint independent" // my changes 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 return nil
} else if !errors.Is(err, errTimedOut) { } else if !errors.Is(err, errTimedOut) {
return err // something else went wrong return err // something else went wrong
} }
// Test III: Request to change port only // 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 = stun.MustBuild(stun.TransactionID, stun.BindingRequest)
request.Add(stun.AttrChangeRequest, []byte{0x00, 0x00, 0x00, 0x02}) request.Add(stun.AttrChangeRequest, []byte{0x00, 0x00, 0x00, 0x02})
@@ -161,10 +201,14 @@ func FilteringTests(addrStr string) error {
if err == nil { if err == nil {
parse(resp) // just to print out the resp parse(resp) // just to print out the resp
model.NatFilteringBehavior = "address dependent" // my changes 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) { } else if errors.Is(err, errTimedOut) {
model.NatFilteringBehavior = "address and port dependent" // my changes 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() return mapTestConn.Close()
@@ -199,12 +243,14 @@ func parse(msg *stun.Message) (ret struct {
if ret.software.GetFrom(msg) != nil { if ret.software.GetFrom(msg) != nil {
ret.software = nil ret.software = nil
} }
model.Log.Debugf("%v", msg) if model.EnableLoger {
model.Log.Debugf("\tMAPPED-ADDRESS: %v", ret.mappedAddr) model.Log.Debugf("%v", msg)
model.Log.Debugf("\tXOR-MAPPED-ADDRESS: %v", ret.xorAddr) model.Log.Debugf("\tMAPPED-ADDRESS: %v", ret.mappedAddr)
model.Log.Debugf("\tRESPONSE-ORIGIN: %v", ret.respOrigin) model.Log.Debugf("\tXOR-MAPPED-ADDRESS: %v", ret.xorAddr)
model.Log.Debugf("\tOTHER-ADDRESS: %v", ret.otherAddr) model.Log.Debugf("\tRESPONSE-ORIGIN: %v", ret.respOrigin)
model.Log.Debugf("\tSOFTWARE: %v", ret.software) model.Log.Debugf("\tOTHER-ADDRESS: %v", ret.otherAddr)
model.Log.Debugf("\tSOFTWARE: %v", ret.software)
}
for _, attr := range msg.Attributes { for _, attr := range msg.Attributes {
switch attr.Type { switch attr.Type {
case case
@@ -215,7 +261,9 @@ func parse(msg *stun.Message) (ret struct {
stun.AttrSoftware: stun.AttrSoftware:
break //nolint:staticcheck break //nolint:staticcheck
default: 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 return ret
@@ -223,10 +271,14 @@ func parse(msg *stun.Message) (ret struct {
// Given an address string, returns a StunServerConn // Given an address string, returns a StunServerConn
func connect(addrStr string) (*stunServerConn, error) { 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) addr, err := net.ResolveUDPAddr("udp4", addrStr)
if err != nil { 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 return nil, err
} }
@@ -234,8 +286,10 @@ func connect(addrStr string) (*stunServerConn, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
model.Log.Infof("Local address: %s", c.LocalAddr()) if model.EnableLoger {
model.Log.Infof("Remote address: %s", addr.String()) model.Log.Infof("Local address: %s", c.LocalAddr())
model.Log.Infof("Remote address: %s", addr.String())
}
mChan := listen(c) mChan := listen(c)
@@ -250,14 +304,18 @@ func connect(addrStr string) (*stunServerConn, error) {
// Send request and wait for response or timeout // Send request and wait for response or timeout
func (c *stunServerConn) roundTrip(msg *stun.Message, addr net.Addr) (*stun.Message, error) { func (c *stunServerConn) roundTrip(msg *stun.Message, addr net.Addr) (*stun.Message, error) {
_ = msg.NewTransactionID() _ = msg.NewTransactionID()
model.Log.Infof("Sending to %v: (%v bytes)", addr, msg.Length+messageHeaderSize) if model.EnableLoger {
model.Log.Debugf("%v", msg) model.Log.Infof("Sending to %v: (%v bytes)", addr, msg.Length+messageHeaderSize)
for _, attr := range msg.Attributes { model.Log.Debugf("%v", msg)
model.Log.Debugf("\t%v (l=%v)", attr, attr.Length) for _, attr := range msg.Attributes {
model.Log.Debugf("\t%v (l=%v)", attr, attr.Length)
}
} }
_, err := c.conn.WriteTo(msg.Raw, addr) _, err := c.conn.WriteTo(msg.Raw, addr)
if err != nil { 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 return nil, err
} }
@@ -269,7 +327,9 @@ func (c *stunServerConn) roundTrip(msg *stun.Message, addr net.Addr) (*stun.Mess
} }
return m, nil return m, nil
case <-time.After(time.Duration(model.Timeout) * time.Second): 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 return nil, errTimedOut
} }
} }
@@ -286,18 +346,21 @@ func listen(conn *net.UDPConn) (messages chan *stun.Message) {
close(messages) close(messages)
return 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] buf = buf[:n]
m := new(stun.Message) m := new(stun.Message)
m.Raw = buf m.Raw = buf
err = m.Decode() err = m.Decode()
if err != nil { if err != nil {
model.Log.Infof("Error decoding message: %v", err) if model.EnableLoger {
model.Log.Infof("Error decoding message: %v", err)
}
close(messages) close(messages)
return return
} }
messages <- m messages <- m
} }
}() }()