123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- package outbound
- import (
- "context"
- "errors"
- "runtime"
- CN "github.com/metacubex/mihomo/common/net"
- "github.com/metacubex/mihomo/component/dialer"
- "github.com/metacubex/mihomo/component/proxydialer"
- "github.com/metacubex/mihomo/component/resolver"
- C "github.com/metacubex/mihomo/constant"
- "github.com/metacubex/mihomo/log"
- mux "github.com/sagernet/sing-mux"
- E "github.com/sagernet/sing/common/exceptions"
- M "github.com/sagernet/sing/common/metadata"
- )
- type SingMux struct {
- C.ProxyAdapter
- base ProxyBase
- client *mux.Client
- dialer proxydialer.SingDialer
- onlyTcp bool
- }
- type SingMuxOption struct {
- Enabled bool `proxy:"enabled,omitempty"`
- Protocol string `proxy:"protocol,omitempty"`
- MaxConnections int `proxy:"max-connections,omitempty"`
- MinStreams int `proxy:"min-streams,omitempty"`
- MaxStreams int `proxy:"max-streams,omitempty"`
- Padding bool `proxy:"padding,omitempty"`
- Statistic bool `proxy:"statistic,omitempty"`
- OnlyTcp bool `proxy:"only-tcp,omitempty"`
- BrutalOpts BrutalOption `proxy:"brutal-opts,omitempty"`
- }
- type BrutalOption struct {
- Enabled bool `proxy:"enabled,omitempty"`
- Up string `proxy:"up,omitempty"`
- Down string `proxy:"down,omitempty"`
- }
- type ProxyBase interface {
- DialOptions(opts ...dialer.Option) []dialer.Option
- }
- func (s *SingMux) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) {
- options := s.base.DialOptions(opts...)
- s.dialer.SetDialer(dialer.NewDialer(options...))
- c, err := s.client.DialContext(ctx, "tcp", M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort))
- if err != nil {
- return nil, err
- }
- return NewConn(CN.NewRefConn(c, s), s.ProxyAdapter), err
- }
- func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) {
- if s.onlyTcp {
- return s.ProxyAdapter.ListenPacketContext(ctx, metadata, opts...)
- }
- options := s.base.DialOptions(opts...)
- s.dialer.SetDialer(dialer.NewDialer(options...))
- // sing-mux 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
- }
- pc, err := s.client.ListenPacket(ctx, M.SocksaddrFromNet(metadata.UDPAddr()))
- if err != nil {
- return nil, err
- }
- if pc == nil {
- return nil, E.New("packetConn is nil")
- }
- return newPacketConn(CN.NewRefPacketConn(CN.NewThreadSafePacketConn(pc), s), s.ProxyAdapter), nil
- }
- func (s *SingMux) SupportUDP() bool {
- if s.onlyTcp {
- return s.ProxyAdapter.SupportUDP()
- }
- return true
- }
- func (s *SingMux) SupportUOT() bool {
- if s.onlyTcp {
- return s.ProxyAdapter.SupportUOT()
- }
- return true
- }
- func closeSingMux(s *SingMux) {
- _ = s.client.Close()
- }
- func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) {
- // TODO
- // "TCP Brutal is only supported on Linux-based systems"
- singDialer := proxydialer.NewSingDialer(proxy, dialer.NewDialer(), option.Statistic)
- client, err := mux.NewClient(mux.Options{
- Dialer: singDialer,
- Logger: log.SingLogger,
- Protocol: option.Protocol,
- MaxConnections: option.MaxConnections,
- MinStreams: option.MinStreams,
- MaxStreams: option.MaxStreams,
- Padding: option.Padding,
- Brutal: mux.BrutalOptions{
- Enabled: option.BrutalOpts.Enabled,
- SendBPS: StringToBps(option.BrutalOpts.Up),
- ReceiveBPS: StringToBps(option.BrutalOpts.Down),
- },
- })
- if err != nil {
- return nil, err
- }
- outbound := &SingMux{
- ProxyAdapter: proxy,
- base: base,
- client: client,
- dialer: singDialer,
- onlyTcp: option.OnlyTcp,
- }
- runtime.SetFinalizer(outbound, closeSingMux)
- return outbound, nil
- }
|