Resolve and race all WireGuard addresses on handshake

This commit is contained in:
世界
2026-08-30 17:41:45 +08:00
parent ce25e7791d
commit 1e2846a1a5
8 changed files with 332 additions and 243 deletions
+5
View File
@@ -27,6 +27,7 @@ type ClientBind struct {
bindCtx context.Context
bindDone context.CancelFunc
dialer N.Dialer
reservedAccess sync.RWMutex
reservedForEndpoint map[netip.AddrPort][3]uint8
connAccess sync.Mutex
conn *wireConn
@@ -175,7 +176,9 @@ func (c *ClientBind) Send(bufs [][]byte, ep conn.Endpoint, offset int) error {
buf = buf[offset:]
}
if len(buf) > 3 {
c.reservedAccess.RLock()
reserved, loaded := c.reservedForEndpoint[destination]
c.reservedAccess.RUnlock()
if !loaded {
reserved = c.reserved
}
@@ -203,7 +206,9 @@ func (c *ClientBind) BatchSize() int {
}
func (c *ClientBind) SetReservedForEndpoint(destination netip.AddrPort, reserved [3]byte) {
c.reservedAccess.Lock()
c.reservedForEndpoint[destination] = reserved
c.reservedAccess.Unlock()
}
type wireConn struct {
+43 -25
View File
@@ -8,9 +8,7 @@ import (
"net"
"net/netip"
"os"
"reflect"
"strings"
"unsafe"
"github.com/sagernet/sing-box/common/dialer"
"github.com/sagernet/sing-tun"
@@ -133,24 +131,11 @@ func NewEndpoint(options EndpointOptions) (*Endpoint, error) {
}, nil
}
func (e *Endpoint) Start(resolve bool) error {
if common.Any(e.peers, func(peer peerConfig) bool {
return !peer.endpoint.IsValid() && peer.destination.IsDomain()
}) {
if !resolve {
return nil
}
for peerIndex, peer := range e.peers {
if peer.endpoint.IsValid() || !peer.destination.IsDomain() {
continue
}
destinationAddress, err := e.options.ResolvePeer(peer.destination.Fqdn)
if err != nil {
return E.Cause(err, "resolve endpoint domain for peer[", peerIndex, "]: ", peer.destination)
}
e.peers[peerIndex].endpoint = netip.AddrPortFrom(destinationAddress, peer.destination.Port)
}
} else if resolve {
func (e *Endpoint) Start(postStart bool) error {
hasDomainPeer := common.Any(e.peers, func(peer peerConfig) bool {
return peer.destination.IsDomain()
})
if postStart != hasDomainPeer {
return nil
}
var bind conn.Bind
@@ -174,16 +159,18 @@ func (e *Endpoint) Start(resolve bool) error {
connectAddr netip.AddrPort
reserved [3]uint8
)
if len(e.peers) == 1 && e.peers[0].endpoint.IsValid() {
isConnect = true
connectAddr = e.peers[0].endpoint
if len(e.peers) == 1 {
reserved = e.peers[0].reserved
if e.peers[0].endpoint.IsValid() {
isConnect = true
connectAddr = e.peers[0].endpoint
}
}
bind = NewClientBind(e.options.Context, e.options.Logger, e.options.Dialer, isConnect, connectAddr, reserved)
}
if isUDPListener || len(e.peers) > 1 {
for _, peer := range e.peers {
if peer.reserved != [3]uint8{} {
if peer.endpoint.IsValid() && peer.reserved != [3]uint8{} {
bind.SetReservedForEndpoint(peer.endpoint, peer.reserved)
}
}
@@ -212,12 +199,43 @@ func (e *Endpoint) Start(resolve bool) error {
wgDevice.Close()
return E.Cause(err, "setup wireguard: \n", ipcConf.String())
}
for _, peer := range e.peers {
if !peer.destination.IsDomain() {
continue
}
var publicKey device.NoisePublicKey
common.Must(publicKey.FromHex(peer.publicKeyHex))
wgPeer, found := wgDevice.LookupActivePeer(publicKey)
if !found {
wgDevice.Close()
return E.New("missing configured peer: ", peer.destination)
}
wgPeer.SetEndpointResolver(func() ([]conn.Endpoint, error) {
addresses, lookupErr := e.options.ResolvePeer(peer.destination.Fqdn)
if lookupErr != nil {
return nil, lookupErr
}
endpoints := make([]conn.Endpoint, 0, len(addresses))
for _, address := range addresses {
destination := netip.AddrPortFrom(address, peer.destination.Port)
if peer.reserved != ([3]uint8{}) {
bind.SetReservedForEndpoint(destination, peer.reserved)
}
endpoint, parseErr := bind.ParseEndpoint(destination.String())
if parseErr != nil {
return nil, parseErr
}
endpoints = append(endpoints, endpoint)
}
return endpoints, nil
})
}
e.device = wgDevice
e.pause = service.FromContext[pause.Manager](e.options.Context)
if e.pause != nil {
e.pauseCallback = e.pause.RegisterCallback(e.onPauseUpdated)
}
e.allowedIPs = (*device.AllowedIPs)(unsafe.Pointer(reflect.Indirect(reflect.ValueOf(wgDevice)).FieldByName("allowedips").UnsafeAddr()))
e.allowedIPs = wgDevice.AllowedIPs()
return nil
}
+1 -1
View File
@@ -32,7 +32,7 @@ type EndpointOptions struct {
Address []netip.Prefix
PrivateKey string
ListenPort uint16
ResolvePeer func(domain string) (netip.Addr, error)
ResolvePeer func(domain string) ([]netip.Addr, error)
Peers []PeerOptions
Workers int
}