Files
x/resolver/plugin/grpc.go
T
ginuerzh 28d3ffa310 fix(resolver): fix async context leak, gRPC error swallowing, add 48 tests
Fix async resolve goroutine using caller's cancelable context by
switching to context.WithoutCancel. Fix NewGRPCPlugin silently
returning broken resolver on connection failure. Fix "resolover"
typo in log field. Add doc comments to all exported symbols.
2026-05-25 20:52:19 +08:00

80 lines
1.6 KiB
Go

package resolver
import (
"context"
"io"
"net"
"github.com/go-gost/core/logger"
"github.com/go-gost/core/resolver"
"github.com/go-gost/plugin/resolver/proto"
ctxvalue "github.com/go-gost/x/ctx"
"github.com/go-gost/x/internal/plugin"
"google.golang.org/grpc"
)
type grpcPlugin struct {
conn grpc.ClientConnInterface
client proto.ResolverClient
log logger.Logger
}
// NewGRPCPlugin creates a Resolver plugin based on gRPC.
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) (resolver.Resolver, error) {
var options plugin.Options
for _, opt := range opts {
opt(&options)
}
log := logger.Default().WithFields(map[string]any{
"kind": "resolver",
"resolver": name,
})
conn, err := plugin.NewGRPCConn(addr, &options)
if err != nil {
return nil, err
}
p := &grpcPlugin{
conn: conn,
client: proto.NewResolverClient(conn),
log: log,
}
return p, nil
}
func (p *grpcPlugin) Resolve(ctx context.Context, network, host string, opts ...resolver.Option) (ips []net.IP, err error) {
p.log.Debugf("resolve %s/%s", host, network)
if p.client == nil {
return
}
r, err := p.client.Resolve(ctx,
&proto.ResolveRequest{
Network: network,
Host: host,
Client: string(ctxvalue.ClientIDFromContext(ctx)),
})
if err != nil {
p.log.Error(err)
return
}
for _, s := range r.Ips {
if ip := net.ParseIP(s); ip != nil {
ips = append(ips, ip)
}
}
return
}
func (p *grpcPlugin) Close() error {
if p.conn == nil {
return nil
}
if closer, ok := p.conn.(io.Closer); ok {
return closer.Close()
}
return nil
}