github.com/metacubex/mihomo@v1.18.5/adapter/outbound/direct.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "errors" 6 "net/netip" 7 8 N "github.com/metacubex/mihomo/common/net" 9 "github.com/metacubex/mihomo/component/dialer" 10 "github.com/metacubex/mihomo/component/loopback" 11 "github.com/metacubex/mihomo/component/resolver" 12 C "github.com/metacubex/mihomo/constant" 13 ) 14 15 type Direct struct { 16 *Base 17 loopBack *loopback.Detector 18 } 19 20 type DirectOption struct { 21 BasicOption 22 Name string `proxy:"name"` 23 } 24 25 // DialContext implements C.ProxyAdapter 26 func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { 27 if err := d.loopBack.CheckConn(metadata); err != nil { 28 return nil, err 29 } 30 opts = append(opts, dialer.WithResolver(resolver.DefaultResolver)) 31 c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress(), d.Base.DialOptions(opts...)...) 32 if err != nil { 33 return nil, err 34 } 35 N.TCPKeepAlive(c) 36 return d.loopBack.NewConn(NewConn(c, d)), nil 37 } 38 39 // ListenPacketContext implements C.ProxyAdapter 40 func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { 41 if err := d.loopBack.CheckPacketConn(metadata); err != nil { 42 return nil, err 43 } 44 // net.UDPConn.WriteTo only working with *net.UDPAddr, so we need a net.UDPAddr 45 if !metadata.Resolved() { 46 ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, resolver.DefaultResolver) 47 if err != nil { 48 return nil, errors.New("can't resolve ip") 49 } 50 metadata.DstIP = ip 51 } 52 pc, err := dialer.NewDialer(d.Base.DialOptions(opts...)...).ListenPacket(ctx, "udp", "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) 53 if err != nil { 54 return nil, err 55 } 56 return d.loopBack.NewPacketConn(newPacketConn(pc, d)), nil 57 } 58 59 func NewDirectWithOption(option DirectOption) *Direct { 60 return &Direct{ 61 Base: &Base{ 62 name: option.Name, 63 tp: C.Direct, 64 udp: true, 65 tfo: option.TFO, 66 mpTcp: option.MPTCP, 67 iface: option.Interface, 68 rmark: option.RoutingMark, 69 prefer: C.NewDNSPrefer(option.IPVersion), 70 }, 71 loopBack: loopback.NewDetector(), 72 } 73 } 74 75 func NewDirect() *Direct { 76 return &Direct{ 77 Base: &Base{ 78 name: "DIRECT", 79 tp: C.Direct, 80 udp: true, 81 prefer: C.DualStack, 82 }, 83 loopBack: loopback.NewDetector(), 84 } 85 } 86 87 func NewCompatible() *Direct { 88 return &Direct{ 89 Base: &Base{ 90 name: "COMPATIBLE", 91 tp: C.Compatible, 92 udp: true, 93 prefer: C.DualStack, 94 }, 95 loopBack: loopback.NewDetector(), 96 } 97 }