mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-05 13:28:13 +03:00
119 lines
3.2 KiB
Go
119 lines
3.2 KiB
Go
package dns
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/xtls/xray-core/common/net"
|
|
featureDNS "github.com/xtls/xray-core/features/dns"
|
|
lua "github.com/yuin/gopher-lua"
|
|
)
|
|
|
|
// BenchmarkLuaDNSHook isolates scalar argument bridging and a fixed return.
|
|
// It excludes upstream queries, result decoding, and state pool management.
|
|
func BenchmarkLuaDNSHook(b *testing.B) {
|
|
L := lua.NewState()
|
|
b.Cleanup(L.Close)
|
|
if err := L.DoString(`
|
|
function HandleDNSQuery(domain, ipv4, ipv6, fake)
|
|
return true
|
|
end
|
|
`); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
L.SetContext(context.Background())
|
|
option := featureDNS.IPOption{IPv4Enable: true}
|
|
if err := callLuaQuery(L, "example.com", option); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if L.Get(-3) != lua.LTrue {
|
|
b.Fatal("hook did not return true")
|
|
}
|
|
L.Pop(3)
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
if err := callLuaQuery(L, "example.com", option); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
L.Pop(3)
|
|
}
|
|
}
|
|
|
|
// BenchmarkLuaDNSQuery queries the same preselected, in-memory upstream.
|
|
// client_query compares Client.QueryIP to a preloaded server:Query hook.
|
|
// script_query additionally measures production pool and timeout management.
|
|
// These cases do not measure DNS.LookupIP server selection or network latency.
|
|
func BenchmarkLuaDNSQuery(b *testing.B) {
|
|
ctx := context.Background()
|
|
option := featureDNS.IPOption{IPv4Enable: true}
|
|
ip := net.ParseIP("127.0.0.1")
|
|
upstream := &benchmarkLuaNameServer{ips: []net.IP{ip}}
|
|
client := &Client{server: upstream, ipOption: &option, timeoutMs: time.Second}
|
|
server := &DNS{ctx: ctx, clients: []*Client{client}}
|
|
const script = `
|
|
local server = require("xray.dns").Servers[1]
|
|
function HandleDNSQuery(domain, ipv4, ipv6, fake)
|
|
return server:Query(domain, ipv4, ipv6, fake)
|
|
end
|
|
`
|
|
L := lua.NewState()
|
|
b.Cleanup(L.Close)
|
|
server.registerLua(L)
|
|
if err := L.DoString(script); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
L.SetContext(ctx)
|
|
|
|
path := filepath.Join(b.TempDir(), "query.lua")
|
|
if err := os.WriteFile(path, []byte(script), 0o600); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
engine, err := newScriptEngine(path, server)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
b.Cleanup(engine.close)
|
|
for _, bench := range []struct {
|
|
name string
|
|
query func() ([]net.IP, uint32, error)
|
|
}{
|
|
{"client_query/native", func() ([]net.IP, uint32, error) {
|
|
return client.QueryIP(ctx, "example.com", option)
|
|
}},
|
|
{"client_query/lua", func() ([]net.IP, uint32, error) {
|
|
if err := callLuaQuery(L, "example.com", option); err != nil {
|
|
return nil, 0, err
|
|
}
|
|
ips, ttl, err := readLuaQueryResult(L)
|
|
L.Pop(3)
|
|
return ips, ttl, err
|
|
}},
|
|
{"script_query/lua", func() ([]net.IP, uint32, error) {
|
|
return engine.query("example.com", option)
|
|
}},
|
|
} {
|
|
b.Run(bench.name, func(b *testing.B) {
|
|
ips, ttl, err := bench.query()
|
|
if err != nil || ttl != 60 || len(ips) != 1 || !ips[0].Equal(ip) {
|
|
b.Fatalf("query() = %v, TTL %d, %v; want %v, TTL 60", ips, ttl, err, ip)
|
|
}
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
ips, ttl, err = bench.query()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
}
|
|
b.StopTimer()
|
|
if ttl != 60 || len(ips) != 1 || !ips[0].Equal(ip) {
|
|
b.Fatalf("query() = %v, TTL %d; want %v, TTL 60", ips, ttl, ip)
|
|
}
|
|
})
|
|
}
|
|
}
|