mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2025-12-20 00:50:06 +08:00
chore: rebuild udp dns resolve
Some checks failed
Test / test (1.20, macos-13) (push) Waiting to run
Test / test (1.20, macos-latest) (push) Waiting to run
Test / test (1.20, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.20, windows-latest) (push) Waiting to run
Test / test (1.21, macos-13) (push) Waiting to run
Test / test (1.21, macos-latest) (push) Waiting to run
Test / test (1.21, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.21, windows-latest) (push) Waiting to run
Test / test (1.22, macos-13) (push) Waiting to run
Test / test (1.22, macos-latest) (push) Waiting to run
Test / test (1.22, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.22, windows-latest) (push) Waiting to run
Test / test (1.23, macos-13) (push) Waiting to run
Test / test (1.23, macos-latest) (push) Waiting to run
Test / test (1.23, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.23, windows-latest) (push) Waiting to run
Test / test (1.24, macos-13) (push) Waiting to run
Test / test (1.24, macos-latest) (push) Waiting to run
Test / test (1.24, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.24, windows-latest) (push) Waiting to run
Test / test (1.20, ubuntu-latest) (push) Failing after 1s
Test / test (1.21, ubuntu-latest) (push) Failing after 1s
Test / test (1.22, ubuntu-latest) (push) Failing after 1s
Test / test (1.23, ubuntu-latest) (push) Failing after 1s
Test / test (1.24, ubuntu-latest) (push) Failing after 1s
Trigger CMFA Update / trigger-CMFA-update (push) Failing after 1s
Some checks failed
Test / test (1.20, macos-13) (push) Waiting to run
Test / test (1.20, macos-latest) (push) Waiting to run
Test / test (1.20, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.20, windows-latest) (push) Waiting to run
Test / test (1.21, macos-13) (push) Waiting to run
Test / test (1.21, macos-latest) (push) Waiting to run
Test / test (1.21, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.21, windows-latest) (push) Waiting to run
Test / test (1.22, macos-13) (push) Waiting to run
Test / test (1.22, macos-latest) (push) Waiting to run
Test / test (1.22, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.22, windows-latest) (push) Waiting to run
Test / test (1.23, macos-13) (push) Waiting to run
Test / test (1.23, macos-latest) (push) Waiting to run
Test / test (1.23, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.23, windows-latest) (push) Waiting to run
Test / test (1.24, macos-13) (push) Waiting to run
Test / test (1.24, macos-latest) (push) Waiting to run
Test / test (1.24, ubuntu-24.04-arm) (push) Waiting to run
Test / test (1.24, windows-latest) (push) Waiting to run
Test / test (1.20, ubuntu-latest) (push) Failing after 1s
Test / test (1.21, ubuntu-latest) (push) Failing after 1s
Test / test (1.22, ubuntu-latest) (push) Failing after 1s
Test / test (1.23, ubuntu-latest) (push) Failing after 1s
Test / test (1.24, ubuntu-latest) (push) Failing after 1s
Trigger CMFA Update / trigger-CMFA-update (push) Failing after 1s
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.
This commit is contained in:
parent
12e3952b74
commit
a1c7881229
@ -2,7 +2,6 @@ package outbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -10,7 +9,6 @@ import (
|
|||||||
CN "github.com/metacubex/mihomo/common/net"
|
CN "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/proxydialer"
|
"github.com/metacubex/mihomo/component/proxydialer"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/transport/anytls"
|
"github.com/metacubex/mihomo/transport/anytls"
|
||||||
"github.com/metacubex/mihomo/transport/vmess"
|
"github.com/metacubex/mihomo/transport/vmess"
|
||||||
@ -53,6 +51,10 @@ func (t *AnyTLS) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *AnyTLS) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (t *AnyTLS) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
|
if err = t.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// create tcp
|
// create tcp
|
||||||
c, err := t.client.CreateProxy(ctx, uot.RequestDestination(2))
|
c, err := t.client.CreateProxy(ctx, uot.RequestDestination(2))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -60,13 +62,6 @@ func (t *AnyTLS) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create uot on tcp
|
// create uot on tcp
|
||||||
if !metadata.Resolved() {
|
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
|
||||||
destination := M.SocksaddrFromNet(metadata.UDPAddr())
|
destination := M.SocksaddrFromNet(metadata.UDPAddr())
|
||||||
return newPacketConn(CN.NewThreadSafePacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination})), t), nil
|
return newPacketConn(CN.NewThreadSafePacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination})), t), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
@ -11,6 +12,7 @@ import (
|
|||||||
N "github.com/metacubex/mihomo/common/net"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/common/utils"
|
"github.com/metacubex/mihomo/common/utils"
|
||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
|
"github.com/metacubex/mihomo/component/resolver"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
)
|
)
|
||||||
@ -18,6 +20,7 @@ import (
|
|||||||
type ProxyAdapter interface {
|
type ProxyAdapter interface {
|
||||||
C.ProxyAdapter
|
C.ProxyAdapter
|
||||||
DialOptions() []dialer.Option
|
DialOptions() []dialer.Option
|
||||||
|
ResolveUDP(ctx context.Context, metadata *C.Metadata) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
@ -159,6 +162,17 @@ func (b *Base) DialOptions() (opts []dialer.Option) {
|
|||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Base) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
|
||||||
|
if !metadata.Resolved() {
|
||||||
|
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't resolve ip: %w", err)
|
||||||
|
}
|
||||||
|
metadata.DstIP = ip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Base) Close() error {
|
func (b *Base) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -258,6 +272,11 @@ type packetConn struct {
|
|||||||
adapterName string
|
adapterName string
|
||||||
connID string
|
connID string
|
||||||
adapterAddr string
|
adapterAddr string
|
||||||
|
resolveUDP func(ctx context.Context, metadata *C.Metadata) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packetConn) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
|
||||||
|
return c.resolveUDP(ctx, metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packetConn) RemoteDestination() string {
|
func (c *packetConn) RemoteDestination() string {
|
||||||
@ -296,12 +315,12 @@ func (c *packetConn) AddRef(ref any) {
|
|||||||
c.EnhancePacketConn = N.NewRefPacketConn(c.EnhancePacketConn, ref) // add ref for autoCloseProxyAdapter
|
c.EnhancePacketConn = N.NewRefPacketConn(c.EnhancePacketConn, ref) // add ref for autoCloseProxyAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
|
func newPacketConn(pc net.PacketConn, a ProxyAdapter) C.PacketConn {
|
||||||
epc := N.NewEnhancePacketConn(pc)
|
epc := N.NewEnhancePacketConn(pc)
|
||||||
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
|
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
|
||||||
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
|
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
|
||||||
}
|
}
|
||||||
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), a.Addr()}
|
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), a.Addr(), a.ResolveUDP}
|
||||||
}
|
}
|
||||||
|
|
||||||
type AddRef interface {
|
type AddRef interface {
|
||||||
|
|||||||
@ -2,7 +2,8 @@ package outbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"fmt"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/loopback"
|
"github.com/metacubex/mihomo/component/loopback"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
"github.com/metacubex/mihomo/component/resolver"
|
||||||
@ -38,13 +39,8 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
|||||||
if err := d.loopBack.CheckPacketConn(metadata); err != nil {
|
if err := d.loopBack.CheckPacketConn(metadata); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// net.UDPConn.WriteTo only working with *net.UDPAddr, so we need a net.UDPAddr
|
if err := d.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, resolver.DirectHostResolver)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
pc, err := dialer.NewDialer(d.DialOptions()...).ListenPacket(ctx, "udp", "", metadata.AddrPort())
|
pc, err := dialer.NewDialer(d.DialOptions()...).ListenPacket(ctx, "udp", "", metadata.AddrPort())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -53,6 +49,17 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
|||||||
return d.loopBack.NewPacketConn(newPacketConn(pc, d)), nil
|
return d.loopBack.NewPacketConn(newPacketConn(pc, d)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Direct) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
|
||||||
|
if (!metadata.Resolved() || resolver.DirectHostResolver != resolver.DefaultResolver) && metadata.Host != "" {
|
||||||
|
ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, resolver.DirectHostResolver)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't resolve ip: %w", err)
|
||||||
|
}
|
||||||
|
metadata.DstIP = ip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Direct) IsL3Protocol(metadata *C.Metadata) bool {
|
func (d *Direct) IsL3Protocol(metadata *C.Metadata) bool {
|
||||||
return true // tell DNSDialer don't send domain to DialContext, avoid lookback to DefaultResolver
|
return true // tell DNSDialer don't send domain to DialContext, avoid lookback to DefaultResolver
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
N "github.com/metacubex/mihomo/common/net"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
@ -31,6 +32,9 @@ func (d *Dns) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn, er
|
|||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (d *Dns) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
|
func (d *Dns) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
|
||||||
log.Debugln("[DNS] hijack udp:%s from %s", metadata.RemoteAddress(), metadata.SourceAddrPort())
|
log.Debugln("[DNS] hijack udp:%s from %s", metadata.RemoteAddress(), metadata.SourceAddrPort())
|
||||||
|
if err := d.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
|
||||||
@ -41,6 +45,13 @@ func (d *Dns) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.
|
|||||||
}, d), nil
|
}, d), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Dns) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
|
||||||
|
if !metadata.Resolved() {
|
||||||
|
metadata.DstIP = netip.AddrFrom4([4]byte{127, 0, 0, 2})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type dnsPacket struct {
|
type dnsPacket struct {
|
||||||
data []byte
|
data []byte
|
||||||
put func()
|
put func()
|
||||||
|
|||||||
@ -60,6 +60,9 @@ func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
|
func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
|
||||||
|
if err := h.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
udpConn, err := h.client.DialUDP(h.genHdc(ctx))
|
udpConn, err := h.client.DialUDP(h.genHdc(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -77,6 +77,9 @@ func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata) (_ C.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Hysteria2) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (h *Hysteria2) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
|
if err = h.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
pc, err := h.client.ListenPacket(ctx)
|
pc, err := h.client.ListenPacket(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -54,6 +54,9 @@ func (m *Mieru) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
|
|||||||
|
|
||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (m *Mieru) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (m *Mieru) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
|
if err = m.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := m.ensureClientIsRunning(); err != nil {
|
if err := m.ensureClientIsRunning(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/common/buf"
|
"github.com/metacubex/mihomo/common/buf"
|
||||||
@ -29,9 +30,19 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
|
|||||||
|
|
||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
|
func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (C.PacketConn, error) {
|
||||||
|
if err := r.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return newPacketConn(&nopPacketConn{}, r), nil
|
return newPacketConn(&nopPacketConn{}, r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Reject) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
|
||||||
|
if !metadata.Resolved() {
|
||||||
|
metadata.DstIP = netip.IPv4Unspecified()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func NewRejectWithOption(option RejectOption) *Reject {
|
func NewRejectWithOption(option RejectOption) *Reject {
|
||||||
return &Reject{
|
return &Reject{
|
||||||
Base: &Base{
|
Base: &Base{
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package outbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -11,7 +10,6 @@ import (
|
|||||||
"github.com/metacubex/mihomo/common/structure"
|
"github.com/metacubex/mihomo/common/structure"
|
||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/proxydialer"
|
"github.com/metacubex/mihomo/component/proxydialer"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
gost "github.com/metacubex/mihomo/transport/gost-plugin"
|
gost "github.com/metacubex/mihomo/transport/gost-plugin"
|
||||||
"github.com/metacubex/mihomo/transport/restls"
|
"github.com/metacubex/mihomo/transport/restls"
|
||||||
@ -202,6 +200,9 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err = ss.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
addr, err := resolveUDPAddr(ctx, "udp", ss.addr, ss.prefer)
|
addr, err := resolveUDPAddr(ctx, "udp", ss.addr, ss.prefer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -230,15 +231,9 @@ func (ss *ShadowSocks) ProxyInfo() C.ProxyInfo {
|
|||||||
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
||||||
func (ss *ShadowSocks) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (ss *ShadowSocks) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
if ss.option.UDPOverTCP {
|
if ss.option.UDPOverTCP {
|
||||||
// ss uot use stream-oriented udp with a special address, so we need a net.UDPAddr
|
if err = ss.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
destination := M.SocksaddrFromNet(metadata.UDPAddr())
|
destination := M.SocksaddrFromNet(metadata.UDPAddr())
|
||||||
if ss.option.UDPOverTCPVersion == uot.LegacyVersion {
|
if ss.option.UDPOverTCPVersion == uot.LegacyVersion {
|
||||||
return newPacketConn(N.NewThreadSafePacketConn(uot.NewConn(c, uot.Request{Destination: destination})), ss), nil
|
return newPacketConn(N.NewThreadSafePacketConn(uot.NewConn(c, uot.Request{Destination: destination})), ss), nil
|
||||||
|
|||||||
@ -105,6 +105,9 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err = ssr.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
addr, err := resolveUDPAddr(ctx, "udp", ssr.addr, ssr.prefer)
|
addr, err := resolveUDPAddr(ctx, "udp", ssr.addr, ssr.prefer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -2,12 +2,10 @@ package outbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
|
|
||||||
CN "github.com/metacubex/mihomo/common/net"
|
CN "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/proxydialer"
|
"github.com/metacubex/mihomo/component/proxydialer"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
|
|
||||||
@ -53,16 +51,9 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
|||||||
if s.onlyTcp {
|
if s.onlyTcp {
|
||||||
return s.ProxyAdapter.ListenPacketContext(ctx, metadata)
|
return s.ProxyAdapter.ListenPacketContext(ctx, metadata)
|
||||||
}
|
}
|
||||||
|
if err = s.ProxyAdapter.ResolveUDP(ctx, metadata); err != nil {
|
||||||
// sing-mux use stream-oriented udp with a special address, so we need a net.UDPAddr
|
return nil, err
|
||||||
if !metadata.Resolved() {
|
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pc, err := s.client.ListenPacket(ctx, M.SocksaddrFromNet(metadata.UDPAddr()))
|
pc, err := s.client.ListenPacket(ctx, M.SocksaddrFromNet(metadata.UDPAddr()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -127,6 +127,9 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err = s.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
c, err := dialer.DialContext(ctx, "tcp", s.addr)
|
c, err := dialer.DialContext(ctx, "tcp", s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@ -109,6 +109,9 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err = ss.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
c, err := cDialer.DialContext(ctx, "tcp", ss.addr)
|
c, err := cDialer.DialContext(ctx, "tcp", ss.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("%s connect error: %w", ss.addr, err)
|
err = fmt.Errorf("%s connect error: %w", ss.addr, err)
|
||||||
|
|||||||
@ -219,6 +219,10 @@ func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, met
|
|||||||
|
|
||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
|
if err = t.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var c net.Conn
|
var c net.Conn
|
||||||
|
|
||||||
// grpc transport
|
// grpc transport
|
||||||
@ -250,6 +254,9 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err = t.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
c, err := dialer.DialContext(ctx, "tcp", t.addr)
|
c, err := dialer.DialContext(ctx, "tcp", t.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
|
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
|
||||||
@ -271,12 +278,6 @@ func (t *Trojan) SupportWithDialer() C.NetWork {
|
|||||||
return C.ALLNet
|
return C.ALLNet
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
|
||||||
func (t *Trojan) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
|
||||||
pc := trojan.NewPacketConn(c)
|
|
||||||
return newPacketConn(pc, t), err
|
|
||||||
}
|
|
||||||
|
|
||||||
// SupportUOT implements C.ProxyAdapter
|
// SupportUOT implements C.ProxyAdapter
|
||||||
func (t *Trojan) SupportUOT() bool {
|
func (t *Trojan) SupportUOT() bool {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package outbound
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
@ -14,7 +13,6 @@ import (
|
|||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/ech"
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
"github.com/metacubex/mihomo/component/proxydialer"
|
"github.com/metacubex/mihomo/component/proxydialer"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/transport/tuic"
|
"github.com/metacubex/mihomo/transport/tuic"
|
||||||
@ -91,6 +89,10 @@ func (t *Tuic) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_
|
|||||||
|
|
||||||
// ListenPacketWithDialer implements C.ProxyAdapter
|
// ListenPacketWithDialer implements C.ProxyAdapter
|
||||||
func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
|
if err = t.ResolveUDP(ctx, metadata); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
if t.option.UDPOverStream {
|
if t.option.UDPOverStream {
|
||||||
uotDestination := uot.RequestDestination(uint8(t.option.UDPOverStreamVersion))
|
uotDestination := uot.RequestDestination(uint8(t.option.UDPOverStreamVersion))
|
||||||
uotMetadata := *metadata
|
uotMetadata := *metadata
|
||||||
@ -102,13 +104,6 @@ func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, meta
|
|||||||
}
|
}
|
||||||
|
|
||||||
// tuic uos use stream-oriented udp with a special address, so we need a net.UDPAddr
|
// tuic uos use stream-oriented udp with a special address, so we need a net.UDPAddr
|
||||||
if !metadata.Resolved() {
|
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
|
||||||
|
|
||||||
destination := M.SocksaddrFromNet(metadata.UDPAddr())
|
destination := M.SocksaddrFromNet(metadata.UDPAddr())
|
||||||
if t.option.UDPOverStreamVersion == uot.LegacyVersion {
|
if t.option.UDPOverStreamVersion == uot.LegacyVersion {
|
||||||
|
|||||||
@ -19,7 +19,6 @@ import (
|
|||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/ech"
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
"github.com/metacubex/mihomo/component/proxydialer"
|
"github.com/metacubex/mihomo/component/proxydialer"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/transport/gun"
|
"github.com/metacubex/mihomo/transport/gun"
|
||||||
@ -277,13 +276,8 @@ func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
|
|||||||
|
|
||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
// vless use stream-oriented udp with a special address, so we need a net.UDPAddr
|
if err = v.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
var c net.Conn
|
var c net.Conn
|
||||||
// gun transport
|
// gun transport
|
||||||
@ -315,13 +309,8 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vless use stream-oriented udp with a special address, so we need a net.UDPAddr
|
if err = v.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := dialer.DialContext(ctx, "tcp", v.addr)
|
c, err := dialer.DialContext(ctx, "tcp", v.addr)
|
||||||
@ -347,13 +336,8 @@ func (v *Vless) SupportWithDialer() C.NetWork {
|
|||||||
|
|
||||||
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
||||||
func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
// vless use stream-oriented udp with a special address, so we need a net.UDPAddr
|
if err = v.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.option.XUDP {
|
if v.option.XUDP {
|
||||||
|
|||||||
@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/metacubex/mihomo/component/dialer"
|
"github.com/metacubex/mihomo/component/dialer"
|
||||||
"github.com/metacubex/mihomo/component/ech"
|
"github.com/metacubex/mihomo/component/ech"
|
||||||
"github.com/metacubex/mihomo/component/proxydialer"
|
"github.com/metacubex/mihomo/component/proxydialer"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
|
||||||
tlsC "github.com/metacubex/mihomo/component/tls"
|
tlsC "github.com/metacubex/mihomo/component/tls"
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/ntp"
|
"github.com/metacubex/mihomo/ntp"
|
||||||
@ -330,13 +329,8 @@ func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
|
|||||||
|
|
||||||
// ListenPacketContext implements C.ProxyAdapter
|
// ListenPacketContext implements C.ProxyAdapter
|
||||||
func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
// vmess use stream-oriented udp with a special address, so we need a net.UDPAddr
|
if err = v.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
var c net.Conn
|
var c net.Conn
|
||||||
// gun transport
|
// gun transport
|
||||||
@ -367,13 +361,8 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vmess use stream-oriented udp with a special address, so we need a net.UDPAddr
|
if err = v.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := dialer.DialContext(ctx, "tcp", v.addr)
|
c, err := dialer.DialContext(ctx, "tcp", v.addr)
|
||||||
@ -413,13 +402,8 @@ func (v *Vmess) Close() error {
|
|||||||
|
|
||||||
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
// ListenPacketOnStreamConn implements C.ProxyAdapter
|
||||||
func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) {
|
||||||
// vmess use stream-oriented udp with a special address, so we need a net.UDPAddr
|
if err = v.ResolveUDP(ctx, metadata); err != nil {
|
||||||
if !metadata.Resolved() {
|
return nil, err
|
||||||
ip, err := resolver.ResolveIP(ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if pc, ok := c.(net.PacketConn); ok {
|
if pc, ok := c.(net.PacketConn); ok {
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@ -520,16 +519,8 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat
|
|||||||
if err = w.init(ctx); err != nil {
|
if err = w.init(ctx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if (!metadata.Resolved() || w.resolver != nil) && metadata.Host != "" {
|
if err = w.ResolveUDP(ctx, metadata); err != nil {
|
||||||
r := resolver.DefaultResolver
|
return nil, err
|
||||||
if w.resolver != nil {
|
|
||||||
r = w.resolver
|
|
||||||
}
|
|
||||||
ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("can't resolve ip")
|
|
||||||
}
|
|
||||||
metadata.DstIP = ip
|
|
||||||
}
|
}
|
||||||
pc, err = w.tunDevice.ListenPacket(ctx, M.SocksaddrFrom(metadata.DstIP, metadata.DstPort).Unwrap())
|
pc, err = w.tunDevice.ListenPacket(ctx, M.SocksaddrFrom(metadata.DstIP, metadata.DstPort).Unwrap())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -541,6 +532,21 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat
|
|||||||
return newPacketConn(pc, w), nil
|
return newPacketConn(pc, w), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *WireGuard) ResolveUDP(ctx context.Context, metadata *C.Metadata) error {
|
||||||
|
if (!metadata.Resolved() || w.resolver != nil) && metadata.Host != "" {
|
||||||
|
r := resolver.DefaultResolver
|
||||||
|
if w.resolver != nil {
|
||||||
|
r = w.resolver
|
||||||
|
}
|
||||||
|
ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("can't resolve ip: %w", err)
|
||||||
|
}
|
||||||
|
metadata.DstIP = ip
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsL3Protocol implements C.ProxyAdapter
|
// IsL3Protocol implements C.ProxyAdapter
|
||||||
func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool {
|
func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -76,9 +76,9 @@ func (sniffer *QuicSniffer) SniffData(b []byte) (string, error) {
|
|||||||
|
|
||||||
func (sniffer *QuicSniffer) WrapperSender(packetSender constant.PacketSender, override bool) constant.PacketSender {
|
func (sniffer *QuicSniffer) WrapperSender(packetSender constant.PacketSender, override bool) constant.PacketSender {
|
||||||
return &quicPacketSender{
|
return &quicPacketSender{
|
||||||
sender: packetSender,
|
PacketSender: packetSender,
|
||||||
chClose: make(chan struct{}),
|
chClose: make(chan struct{}),
|
||||||
override: override,
|
override: override,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ type quicPacketSender struct {
|
|||||||
result string
|
result string
|
||||||
override bool
|
override bool
|
||||||
|
|
||||||
sender constant.PacketSender
|
constant.PacketSender
|
||||||
|
|
||||||
chClose chan struct{}
|
chClose chan struct{}
|
||||||
closed bool
|
closed bool
|
||||||
@ -100,7 +100,7 @@ type quicPacketSender struct {
|
|||||||
// Send will send PacketAdapter nonblocking
|
// Send will send PacketAdapter nonblocking
|
||||||
// the implement must call UDPPacket.Drop() inside Send
|
// the implement must call UDPPacket.Drop() inside Send
|
||||||
func (q *quicPacketSender) Send(current constant.PacketAdapter) {
|
func (q *quicPacketSender) Send(current constant.PacketAdapter) {
|
||||||
defer q.sender.Send(current)
|
defer q.PacketSender.Send(current)
|
||||||
|
|
||||||
q.lock.RLock()
|
q.lock.RLock()
|
||||||
if q.closed {
|
if q.closed {
|
||||||
@ -116,29 +116,24 @@ func (q *quicPacketSender) Send(current constant.PacketAdapter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process is a blocking loop to send PacketAdapter to PacketConn and update the WriteBackProxy
|
// DoSniff wait sniffer recv all fragments and update the domain
|
||||||
func (q *quicPacketSender) Process(conn constant.PacketConn, proxy constant.WriteBackProxy) {
|
func (q *quicPacketSender) DoSniff(metadata *constant.Metadata) error {
|
||||||
q.sender.Process(conn, proxy)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResolveUDP wait sniffer recv all fragments and update the domain
|
|
||||||
func (q *quicPacketSender) ResolveUDP(data *constant.Metadata) error {
|
|
||||||
select {
|
select {
|
||||||
case <-q.chClose:
|
case <-q.chClose:
|
||||||
q.lock.RLock()
|
q.lock.RLock()
|
||||||
replaceDomain(data, q.result, q.override)
|
replaceDomain(metadata, q.result, q.override)
|
||||||
q.lock.RUnlock()
|
q.lock.RUnlock()
|
||||||
break
|
break
|
||||||
case <-time.After(quicWaitConn):
|
case <-time.After(quicWaitConn):
|
||||||
q.close()
|
q.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
return q.sender.ResolveUDP(data)
|
return q.PacketSender.DoSniff(metadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close stop the Process loop
|
// Close stop the Process loop
|
||||||
func (q *quicPacketSender) Close() {
|
func (q *quicPacketSender) Close() {
|
||||||
q.sender.Close()
|
q.PacketSender.Close()
|
||||||
q.close()
|
q.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type fakeSender struct {
|
type fakeSender struct {
|
||||||
resultCh chan *constant.Metadata
|
constant.PacketSender
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ constant.PacketSender = (*fakeSender)(nil)
|
var _ constant.PacketSender = (*fakeSender)(nil)
|
||||||
@ -22,18 +22,7 @@ func (e *fakeSender) Send(packet constant.PacketAdapter) {
|
|||||||
packet.Drop()
|
packet.Drop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *fakeSender) Process(constant.PacketConn, constant.WriteBackProxy) {
|
func (e *fakeSender) DoSniff(metadata *constant.Metadata) error { return nil }
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *fakeSender) ResolveUDP(metadata *constant.Metadata) error {
|
|
||||||
e.resultCh <- metadata
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *fakeSender) Close() {
|
|
||||||
panic("not implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
type fakeUDPPacket struct {
|
type fakeUDPPacket struct {
|
||||||
data []byte
|
data []byte
|
||||||
@ -85,16 +74,17 @@ func testQuicSniffer(data []string, async bool) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resultCh := make(chan *constant.Metadata, 1)
|
resultCh := make(chan *constant.Metadata, 1)
|
||||||
emptySender := &fakeSender{resultCh: resultCh}
|
emptySender := &fakeSender{}
|
||||||
|
|
||||||
sender := q.WrapperSender(emptySender, true)
|
sender := q.WrapperSender(emptySender, true)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
meta := constant.Metadata{}
|
meta := constant.Metadata{}
|
||||||
err = sender.ResolveUDP(&meta)
|
err := sender.DoSniff(&meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
resultCh <- &meta
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for _, d := range data {
|
for _, d := range data {
|
||||||
|
|||||||
@ -92,8 +92,7 @@ type Conn interface {
|
|||||||
type PacketConn interface {
|
type PacketConn interface {
|
||||||
N.EnhancePacketConn
|
N.EnhancePacketConn
|
||||||
Connection
|
Connection
|
||||||
// Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed
|
ResolveUDP(ctx context.Context, metadata *Metadata) error
|
||||||
// WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Dialer interface {
|
type Dialer interface {
|
||||||
@ -319,10 +318,15 @@ type PacketSender interface {
|
|||||||
Send(PacketAdapter)
|
Send(PacketAdapter)
|
||||||
// Process is a blocking loop to send PacketAdapter to PacketConn and update the WriteBackProxy
|
// Process is a blocking loop to send PacketAdapter to PacketConn and update the WriteBackProxy
|
||||||
Process(PacketConn, WriteBackProxy)
|
Process(PacketConn, WriteBackProxy)
|
||||||
// ResolveUDP do a local resolve UDP dns blocking if metadata is not resolved
|
|
||||||
ResolveUDP(*Metadata) error
|
|
||||||
// Close stop the Process loop
|
// Close stop the Process loop
|
||||||
Close()
|
Close()
|
||||||
|
// DoSniff will blocking after sniffer work done
|
||||||
|
DoSniff(*Metadata) error
|
||||||
|
// AddMapping add a destination NAT record
|
||||||
|
AddMapping(originMetadata *Metadata, metadata *Metadata)
|
||||||
|
// RestoreReadFrom restore destination NAT for ReadFrom
|
||||||
|
// the implement must ensure returned netip.Add is valid (or just return input addr)
|
||||||
|
RestoreReadFrom(addr netip.Addr) netip.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
type NatTable interface {
|
type NatTable interface {
|
||||||
|
|||||||
@ -261,6 +261,11 @@ func (m *Metadata) Pure() *Metadata {
|
|||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Metadata) Clone() *Metadata {
|
||||||
|
copyM := *m
|
||||||
|
return ©M
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Metadata) AddrPort() netip.AddrPort {
|
func (m *Metadata) AddrPort() netip.AddrPort {
|
||||||
return netip.AddrPortFrom(m.DstIP.Unmap(), m.DstPort)
|
return netip.AddrPortFrom(m.DstIP.Unmap(), m.DstPort)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/metacubex/mihomo/common/lru"
|
|
||||||
N "github.com/metacubex/mihomo/common/net"
|
N "github.com/metacubex/mihomo/common/net"
|
||||||
"github.com/metacubex/mihomo/component/resolver"
|
|
||||||
C "github.com/metacubex/mihomo/constant"
|
C "github.com/metacubex/mihomo/constant"
|
||||||
"github.com/metacubex/mihomo/log"
|
"github.com/metacubex/mihomo/log"
|
||||||
)
|
)
|
||||||
@ -18,7 +17,11 @@ type packetSender struct {
|
|||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
ch chan C.PacketAdapter
|
ch chan C.PacketAdapter
|
||||||
cache *lru.LruCache[string, netip.Addr]
|
|
||||||
|
// destination NAT mapping
|
||||||
|
originToTarget map[string]netip.Addr
|
||||||
|
targetToOrigin map[netip.Addr]netip.Addr
|
||||||
|
mappingMutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// newPacketSender return a chan based C.PacketSender
|
// newPacketSender return a chan based C.PacketSender
|
||||||
@ -30,10 +33,74 @@ func newPacketSender() C.PacketSender {
|
|||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
ch: ch,
|
ch: ch,
|
||||||
cache: lru.New[string, netip.Addr](lru.WithSize[string, netip.Addr](senderCapacity)),
|
|
||||||
|
originToTarget: make(map[string]netip.Addr),
|
||||||
|
targetToOrigin: make(map[netip.Addr]netip.Addr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *packetSender) AddMapping(originMetadata *C.Metadata, metadata *C.Metadata) {
|
||||||
|
s.mappingMutex.Lock()
|
||||||
|
defer s.mappingMutex.Unlock()
|
||||||
|
originKey := originMetadata.String()
|
||||||
|
originAddr := originMetadata.DstIP
|
||||||
|
targetAddr := metadata.DstIP
|
||||||
|
if addr := s.originToTarget[originKey]; !addr.IsValid() { // overwrite only if the record is illegal
|
||||||
|
s.originToTarget[originKey] = targetAddr
|
||||||
|
}
|
||||||
|
if addr := s.targetToOrigin[targetAddr]; !addr.IsValid() { // overwrite only if the record is illegal
|
||||||
|
s.targetToOrigin[targetAddr] = originAddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *packetSender) RestoreReadFrom(addr netip.Addr) netip.Addr {
|
||||||
|
s.mappingMutex.RLock()
|
||||||
|
defer s.mappingMutex.RUnlock()
|
||||||
|
if originAddr := s.targetToOrigin[addr]; originAddr.IsValid() {
|
||||||
|
return originAddr
|
||||||
|
}
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *packetSender) processPacket(pc C.PacketConn, packet C.PacketAdapter) {
|
||||||
|
defer packet.Drop()
|
||||||
|
metadata := packet.Metadata()
|
||||||
|
|
||||||
|
var addr *net.UDPAddr
|
||||||
|
|
||||||
|
s.mappingMutex.RLock()
|
||||||
|
targetAddr := s.originToTarget[metadata.String()]
|
||||||
|
s.mappingMutex.RUnlock()
|
||||||
|
|
||||||
|
if targetAddr.IsValid() {
|
||||||
|
addr = net.UDPAddrFromAddrPort(netip.AddrPortFrom(targetAddr, metadata.DstPort))
|
||||||
|
}
|
||||||
|
|
||||||
|
if addr == nil {
|
||||||
|
originMetadata := metadata // save origin metadata
|
||||||
|
metadata = metadata.Clone() // don't modify PacketAdapter's metadata
|
||||||
|
|
||||||
|
_ = preHandleMetadata(metadata) // error was pre-checked
|
||||||
|
metadata = metadata.Pure()
|
||||||
|
if metadata.Host != "" {
|
||||||
|
// TODO: ResolveUDP may take a long time to block the Process loop
|
||||||
|
// but we want keep sequence sending so can't open a new goroutine
|
||||||
|
if err := pc.ResolveUDP(s.ctx, metadata); err != nil {
|
||||||
|
log.Warnln("[UDP] Resolve Ip error: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !metadata.DstIP.IsValid() {
|
||||||
|
log.Warnln("[UDP] Destination ip not valid: %#v", metadata)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.AddMapping(originMetadata, metadata)
|
||||||
|
addr = metadata.UDPAddr()
|
||||||
|
}
|
||||||
|
_ = handleUDPToRemote(packet, pc, addr)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *packetSender) Process(pc C.PacketConn, proxy C.WriteBackProxy) {
|
func (s *packetSender) Process(pc C.PacketConn, proxy C.WriteBackProxy) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -43,12 +110,7 @@ func (s *packetSender) Process(pc C.PacketConn, proxy C.WriteBackProxy) {
|
|||||||
if proxy != nil {
|
if proxy != nil {
|
||||||
proxy.UpdateWriteBack(packet)
|
proxy.UpdateWriteBack(packet)
|
||||||
}
|
}
|
||||||
if err := s.ResolveUDP(packet.Metadata()); err != nil {
|
s.processPacket(pc, packet)
|
||||||
log.Warnln("[UDP] Resolve Ip error: %s", err)
|
|
||||||
} else {
|
|
||||||
_ = handleUDPToRemote(packet, pc, packet.Metadata())
|
|
||||||
}
|
|
||||||
packet.Drop()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,25 +149,9 @@ func (s *packetSender) Close() {
|
|||||||
s.dropAll()
|
s.dropAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *packetSender) ResolveUDP(metadata *C.Metadata) (err error) {
|
func (s *packetSender) DoSniff(metadata *C.Metadata) error { return nil }
|
||||||
// local resolve UDP dns
|
|
||||||
if !metadata.Resolved() {
|
|
||||||
ip, ok := s.cache.Get(metadata.Host)
|
|
||||||
if !ok {
|
|
||||||
ip, err = resolver.ResolveIP(s.ctx, metadata.Host)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.cache.Set(metadata.Host, ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata.DstIP = ip
|
func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, addr *net.UDPAddr) error {
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error {
|
|
||||||
addr := metadata.UDPAddr()
|
|
||||||
if addr == nil {
|
if addr == nil {
|
||||||
return errors.New("udp addr invalid")
|
return errors.New("udp addr invalid")
|
||||||
}
|
}
|
||||||
@ -119,7 +165,7 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUDPToLocal(writeBack C.WriteBack, pc N.EnhancePacketConn, sender C.PacketSender, key string, oAddrPort netip.AddrPort, fAddr netip.Addr) {
|
func handleUDPToLocal(writeBack C.WriteBack, pc C.PacketConn, sender C.PacketSender, key string, oAddrPort netip.AddrPort) {
|
||||||
defer func() {
|
defer func() {
|
||||||
sender.Close()
|
sender.Close()
|
||||||
_ = pc.Close()
|
_ = pc.Close()
|
||||||
@ -146,10 +192,8 @@ func handleUDPToLocal(writeBack C.WriteBack, pc N.EnhancePacketConn, sender C.Pa
|
|||||||
fromAddrPort := fromUDPAddr.AddrPort()
|
fromAddrPort := fromUDPAddr.AddrPort()
|
||||||
fromAddr := fromAddrPort.Addr().Unmap()
|
fromAddr := fromAddrPort.Addr().Unmap()
|
||||||
|
|
||||||
// restore fakeip
|
// restore DestinationNAT
|
||||||
if fAddr.IsValid() && (oAddrPort.Addr() == fromAddr) { // oAddrPort was Unmapped
|
fromAddr = sender.RestoreReadFrom(fromAddr).Unmap()
|
||||||
fromAddr = fAddr.Unmap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fromAddrPort = netip.AddrPortFrom(fromAddr, fromAddrPort.Port())
|
fromAddrPort = netip.AddrPortFrom(fromAddr, fromAddrPort.Port())
|
||||||
|
|
||||||
|
|||||||
@ -366,15 +366,9 @@ func handleUDPConn(packet C.PacketAdapter) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// make a fAddr if request ip is fakeip
|
if err := preHandleMetadata(metadata.Clone()); err != nil { // precheck without modify metadata
|
||||||
var fAddr netip.Addr
|
|
||||||
if resolver.IsExistFakeIP(metadata.DstIP) {
|
|
||||||
fAddr = metadata.DstIP
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := preHandleMetadata(metadata); err != nil {
|
|
||||||
packet.Drop()
|
packet.Drop()
|
||||||
log.Debugln("[Metadata PreHandle] error: %s", err)
|
log.Warnln("[Metadata PreHandle] error: %s", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,21 +382,27 @@ func handleUDPConn(packet C.PacketAdapter) {
|
|||||||
})
|
})
|
||||||
if !loaded {
|
if !loaded {
|
||||||
dial := func() (C.PacketConn, C.WriteBackProxy, error) {
|
dial := func() (C.PacketConn, C.WriteBackProxy, error) {
|
||||||
if err := sender.ResolveUDP(metadata); err != nil {
|
originMetadata := metadata // save origin metadata
|
||||||
log.Warnln("[UDP] Resolve Ip error: %s", err)
|
metadata = metadata.Clone() // don't modify PacketAdapter's metadata
|
||||||
|
|
||||||
|
if err := sender.DoSniff(metadata); err != nil {
|
||||||
|
log.Warnln("[UDP] DoSniff error: %s", err.Error())
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = preHandleMetadata(metadata) // error was pre-checked
|
||||||
|
|
||||||
proxy, rule, err := resolveMetadata(metadata)
|
proxy, rule, err := resolveMetadata(metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnln("[UDP] Parse metadata failed: %s", err.Error())
|
log.Warnln("[UDP] Parse metadata failed: %s", err.Error())
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialMetadata := metadata.Pure()
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) {
|
rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) {
|
||||||
return proxy.ListenPacketContext(ctx, metadata.Pure())
|
return proxy.ListenPacketContext(ctx, dialMetadata)
|
||||||
}, func(err error) {
|
}, func(err error) {
|
||||||
logMetadataErr(metadata, rule, proxy, err)
|
logMetadataErr(metadata, rule, proxy, err)
|
||||||
})
|
})
|
||||||
@ -413,10 +413,11 @@ func handleUDPConn(packet C.PacketAdapter) {
|
|||||||
|
|
||||||
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true)
|
pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true)
|
||||||
|
|
||||||
oAddrPort := metadata.AddrPort()
|
sender.AddMapping(originMetadata, dialMetadata)
|
||||||
|
oAddrPort := dialMetadata.AddrPort()
|
||||||
writeBackProxy := nat.NewWriteBackProxy(packet)
|
writeBackProxy := nat.NewWriteBackProxy(packet)
|
||||||
|
|
||||||
go handleUDPToLocal(writeBackProxy, pc, sender, key, oAddrPort, fAddr)
|
go handleUDPToLocal(writeBackProxy, pc, sender, key, oAddrPort)
|
||||||
return pc, writeBackProxy, nil
|
return pc, writeBackProxy, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user