update nat test info

master
兔子 4 months ago
parent 1a04780474
commit c7d94d8f95

@ -1,6 +1,8 @@
module b612.me/apps/b612 module b612.me/apps/b612
go 1.19 go 1.21
toolchain go1.21.2
require ( require (
b612.me/notify v1.2.5 b612.me/notify v1.2.5

@ -17,6 +17,9 @@ func init() {
Cmd.AddCommand(netforward.CmdNetforward) Cmd.AddCommand(netforward.CmdNetforward)
} }
var nattestc NatTesterClient
var nettests NatTesterServer
var natc NatClient var natc NatClient
var nats NatServer var nats NatServer
@ -28,22 +31,22 @@ var bindAddr string
var hideIncorrect bool var hideIncorrect bool
func init() { func init() {
CmdNatClient.Flags().StringVarP(&natc.ServiceTarget, "target", "t", "", "forward server target address") CmdNatPClient.Flags().StringVarP(&natc.ServiceTarget, "target", "t", "", "forward server target address")
CmdNatClient.Flags().StringVarP(&natc.CmdTarget, "server", "s", "", "nat server command address") CmdNatPClient.Flags().StringVarP(&natc.CmdTarget, "server", "s", "", "nat server command address")
CmdNatClient.Flags().StringVarP(&natc.Passwd, "passwd", "p", "", "password") CmdNatPClient.Flags().StringVarP(&natc.Passwd, "passwd", "p", "", "password")
CmdNatClient.Flags().BoolVarP(&natc.enableTCP, "enable-tcp", "T", true, "enable tcp forward") CmdNatPClient.Flags().BoolVarP(&natc.enableTCP, "enable-tcp", "T", true, "enable tcp forward")
CmdNatClient.Flags().BoolVarP(&natc.enableUDP, "enable-udp", "U", true, "enable udp forward") CmdNatPClient.Flags().BoolVarP(&natc.enableUDP, "enable-udp", "U", true, "enable udp forward")
CmdNatClient.Flags().IntVarP(&natc.DialTimeout, "dial-timeout", "d", 10000, "dial timeout milliseconds") CmdNatPClient.Flags().IntVarP(&natc.DialTimeout, "dial-timeout", "d", 10000, "dial timeout milliseconds")
CmdNatClient.Flags().IntVarP(&natc.UdpTimeout, "udp-timeout", "D", 60000, "udp connection timeout milliseconds") CmdNatPClient.Flags().IntVarP(&natc.UdpTimeout, "udp-timeout", "D", 60000, "udp connection timeout milliseconds")
Cmd.AddCommand(CmdNatClient) Cmd.AddCommand(CmdNatPClient)
CmdNatServer.Flags().StringVarP(&nats.ListenAddr, "listen", "l", "", "listen address") CmdNatPServer.Flags().StringVarP(&nats.ListenAddr, "listen", "l", "", "listen address")
CmdNatServer.Flags().StringVarP(&nats.Passwd, "passwd", "p", "", "password") CmdNatPServer.Flags().StringVarP(&nats.Passwd, "passwd", "p", "", "password")
CmdNatServer.Flags().Int64VarP(&nats.UDPTimeout, "udp-timeout", "D", 60000, "udp connection timeout milliseconds") CmdNatPServer.Flags().Int64VarP(&nats.UDPTimeout, "udp-timeout", "D", 60000, "udp connection timeout milliseconds")
CmdNatServer.Flags().Int64VarP(&nats.NetTimeout, "dial-timeout", "d", 10000, "dial timeout milliseconds") CmdNatPServer.Flags().Int64VarP(&nats.NetTimeout, "dial-timeout", "d", 10000, "dial timeout milliseconds")
CmdNatServer.Flags().BoolVarP(&nats.enableTCP, "enable-tcp", "T", true, "enable tcp forward") CmdNatPServer.Flags().BoolVarP(&nats.enableTCP, "enable-tcp", "T", true, "enable tcp forward")
CmdNatServer.Flags().BoolVarP(&nats.enableUDP, "enable-udp", "U", true, "enable udp forward") CmdNatPServer.Flags().BoolVarP(&nats.enableUDP, "enable-udp", "U", true, "enable udp forward")
Cmd.AddCommand(CmdNatServer) Cmd.AddCommand(CmdNatPServer)
CmdNetTrace.Flags().StringVarP(&dns, "dns", "d", "", "自定义dns服务器") CmdNetTrace.Flags().StringVarP(&dns, "dns", "d", "", "自定义dns服务器")
CmdNetTrace.Flags().StringVarP(&ipinfoaddr, "ipinfo", "i", "https://ip.b612.me/{ip}/detail", "自定义ip信息查询地址") CmdNetTrace.Flags().StringVarP(&ipinfoaddr, "ipinfo", "i", "https://ip.b612.me/{ip}/detail", "自定义ip信息查询地址")
@ -54,9 +57,13 @@ func init() {
CmdNetTrace.Flags().BoolVarP(&hideIncorrect, "hide-incorrect", "H", false, "隐藏错误节点") CmdNetTrace.Flags().BoolVarP(&hideIncorrect, "hide-incorrect", "H", false, "隐藏错误节点")
Cmd.AddCommand(CmdNetTrace, cmdSSHJar) Cmd.AddCommand(CmdNetTrace, cmdSSHJar)
CmdNatClient.Flags().IntVarP(&nattestc.RetryTime, "retry", "r", 2, "重试次数")
CmdNatClient.Flags().IntVarP(&nattestc.Timeout, "timeout", "t", 2, "超时时间")
CmdNatClient.Flags().StringSliceVarP(&nattestc.dns, "dns", "d", nil, "自定义dns服务器")
Cmd.AddCommand(CmdNatClient)
} }
var CmdNatClient = &cobra.Command{ var CmdNatPClient = &cobra.Command{
Use: "natpc", Use: "natpc",
Short: "nat穿透客户端", Short: "nat穿透客户端",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
@ -68,7 +75,7 @@ var CmdNatClient = &cobra.Command{
}, },
} }
var CmdNatServer = &cobra.Command{ var CmdNatPServer = &cobra.Command{
Use: "natps", Use: "natps",
Short: "nat穿透服务端", Short: "nat穿透服务端",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
@ -77,6 +84,34 @@ var CmdNatServer = &cobra.Command{
}, },
} }
var CmdNatClient = &cobra.Command{
Use: "natc",
Short: "nat类型测试工具",
Long: "基于RFC3489的nat类型测试工具",
Run: func(cmd *cobra.Command, args []string) {
if nattestc.dns != nil {
UseCustomeDNS(nattestc.dns)
for _, v := range nattestc.dns {
starlog.Infoln("使用自定义DNS:", v)
}
}
natserver := "nat.b612.me"
if len(args) == 0 {
starlog.Infoln("使用默认NAT测试服务器nat.b612.me")
} else {
natserver = args[0]
starlog.Infoln("使用NAT测试服务器", natserver)
}
res, err := nattestc.ServeAndRun(natserver)
if err != nil {
starlog.Errorln("测试NAT类型失败", err)
return
}
fmt.Println("-----------------\n")
starlog.Green("您的NAT类型为%v - %v\nswitch可能显示NAT类型为%v\n%v", res.Code, res.RFC3489, res.NintendoSwitch, res.Desc)
},
}
var CmdNetTrace = &cobra.Command{ var CmdNetTrace = &cobra.Command{
Use: "trace", Use: "trace",
Short: "网络路径追踪", Short: "网络路径追踪",

@ -0,0 +1,274 @@
package net
import (
"b612.me/starlog"
"context"
"encoding/json"
"fmt"
"net"
"strings"
"time"
)
type NatTesterClient struct {
MainPort string `json:"mainport"`
AltPort string `json:"altport"`
MainIP string `json:"mainip"`
AltIP string `json:"altip"`
RetryTime int `json:"retrytime"`
Timeout int `json:"timeout"`
dns []string
ch chan Message
}
type Message struct {
Success bool
Cmd string
Msg string
Address string
}
type NatType struct {
Code string
RFC3489 string
NintendoSwitch string
Desc string
}
func (n *NatTesterClient) GetMsg() Message {
select {
case msg := <-n.ch:
return msg
case <-time.After(time.Second * time.Duration(n.Timeout)):
return Message{Success: false, Msg: "timeout"}
}
}
func (n *NatTesterClient) RecvMsg(c *net.UDPConn) {
for {
buf := make([]byte, 1024)
num, r, e := c.ReadFromUDP(buf)
if e != nil {
return
}
go n.Analyse(r, strings.Split(string(buf[:num]), "::"))
}
}
func (n *NatTesterClient) Analyse(r *net.UDPAddr, cmds []string) {
switch cmds[0] {
case "ip":
if len(cmds) == 2 {
n.ch <- Message{Success: true, Cmd: "ip", Msg: cmds[1], Address: r.String()}
}
case "stage1":
n.ch <- Message{Success: true, Cmd: "stage1", Msg: "stage1", Address: r.String()}
case "stage2":
n.ch <- Message{Success: true, Cmd: "stage2", Msg: "stage2", Address: r.String()}
case "stage3":
n.ch <- Message{Success: true, Cmd: "stage3", Msg: "stage3", Address: r.String()}
}
}
func (n *NatTesterClient) Run() (NatType, error) {
var firstAddr, secondAddr string
var natTypeMap = map[string]NatType{
"Block": {Code: "Block", RFC3489: "Block", NintendoSwitch: "NAT F", Desc: "您的网络似乎禁止了UDP无法连接到外部网络"},
"Open": {Code: "Open", RFC3489: "Open", NintendoSwitch: "Open", Desc: "您的网络为开放网络,拥有最好的上网体验"},
"OpenBlock": {Code: "OpenBlock", RFC3489: "Symmetric Firewall", NintendoSwitch: "NAT F", Desc: "您的网络虽然时开放网络,但是存在对称型防火墙,可能会遇到严重的连接问题"},
"NAT1": {Code: "NAT1", RFC3489: "Full Cone", NintendoSwitch: "NAT A", Desc: "您的NAT类型为全锥形NAT拥有最好的NAT体验"},
"NAT2": {Code: "NAT2", RFC3489: "Address Restricted Cone", NintendoSwitch: "NAT B", Desc: "您的NAT类型为地址限制锥形NAT拥有良好的NAT体验"},
"NAT3": {Code: "NAT3", RFC3489: "Port Restricted Cone", NintendoSwitch: "NAT B/C", Desc: "您的NAT类型为端口限制锥形NAT可能会遇到一些连接问题"},
"NAT4": {Code: "NAT4", RFC3489: "Symmetric", NintendoSwitch: "NAT C/D", Desc: "您的NAT类型为对称NAT可能会遇到严重的连接问题"},
"Unknown": {Code: "Unknown", RFC3489: "Unknown", NintendoSwitch: "Unknown", Desc: "无法确定您的NAT类型"},
}
tmp, err := net.Dial("udp", n.MainIP+":80")
if err != nil {
return NatType{}, err
}
curIp := tmp.LocalAddr().(*net.UDPAddr).IP.String()
starlog.Infof("Current Output IP: %s\n", curIp)
localAddr, err := net.ResolveUDPAddr("udp", curIp+":0")
if err != nil {
return NatType{}, err
}
conn, err := net.ListenUDP("udp", localAddr)
if err != nil {
return NatType{}, err
}
starlog.Infof("Listening on %s\n", conn.LocalAddr().String())
defer conn.Close()
go n.RecvMsg(conn)
n.ch = make(chan Message)
defer close(n.ch)
succ := false
mainAddr, err := net.ResolveUDPAddr("udp", n.MainIP+":"+n.MainPort)
if err != nil {
return NatType{}, err
}
altAddr, err := net.ResolveUDPAddr("udp", n.AltIP+":"+n.AltPort)
if err != nil {
return NatType{}, err
}
starlog.Noticef("Getting IP from NatServer Main\n")
for i := 0; i < n.RetryTime; i++ {
_, err = conn.WriteToUDP([]byte("ip"), mainAddr)
if err != nil {
starlog.Errorln("failed to get main ip,retrying:" + err.Error())
continue
}
msg := n.GetMsg()
if msg.Success && msg.Cmd == "ip" {
starlog.Noticef("Remote IP: %s\n", msg.Address)
starlog.Infof("Current IP: %s\n", msg.Msg)
succ = true
firstAddr = msg.Msg
break
}
starlog.Errorln("failed to get main ip,retrying:" + msg.Msg)
}
if !succ {
return NatType{}, fmt.Errorf("failed to get current ip")
}
{
starlog.Noticef("Start NAT1 Test\n")
succ = false
for i := 0; i < n.RetryTime; i++ {
_, err = conn.WriteToUDP([]byte("startnat1"), mainAddr)
if err != nil {
starlog.Errorln("failed to send nat1 test data,retrying:" + err.Error())
continue
}
msg := n.GetMsg()
if msg.Success && msg.Cmd == "stage1" {
starlog.Noticef("Recv Nat1 Data From Remote IP: %s\n", msg.Address)
succ = true
break
}
starlog.Errorln("failed to recv Nat1 data,retrying:" + msg.Msg)
}
if succ {
if strings.Split(firstAddr, ":")[0] == curIp {
starlog.Infof("Current NAT Type: Open\n")
return natTypeMap["Open"], nil
}
starlog.Infof("Current NAT Type: NAT1\n")
return natTypeMap["NAT1"], nil
} else {
if strings.Split(firstAddr, ":")[0] == curIp {
starlog.Infof("Current NAT Type: OpenBlock\n")
return natTypeMap["OpenBlock"], nil
}
}
}
{
starlog.Noticef("Start NAT2 Test\n")
succ = false
for i := 0; i < n.RetryTime; i++ {
_, err = conn.WriteToUDP([]byte("startnat2"), mainAddr)
if err != nil {
starlog.Errorln("failed to send nat2 test data,retrying:" + err.Error())
continue
}
msg := n.GetMsg()
if msg.Success && msg.Cmd == "stage2" {
starlog.Noticef("Recv Nat2 Data From Remote IP: %s\n", msg.Address)
succ = true
break
}
starlog.Errorln("failed to recv Nat2 data,retrying:" + msg.Msg)
}
if succ {
starlog.Infof("Current NAT Type: NAT2\n")
return natTypeMap["NAT2"], nil
}
}
{
starlog.Noticef("Start NAT3 Test\n")
succ = false
for i := 0; i < n.RetryTime; i++ {
_, err = conn.WriteToUDP([]byte("startnat3"), mainAddr)
if err != nil {
starlog.Errorln("failed to send nat1 test data,retrying:" + err.Error())
continue
}
msg := n.GetMsg()
if msg.Success && msg.Cmd == "stage3" {
starlog.Noticef("Recv Nat1 Data From Remote IP: %s\n", msg.Address)
succ = true
break
}
starlog.Errorln("failed to recv Nat3 data,retrying:" + msg.Msg)
}
if !succ {
starlog.Errorf("Failed to get NAT Type\n")
return natTypeMap["Unknown"], fmt.Errorf("failed to get nat type")
}
}
succ = false
starlog.Noticef("Gettting IP from NatServer Alt\n")
for i := 0; i < n.RetryTime; i++ {
_, err = conn.WriteToUDP([]byte("ip"), altAddr)
if err != nil {
starlog.Errorln("failed to get alt ip,retrying:" + err.Error())
continue
}
msg := n.GetMsg()
if msg.Success && msg.Cmd == "ip" {
starlog.Noticef("Remote IP: %s\n", msg.Address)
starlog.Infof("Current IP: %s\n", msg.Msg)
succ = true
secondAddr = msg.Msg
break
}
starlog.Errorln("failed to get alt ip,retrying:" + msg.Msg)
}
if !succ {
starlog.Errorf("Failed to get NAT Type\n")
return natTypeMap["Unknown"], fmt.Errorf("failed to get nat type")
}
starlog.Debugf("First IP: %s, Second IP: %s\n", firstAddr, secondAddr)
starlog.Debugf("Listening on %s\n", conn.LocalAddr().String())
if firstAddr == secondAddr {
starlog.Infof("Current NAT Type: NAT3\n")
return natTypeMap["NAT3"], nil
}
starlog.Infof("Current NAT Type: NAT4\n")
return natTypeMap["NAT4"], nil
}
func (n *NatTesterClient) ServeAndRun(addr string) (NatType, error) {
starlog.SetShowFlag(false)
starlog.SetShowFuncName(false)
starlog.SetShowOriginFile(false)
data, err := net.LookupTXT(addr)
if err != nil {
return NatType{}, err
}
if len(data) == 0 {
return NatType{}, fmt.Errorf("no data found")
}
err = json.Unmarshal([]byte(data[0]), n)
if err != nil {
return NatType{}, err
}
starlog.Debugf("MainIP: %s, MainPort: %s, AltIP: %s, AltPort: %s\n", n.MainIP, n.MainPort, n.AltIP, n.AltPort)
return n.Run()
}
func UseCustomeDNS(dns []string) {
resolver := net.Resolver{
PreferGo: true,
Dial: func(ctx context.Context, network, address string) (conn net.Conn, err error) {
for _, addr := range dns {
if conn, err = net.Dial("udp", addr+":53"); err != nil {
continue
} else {
return conn, nil
}
}
return
},
}
net.DefaultResolver = &resolver
}

@ -0,0 +1,143 @@
package net
import (
"b612.me/starlog"
"context"
"fmt"
"net"
"strings"
"sync/atomic"
)
type NatTesterServer struct {
MainPort string
AltPort string
MainIP string
AltIP string
LogPath string
stopCtx context.Context
stopFn context.CancelFunc
maina *net.UDPConn
mainb *net.UDPConn
alt *net.UDPConn
running int32
}
func (n *NatTesterServer) Run() error {
if atomic.LoadInt32(&n.running) > 0 {
starlog.Errorln("already running")
return fmt.Errorf("already running")
}
atomic.StoreInt32(&n.running, 1)
defer atomic.StoreInt32(&n.running, 0)
if n.LogPath != "" {
starlog.SetLogFile(n.LogPath, starlog.Std, true)
starlog.Infof("Log file set to %s\n", n.LogPath)
}
starlog.Infof("MainPort: %s\n", n.MainPort)
starlog.Infof("AltPort: %s\n", n.AltPort)
tmp, err := net.Dial("udp", "8.8.8.8:53")
if err != nil {
return err
}
starlog.Infof("Current Output IP: %s\n", tmp.LocalAddr().(*net.UDPAddr).IP.String())
tmp.Close()
n.stopCtx, n.stopFn = context.WithCancel(context.Background())
mainaaddr, err := net.ResolveUDPAddr("udp", n.MainIP+":"+n.MainPort)
if err != nil {
return err
}
mainbaddr, err := net.ResolveUDPAddr("udp", n.MainIP+":"+n.AltPort)
if err != nil {
return err
}
n.maina, err = net.ListenUDP("udp", mainaaddr)
if err != nil {
return err
}
starlog.Infof("UDP MainIP:MainPort Listening on %s\n", n.maina.LocalAddr().String())
n.mainb, err = net.ListenUDP("udp", mainbaddr)
if err != nil {
return err
}
starlog.Infof("UDP MainIP:AltPort Listening on %s\n", n.mainb.LocalAddr().String())
altaddr, err := net.ResolveUDPAddr("udp", n.AltIP+":"+n.AltPort)
if err != nil {
return err
}
n.alt, err = net.ListenUDP("udp", altaddr)
if err != nil {
return err
}
starlog.Infof("UDP AltIP:AltPort Listening on %s\n", n.alt.LocalAddr().String())
go func() {
for {
select {
case <-n.stopCtx.Done():
starlog.Infoln("Stopping,Reason: Context Done")
return
default:
}
buf := make([]byte, 1024)
num, r, e := n.alt.ReadFromUDP(buf)
if e != nil {
continue
}
go n.Analyse(n.alt, r, strings.Split(string(buf[:num]), "::"))
}
}()
for {
select {
case <-n.stopCtx.Done():
starlog.Infoln("Stopping,Reason: Context Done")
n.maina.Close()
n.mainb.Close()
n.alt.Close()
return nil
default:
}
buf := make([]byte, 1024)
num, r, e := n.maina.ReadFromUDP(buf)
if e != nil {
continue
}
go n.Analyse(n.maina, r, strings.Split(string(buf[:num]), "::"))
}
}
func (n *NatTesterServer) Analyse(c *net.UDPConn, r *net.UDPAddr, cmds []string) error {
switch cmds[0] {
case "ip":
c.WriteToUDP([]byte("ip::"+r.String()), r)
starlog.Infof("Recv IP Request from %s,Local: %s\n", r.String(), c.LocalAddr().String())
case "startnat1":
n.alt.WriteToUDP([]byte("stage1"), r)
starlog.Infof("Start NAT1 Test from %s,Recv Local:%s Send Local:%s\n", r.String(), c.LocalAddr().String(), n.alt.LocalAddr().String())
case "stage1recv":
n.maina.WriteToUDP([]byte("result::nat1"), r)
starlog.Infof("Recv NAT1 Test from %s,Recv Local:%s Send Local:%s\n", r.String(), c.LocalAddr().String(), n.maina.LocalAddr().String())
case "startnat2":
n.mainb.WriteToUDP([]byte("stage2"), r)
starlog.Infof("Start NAT2 Test from %s,Recv Local:%s Send Local:%s\n", r.String(), c.LocalAddr().String(), n.mainb.LocalAddr().String())
case "stage2recv":
n.maina.WriteToUDP([]byte("result::nat2"), r)
starlog.Infof("Recv NAT2 Test from %s,Recv Local:%s Send Local:%s\n", r.String(), c.LocalAddr().String(), n.maina.LocalAddr().String())
case "startnat3":
n.maina.WriteToUDP([]byte("stage3"), r)
starlog.Infof("Start NAT3 Test from %s,Recv Local:%s Send Local:%s\n", r.String(), c.LocalAddr().String(), n.maina.LocalAddr().String())
case "stage3recv":
n.maina.WriteToUDP([]byte("result::nat3"), r)
starlog.Infof("Recv NAT3 Test from %s,Recv Local:%s Send Local:%s\n", r.String(), c.LocalAddr().String(), n.maina.LocalAddr().String())
}
return nil
}
func main() {
server := NatTesterServer{
MainIP: "10.0.0.5",
AltIP: "10.0.0.2",
MainPort: "41127",
AltPort: "46610",
}
fmt.Println(server.Run())
}
Loading…
Cancel
Save