Skip to content

Commit a1c7881

Browse files
committed
chore: rebuild udp dns resolve
The DNS resolution of the overall UDP part has been delayed to the connection initiation stage. During the rule matching process, it will only be triggered when the IP rule without no-resolve is matched. For direct and wireguard outbound, the same logic as the TCP part will be followed, that is, when direct-nameserver (or DNS configured by wireguard) exists, the result of the matching process will be discarded and the domain name will be re-resolved. This re-resolution logic is only effective for fakeip. For reject and DNS outbound, no resolution is required. For other outbound, resolution will still be performed when the connection is initiated, and the domain name will not be sent directly to the remote server at present.
1 parent 12e3952 commit a1c7881

24 files changed

+245
-189
lines changed

adapter/outbound/anytls.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,13 @@ package outbound
22

33
import (
44
"context"
5-
"errors"
65
"net"
76
"strconv"
87
"time"
98

109
CN "github.com/metacubex/mihomo/common/net"
1110
"github.com/metacubex/mihomo/component/dialer"
1211
"github.com/metacubex/mihomo/component/proxydialer"
13-
"github.com/metacubex/mihomo/component/resolver"
1412
C "github.com/metacubex/mihomo/constant"
1513
"github.com/metacubex/mihomo/transport/anytls"
1614
"github.com/metacubex/mihomo/transport/vmess"
@@ -53,20 +51,17 @@ func (t *AnyTLS) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
5351
}
5452

5553
func (t *AnyTLS) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
54+
if err = t.ResolveUDP(ctx, metadata); err != nil {
55+
return nil, err
56+
}
57+
5658
// create tcp
5759
c, err := t.client.CreateProxy(ctx, uot.RequestDestination(2))
5860
if err != nil {
5961
return nil, err
6062
}
6163

6264
// create uot on tcp
63-
if !metadata.Resolved() {
64-
ip, err := resolver.ResolveIP(ctx, metadata.Host)
65-
if err != nil {
66-
return nil, errors.New("can't resolve ip")
67-
}
68-
metadata.DstIP = ip
69-
}
7065
destination := M.SocksaddrFromNet(metadata.UDPAddr())
7166
return newPacketConn(CN.NewThreadSafePacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination})), t), nil
7267
}

adapter/outbound/base.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package outbound
33
import (
44
"context"
55
"encoding/json"
6+
"fmt"
67
"net"
78
"runtime"
89
"sync"
@@ -11,13 +12,15 @@ import (
1112
N "github.com/metacubex/mihomo/common/net"
1213
"github.com/metacubex/mihomo/common/utils"
1314
"github.com/metacubex/mihomo/component/dialer"
15+
"github.com/metacubex/mihomo/component/resolver"
1416
C "github.com/metacubex/mihomo/constant"
1517
"github.com/metacubex/mihomo/log"
1618
)
1719

1820
type ProxyAdapter interface {
1921
C.ProxyAdapter
2022
DialOptions() []dialer.Option
23+
ResolveUDP(ctx context.Context, metadata *C.Metadata) error
2124
}
2225

2326
type Base struct {
@@ -159,6 +162,17 @@ func (b *Base) DialOptions() (opts []dialer.Option) {
159162
return opts
160163
}
161164

165+
func (b *Base) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
166+
if !metadata.Resolved() {
167+
ip, err := resolver.ResolveIP(ctx, metadata.Host)
168+
if err != nil {
169+
return fmt.Errorf("can't resolve ip: %w", err)
170+
}
171+
metadata.DstIP = ip
172+
}
173+
return nil
174+
}
175+
162176
func (b *Base) Close() error {
163177
return nil
164178
}
@@ -258,6 +272,11 @@ type packetConn struct {
258272
adapterName string
259273
connID string
260274
adapterAddr string
275+
resolveUDP func(ctx context.Context, metadata *C.Metadata) error
276+
}
277+
278+
func (c *packetConn) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
279+
return c.resolveUDP(ctx, metadata)
261280
}
262281

263282
func (c *packetConn) RemoteDestination() string {
@@ -296,12 +315,12 @@ func (c *packetConn) AddRef(ref any) {
296315
c.EnhancePacketConn = N.NewRefPacketConn(c.EnhancePacketConn, ref) // add ref for autoCloseProxyAdapter
297316
}
298317

299-
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
318+
func newPacketConn(pc net.PacketConn, a ProxyAdapter) C.PacketConn {
300319
epc := N.NewEnhancePacketConn(pc)
301320
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
302321
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
303322
}
304-
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), a.Addr()}
323+
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), a.Addr(), a.ResolveUDP}
305324
}
306325

