mihomo/component/proxydialer/proxydialer.go

67 lines
1.9 KiB
Go

package proxydialer
import (
"context"
"net"
"net/netip"
"strings"
N "github.com/metacubex/mihomo/common/net"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/tunnel/statistic"
)
type proxyDialer struct {
proxy C.ProxyAdapter
statistic bool
}
func New(proxy C.ProxyAdapter, statistic bool) C.Dialer {
return proxyDialer{proxy: proxy, statistic: statistic}
}
func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
currentMeta := &C.Metadata{Type: C.INNER}
if err := currentMeta.SetRemoteAddress(address); err != nil {
return nil, err
}
if strings.Contains(network, "udp") { // using in wireguard outbound
pc, err := p.listenPacket(ctx, currentMeta)
if err != nil {
return nil, err
}
if !currentMeta.Resolved() { // should not happen, maybe by a wrongly implemented proxy, but we can handle this (:
err = pc.ResolveUDP(ctx, currentMeta)
if err != nil {
return nil, err
}
}
return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil
}
conn, err := p.proxy.DialContext(ctx, currentMeta)
if err != nil {
return nil, err
}
if p.statistic {
conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, currentMeta, nil, 0, 0, false)
}
return conn, err
}
func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) {
currentMeta := &C.Metadata{Type: C.INNER, DstIP: rAddrPort.Addr(), DstPort: rAddrPort.Port()}
return p.listenPacket(ctx, currentMeta)
}
func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (C.PacketConn, error) {
currentMeta.NetWork = C.UDP
pc, err := p.proxy.ListenPacketContext(ctx, currentMeta)
if err != nil {
return nil, err
}
if p.statistic {
pc = statistic.NewUDPTracker(pc, statistic.DefaultManager, currentMeta, nil, 0, 0, false)
}
return pc, nil
}