diff --git a/go/cmd/nekobox_core/core_box.go b/go/cmd/nekobox_core/core_box.go index 19ac2d0..ff31f96 100644 --- a/go/cmd/nekobox_core/core_box.go +++ b/go/cmd/nekobox_core/core_box.go @@ -2,6 +2,7 @@ package main import ( "context" + "net" "net/http" "github.com/matsuridayo/libneko/neko_common" @@ -18,7 +19,32 @@ func setupCore() { boxmain.DisableColor() // neko_log.SetupLog(50*1024, "./neko.log") - neko_common.GetProxyHttpClient = func() *http.Client { + // + neko_common.GetCurrentInstance = func() interface{} { + return instance + } + neko_common.DialContext = func(ctx context.Context, specifiedInstance interface{}, network, addr string) (net.Conn, error) { + if i, ok := specifiedInstance.(*boxbox.Box); ok { + return boxapi.DialContext(ctx, i, network, addr) + } + if instance != nil { + return boxapi.DialContext(ctx, instance, network, addr) + } + return neko_common.DialContextSystem(ctx, network, addr) + } + neko_common.DialUDP = func(ctx context.Context, specifiedInstance interface{}) (net.PacketConn, error) { + if i, ok := specifiedInstance.(*boxbox.Box); ok { + return boxapi.DialUDP(ctx, i) + } + if instance != nil { + return boxapi.DialUDP(ctx, instance) + } + return neko_common.DialUDPSystem(ctx) + } + neko_common.CreateProxyHttpClient = func(specifiedInstance interface{}) *http.Client { + if i, ok := specifiedInstance.(*boxbox.Box); ok { + return boxapi.CreateProxyHttpClient(i) + } return boxapi.CreateProxyHttpClient(instance) } } diff --git a/go/cmd/nekobox_core/grpc_box.go b/go/cmd/nekobox_core/grpc_box.go index eed6d1d..44f3623 100644 --- a/go/cmd/nekobox_core/grpc_box.go +++ b/go/cmd/nekobox_core/grpc_box.go @@ -95,11 +95,13 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, if in.Mode == gen.TestMode_UrlTest { var i *boxbox.Box + var cancel context.CancelFunc if in.Config != nil { // Test instance - i, instance_cancel, err = boxmain.Create([]byte(in.Config.CoreConfig)) - if instance_cancel != nil { - defer instance_cancel() + i, cancel, err = boxmain.Create([]byte(in.Config.CoreConfig)) + if i != nil { + defer i.Close() + defer cancel() } if err != nil { return @@ -115,8 +117,16 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, out.Ms, err = speedtest.UrlTest(boxapi.CreateProxyHttpClient(i), in.Url, in.Timeout) } else if in.Mode == gen.TestMode_TcpPing { out.Ms, err = speedtest.TcpPing(in.Address, in.Timeout) - } else { - err = fmt.Errorf("not available") + } else if in.Mode == gen.TestMode_FullTest { + i, cancel, err := boxmain.Create([]byte(in.Config.CoreConfig)) + if i != nil { + defer i.Close() + defer cancel() + } + if err != nil { + return + } + return grpc_server.DoFullTest(ctx, in, i) } return diff --git a/go/cmd/nekoray_core/core_ray.go b/go/cmd/nekoray_core/core_ray.go index d4393ec..e704811 100644 --- a/go/cmd/nekoray_core/core_ray.go +++ b/go/cmd/nekoray_core/core_ray.go @@ -69,29 +69,51 @@ func setupCore() { return resolver_go.LookupIP(context.Background(), network, host) }) // - neko_common.GetProxyHttpClient = func() *http.Client { - return getProxyHttpClient(instance) + neko_common.GetCurrentInstance = func() interface{} { + return instance + } + neko_common.DialContext = func(ctx context.Context, specifiedInstance interface{}, network, addr string) (net.Conn, error) { + dest, err := v2rayNet.ParseDestination(fmt.Sprintf("%s:%s", network, addr)) + if err != nil { + return nil, err + } + if i, ok := specifiedInstance.(*NekoV2RayInstance); ok { + return core.Dial(ctx, i.Instance, dest) + } + if instance != nil { + return core.Dial(ctx, instance.Instance, dest) + } + return neko_common.DialContextSystem(ctx, network, addr) + } + neko_common.DialUDP = func(ctx context.Context, specifiedInstance interface{}) (net.PacketConn, error) { + if i, ok := specifiedInstance.(*NekoV2RayInstance); ok { + return core.DialUDP(ctx, i.Instance) + } + if instance != nil { + return core.DialUDP(ctx, instance.Instance) + } + return neko_common.DialUDPSystem(ctx) + } + neko_common.CreateProxyHttpClient = func(specifiedInstance interface{}) *http.Client { + if i, ok := specifiedInstance.(*NekoV2RayInstance); ok { + return createProxyHttpClient(i) + } + return createProxyHttpClient(instance) } } // PROXY -func getProxyHttpClient(_instance *NekoV2RayInstance) *http.Client { - dailContext := func(ctx context.Context, network, addr string) (net.Conn, error) { - dest, err := v2rayNet.ParseDestination(fmt.Sprintf("%s:%s", network, addr)) - if err != nil { - return nil, err - } - return core.Dial(ctx, _instance.Instance, dest) - } - +func createProxyHttpClient(i *NekoV2RayInstance) *http.Client { transport := &http.Transport{ TLSHandshakeTimeout: time.Second * 3, ResponseHeaderTimeout: time.Second * 3, } - if _instance != nil { - transport.DialContext = dailContext + if i != nil { + transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) { + return neko_common.DialContext(ctx, i, network, addr) + } } client := &http.Client{ diff --git a/go/cmd/nekoray_core/grpc_ray.go b/go/cmd/nekoray_core/grpc_ray.go index bff09c7..a6f03cb 100644 --- a/go/cmd/nekoray_core/grpc_ray.go +++ b/go/cmd/nekoray_core/grpc_ray.go @@ -2,22 +2,15 @@ package main import ( "context" - "encoding/hex" - "encoding/json" "errors" "fmt" "grpc_server" "grpc_server/gen" - "io" "log" - "net" - "strings" - "time" "github.com/matsuridayo/libneko/neko_common" "github.com/matsuridayo/libneko/speedtest" - core "github.com/v2fly/v2ray-core/v5" "github.com/v2fly/v2ray-core/v5/nekoutils" ) @@ -120,7 +113,7 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, // Latency var t int32 - t, err = speedtest.UrlTest(getProxyHttpClient(i), in.Url, in.Timeout) + t, err = speedtest.UrlTest(createProxyHttpClient(i), in.Url, in.Timeout) out.Ms = t // sn: ms==0 是错误 } else if in.Mode == gen.TestMode_TcpPing { out.Ms, err = speedtest.TcpPing(in.Address, in.Timeout) @@ -140,123 +133,7 @@ func (s *server) Test(ctx context.Context, in *gen.TestReq) (out *gen.TestResp, return } - // Latency - var latency string - if in.FullLatency { - t, _ := speedtest.UrlTest(getProxyHttpClient(i), in.Url, in.Timeout) - out.Ms = t - if t > 0 { - latency = fmt.Sprint(t, "ms") - } else { - latency = "Error" - } - } - - // UDP Latency - var udpLatency string - if in.FullUdpLatency { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) - result := make(chan string) - - go func() { - var startTime = time.Now() - pc, err := core.DialUDP(ctx, i.Instance) - if err == nil { - defer pc.Close() - dnsPacket, _ := hex.DecodeString("0000010000010000000000000377777706676f6f676c6503636f6d0000010001") - addr := &net.UDPAddr{ - IP: net.ParseIP("8.8.8.8"), - Port: 53, - } - _, err = pc.WriteTo(dnsPacket, addr) - if err == nil { - var buf [1400]byte - _, _, err = pc.ReadFrom(buf[:]) - } - } - if err == nil { - var endTime = time.Now() - result <- fmt.Sprint(endTime.Sub(startTime).Abs().Milliseconds(), "ms") - } else { - result <- "Error" - } - close(result) - }() - - select { - case <-ctx.Done(): - udpLatency = "Timeout" - case r := <-result: - udpLatency = r - } - cancel() - } - - // 入口 IP - var in_ip string - if in.FullInOut { - _in_ip, err := net.ResolveIPAddr("ip", in.InAddress) - if err == nil { - in_ip = _in_ip.String() - } else { - in_ip = err.Error() - } - } - - client := getProxyHttpClient(i) - - // 出口 IP - var out_ip string - if in.FullInOut { - resp, err := client.Get("https://httpbin.org/get") - if err == nil { - v := make(map[string]interface{}) - json.NewDecoder(resp.Body).Decode(&v) - if a, ok := v["origin"]; ok { - if s, ok := a.(string); ok { - out_ip = s - } - } - resp.Body.Close() - } else { - out_ip = "Error" - } - } - - // 下载 - var speed string - if in.FullSpeed { - resp, err := client.Get("http://cachefly.cachefly.net/10mb.test") - if err == nil { - time_start := time.Now() - n, _ := io.Copy(io.Discard, resp.Body) - time_end := time.Now() - - speed = fmt.Sprintf("%.2fMiB/s", (float64(n)/time_end.Sub(time_start).Seconds())/1048576) - resp.Body.Close() - } else { - speed = "Error" - } - } - - fr := make([]string, 0) - if latency != "" { - fr = append(fr, fmt.Sprintf("Latency: %s", latency)) - } - if udpLatency != "" { - fr = append(fr, fmt.Sprintf("UDPLatency: %s", udpLatency)) - } - if speed != "" { - fr = append(fr, fmt.Sprintf("Speed: %s", speed)) - } - if in_ip != "" { - fr = append(fr, fmt.Sprintf("In: %s", in_ip)) - } - if out_ip != "" { - fr = append(fr, fmt.Sprintf("Out: %s", out_ip)) - } - - out.FullReport = strings.Join(fr, " / ") + return grpc_server.DoFullTest(ctx, in, i) } return diff --git a/go/grpc_server/fulltest.go b/go/grpc_server/fulltest.go new file mode 100644 index 0000000..4add16e --- /dev/null +++ b/go/grpc_server/fulltest.go @@ -0,0 +1,137 @@ +package grpc_server + +import ( + "context" + "encoding/hex" + "encoding/json" + "fmt" + "grpc_server/gen" + "io" + "log" + "net" + "strings" + "time" + + "github.com/matsuridayo/libneko/neko_common" + "github.com/matsuridayo/libneko/speedtest" +) + +func DoFullTest(ctx context.Context, in *gen.TestReq, instance interface{}) (out *gen.TestResp, _ error) { + out = &gen.TestResp{} + httpClient := neko_common.CreateProxyHttpClient(instance) + + // Latency + var latency string + if in.FullLatency { + t, _ := speedtest.UrlTest(httpClient, in.Url, in.Timeout) + out.Ms = t + if t > 0 { + latency = fmt.Sprint(t, "ms") + } else { + latency = "Error" + } + } + + // UDP Latency + var udpLatency string + if in.FullUdpLatency { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + result := make(chan string) + + go func() { + var startTime = time.Now() + pc, err := neko_common.DialContext(ctx, instance, "udp", "8.8.8.8:53") + if err == nil { + defer pc.Close() + dnsPacket, _ := hex.DecodeString("0000010000010000000000000377777706676f6f676c6503636f6d0000010001") + _, err = pc.Write(dnsPacket) + if err == nil { + var buf [1400]byte + _, err = pc.Read(buf[:]) + } + } + if err == nil { + var endTime = time.Now() + result <- fmt.Sprint(endTime.Sub(startTime).Abs().Milliseconds(), "ms") + } else { + log.Println("UDP Latency test error:", err) + result <- "Error" + } + close(result) + }() + + select { + case <-ctx.Done(): + udpLatency = "Timeout" + case r := <-result: + udpLatency = r + } + cancel() + } + + // 入口 IP + var in_ip string + if in.FullInOut { + _in_ip, err := net.ResolveIPAddr("ip", in.InAddress) + if err == nil { + in_ip = _in_ip.String() + } else { + in_ip = err.Error() + } + } + + // 出口 IP + var out_ip string + if in.FullInOut { + resp, err := httpClient.Get("https://httpbin.org/get") + if err == nil { + v := make(map[string]interface{}) + json.NewDecoder(resp.Body).Decode(&v) + if a, ok := v["origin"]; ok { + if s, ok := a.(string); ok { + out_ip = s + } + } + resp.Body.Close() + } else { + out_ip = "Error" + } + } + + // 下载 + var speed string + if in.FullSpeed { + resp, err := httpClient.Get("http://cachefly.cachefly.net/10mb.test") + if err == nil { + time_start := time.Now() + n, _ := io.Copy(io.Discard, resp.Body) + time_end := time.Now() + + speed = fmt.Sprintf("%.2fMiB/s", (float64(n)/time_end.Sub(time_start).Seconds())/1048576) + resp.Body.Close() + } else { + speed = "Error" + } + } + + fr := make([]string, 0) + if latency != "" { + fr = append(fr, fmt.Sprintf("Latency: %s", latency)) + } + if udpLatency != "" { + fr = append(fr, fmt.Sprintf("UDPLatency: %s", udpLatency)) + } + if speed != "" { + fr = append(fr, fmt.Sprintf("Speed: %s", speed)) + } + if in_ip != "" { + fr = append(fr, fmt.Sprintf("In: %s", in_ip)) + } + if out_ip != "" { + fr = append(fr, fmt.Sprintf("Out: %s", out_ip)) + } + + out.FullReport = strings.Join(fr, " / ") + + return +} diff --git a/go/grpc_server/update.go b/go/grpc_server/update.go index 24cf3c3..f3acfa6 100644 --- a/go/grpc_server/update.go +++ b/go/grpc_server/update.go @@ -19,7 +19,7 @@ var update_download_url string func (s *BaseServer) Update(ctx context.Context, in *gen.UpdateReq) (*gen.UpdateResp, error) { ret := &gen.UpdateResp{} - client := neko_common.GetProxyHttpClient() + client := neko_common.CreateProxyHttpClient(neko_common.GetCurrentInstance()) if in.Action == gen.UpdateAction_Check { // Check update ctx, cancel := context.WithTimeout(ctx, time.Second*10) diff --git a/libs/get_source_env.sh b/libs/get_source_env.sh index c67384e..fae5077 100644 --- a/libs/get_source_env.sh +++ b/libs/get_source_env.sh @@ -1,5 +1,5 @@ if [ ! -z $ENV_NEKORAY ]; then - export COMMIT_SING_BOX_EXTRA="e7c37b1587c38841f4eb687249a43dab421d8eff" + export COMMIT_SING_BOX_EXTRA="1ea593f166ddb44e12ba9c7b41bcc6e73b66b550" export COMMIT_MATSURI_V2RAY="8134d3cc23aa6b8e2a056887addf22d7d22bd969" fi diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 0ec5050..a5b2777 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -375,7 +375,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi ui->menuCurrent_Group->insertAction(ui->actionfake_5, ui->menu_clear_test_result); ui->menuCurrent_Group->insertAction(ui->actionfake_5, ui->menu_resolve_domain); } - ui->menu_full_test->setVisible(!IS_NEKO_BOX); set_selected_or_group(menuCurrent_Select ? 1 : 0); }; };