feat: full test for nekobox

This commit is contained in:
arm64v8a
2023-05-30 13:21:24 +09:00
parent f164f73888
commit d7fadc91d2
8 changed files with 218 additions and 147 deletions

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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{

View File

@@ -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

137
go/grpc_server/fulltest.go Normal file
View File

@@ -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
}

View File

@@ -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)

View File

@@ -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

View File

@@ -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);
};
};