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 }