github.com/yaling888/clash@v1.53.0/listener/mitm/server.go (about)

     1  package mitm
     2  
     3  import (
     4  	"crypto/rsa"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"net"
     8  	"os"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/phuslu/log"
    13  	"go.uber.org/atomic"
    14  
    15  	"github.com/yaling888/clash/adapter/outbound"
    16  	"github.com/yaling888/clash/common/cache"
    17  	"github.com/yaling888/clash/common/cert"
    18  	"github.com/yaling888/clash/component/auth"
    19  	C "github.com/yaling888/clash/constant"
    20  	authStore "github.com/yaling888/clash/listener/auth"
    21  	"github.com/yaling888/clash/mitm"
    22  	"github.com/yaling888/clash/tunnel"
    23  )
    24  
    25  var proxyDone = atomic.NewUint32(0)
    26  
    27  type Listener struct {
    28  	listener net.Listener
    29  	addr     string
    30  	auth     auth.Authenticator
    31  	closed   bool
    32  	asProxy  bool
    33  }
    34  
    35  // RawAddress implements C.Listener
    36  func (l *Listener) RawAddress() string {
    37  	return l.addr
    38  }
    39  
    40  // Address implements C.Listener
    41  func (l *Listener) Address() string {
    42  	return l.listener.Addr().String()
    43  }
    44  
    45  // Close implements C.Listener
    46  func (l *Listener) Close() error {
    47  	if l.asProxy {
    48  		l.asProxy = false
    49  		tunnel.SetMitmOutbound(nil)
    50  		proxyDone.Store(0)
    51  	}
    52  	l.closed = true
    53  	return l.listener.Close()
    54  }
    55  
    56  // SetAuthenticator implements C.AuthenticatorListener
    57  func (l *Listener) SetAuthenticator(users []auth.AuthUser) {
    58  	l.auth = auth.NewAuthenticator(users)
    59  }
    60  
    61  func New(addr string, in chan<- C.ConnContext) (C.Listener, error) {
    62  	mitmOption, err := initOption()
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	ml, err := NewWithAuthenticate(addr, mitmOption, in, true)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  
    72  	if proxyDone.Load() == 0 {
    73  		ml.asProxy = true
    74  		proxyDone.Store(1)
    75  		auths := ml.auth
    76  		if auths == nil {
    77  			auths = authStore.Authenticator()
    78  		}
    79  		tunnel.SetMitmOutbound(outbound.NewMitm(ml.Address(), auths))
    80  	}
    81  
    82  	return ml, nil
    83  }
    84  
    85  func NewWithAuthenticate(addr string, option *C.MitmOption, in chan<- C.ConnContext, authenticate bool) (*Listener, error) {
    86  	l, err := net.Listen("tcp", addr)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	var c *cache.LruCache[string, bool]
    92  	if authenticate {
    93  		c = cache.New[string, bool](cache.WithAge[string, bool](90))
    94  	}
    95  
    96  	ml := &Listener{
    97  		listener: l,
    98  		addr:     addr,
    99  	}
   100  	go func() {
   101  		for {
   102  			conn, err1 := ml.listener.Accept()
   103  			if err1 != nil {
   104  				if ml.closed {
   105  					break
   106  				}
   107  				continue
   108  			}
   109  			go HandleConn(conn, option, in, c, ml.auth)
   110  		}
   111  	}()
   112  
   113  	return ml, nil
   114  }
   115  
   116  var initOption = sync.OnceValues(func() (*C.MitmOption, error) {
   117  	if err := initCert(); err != nil {
   118  		return nil, err
   119  	}
   120  
   121  	rootCACert, err := tls.LoadX509KeyPair(C.Path.RootCA(), C.Path.CAKey())
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  
   126  	privateKey, ok := rootCACert.PrivateKey.(*rsa.PrivateKey)
   127  	if !ok {
   128  		return nil, rsa.ErrVerification
   129  	}
   130  
   131  	x509c, err := x509.ParseCertificate(rootCACert.Certificate[0])
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  
   136  	certOption, err := cert.NewConfig(
   137  		x509c,
   138  		privateKey,
   139  	)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	certOption.SetValidity(time.Hour * 24 * 365) // 1 years
   145  
   146  	option := &C.MitmOption{
   147  		ApiHost:    "mitm.clash",
   148  		CertConfig: certOption,
   149  		Handler:    &mitm.RewriteHandler{},
   150  	}
   151  
   152  	return option, nil
   153  })
   154  
   155  func initCert() error {
   156  	if _, err := os.Stat(C.Path.RootCA()); os.IsNotExist(err) {
   157  		log.Info().Msg("[Config] can't find mitm_ca.crt, start generate")
   158  		err = cert.GenerateAndSave(C.Path.RootCA(), C.Path.CAKey())
   159  		if err != nil {
   160  			return err
   161  		}
   162  		log.Info().Msg("[Config] generated CA private key and CA certificate")
   163  	}
   164  
   165  	return nil
   166  }