307326
type AddRef interface {

adapter/outbound/direct.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ package outbound
22

33
import (
44
"context"
5-
"errors"
5+
"fmt"
6+
67
"github.com/metacubex/mihomo/component/dialer"
78
"github.com/metacubex/mihomo/component/loopback"
89
"github.com/metacubex/mihomo/component/resolver"
@@ -38,13 +39,8 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
3839
if err := d.loopBack.CheckPacketConn(metadata); err != nil {
3940
return nil, err
4041
}
41-
// net.UDPConn.WriteTo only working with *net.UDPAddr, so we need a net.UDPAddr
42-
if !metadata.Resolved() {
43-
ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, resolver.DirectHostResolver)
44-
if err != nil {
45-
return nil, errors.New("can't resolve ip")
46-
}
47-
metadata.DstIP = ip
42+
if err := d.ResolveUDP(ctx, metadata); err != nil {
43+
return nil, err
4844
}
4945
pc, err := dialer.NewDialer(d.DialOptions()...).ListenPacket(ctx, "udp", "", metadata.AddrPort())
5046
if err != nil {
@@ -53,6 +49,17 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
5349
return d.loopBack.NewPacketConn(newPacketConn(pc, d)), nil
5450
}
5551

52+
func (d *Direct) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
53+
if (!metadata.Resolved() || resolver.DirectHostResolver != resolver.DefaultResolver) && metadata.Host != "" {
54+
ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, resolver.DirectHostResolver)
55+
if err != nil {
56+
return fmt.Errorf("can't resolve ip: %w", err)
57+
}
58+
metadata.DstIP = ip
59+
}
60+
return nil
61+
}
62+
5663
func (d *Direct) IsL3Protocol(metadata *C.Metadata) bool {
5764
return true // tell DNSDialer don't send domain to DialContext, avoid lookback to DefaultResolver
5865
}

adapter/outbound/dns.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package outbound
33
import (
44
"context"
55
"net"
6+
"net/netip"
67
"time"
78

89
N "github.com/metacubex/mihomo/common/net"
@@ -31,6 +32,9 @@ func (d *Dns) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, er
3132
// ListenPacketContext implements C.ProxyAdapter
3233
func (d *Dns) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
3334
log.Debugln("[DNS] hijack udp:%s from %s", metadata.RemoteAddress(), metadata.SourceAddrPort())
35+
if err := d.ResolveUDP(ctx, metadata); err != nil {
36+
return nil, err
37+
}
3438

3539
ctx, cancel := context.WithCancel(context.Background())
3640

@@ -41,6 +45,13 @@ func (d *Dns) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.
4145
}, d), nil
4246
}
4347

48+
func (d *Dns) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
49+
if !metadata.Resolved() {
50+
metadata.DstIP = netip.AddrFrom4([4]byte{127, 0, 0, 2})
51+
}
52+
return nil
53+
}
54+
4455
type dnsPacket struct {
4556
data []byte
4657
put func()

adapter/outbound/hysteria.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
6060
}
6161

6262
func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
63+
if err := h.ResolveUDP(ctx, metadata); err != nil {
64+
return nil, err
65+
}
6366
udpConn, err := h.client.DialUDP(h.genHdc(ctx))
6467
if err != nil {
6568
return nil, err

adapter/outbound/hysteria2.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.
7777
}
7878

7979
func (h *Hysteria2) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
80+
if err = h.ResolveUDP(ctx, metadata); err != nil {
81+
return nil, err
82+
}
8083
pc, err := h.client.ListenPacket(ctx)
8184
if err != nil {
8285
return nil, err

adapter/outbound/mieru.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ func (m *Mieru) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
5454

5555
// ListenPacketContext implements C.ProxyAdapter
5656
func (m *Mieru) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
57+
if err = m.ResolveUDP(ctx, metadata); err != nil {
58+
return nil, err
59+
}
5760
if err := m.ensureClientIsRunning(); err != nil {
5861
return nil, err
5962
}

adapter/outbound/reject.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"io"
66
"net"
7+
"net/netip"
78
"time"
89

910
"github.com/metacubex/mihomo/common/buf"
@@ -29,9 +30,19 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
2930

3031
// ListenPacketContext implements C.ProxyAdapter
3132
func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
33+
if err := r.ResolveUDP(ctx, metadata); err != nil {
34+
return nil, err
35+
}
3236
return newPacketConn(&nopPacketConn{}, r), nil
3337
}
3438

