clash/adapter/outbound/base.go

280 lines
6.6 KiB
Go
Raw Normal View History

2021-06-10 06:05:56 +00:00
package outbound
import (
"context"
2021-06-10 06:05:56 +00:00
"encoding/json"
"net"
"strings"
"syscall"
2021-06-10 06:05:56 +00:00
N "github.com/Dreamacro/clash/common/net"
2023-03-05 03:00:14 +00:00
"github.com/Dreamacro/clash/common/utils"
"github.com/Dreamacro/clash/component/dialer"
2021-06-10 06:05:56 +00:00
C "github.com/Dreamacro/clash/constant"
)
type Base struct {
2022-08-28 05:41:19 +00:00
name string
addr string
iface string
tp C.AdapterType
udp bool
xudp bool
tfo bool
2022-08-28 05:41:19 +00:00
rmark int
id string
prefer C.DNSPrefer
2021-06-10 06:05:56 +00:00
}
// Name implements C.ProxyAdapter
func (b *Base) Name() string {
return b.name
}
2022-05-17 08:47:21 +00:00
// Id implements C.ProxyAdapter
func (b *Base) Id() string {
if b.id == "" {
2023-03-15 02:10:03 +00:00
b.id = utils.NewUUIDV6().String()
2022-05-17 08:47:21 +00:00
}
return b.id
}
2021-06-10 06:05:56 +00:00
// Type implements C.ProxyAdapter
func (b *Base) Type() C.AdapterType {
return b.tp
}
// StreamConnContext implements C.ProxyAdapter
func (b *Base) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
return c, C.ErrNotSupport
2021-06-10 06:05:56 +00:00
}
2022-05-30 13:55:09 +00:00
func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) {
return nil, C.ErrNotSupport
2022-05-30 13:55:09 +00:00
}
2022-12-19 13:34:07 +00:00
// DialContextWithDialer implements C.ProxyAdapter
func (b *Base) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) {
return nil, C.ErrNotSupport
2022-12-19 13:34:07 +00:00
}
// ListenPacketContext implements C.ProxyAdapter
func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) {
return nil, C.ErrNotSupport
2021-06-10 06:05:56 +00:00
}
2022-12-19 13:34:07 +00:00
// ListenPacketWithDialer implements C.ProxyAdapter
func (b *Base) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) {
return nil, C.ErrNotSupport
}
2022-12-19 13:34:07 +00:00
// SupportWithDialer implements C.ProxyAdapter
func (b *Base) SupportWithDialer() C.NetWork {
return C.InvalidNet
}
// SupportUOT implements C.ProxyAdapter
func (b *Base) SupportUOT() bool {
return false
}
2021-06-10 06:05:56 +00:00
// SupportUDP implements C.ProxyAdapter
func (b *Base) SupportUDP() bool {
return b.udp
}
// SupportXUDP implements C.ProxyAdapter
func (b *Base) SupportXUDP() bool {
return b.xudp
}
// SupportTFO implements C.ProxyAdapter
func (b *Base) SupportTFO() bool {
return b.tfo
}
// IsL3Protocol implements C.ProxyAdapter
func (b *Base) IsL3Protocol(metadata *C.Metadata) bool {
return false
}
2021-06-10 06:05:56 +00:00
// MarshalJSON implements C.ProxyAdapter
func (b *Base) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]string{
"type": b.Type().String(),
2022-05-17 08:47:21 +00:00
"id": b.Id(),
2021-06-10 06:05:56 +00:00
})
}
// Addr implements C.ProxyAdapter
func (b *Base) Addr() string {
return b.addr
}
// Unwrap implements C.ProxyAdapter
2022-10-30 15:08:18 +00:00
func (b *Base) Unwrap(metadata *C.Metadata, touch bool) C.Proxy {
2021-06-10 06:05:56 +00:00
return nil
}
// DialOptions return []dialer.Option from struct
func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option {
if b.iface != "" {
opts = append(opts, dialer.WithInterface(b.iface))
}
2021-11-08 08:59:48 +00:00
if b.rmark != 0 {
opts = append(opts, dialer.WithRoutingMark(b.rmark))
}
2022-08-28 05:41:19 +00:00
switch b.prefer {
case C.IPv4Only:
opts = append(opts, dialer.WithOnlySingleStack(true))
case C.IPv6Only:
opts = append(opts, dialer.WithOnlySingleStack(false))
case C.IPv4Prefer:
opts = append(opts, dialer.WithPreferIPv4())
case C.IPv6Prefer:
opts = append(opts, dialer.WithPreferIPv6())
default:
}
2023-02-24 05:53:44 +00:00
if b.tfo {
opts = append(opts, dialer.WithTFO(true))
}
return opts
}
type BasicOption struct {
2023-02-24 05:53:44 +00:00
TFO bool `proxy:"tfo,omitempty" group:"tfo,omitempty"`
2021-11-08 08:59:48 +00:00
Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"`
RoutingMark int `proxy:"routing-mark,omitempty" group:"routing-mark,omitempty"`
2022-08-28 05:41:19 +00:00
IPVersion string `proxy:"ip-version,omitempty" group:"ip-version,omitempty"`
DialerProxy string `proxy:"dialer-proxy,omitempty"` // don't apply this option into groups, but can set a group name in a proxy
}
type BaseOption struct {
2021-11-08 08:59:48 +00:00
Name string
Addr string
Type C.AdapterType
UDP bool
XUDP bool
TFO bool
2021-11-08 08:59:48 +00:00
Interface string
RoutingMark int
2022-08-28 05:41:19 +00:00
Prefer C.DNSPrefer
}
func NewBase(opt BaseOption) *Base {
return &Base{
2022-08-28 05:41:19 +00:00
name: opt.Name,
addr: opt.Addr,
tp: opt.Type,
udp: opt.UDP,
xudp: opt.XUDP,
tfo: opt.TFO,
2022-08-28 05:41:19 +00:00
iface: opt.Interface,
rmark: opt.RoutingMark,
prefer: opt.Prefer,
}
2021-06-10 06:05:56 +00:00
}
type conn struct {
N.ExtendedConn
chain C.Chain
actualRemoteDestination string
2022-05-26 15:41:09 +00:00
}
func (c *conn) RemoteDestination() string {
return c.actualRemoteDestination
2021-06-10 06:05:56 +00:00
}
// Chains implements C.Connection
func (c *conn) Chains() C.Chain {
return c.chain
}
// AppendToChains implements C.Connection
func (c *conn) AppendToChains(a C.ProxyAdapter) {
c.chain = append(c.chain, a.Name())
}
2023-01-16 01:42:03 +00:00
func (c *conn) Upstream() any {
return c.ExtendedConn
}
func (c *conn) WriterReplaceable() bool {
return true
}
func (c *conn) ReaderReplaceable() bool {
return true
}
2021-06-10 06:05:56 +00:00
func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn
c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly
}
return &conn{N.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())}
2021-06-10 06:05:56 +00:00
}
type packetConn struct {
N.EnhancePacketConn
chain C.Chain
adapterName string
connID string
actualRemoteDestination string
2022-05-26 15:41:09 +00:00
}
func (c *packetConn) RemoteDestination() string {
return c.actualRemoteDestination
2021-06-10 06:05:56 +00:00
}
// Chains implements C.Connection
func (c *packetConn) Chains() C.Chain {
return c.chain
}
// AppendToChains implements C.Connection
func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
c.chain = append(c.chain, a.Name())
}
func (c *packetConn) LocalAddr() net.Addr {
lAddr := c.EnhancePacketConn.LocalAddr()
return N.NewCustomAddr(c.adapterName, c.connID, lAddr) // make quic-go's connMultiplexer happy
}
func (c *packetConn) Upstream() any {
return c.EnhancePacketConn
}
func (c *packetConn) WriterReplaceable() bool {
return true
}
func (c *packetConn) ReaderReplaceable() bool {
return true
}
2021-06-10 06:05:56 +00:00
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
epc := N.NewEnhancePacketConn(pc)
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
}
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())}
}
func parseRemoteDestination(addr string) string {
if dst, _, err := net.SplitHostPort(addr); err == nil {
return dst
} else {
if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
return dst
} else {
return ""
}
}
2021-06-10 06:05:56 +00:00
}