39+
func (r *Reject) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
40+
if !metadata.Resolved() {
41+
metadata.DstIP = netip.IPv4Unspecified()
42+
}
43+
return nil
44+
}
45+
3546
func NewRejectWithOption(option RejectOption) *Reject {
3647
return &Reject{
3748
Base: &Base{

adapter/outbound/shadowsocks.go

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package outbound
22

33
import (
44
"context"
5-
"errors"
65
"fmt"
76
"net"
87
"strconv"
@@ -11,7 +10,6 @@ import (
1110
"github.com/metacubex/mihomo/common/structure"
1211
"github.com/metacubex/mihomo/component/dialer"
1312
"github.com/metacubex/mihomo/component/proxydialer"
14-
"github.com/metacubex/mihomo/component/resolver"
1513
C "github.com/metacubex/mihomo/constant"
1614
gost "github.com/metacubex/mihomo/transport/gost-plugin"
1715
"github.com/metacubex/mihomo/transport/restls"
@@ -202,6 +200,9 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial
202200
return nil, err
203201
}
204202
}
203+
if err = ss.ResolveUDP(ctx, metadata); err != nil {
204+
return nil, err
205+
}
205206
addr, err := resolveUDPAddr(ctx, "udp", ss.addr, ss.prefer)
206207
if err != nil {
207208
return nil, err
@@ -230,15 +231,9 @@ func (ss *ShadowSocks) ProxyInfo() C.ProxyInfo {
230231
// ListenPacketOnStreamConn implements C.ProxyAdapter
231232
func (ss *ShadowSocks) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
232233
if ss.option.UDPOverTCP {
233-
// ss uot use stream-oriented udp with a special address, so we need a net.UDPAddr
234-
if !metadata.Resolved() {
235-
ip, err := resolver.ResolveIP(ctx, metadata.Host)
236-
if err != nil {
237-
return nil, errors.New("can't resolve ip")
238-
}
239-
metadata.DstIP = ip
234+
if err = ss.ResolveUDP(ctx, metadata); err != nil {
235+
return nil, err
240236
}
241-
242237
destination := M.SocksaddrFromNet(metadata.UDPAddr())
243238
if ss.option.UDPOverTCPVersion == uot.LegacyVersion {
244239
return newPacketConn(N.NewThreadSafePacketConn(uot.NewConn(c, uot.Request{Destination: destination})), ss), nil

adapter/outbound/shadowsocksr.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di
105105
return nil, err
106106
}
107107
}
108+
if err = ssr.ResolveUDP(ctx, metadata); err != nil {
109+
return nil, err
110+
}
108111
addr, err := resolveUDPAddr(ctx, "udp", ssr.addr, ssr.prefer)
109112
if err != nil {
110113
return nil, err

adapter/outbound/singmux.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@ package outbound
22

33
import (
44
"context"
5-
"errors"
65

76
CN "github.com/metacubex/mihomo/common/net"
87
"github.com/metacubex/mihomo/component/dialer"
98
"github.com/metacubex/mihomo/component/proxydialer"
10-
"github.com/metacubex/mihomo/component/resolver"
119
C "github.com/metacubex/mihomo/constant"
1210
"github.com/metacubex/mihomo/log"
1311

@@ -53,16 +51,9 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
5351
if s.onlyTcp {
5452
return s.ProxyAdapter.ListenPacketContext(ctx, metadata)
5553
}
56-
57-
// sing-mux use stream-oriented udp with a special address, so we need a net.UDPAddr
58-
if !metadata.Resolved() {
59-
ip, err := resolver.ResolveIP(ctx, metadata.Host)
60-
if err != nil {
61-
return nil, errors.New("can't resolve ip")
62-
}
63-
metadata.DstIP = ip
54+
if err = s.ProxyAdapter.ResolveUDP(ctx, metadata); err != nil {
55+
return nil, err
6456
}
65-
6657
pc, err := s.client.ListenPacket(ctx, M.SocksaddrFromNet(metadata.UDPAddr()))
6758
if err != nil {
6859
return nil, err

adapter/outbound/snell.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,9 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
127127
return nil, err
128128
}
129129
}
130+
if err = s.ResolveUDP(ctx, metadata); err != nil {
131+
return nil, err
132+
}
130133
c, err := dialer.DialContext(ctx, "tcp", s.addr)
131134
if err != nil {
132135
return nil, err

adapter/outbound/socks5.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
109109
return nil, err
110110
}
111111
}
112+
if err = ss.ResolveUDP(ctx, metadata); err != nil {
113+
return nil, err
114+
}
112115
c, err := cDialer.DialContext(ctx, "tcp", ss.addr)
113116
if err != nil {
114117
err = fmt.Errorf("%s connect error: %w", ss.addr, err)

adapter/outbound/trojan.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, met
219219

220220
// ListenPacketContext implements C.ProxyAdapter
221221
func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
222+
if err = t.ResolveUDP(ctx, metadata); err != nil {
223+
return nil, err
224+
}
225+
222226
var c net.Conn
223227

224228
// grpc transport
@@ -250,6 +254,9 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me
250254
return nil, err
251255
}
252256
}
257+
if err = t.ResolveUDP(ctx, metadata); err != nil {
258+
return nil, err
259+
}
253260
c, err := dialer.DialContext(ctx, "tcp", t.addr)
254261
if err != nil {
255262
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
@@ -271,12 +278,6 @@ func (t *Trojan) SupportWithDialer() C.NetWork {
271278
return C.ALLNet
272279
}
273280

274-
// ListenPacketOnStreamConn implements C.ProxyAdapter
275-
func (t *Trojan) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
276-
pc := trojan.NewPacketConn(c)
277-
return newPacketConn(pc, t), err
278-
}
279-
280281
// SupportUOT implements C.ProxyAdapter
281282
func (t *Trojan) SupportUOT() bool {
282283
return true

0 commit comments

Comments
 (0)