mirror of
				https://github.com/bolucat/Archive.git
				synced 2025-10-31 20:03:10 +08:00 
			
		
		
		
	Update On Sat Sep 13 20:34:35 CEST 2025
This commit is contained in:
		
							
								
								
									
										1
									
								
								.github/update.log
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/update.log
									
									
									
									
										vendored
									
									
								
							| @@ -1119,3 +1119,4 @@ Update On Tue Sep  9 20:33:51 CEST 2025 | ||||
| Update On Wed Sep 10 20:42:57 CEST 2025 | ||||
| Update On Thu Sep 11 20:34:24 CEST 2025 | ||||
| Update On Fri Sep 12 20:36:01 CEST 2025 | ||||
| Update On Sat Sep 13 20:34:27 CEST 2025 | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package adapter | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| @@ -236,6 +235,11 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In | ||||
| 	} | ||||
| 	req = req.WithContext(ctx) | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	transport := &http.Transport{ | ||||
| 		DialContext: func(context.Context, string, string) (net.Conn, error) { | ||||
| 			return instance, nil | ||||
| @@ -245,7 +249,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In | ||||
| 		IdleConnTimeout:       90 * time.Second, | ||||
| 		TLSHandshakeTimeout:   10 * time.Second, | ||||
| 		ExpectContinueTimeout: 1 * time.Second, | ||||
| 		TLSClientConfig:       ca.GetGlobalTLSConfig(&tls.Config{}), | ||||
| 		TLSClientConfig:       tlsConfig, | ||||
| 	} | ||||
|  | ||||
| 	client := http.Client{ | ||||
|   | ||||
| @@ -167,10 +167,13 @@ func NewHttp(option HttpOption) (*Http, error) { | ||||
| 			sni = option.SNI | ||||
| 		} | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{ | ||||
| 		tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				ServerName:         sni, | ||||
| 		}, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
| @@ -160,14 +160,16 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { | ||||
| 		serverName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         serverName, | ||||
| 			InsecureSkipVerify: option.SkipCertVerify, | ||||
| 			MinVersion:         tls.VersionTLS13, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) | ||||
| 		}, | ||||
| 		Fingerprint:    option.Fingerprint, | ||||
| 		CustomCA:       option.CustomCA, | ||||
| 		CustomCAString: option.CustomCAString, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -141,14 +141,16 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { | ||||
| 		serverName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         serverName, | ||||
| 			InsecureSkipVerify: option.SkipCertVerify, | ||||
| 			MinVersion:         tls.VersionTLS13, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) | ||||
| 		}, | ||||
| 		Fingerprint:    option.Fingerprint, | ||||
| 		CustomCA:       option.CustomCA, | ||||
| 		CustomCAString: option.CustomCAString, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -193,13 +193,14 @@ func (ss *Socks5) clientHandshakeContext(ctx context.Context, c net.Conn, addr s | ||||
| func NewSocks5(option Socks5Option) (*Socks5, error) { | ||||
| 	var tlsConfig *tls.Config | ||||
| 	if option.TLS { | ||||
| 		tlsConfig = &tls.Config{ | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				ServerName:         option.Server, | ||||
| 		} | ||||
|  | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
| @@ -100,14 +100,15 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C. | ||||
| 		} | ||||
|  | ||||
| 		wsOpts.TLS = true | ||||
| 		tlsConfig := &tls.Config{ | ||||
| 		wsOpts.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				NextProtos:         alpn, | ||||
| 				MinVersion:         tls.VersionTLS12, | ||||
| 				InsecureSkipVerify: t.option.SkipCertVerify, | ||||
| 				ServerName:         t.option.SNI, | ||||
| 		} | ||||
|  | ||||
| 		wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: t.option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -363,15 +364,15 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { | ||||
| 			return c, nil | ||||
| 		} | ||||
|  | ||||
| 		tlsConfig := &tls.Config{ | ||||
| 		tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				NextProtos:         option.ALPN, | ||||
| 				MinVersion:         tls.VersionTLS12, | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				ServerName:         option.SNI, | ||||
| 		} | ||||
|  | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
| @@ -161,17 +161,20 @@ func (t *Tuic) ProxyInfo() C.ProxyInfo { | ||||
| func NewTuic(option TuicOption) (*Tuic, error) { | ||||
| 	addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) | ||||
| 	serverName := option.Server | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	if option.SNI != "" { | ||||
| 		serverName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         serverName, | ||||
| 			InsecureSkipVerify: option.SkipCertVerify, | ||||
| 			MinVersion:         tls.VersionTLS13, | ||||
| 	} | ||||
| 	if option.SNI != "" { | ||||
| 		tlsConfig.ServerName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) | ||||
| 		}, | ||||
| 		Fingerprint:    option.Fingerprint, | ||||
| 		CustomCA:       option.CustomCA, | ||||
| 		CustomCAString: option.CustomCAString, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -95,14 +95,15 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M | ||||
| 		} | ||||
| 		if v.option.TLS { | ||||
| 			wsOpts.TLS = true | ||||
| 			tlsConfig := &tls.Config{ | ||||
| 			wsOpts.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					MinVersion:         tls.VersionTLS12, | ||||
| 					ServerName:         host, | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					NextProtos:         []string{"http/1.1"}, | ||||
| 			} | ||||
|  | ||||
| 			wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @@ -498,10 +499,13 @@ func NewVless(option VlessOption) (*Vless, error) { | ||||
| 		} | ||||
| 		var tlsConfig *tls.Config | ||||
| 		if option.TLS { | ||||
| 			tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{ | ||||
| 			tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					ServerName:         v.option.ServerName, | ||||
| 			}, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|   | ||||
| @@ -123,13 +123,14 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M | ||||
|  | ||||
| 		if v.option.TLS { | ||||
| 			wsOpts.TLS = true | ||||
| 			tlsConfig := &tls.Config{ | ||||
| 			wsOpts.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					ServerName:         host, | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					NextProtos:         []string{"http/1.1"}, | ||||
| 			} | ||||
|  | ||||
| 			wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @@ -501,10 +502,13 @@ func NewVmess(option VmessOption) (*Vmess, error) { | ||||
| 		} | ||||
| 		var tlsConfig *tls.Config | ||||
| 		if option.TLS { | ||||
| 			tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{ | ||||
| 			tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					ServerName:         v.option.ServerName, | ||||
| 			}, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|   | ||||
| @@ -10,7 +10,9 @@ import ( | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/metacubex/mihomo/common/once" | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| ) | ||||
|  | ||||
| var globalCertPool *x509.CertPool | ||||
| @@ -65,18 +67,6 @@ func ResetCertificate() { | ||||
| 	initializeCertPool() | ||||
| } | ||||
|  | ||||
| func getCertPool() *x509.CertPool { | ||||
| 	if globalCertPool == nil { | ||||
| 		mutex.Lock() | ||||
| 		defer mutex.Unlock() | ||||
| 		if globalCertPool != nil { | ||||
| 			return globalCertPool | ||||
| 		} | ||||
| 		initializeCertPool() | ||||
| 	} | ||||
| 	return globalCertPool | ||||
| } | ||||
|  | ||||
| func GetCertPool(customCA string, customCAString string) (*x509.CertPool, error) { | ||||
| 	var certificate []byte | ||||
| 	var err error | ||||
| @@ -99,22 +89,41 @@ func GetCertPool(customCA string, customCAString string) (*x509.CertPool, error) | ||||
| 		} | ||||
| 		return certPool, nil | ||||
| 	} else { | ||||
| 		return getCertPool(), nil | ||||
| 		mutex.Lock() | ||||
| 		defer mutex.Unlock() | ||||
| 		if globalCertPool == nil { | ||||
| 			initializeCertPool() | ||||
| 		} | ||||
| 		return globalCertPool, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetTLSConfig specified fingerprint, customCA and customCAString | ||||
| func GetTLSConfig(tlsConfig *tls.Config, fingerprint string, customCA string, customCAString string) (_ *tls.Config, err error) { | ||||
| type Option struct { | ||||
| 	TLSConfig      *tls.Config | ||||
| 	Fingerprint    string | ||||
| 	CustomCA       string | ||||
| 	CustomCAString string | ||||
| 	ZeroTrust      bool | ||||
| } | ||||
|  | ||||
| func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) { | ||||
| 	tlsConfig = opt.TLSConfig | ||||
| 	if tlsConfig == nil { | ||||
| 		tlsConfig = &tls.Config{} | ||||
| 	} | ||||
| 	tlsConfig.RootCAs, err = GetCertPool(customCA, customCAString) | ||||
| 	tlsConfig.Time = ntp.Now | ||||
|  | ||||
| 	if opt.ZeroTrust { | ||||
| 		tlsConfig.RootCAs = zeroTrustCertPool() | ||||
| 	} else { | ||||
| 		tlsConfig.RootCAs, err = GetCertPool(opt.CustomCA, opt.CustomCAString) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(fingerprint) > 0 { | ||||
| 		tlsConfig.VerifyPeerCertificate, err = NewFingerprintVerifier(fingerprint) | ||||
| 	if len(opt.Fingerprint) > 0 { | ||||
| 		tlsConfig.VerifyPeerCertificate, err = NewFingerprintVerifier(opt.Fingerprint) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -123,12 +132,12 @@ func GetTLSConfig(tlsConfig *tls.Config, fingerprint string, customCA string, cu | ||||
| 	return tlsConfig, nil | ||||
| } | ||||
|  | ||||
| // GetSpecifiedFingerprintTLSConfig specified fingerprint | ||||
| func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) (*tls.Config, error) { | ||||
| 	return GetTLSConfig(tlsConfig, fingerprint, "", "") | ||||
| var zeroTrustCertPool = once.OnceValue(func() *x509.CertPool { | ||||
| 	if len(_CaCertificates) != 0 { // always using embed cert first | ||||
| 		zeroTrustCertPool := x509.NewCertPool() | ||||
| 		if zeroTrustCertPool.AppendCertsFromPEM(_CaCertificates) { | ||||
| 			return zeroTrustCertPool | ||||
| 		} | ||||
|  | ||||
| func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { | ||||
| 	tlsConfig, _ = GetTLSConfig(tlsConfig, "", "", "") | ||||
| 	return tlsConfig | ||||
| 	} | ||||
| 	return nil // fallback to system pool | ||||
| }) | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package http | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| @@ -28,11 +27,11 @@ func SetUA(UA string) { | ||||
| 	ua = UA | ||||
| } | ||||
|  | ||||
| func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { | ||||
| 	return HttpRequestWithProxy(ctx, url, method, header, body, "") | ||||
| func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader, options ...Option) (*http.Response, error) { | ||||
| 	opt := option{} | ||||
| 	for _, o := range options { | ||||
| 		o(&opt) | ||||
| 	} | ||||
|  | ||||
| func HttpRequestWithProxy(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) { | ||||
| 	method = strings.ToUpper(method) | ||||
| 	urlRes, err := URL.Parse(url) | ||||
| 	if err != nil { | ||||
| @@ -40,6 +39,10 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
| 	} | ||||
|  | ||||
| 	req, err := http.NewRequest(method, urlRes.String(), body) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for k, v := range header { | ||||
| 		for _, v := range v { | ||||
| 			req.Header.Add(k, v) | ||||
| @@ -50,10 +53,6 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
| 		req.Header.Set("User-Agent", UA()) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if user := urlRes.User; user != nil { | ||||
| 		password, _ := user.Password() | ||||
| 		req.SetBasicAuth(user.Username(), password) | ||||
| @@ -61,6 +60,11 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
|  | ||||
| 	req = req.WithContext(ctx) | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(opt.caOption) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	transport := &http.Transport{ | ||||
| 		// from http.DefaultTransport | ||||
| 		DisableKeepAlives:     runtime.GOOS == "android", | ||||
| @@ -69,15 +73,34 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
| 		TLSHandshakeTimeout:   10 * time.Second, | ||||
| 		ExpectContinueTimeout: 1 * time.Second, | ||||
| 		DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { | ||||
| 			if conn, err := inner.HandleTcp(inner.GetTunnel(), address, specialProxy); err == nil { | ||||
| 			if conn, err := inner.HandleTcp(inner.GetTunnel(), address, opt.specialProxy); err == nil { | ||||
| 				return conn, nil | ||||
| 			} else { | ||||
| 				return dialer.DialContext(ctx, network, address) | ||||
| 			} | ||||
| 		}, | ||||
| 		TLSClientConfig: ca.GetGlobalTLSConfig(&tls.Config{}), | ||||
| 		TLSClientConfig: tlsConfig, | ||||
| 	} | ||||
|  | ||||
| 	client := http.Client{Transport: transport} | ||||
| 	return client.Do(req) | ||||
| } | ||||
|  | ||||
| type Option func(opt *option) | ||||
|  | ||||
| type option struct { | ||||
| 	specialProxy string | ||||
| 	caOption     ca.Option | ||||
| } | ||||
|  | ||||
| func WithSpecialProxy(name string) Option { | ||||
| 	return func(opt *option) { | ||||
| 		opt.specialProxy = name | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WithCAOption(caOption ca.Option) Option { | ||||
| 	return func(opt *option) { | ||||
| 		opt.caOption = caOption | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -135,7 +135,7 @@ func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []b | ||||
| 			setIfNoneMatch = true | ||||
| 		} | ||||
| 	} | ||||
| 	resp, err := mihomoHttp.HttpRequestWithProxy(ctx, h.url, http.MethodGet, header, nil, h.proxy) | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, header, nil, mihomoHttp.WithSpecialProxy(h.proxy)) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -15,6 +15,7 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/metacubex/mihomo/component/ca" | ||||
| 	mihomoHttp "github.com/metacubex/mihomo/component/http" | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	"github.com/metacubex/mihomo/constant/features" | ||||
| @@ -171,7 +172,7 @@ func (u *CoreUpdater) Update(currentExePath string, channel string, force bool) | ||||
| func (u *CoreUpdater) getLatestVersion(versionURL string) (version string, err error) { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) | ||||
| 	defer cancel() | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, nil, nil) | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, nil, nil, mihomoHttp.WithCAOption(ca.Option{ZeroTrust: true})) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| @@ -194,7 +195,7 @@ func (u *CoreUpdater) getLatestVersion(versionURL string) (version string, err e | ||||
| func (u *CoreUpdater) download(updateDir, packagePath, packageURL string) (err error) { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) | ||||
| 	defer cancel() | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, nil, nil) | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, nil, nil, mihomoHttp.WithCAOption(ca.Option{ZeroTrust: true})) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("http request failed: %w", err) | ||||
| 	} | ||||
|   | ||||
| @@ -48,6 +48,13 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) | ||||
| 		network = "tcp" | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: c.Client.TLSConfig, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	addr := net.JoinHostPort(c.host, c.port) | ||||
| 	conn, err := c.dialer.DialContext(ctx, network, addr) | ||||
| 	if err != nil { | ||||
| @@ -66,7 +73,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) | ||||
| 	ch := make(chan result, 1) | ||||
| 	go func() { | ||||
| 		if strings.HasSuffix(c.Client.Net, "tls") { | ||||
| 			conn = tls.Client(conn, ca.GetGlobalTLSConfig(c.Client.TLSConfig)) | ||||
| 			conn = tls.Client(conn, tlsConfig) | ||||
| 		} | ||||
|  | ||||
| 		dConn := &D.Conn{ | ||||
|   | ||||
| @@ -397,12 +397,16 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp | ||||
| 		return transport, nil | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := ca.GetGlobalTLSConfig( | ||||
| 		&tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			InsecureSkipVerify:     doh.skipCertVerify, | ||||
| 			MinVersion:             tls.VersionTLS12, | ||||
| 			SessionTicketsDisabled: false, | ||||
| 		}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var nextProtos []string | ||||
| 	for _, v := range doh.httpVersions { | ||||
| 		nextProtos = append(nextProtos, string(v)) | ||||
|   | ||||
| @@ -331,15 +331,19 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn *quic.Conn, er | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := ca.GetGlobalTLSConfig( | ||||
| 		&tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         host, | ||||
| 			InsecureSkipVerify: doq.skipCertVerify, | ||||
| 			NextProtos: []string{ | ||||
| 				NextProtoDQ, | ||||
| 			}, | ||||
| 			SessionTicketsDisabled: false, | ||||
| 		}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	transport := quic.Transport{Conn: udp} | ||||
| 	transport.SetCreatedConn(true) // auto close conn | ||||
|   | ||||
| @@ -6,7 +6,7 @@ require ( | ||||
| 	github.com/bahlo/generic-list-go v0.2.0 | ||||
| 	github.com/coreos/go-iptables v0.8.0 | ||||
| 	github.com/dlclark/regexp2 v1.11.5 | ||||
| 	github.com/enfein/mieru/v3 v3.19.1 | ||||
| 	github.com/enfein/mieru/v3 v3.20.0 | ||||
| 	github.com/go-chi/chi/v5 v5.2.3 | ||||
| 	github.com/go-chi/render v1.0.3 | ||||
| 	github.com/gobwas/ws v1.4.0 | ||||
|   | ||||
| @@ -25,8 +25,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ | ||||
| github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= | ||||
| github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= | ||||
| github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= | ||||
| github.com/enfein/mieru/v3 v3.19.1 h1:19b9kgFC7oJXX9RLEO5Pi1gO6yek5cWlpK7IJVUoE8I= | ||||
| github.com/enfein/mieru/v3 v3.19.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM= | ||||
| github.com/enfein/mieru/v3 v3.20.0 h1:1ob7pCIVSH5FYFAfYvim8isLW1vBOS4cFOUF9exJS38= | ||||
| github.com/enfein/mieru/v3 v3.20.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM= | ||||
| github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo= | ||||
| github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= | ||||
| github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= | ||||
|   | ||||
| @@ -20,6 +20,7 @@ import ( | ||||
| 	tlsC "github.com/metacubex/mihomo/component/tls" | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	"github.com/metacubex/mihomo/log" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/tunnel/statistic" | ||||
|  | ||||
| 	"github.com/go-chi/chi/v5" | ||||
| @@ -201,7 +202,7 @@ func startTLS(cfg *Config) { | ||||
| 		} | ||||
|  | ||||
| 		log.Infoln("RESTful API tls listening at: %s", l.Addr().String()) | ||||
| 		tlsConfig := &tlsC.Config{} | ||||
| 		tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 		tlsConfig.NextProtos = []string{"h2", "http/1.1"} | ||||
| 		tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} | ||||
|  | ||||
|   | ||||
| @@ -17,6 +17,7 @@ import ( | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/anytls/padding" | ||||
| 	"github.com/metacubex/mihomo/transport/anytls/session" | ||||
|  | ||||
| @@ -42,7 +43,7 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	if config.Certificate != "" && config.PrivateKey != "" { | ||||
| 		cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import ( | ||||
| 	authStore "github.com/metacubex/mihomo/listener/auth" | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| ) | ||||
|  | ||||
| type Listener struct { | ||||
| @@ -65,7 +66,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
|  | ||||
| 	if config.Certificate != "" && config.PrivateKey != "" { | ||||
|   | ||||
| @@ -39,7 +39,7 @@ var userUUID = utils.NewUUIDV4().String() | ||||
| var tlsCertificate, tlsPrivateKey, tlsFingerprint, _ = ca.NewRandomTLSKeyPair(ca.KeyPairTypeP256) | ||||
| var tlsConfigCert, _ = tls.X509KeyPair([]byte(tlsCertificate), []byte(tlsPrivateKey)) | ||||
| var tlsConfig = &tls.Config{Certificates: []tls.Certificate{tlsConfigCert}, NextProtos: []string{"h2", "http/1.1"}} | ||||
| var tlsClientConfig, _ = ca.GetTLSConfig(nil, tlsFingerprint, "", "") | ||||
| var tlsClientConfig, _ = ca.GetTLSConfig(ca.Option{Fingerprint: tlsFingerprint}) | ||||
| var realityPrivateKey, realityPublickey string | ||||
| var realityDest = "itunes.apple.com" | ||||
| var realityShortid = "10f897e26c4b9478" | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import ( | ||||
| 	"github.com/metacubex/mihomo/listener/http" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/listener/socks" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/socks4" | ||||
| 	"github.com/metacubex/mihomo/transport/socks5" | ||||
| ) | ||||
| @@ -61,7 +62,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
|  | ||||
| 	if config.Certificate != "" && config.PrivateKey != "" { | ||||
|   | ||||
| @@ -20,6 +20,7 @@ import ( | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/log" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
|  | ||||
| 	"github.com/metacubex/sing-quic/hysteria2" | ||||
|  | ||||
| @@ -61,6 +62,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	tlsConfig := &tlsC.Config{ | ||||
| 		Time:       ntp.Now, | ||||
| 		MinVersion: tlsC.VersionTLS13, | ||||
| 	} | ||||
| 	tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} | ||||
|   | ||||
| @@ -15,6 +15,7 @@ import ( | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/gun" | ||||
| 	"github.com/metacubex/mihomo/transport/vless/encryption" | ||||
| 	mihomoVMess "github.com/metacubex/mihomo/transport/vmess" | ||||
| @@ -75,7 +76,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) | ||||
| 		}() | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
| 	var httpServer http.Server | ||||
|  | ||||
|   | ||||
| @@ -76,7 +76,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) | ||||
|  | ||||
| 	sl = &Listener{false, config, nil, service} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
| 	var httpServer http.Server | ||||
|  | ||||
|   | ||||
| @@ -15,6 +15,7 @@ import ( | ||||
| 	authStore "github.com/metacubex/mihomo/listener/auth" | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/socks4" | ||||
| 	"github.com/metacubex/mihomo/transport/socks5" | ||||
| ) | ||||
| @@ -60,7 +61,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
|  | ||||
| 	if config.Certificate != "" && config.PrivateKey != "" { | ||||
|   | ||||
| @@ -15,6 +15,7 @@ import ( | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/gun" | ||||
| 	"github.com/metacubex/mihomo/transport/shadowsocks/core" | ||||
| 	"github.com/metacubex/mihomo/transport/socks5" | ||||
| @@ -70,7 +71,7 @@ func New(config LC.TrojanServer, tunnel C.Tunnel, additions ...inbound.Addition) | ||||
| 	} | ||||
| 	sl = &Listener{false, config, nil, keys, pickCipher, h} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
| 	var httpServer http.Server | ||||
|  | ||||
|   | ||||
| @@ -14,6 +14,7 @@ import ( | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/log" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/socks5" | ||||
| 	"github.com/metacubex/mihomo/transport/tuic" | ||||
|  | ||||
| @@ -53,6 +54,7 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	tlsConfig := &tlsC.Config{ | ||||
| 		Time:       ntp.Now, | ||||
| 		MinVersion: tlsC.VersionTLS13, | ||||
| 	} | ||||
| 	tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} | ||||
|   | ||||
| @@ -23,24 +23,21 @@ type Service struct { | ||||
| 	ticker         *time.Ticker | ||||
| 	ctx            context.Context | ||||
| 	cancel         context.CancelFunc | ||||
| 	mu             sync.RWMutex | ||||
| 	offset         time.Duration | ||||
| 	offset         atomic.Int64 // [time.Duration] | ||||
| 	syncSystemTime bool | ||||
| 	running        bool | ||||
| } | ||||
|  | ||||
| func ReCreateNTPService(server string, interval time.Duration, dialerProxy string, syncSystemTime bool) { | ||||
| 	globalMu.Lock() | ||||
| 	defer globalMu.Unlock() | ||||
| 	service := globalSrv.Swap(nil) | ||||
| 	if service != nil { | ||||
| 	if service := globalSrv.Swap(nil); service != nil { | ||||
| 		service.Stop() | ||||
| 	} | ||||
| 	if server == "" { | ||||
| 	if server == "" || interval <= 0 { | ||||
| 		return | ||||
| 	} | ||||
| 	ctx, cancel := context.WithCancel(context.Background()) | ||||
| 	service = &Service{ | ||||
| 	service := &Service{ | ||||
| 		server:         M.ParseSocksaddr(server), | ||||
| 		dialer:         proxydialer.NewByNameSingDialer(dialerProxy, dialer.NewDialer()), | ||||
| 		ticker:         time.NewTicker(interval * time.Minute), | ||||
| @@ -53,38 +50,17 @@ func ReCreateNTPService(server string, interval time.Duration, dialerProxy strin | ||||
| } | ||||
|  | ||||
| func (srv *Service) Start() { | ||||
| 	srv.mu.Lock() | ||||
| 	defer srv.mu.Unlock() | ||||
| 	log.Infoln("NTP service start, sync system time is %t", srv.syncSystemTime) | ||||
| 	err := srv.update() | ||||
| 	if err != nil { | ||||
| 		log.Errorln("Initialize NTP time failed: %s", err) | ||||
| 		return | ||||
| 	} | ||||
| 	srv.running = true | ||||
| 	go srv.loopUpdate() | ||||
| } | ||||
|  | ||||
| func (srv *Service) Stop() { | ||||
| 	srv.mu.Lock() | ||||
| 	defer srv.mu.Unlock() | ||||
| 	if srv.running { | ||||
| 		srv.ticker.Stop() | ||||
| 	log.Infoln("NTP service stop") | ||||
| 	srv.cancel() | ||||
| 		srv.running = false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (srv *Service) Offset() time.Duration { | ||||
| 	if srv == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	srv.mu.RLock() | ||||
| 	defer srv.mu.RUnlock() | ||||
| 	if srv.running { | ||||
| 		return srv.offset | ||||
| 	} | ||||
| 	return 0 | ||||
| 	return time.Duration(srv.offset.Load()) | ||||
| } | ||||
|  | ||||
| func (srv *Service) update() error { | ||||
| @@ -93,6 +69,9 @@ func (srv *Service) update() error { | ||||
| 	for i := 0; i < 3; i++ { | ||||
| 		response, err = ntp.Exchange(srv.ctx, srv.dialer, srv.server) | ||||
| 		if err != nil { | ||||
| 			if srv.ctx.Err() != nil { | ||||
| 				return nil | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		offset := response.ClockOffset | ||||
| @@ -101,9 +80,7 @@ func (srv *Service) update() error { | ||||
| 		} else if offset < time.Duration(0) { | ||||
| 			log.Infoln("System clock is behind NTP time by %s", -offset) | ||||
| 		} | ||||
| 		srv.mu.Lock() | ||||
| 		srv.offset = offset | ||||
| 		srv.mu.Unlock() | ||||
| 		srv.offset.Store(int64(offset)) | ||||
| 		if srv.syncSystemTime { | ||||
| 			timeNow := response.Time | ||||
| 			syncErr := setSystemTime(timeNow) | ||||
| @@ -120,23 +97,27 @@ func (srv *Service) update() error { | ||||
| } | ||||
|  | ||||
| func (srv *Service) loopUpdate() { | ||||
| 	defer srv.offset.Store(0) | ||||
| 	defer srv.ticker.Stop() | ||||
| 	for { | ||||
| 		err := srv.update() | ||||
| 		if err != nil { | ||||
| 			log.Warnln("Sync time failed: %s", err) | ||||
| 		} | ||||
| 		select { | ||||
| 		case <-srv.ctx.Done(): | ||||
| 			return | ||||
| 		case <-srv.ticker.C: | ||||
| 		} | ||||
| 		err := srv.update() | ||||
| 		if err != nil { | ||||
| 			log.Warnln("Sync time failed: %s", err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Now() time.Time { | ||||
| 	now := time.Now() | ||||
| 	if offset := globalSrv.Load().Offset(); offset.Abs() > 0 { | ||||
| 	if service := globalSrv.Load(); service != nil { | ||||
| 		if offset := service.Offset(); offset.Abs() > 0 { | ||||
| 			now = now.Add(offset) | ||||
| 		} | ||||
| 	} | ||||
| 	return now | ||||
| } | ||||
|   | ||||
| @@ -57,15 +57,17 @@ func NewGostWebsocket(ctx context.Context, conn net.Conn, option *Option) (net.C | ||||
| 		Headers:   header, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	if option.TLS { | ||||
| 		config.TLS = true | ||||
| 		tlsConfig := &tls.Config{ | ||||
| 		config.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				ServerName:         option.Host, | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				NextProtos:         []string{"http/1.1"}, | ||||
| 		} | ||||
| 		var err error | ||||
| 		config.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -75,7 +77,6 @@ func NewGostWebsocket(ctx context.Context, conn net.Conn, option *Option) (net.C | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	conn, err = vmess.StreamWebsocketConn(ctx, conn, config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|   | ||||
| @@ -6,9 +6,9 @@ import ( | ||||
| 	"encoding/binary" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/metacubex/mihomo/common/pool" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -145,7 +145,7 @@ func makeClientHelloMsg(data []byte, server string) []byte { | ||||
| 	buf.Write([]byte{0x03, 0x03}) | ||||
|  | ||||
| 	// random with timestamp, sid len, sid | ||||
| 	binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix())) | ||||
| 	binary.Write(buf, binary.BigEndian, uint32(ntp.Now().Unix())) | ||||
| 	buf.Write(random) | ||||
| 	buf.WriteByte(32) | ||||
| 	buf.Write(sessionID) | ||||
|   | ||||
| @@ -33,22 +33,23 @@ type ShadowTLSOption struct { | ||||
| } | ||||
|  | ||||
| func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (net.Conn, error) { | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			NextProtos:         option.ALPN, | ||||
| 			MinVersion:         tls.VersionTLS12, | ||||
| 			InsecureSkipVerify: option.SkipCertVerify, | ||||
| 			ServerName:         option.Host, | ||||
| 	} | ||||
| 	if option.Version == 1 { | ||||
| 		tlsConfig.MaxVersion = tls.VersionTLS12 // ShadowTLS v1 only support TLS 1.2 | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) | ||||
| 		}, | ||||
| 		Fingerprint: option.Fingerprint, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if option.Version == 1 { | ||||
| 		tlsConfig.MaxVersion = tls.VersionTLS12 // ShadowTLS v1 only support TLS 1.2 | ||||
| 	} | ||||
|  | ||||
| 	tlsHandshake := uTLSHandshakeFunc(tlsConfig, option.ClientFingerprint, option.Version) | ||||
| 	client, err := shadowtls.NewClient(shadowtls.ClientConfig{ | ||||
| 		Version:      option.Version, | ||||
|   | ||||
| @@ -7,9 +7,9 @@ import ( | ||||
| 	"encoding/binary" | ||||
| 	"net" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/metacubex/mihomo/common/pool" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/ssr/tools" | ||||
|  | ||||
| 	"github.com/metacubex/randv2" | ||||
| @@ -182,7 +182,7 @@ func packData(buf *bytes.Buffer, data []byte) { | ||||
| } | ||||
|  | ||||
| func (t *tls12Ticket) packAuthData(buf *bytes.Buffer) { | ||||
| 	binary.Write(buf, binary.BigEndian, uint32(time.Now().Unix())) | ||||
| 	binary.Write(buf, binary.BigEndian, uint32(ntp.Now().Unix())) | ||||
| 	tools.AppendRandBytes(buf, 18) | ||||
| 	buf.Write(t.hmacSHA1(buf.Bytes()[buf.Len()-22:])[:10]) | ||||
| } | ||||
|   | ||||
| @@ -8,10 +8,10 @@ import ( | ||||
| 	"encoding/base64" | ||||
| 	"encoding/binary" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/metacubex/mihomo/common/pool" | ||||
| 	"github.com/metacubex/mihomo/log" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/shadowsocks/core" | ||||
|  | ||||
| 	"github.com/metacubex/randv2" | ||||
| @@ -49,7 +49,7 @@ func (a *authData) next() *authData { | ||||
| } | ||||
|  | ||||
| func (a *authData) putAuthData(buf *bytes.Buffer) { | ||||
| 	binary.Write(buf, binary.LittleEndian, uint32(time.Now().Unix())) | ||||
| 	binary.Write(buf, binary.LittleEndian, uint32(ntp.Now().Unix())) | ||||
| 	buf.Write(a.clientID[:]) | ||||
| 	binary.Write(buf, binary.LittleEndian, a.connectionID) | ||||
| } | ||||
| @@ -57,7 +57,7 @@ func (a *authData) putAuthData(buf *bytes.Buffer) { | ||||
| func (a *authData) putEncryptedData(b *bytes.Buffer, userKey []byte, paddings [2]int, salt string) error { | ||||
| 	encrypt := pool.Get(16) | ||||
| 	defer pool.Put(encrypt) | ||||
| 	binary.LittleEndian.PutUint32(encrypt, uint32(time.Now().Unix())) | ||||
| 	binary.LittleEndian.PutUint32(encrypt, uint32(ntp.Now().Unix())) | ||||
| 	copy(encrypt[4:], a.clientID[:]) | ||||
| 	binary.LittleEndian.PutUint32(encrypt[8:], a.connectionID) | ||||
| 	binary.LittleEndian.PutUint16(encrypt[12:], uint16(paddings[0])) | ||||
|   | ||||
| @@ -43,15 +43,17 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, | ||||
| 		Headers:                  header, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	if option.TLS { | ||||
| 		config.TLS = true | ||||
| 		tlsConfig := &tls.Config{ | ||||
| 		config.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				ServerName:         option.Host, | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				NextProtos:         []string{"http/1.1"}, | ||||
| 		} | ||||
| 		var err error | ||||
| 		config.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -61,7 +63,6 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	conn, err = vmess.StreamWebsocketConn(ctx, conn, config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
|   | ||||
| @@ -26,14 +26,14 @@ type ECHConfig struct { | ||||
| } | ||||
|  | ||||
| func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) { | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         cfg.Host, | ||||
| 			InsecureSkipVerify: cfg.SkipCertVerify, | ||||
| 			NextProtos:         cfg.NextProtos, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, cfg.FingerPrint) | ||||
| 		}, | ||||
| 		Fingerprint: cfg.FingerPrint, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|   "manifest_version": 1, | ||||
|   "latest": { | ||||
|     "mihomo": "v1.19.13", | ||||
|     "mihomo_alpha": "alpha-909729c", | ||||
|     "mihomo_alpha": "alpha-4f4f13d", | ||||
|     "clash_rs": "v0.9.0", | ||||
|     "clash_premium": "2023-09-05-gdcc8d87", | ||||
|     "clash_rs_alpha": "0.9.0-alpha+sha.50f295d" | ||||
| @@ -69,5 +69,5 @@ | ||||
|       "linux-armv7hf": "clash-armv7-unknown-linux-gnueabihf" | ||||
|     } | ||||
|   }, | ||||
|   "updated_at": "2025-09-11T22:20:53.894Z" | ||||
|   "updated_at": "2025-09-12T22:20:41.506Z" | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,65 @@ | ||||
|  | ||||
| All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. | ||||
|  | ||||
| ## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13) | ||||
|  | ||||
|  | ||||
| ### Features | ||||
|  | ||||
| * "save changes" button to discard changes dialog ([84e8632](https://github.com/filebrowser/filebrowser/commit/84e8632b98e315bfef2da77dd7d1049daec99241)) | ||||
| * Translate frontend/src/i18n/en.json in es ([571ce6c](https://github.com/filebrowser/filebrowser/commit/571ce6cb0d7c8725d1cc1a3238ea506ddc72b060)) | ||||
| * Translate frontend/src/i18n/en.json in fr ([6b1fa87](https://github.com/filebrowser/filebrowser/commit/6b1fa87ad38ebbb1a9c5d0e5fc88ba796c148bcf)) | ||||
| * Updates for project File Browser ([#5427](https://github.com/filebrowser/filebrowser/issues/5427)) ([8950585](https://github.com/filebrowser/filebrowser/commit/89505851414bfcee6b9ff02087eb4cec51c330f6)) | ||||
|  | ||||
|  | ||||
| ### Bug Fixes | ||||
|  | ||||
| * optimize markdown preview height ([783503a](https://github.com/filebrowser/filebrowser/commit/783503aece7fca9e26f7e849b0e7478aba976acb)) | ||||
|  | ||||
|  | ||||
| ### Reverts | ||||
|  | ||||
| * build(deps): bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([0769265](https://github.com/filebrowser/filebrowser/commit/07692653ffe0ea5e517e6dc1fd3961172e931843)) | ||||
|  | ||||
|  | ||||
| ### Build | ||||
|  | ||||
| * **deps-dev:** bump vite from 6.1.6 to 6.3.6 in /frontend ([36c6cc2](https://github.com/filebrowser/filebrowser/commit/36c6cc203e10947439519a0413d5817921a1690d)) | ||||
| * **deps:** bump github.com/go-viper/mapstructure/v2 in /tools ([280fa56](https://github.com/filebrowser/filebrowser/commit/280fa562a67824887ae6e2530a3b73739d6e1bb4)) | ||||
| * **deps:** bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([950028a](https://github.com/filebrowser/filebrowser/commit/950028abebe2898bac4ecfd8715c0967246310cb)) | ||||
|  | ||||
|  | ||||
| ### Refactorings | ||||
|  | ||||
| * to use strings.Lines ([b482a9b](https://github.com/filebrowser/filebrowser/commit/b482a9bf0d292ec6542d2145a4408971e4c985f1)) | ||||
|  | ||||
| ## [2.43.0](https://github.com/filebrowser/filebrowser/compare/v2.42.5...v2.43.0) (2025-09-13) | ||||
|  | ||||
|  | ||||
| ### Features | ||||
|  | ||||
| * "save changes" button to discard changes dialog ([84e8632](https://github.com/filebrowser/filebrowser/commit/84e8632b98e315bfef2da77dd7d1049daec99241)) | ||||
| * Translate frontend/src/i18n/en.json in es ([571ce6c](https://github.com/filebrowser/filebrowser/commit/571ce6cb0d7c8725d1cc1a3238ea506ddc72b060)) | ||||
| * Translate frontend/src/i18n/en.json in fr ([6b1fa87](https://github.com/filebrowser/filebrowser/commit/6b1fa87ad38ebbb1a9c5d0e5fc88ba796c148bcf)) | ||||
| * Updates for project File Browser ([#5427](https://github.com/filebrowser/filebrowser/issues/5427)) ([8950585](https://github.com/filebrowser/filebrowser/commit/89505851414bfcee6b9ff02087eb4cec51c330f6)) | ||||
|  | ||||
|  | ||||
| ### Bug Fixes | ||||
|  | ||||
| * optimize markdown preview height ([783503a](https://github.com/filebrowser/filebrowser/commit/783503aece7fca9e26f7e849b0e7478aba976acb)) | ||||
|  | ||||
|  | ||||
| ### Build | ||||
|  | ||||
| * **deps-dev:** bump vite from 6.1.6 to 6.3.6 in /frontend ([36c6cc2](https://github.com/filebrowser/filebrowser/commit/36c6cc203e10947439519a0413d5817921a1690d)) | ||||
| * **deps:** bump github.com/go-viper/mapstructure/v2 in /tools ([280fa56](https://github.com/filebrowser/filebrowser/commit/280fa562a67824887ae6e2530a3b73739d6e1bb4)) | ||||
| * **deps:** bump github.com/ulikunitz/xz from 0.5.12 to 0.5.14 ([950028a](https://github.com/filebrowser/filebrowser/commit/950028abebe2898bac4ecfd8715c0967246310cb)) | ||||
|  | ||||
|  | ||||
| ### Refactorings | ||||
|  | ||||
| * to use strings.Lines ([b482a9b](https://github.com/filebrowser/filebrowser/commit/b482a9bf0d292ec6542d2145a4408971e4c985f1)) | ||||
|  | ||||
| ### [2.42.5](https://github.com/filebrowser/filebrowser/compare/v2.42.4...v2.42.5) (2025-08-16) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -123,7 +123,7 @@ func (a *HookAuth) GetValues(s string) { | ||||
| 	s = strings.ReplaceAll(s, "\r\n", "\n") | ||||
|  | ||||
| 	// iterate input lines | ||||
| 	for _, val := range strings.Split(s, "\n") { | ||||
| 	for val := range strings.Lines(s) { | ||||
| 		v := strings.SplitN(val, "=", 2) | ||||
|  | ||||
| 		// skips non key and value format | ||||
|   | ||||
| @@ -11,17 +11,26 @@ | ||||
|         @click="closeHovers" | ||||
|         :aria-label="$t('buttons.cancel')" | ||||
|         :title="$t('buttons.cancel')" | ||||
|         tabindex="2" | ||||
|         tabindex="3" | ||||
|       > | ||||
|         {{ $t("buttons.cancel") }} | ||||
|       </button> | ||||
|       <button | ||||
|         class="button button--flat button--blue" | ||||
|         @click="saveAndClose" | ||||
|         :aria-label="$t('buttons.saveChanges')" | ||||
|         :title="$t('buttons.saveChanges')" | ||||
|         tabindex="1" | ||||
|       > | ||||
|         {{ $t("buttons.saveChanges") }} | ||||
|       </button> | ||||
|       <button | ||||
|         id="focus-prompt" | ||||
|         @click="currentPrompt.confirm" | ||||
|         class="button button--flat button--red" | ||||
|         :aria-label="$t('buttons.discardChanges')" | ||||
|         :title="$t('buttons.discardChanges')" | ||||
|         tabindex="1" | ||||
|         tabindex="2" | ||||
|       > | ||||
|         {{ $t("buttons.discardChanges") }} | ||||
|       </button> | ||||
| @@ -40,6 +49,12 @@ export default { | ||||
|   }, | ||||
|   methods: { | ||||
|     ...mapActions(useLayoutStore, ["closeHovers"]), | ||||
|     saveAndClose() { | ||||
|       if (this.currentPrompt?.saveAction) { | ||||
|         this.currentPrompt.saveAction(); | ||||
|       } | ||||
|       this.closeHovers(); | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| .md_preview { | ||||
|   overflow-y: auto; | ||||
|   max-height: 80vh; | ||||
|   padding: 1rem; | ||||
|   border: 1px solid #000; | ||||
|   font-size: 20px; | ||||
| @@ -9,5 +7,5 @@ | ||||
|  | ||||
| #preview-container { | ||||
|   overflow: auto; | ||||
|   max-height: 80vh; /* Match the max-height of md_preview for scrolling */ | ||||
|   flex: 1; | ||||
| } | ||||
|   | ||||
| @@ -42,7 +42,8 @@ | ||||
|     "update": "Update", | ||||
|     "upload": "Upload", | ||||
|     "openFile": "Open file", | ||||
|     "discardChanges": "Discard" | ||||
|   "discardChanges": "Discard", | ||||
|   "saveChanges": "Save changes" | ||||
|   }, | ||||
|   "download": { | ||||
|     "downloadFile": "Download File", | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|     "copy": "Copiar", | ||||
|     "copyFile": "Copiar archivo", | ||||
|     "copyToClipboard": "Copiar al portapapeles", | ||||
|     "copyDownloadLinkToClipboard": "Copy download link to clipboard", | ||||
|     "copyDownloadLinkToClipboard": "Copiar enlace de descarga al portapapeles", | ||||
|     "create": "Crear", | ||||
|     "delete": "Borrar", | ||||
|     "download": "Descargar", | ||||
|   | ||||
| @@ -41,6 +41,7 @@ export const useLayoutStore = defineStore("layout", { | ||||
|           prompt: value, | ||||
|           confirm: null, | ||||
|           action: undefined, | ||||
|           saveAction: undefined, | ||||
|           props: null, | ||||
|           close: null, | ||||
|         }); | ||||
| @@ -51,6 +52,7 @@ export const useLayoutStore = defineStore("layout", { | ||||
|         prompt: value.prompt, | ||||
|         confirm: value?.confirm, | ||||
|         action: value?.action, | ||||
|         saveAction: value?.saveAction, | ||||
|         props: value?.props, | ||||
|         close: value?.close, | ||||
|       }); | ||||
|   | ||||
							
								
								
									
										1
									
								
								filebrowser/frontend/src/types/layout.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								filebrowser/frontend/src/types/layout.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -2,6 +2,7 @@ interface PopupProps { | ||||
|   prompt: string; | ||||
|   confirm?: any; | ||||
|   action?: PopupAction; | ||||
|   saveAction?: () => void; | ||||
|   props?: any; | ||||
|   close?: (() => Promise<string>) | null; | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| <template> | ||||
|   <div id="editor-container" @wheel.prevent.stop> | ||||
|   <div id="editor-container"> | ||||
|     <header-bar> | ||||
|       <action icon="close" :label="t('buttons.close')" @action="close()" /> | ||||
|       <title>{{ fileStore.req?.name ?? "" }}</title> | ||||
| @@ -97,7 +97,6 @@ const isMarkdownFile = | ||||
|  | ||||
| onMounted(() => { | ||||
|   window.addEventListener("keydown", keyEvent); | ||||
|   window.addEventListener("wheel", handleScroll); | ||||
|   window.addEventListener("beforeunload", handlePageChange); | ||||
|  | ||||
|   const fileContent = fileStore.req?.content || ""; | ||||
| @@ -111,13 +110,6 @@ onMounted(() => { | ||||
|         console.error("Failed to convert content to HTML:", error); | ||||
|         previewContent.value = ""; | ||||
|       } | ||||
|  | ||||
|       const previewContainer = document.getElementById("preview-container"); | ||||
|       if (previewContainer) { | ||||
|         previewContainer.addEventListener("wheel", handleScroll, { | ||||
|           capture: true, | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|  | ||||
| @@ -148,7 +140,6 @@ onMounted(() => { | ||||
|  | ||||
| onBeforeUnmount(() => { | ||||
|   window.removeEventListener("keydown", keyEvent); | ||||
|   window.removeEventListener("wheel", handleScroll); | ||||
|   window.removeEventListener("beforeunload", handlePageChange); | ||||
|   editor.value?.destroy(); | ||||
| }); | ||||
| @@ -166,6 +157,10 @@ onBeforeRouteUpdate((to, from, next) => { | ||||
|       event.preventDefault(); | ||||
|       next(); | ||||
|     }, | ||||
|     saveAction: async () => { | ||||
|       await save(); | ||||
|       next(); | ||||
|     }, | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| @@ -186,13 +181,6 @@ const keyEvent = (event: KeyboardEvent) => { | ||||
|   save(); | ||||
| }; | ||||
|  | ||||
| const handleScroll = (event: WheelEvent) => { | ||||
|   const editorContainer = document.getElementById("preview-container"); | ||||
|   if (editorContainer) { | ||||
|     editorContainer.scrollTop += event.deltaY; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| const handlePageChange = (event: BeforeUnloadEvent) => { | ||||
|   if (!editor.value?.session.getUndoManager().isClean()) { | ||||
|     event.preventDefault(); | ||||
|   | ||||
| @@ -65,7 +65,7 @@ require ( | ||||
| 	github.com/sourcegraph/conc v0.3.0 // indirect | ||||
| 	github.com/spf13/cast v1.9.2 // indirect | ||||
| 	github.com/subosito/gotenv v1.6.0 // indirect | ||||
| 	github.com/ulikunitz/xz v0.5.14 // indirect | ||||
| 	github.com/ulikunitz/xz v0.5.12 // indirect | ||||
| 	github.com/yusufpapurcu/wmi v1.2.4 // indirect | ||||
| 	go.uber.org/multierr v1.11.0 // indirect | ||||
| 	go4.org v0.0.0-20230225012048-214862532bf5 // indirect | ||||
|   | ||||
| @@ -232,8 +232,8 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW | ||||
| github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc= | ||||
| github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= | ||||
| github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= | ||||
| github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg= | ||||
| github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= | ||||
| github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= | ||||
| github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= | ||||
| github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= | ||||
| github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= | ||||
| github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= | ||||
|   | ||||
| @@ -7,14 +7,12 @@ | ||||
| include $(TOPDIR)/rules.mk | ||||
|  | ||||
| PKG_NAME:=erofs-utils | ||||
| PKG_VERSION:=1.8.9 | ||||
| PKG_VERSION:=1.8.10 | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_SOURCE_PROTO:=git | ||||
| PKG_SOURCE_URL=https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git | ||||
| PKG_MIRROR_HASH:=dfeeca4e3b1337cf05d2b40f6f3956601b98fba0b6a8d7363071ae366a2020e1 | ||||
| PKG_SOURCE_DATE:=2025-06-26 | ||||
| PKG_SOURCE_VERSION:=81169bf3cfd26b8f2b3aa3b20da23971168a90a9 | ||||
| PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz | ||||
| PKG_SOURCE_URL=https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git/snapshot/ | ||||
| PKG_HASH:=05eb4edebe11decce6ecb34e98d2f80c8cd283c2f2967d8ba7efd58418570514 | ||||
|  | ||||
| PKG_FIXUP:=autoreconf | ||||
|  | ||||
|   | ||||
							
								
								
									
										2
									
								
								mieru/.github/workflows/integration.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								mieru/.github/workflows/integration.yaml
									
									
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ on: [push, pull_request, workflow_dispatch] | ||||
| jobs: | ||||
|   run-test: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 10 | ||||
|     timeout-minutes: 15 | ||||
|     steps: | ||||
|       - name: Check out repository code | ||||
|         uses: actions/checkout@v4 | ||||
|   | ||||
| @@ -32,7 +32,7 @@ PROJECT_NAME=$(shell basename "${ROOT}") | ||||
| # - pkg/version/current.go | ||||
| # | ||||
| # Use `tools/bump_version.sh` script to change all those files at one shot. | ||||
| VERSION="3.19.2" | ||||
| VERSION="3.20.0" | ||||
|  | ||||
| # Build binaries and installation packages. | ||||
| .PHONY: build | ||||
|   | ||||
| @@ -74,6 +74,10 @@ type ClientNetworkService interface { | ||||
| 	// DialContext returns a new proxy connection to reach the destination. | ||||
| 	// It uses the dialer in ClientConfig to connect to a proxy server endpoint. | ||||
| 	// | ||||
| 	// If HandshakeMode in ClientConfig is HANDSHAKE_NO_WAIT, handshake is performed | ||||
| 	// upon the first write to the network connection. Otherwise, handshake is | ||||
| 	// performed before this method returns. | ||||
| 	// | ||||
| 	// This is a streaming based proxy connection. If the destination is a packet | ||||
| 	// endpoint, packets are encapsulated in the streaming connection. | ||||
| 	// | ||||
| @@ -84,6 +88,7 @@ type ClientNetworkService interface { | ||||
|  | ||||
| // ClientConfig stores proxy client configuration. | ||||
| type ClientConfig struct { | ||||
| 	// Main configuration. | ||||
| 	Profile *appctlpb.ClientProfile | ||||
|  | ||||
| 	// A dialer to connect to proxy server via stream-oriented network connections. | ||||
|   | ||||
| @@ -246,6 +246,9 @@ func (mc *mieruClient) DialContext(ctx context.Context, addr net.Addr) (net.Conn | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if mc.config.Profile.GetHandshakeMode() == appctlpb.HandshakeMode_HANDSHAKE_NO_WAIT { | ||||
| 		return apicommon.NewEarlyConn(conn, netAddrSpec), nil | ||||
| 	} | ||||
| 	return mc.dialPostHandshake(conn, netAddrSpec) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Package: mieru | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Section: net | ||||
| Priority: optional | ||||
| Architecture: amd64 | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Name: mieru | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Release: 1%{?dist} | ||||
| Summary: Mieru proxy client | ||||
| License: GPLv3+ | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Package: mieru | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Section: net | ||||
| Priority: optional | ||||
| Architecture: arm64 | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Name: mieru | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Release: 1%{?dist} | ||||
| Summary: Mieru proxy client | ||||
| License: GPLv3+ | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Package: mita | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Section: net | ||||
| Priority: optional | ||||
| Architecture: amd64 | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Name: mita | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Release: 1%{?dist} | ||||
| Summary: Mieru proxy server | ||||
| License: GPLv3+ | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Package: mita | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Section: net | ||||
| Priority: optional | ||||
| Architecture: arm64 | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| Name: mita | ||||
| Version: 3.19.2 | ||||
| Version: 3.20.0 | ||||
| Release: 1%{?dist} | ||||
| Summary: Mieru proxy server | ||||
| License: GPLv3+ | ||||
|   | ||||
| @@ -18,32 +18,32 @@ Or you can manually install and configure proxy server using the steps below. | ||||
|  | ||||
| ```sh | ||||
| # Debian / Ubuntu - X86_64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_amd64.deb | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita_3.20.0_amd64.deb | ||||
|  | ||||
| # Debian / Ubuntu - ARM 64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_arm64.deb | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita_3.20.0_arm64.deb | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - X86_64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.x86_64.rpm | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita-3.20.0-1.x86_64.rpm | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - ARM 64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.aarch64.rpm | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita-3.20.0-1.aarch64.rpm | ||||
| ``` | ||||
|  | ||||
| ## Install mita package | ||||
|  | ||||
| ```sh | ||||
| # Debian / Ubuntu - X86_64 | ||||
| sudo dpkg -i mita_3.19.2_amd64.deb | ||||
| sudo dpkg -i mita_3.20.0_amd64.deb | ||||
|  | ||||
| # Debian / Ubuntu - ARM 64 | ||||
| sudo dpkg -i mita_3.19.2_arm64.deb | ||||
| sudo dpkg -i mita_3.20.0_arm64.deb | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - X86_64 | ||||
| sudo rpm -Uvh --force mita-3.19.2-1.x86_64.rpm | ||||
| sudo rpm -Uvh --force mita-3.20.0-1.x86_64.rpm | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - ARM 64 | ||||
| sudo rpm -Uvh --force mita-3.19.2-1.aarch64.rpm | ||||
| sudo rpm -Uvh --force mita-3.20.0-1.aarch64.rpm | ||||
| ``` | ||||
|  | ||||
| Those instructions can also be used to upgrade the version of mita software package. | ||||
|   | ||||
| @@ -18,32 +18,32 @@ sudo python3 setup.py --lang=zh | ||||
|  | ||||
| ```sh | ||||
| # Debian / Ubuntu - X86_64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_amd64.deb | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita_3.20.0_amd64.deb | ||||
|  | ||||
| # Debian / Ubuntu - ARM 64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita_3.19.2_arm64.deb | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita_3.20.0_arm64.deb | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - X86_64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.x86_64.rpm | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita-3.20.0-1.x86_64.rpm | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - ARM 64 | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.19.2/mita-3.19.2-1.aarch64.rpm | ||||
| curl -LSO https://github.com/enfein/mieru/releases/download/v3.20.0/mita-3.20.0-1.aarch64.rpm | ||||
| ``` | ||||
|  | ||||
| ## 安装 mita 软件包 | ||||
|  | ||||
| ```sh | ||||
| # Debian / Ubuntu - X86_64 | ||||
| sudo dpkg -i mita_3.19.2_amd64.deb | ||||
| sudo dpkg -i mita_3.20.0_amd64.deb | ||||
|  | ||||
| # Debian / Ubuntu - ARM 64 | ||||
| sudo dpkg -i mita_3.19.2_arm64.deb | ||||
| sudo dpkg -i mita_3.20.0_arm64.deb | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - X86_64 | ||||
| sudo rpm -Uvh --force mita-3.19.2-1.x86_64.rpm | ||||
| sudo rpm -Uvh --force mita-3.20.0-1.x86_64.rpm | ||||
|  | ||||
| # RedHat / CentOS / Rocky Linux - ARM 64 | ||||
| sudo rpm -Uvh --force mita-3.19.2-1.aarch64.rpm | ||||
| sudo rpm -Uvh --force mita-3.20.0-1.aarch64.rpm | ||||
| ``` | ||||
|  | ||||
| 上述指令也可以用来升级 mita 软件包的版本。 | ||||
|   | ||||
| @@ -16,5 +16,5 @@ | ||||
| package version | ||||
|  | ||||
| const ( | ||||
| 	AppVersion = "3.19.2" | ||||
| 	AppVersion = "3.20.0" | ||||
| ) | ||||
|   | ||||
| @@ -41,6 +41,7 @@ var ( | ||||
| 	serverIP       = flag.String("server_ip", "", "IP address of mieru proxy server") | ||||
| 	serverPort     = flag.Int("server_port", 0, "Port number of mieru proxy server") | ||||
| 	serverProtocol = flag.String("server_protocol", "TCP", "Transport protocol: TCP or UDP") | ||||
| 	handshakeMode  = flag.String("handshake_mode", "HANDSHAKE_STANDARD", "Handshake mode: HANDSHAKE_STANDARD or HANDSHAKE_NO_WAIT") | ||||
| 	debug          = flag.Bool("debug", false, "Display debug messages") | ||||
| ) | ||||
|  | ||||
| @@ -73,6 +74,15 @@ func main() { | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("Transport protocol %q is invalid", *serverProtocol)) | ||||
| 	} | ||||
| 	var handshakeModeConfig appctlpb.HandshakeMode | ||||
| 	switch *handshakeMode { | ||||
| 	case "HANDSHAKE_STANDARD": | ||||
| 		handshakeModeConfig = appctlpb.HandshakeMode_HANDSHAKE_STANDARD | ||||
| 	case "HANDSHAKE_NO_WAIT": | ||||
| 		handshakeModeConfig = appctlpb.HandshakeMode_HANDSHAKE_NO_WAIT | ||||
| 	default: | ||||
| 		panic(fmt.Sprintf("Handshake mode %q is invalid", *handshakeMode)) | ||||
| 	} | ||||
|  | ||||
| 	c := client.NewClient() | ||||
| 	if err := c.Store(&client.ClientConfig{ | ||||
| @@ -94,6 +104,7 @@ func main() { | ||||
| 				}, | ||||
| 			}, | ||||
| 			Mtu:           proto.Int32(1400), | ||||
| 			HandshakeMode: &handshakeModeConfig, | ||||
| 		}, | ||||
| 	}); err != nil { | ||||
| 		panic(err) | ||||
|   | ||||
| @@ -35,9 +35,18 @@ sleep 1 | ||||
| ./mita run & | ||||
| sleep 1 | ||||
|  | ||||
| # Start mieru API client. | ||||
| # Start mieru API clients. | ||||
| ./exampleapiclient -port=1081 -username=baozi -password=manlianpenfen \ | ||||
|   -server_ip=127.0.0.1 -server_port=8964 & | ||||
|   -server_ip=127.0.0.1 -server_port=8964 -server_protocol=TCP & | ||||
| sleep 1 | ||||
| ./exampleapiclient -port=1082 -username=baozi -password=manlianpenfen \ | ||||
|   -server_ip=127.0.0.1 -server_port=8964 -server_protocol=UDP & | ||||
| sleep 1 | ||||
| ./exampleapiclient -port=1083 -username=baozi -password=manlianpenfen \ | ||||
|   -server_ip=127.0.0.1 -server_port=8964 -server_protocol=TCP -handshake_mode=HANDSHAKE_NO_WAIT & | ||||
| sleep 1 | ||||
| ./exampleapiclient -port=1084 -username=baozi -password=manlianpenfen \ | ||||
|   -server_ip=127.0.0.1 -server_port=8964 -server_protocol=UDP -handshake_mode=HANDSHAKE_NO_WAIT & | ||||
| sleep 1 | ||||
|  | ||||
| # Run TCP test. | ||||
|   | ||||
| @@ -105,6 +105,19 @@ if [ "$?" -ne "0" ]; then | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| sleep 1 | ||||
| echo ">>> socks5 UDP associate - TCP with API client - handshake no wait <<<" | ||||
| ./socksudpclient -dst_host=127.0.0.1 -dst_port=9090 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1083 \ | ||||
|   -interval_ms=10 -num_request=100 -num_conn=60 | ||||
| if [ "$?" -ne "0" ]; then | ||||
|     print_mieru_client_log | ||||
|     print_mieru_client_thread_dump | ||||
|     print_mieru_server_thread_dump | ||||
|     echo "Test UDP associate - TCP with API client (handshake no wait) failed." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # Collect profile with UDP associate. | ||||
| ./mieru get heap-profile /test/mieru.associate.heap.gz | ||||
| ./mita get heap-profile /test/mita.associate.heap.gz | ||||
|   | ||||
| @@ -149,7 +149,7 @@ fi | ||||
|  | ||||
| # Start testing. | ||||
| sleep 2 | ||||
| echo ">>> socks5 - new connections - TCP <<<" | ||||
| echo ">>> socks5 - new connections - TCP - handshake no wait <<<" | ||||
| ./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1080 \ | ||||
|   -test_case=new_conn -num_request=3000 | ||||
| @@ -161,6 +161,16 @@ if [ "$?" -ne "0" ]; then | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| sleep 1 | ||||
| echo ">>> socks5 - new connections with API client - TCP - handshake no wait <<<" | ||||
| ./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1083 \ | ||||
|   -test_case=new_conn -num_request=3000 | ||||
| if [ "$?" -ne "0" ]; then | ||||
|     echo "TCP - test socks5 new_conn (handshake no wait) with API client failed." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # Stop mieru client. | ||||
| ./mieru stop | ||||
| if [[ "$?" -ne 0 ]]; then | ||||
|   | ||||
| @@ -55,10 +55,6 @@ if [[ "$?" -ne 0 ]]; then | ||||
| fi | ||||
| ./mieru profile cpu start /test/mieru.udp.cpu.gz | ||||
|  | ||||
| # Start mieru API client. | ||||
| ./exampleapiclient -port=1082 -username=baozi -password=manlianpenfen \ | ||||
|   -server_ip=127.0.0.1 -server_port=8964 -server_protocol=UDP & | ||||
|  | ||||
| # Start testing. | ||||
| sleep 2 | ||||
| echo ">>> socks5 - new connections - UDP <<<" | ||||
| @@ -153,7 +149,7 @@ fi | ||||
|  | ||||
| # Start testing. | ||||
| sleep 2 | ||||
| echo ">>> socks5 - new connections - UDP <<<" | ||||
| echo ">>> socks5 - new connections - UDP - handshake no wait <<<" | ||||
| ./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1080 \ | ||||
|   -test_case=new_conn -num_request=3000 | ||||
| @@ -165,6 +161,16 @@ if [ "$?" -ne "0" ]; then | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| sleep 1 | ||||
| echo ">>> socks5 - new connections with API client - UDP - handshake no wait <<<" | ||||
| ./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1084 \ | ||||
|   -test_case=new_conn -num_request=3000 | ||||
| if [ "$?" -ne "0" ]; then | ||||
|     echo "UDP - test socks5 new_conn (handshake no wait) with API client failed." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # Stop mieru client. | ||||
| ./mieru stop | ||||
| if [[ "$?" -ne 0 ]]; then | ||||
|   | ||||
| @@ -22,6 +22,7 @@ WORKDIR /test | ||||
| # Copy binaries, data and test script into the container. | ||||
| COPY mihomo mita httpserver sockshttpclient socksudpclient udpserver \ | ||||
|     test/deploy/mihomo/mihomo-config.yaml \ | ||||
|     test/deploy/mihomo/mihomo-config-no-wait.yaml \ | ||||
|     test/deploy/mihomo/server_tcp.json \ | ||||
|     test/deploy/mihomo/libtest.sh \ | ||||
|     test/deploy/mihomo/test_tcp.sh \ | ||||
|   | ||||
							
								
								
									
										19
									
								
								mieru/test/deploy/mihomo/mihomo-config-no-wait.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								mieru/test/deploy/mihomo/mihomo-config-no-wait.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| dns: | ||||
|   enable: true | ||||
|   nameserver: | ||||
|     - 8.8.8.8 | ||||
| log-level: warning | ||||
| mixed-port: 1081 | ||||
| mode: rule | ||||
| proxies: | ||||
|   - name: mieru | ||||
|     type: mieru | ||||
|     server: 127.0.0.1 | ||||
|     port: 8964 | ||||
|     transport: TCP | ||||
|     udp: true | ||||
|     username: baozi | ||||
|     password: manlianpenfen | ||||
|     handshake-mode: HANDSHAKE_NO_WAIT | ||||
| rules: | ||||
|   - MATCH,mieru | ||||
| @@ -40,6 +40,8 @@ fi | ||||
| # Start mihomo. | ||||
| ./mihomo -f mihomo-config.yaml & | ||||
| sleep 1 | ||||
| ./mihomo -f mihomo-config-no-wait.yaml & | ||||
| sleep 1 | ||||
|  | ||||
| # Start testing. | ||||
| sleep 2 | ||||
| @@ -86,6 +88,50 @@ if [ "$?" -ne "0" ]; then | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| sleep 1 | ||||
| echo ">>> socks5 - new connections - TCP - handshake no wait <<<" | ||||
| ./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1081 \ | ||||
|   -test_case=new_conn -num_request=3000 | ||||
| if [ "$?" -ne "0" ]; then | ||||
|     print_mieru_server_thread_dump | ||||
|     echo "TCP - test socks5 new_conn (handshake no wait) failed." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| sleep 1 | ||||
| echo ">>> http - new connections - TCP - handshake no wait <<<" | ||||
| ./sockshttpclient -proxy_mode=http -dst_host=127.0.0.1 -dst_port=8080 \ | ||||
|   -local_http_host=127.0.0.1 -local_http_port=1081 \ | ||||
|   -test_case=new_conn -num_request=1000 | ||||
| if [ "$?" -ne "0" ]; then | ||||
|     print_mieru_server_thread_dump | ||||
|     echo "TCP - test HTTP new_conn (handshake no wait) failed." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| sleep 1 | ||||
| echo ">>> socks5 - reuse one connection - TCP - handshake no wait <<<" | ||||
| ./sockshttpclient -dst_host=127.0.0.1 -dst_port=8080 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1081 \ | ||||
|   -test_case=reuse_conn -test_time_sec=30 | ||||
| if [ "$?" -ne "0" ]; then | ||||
|     print_mieru_server_thread_dump | ||||
|     echo "TCP - test socks5 reuse_conn (handshake no wait) failed." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| sleep 1 | ||||
| echo ">>> socks5 UDP associate - TCP - handshake no wait <<<" | ||||
| ./socksudpclient -dst_host=127.0.0.1 -dst_port=9090 \ | ||||
|   -local_proxy_host=127.0.0.1 -local_proxy_port=1081 \ | ||||
|   -interval_ms=10 -num_request=100 -num_conn=60 | ||||
| if [ "$?" -ne "0" ]; then | ||||
|     print_mieru_server_thread_dump | ||||
|     echo "TCP - test socks5 udp_associate (handshake no wait) failed." | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # Print metrics and memory statistics. | ||||
| print_mieru_server_metrics | ||||
| sleep 1 | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package adapter | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| @@ -236,6 +235,11 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In | ||||
| 	} | ||||
| 	req = req.WithContext(ctx) | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{}) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	transport := &http.Transport{ | ||||
| 		DialContext: func(context.Context, string, string) (net.Conn, error) { | ||||
| 			return instance, nil | ||||
| @@ -245,7 +249,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In | ||||
| 		IdleConnTimeout:       90 * time.Second, | ||||
| 		TLSHandshakeTimeout:   10 * time.Second, | ||||
| 		ExpectContinueTimeout: 1 * time.Second, | ||||
| 		TLSClientConfig:       ca.GetGlobalTLSConfig(&tls.Config{}), | ||||
| 		TLSClientConfig:       tlsConfig, | ||||
| 	} | ||||
|  | ||||
| 	client := http.Client{ | ||||
|   | ||||
| @@ -167,10 +167,13 @@ func NewHttp(option HttpOption) (*Http, error) { | ||||
| 			sni = option.SNI | ||||
| 		} | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{ | ||||
| 		tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				ServerName:         sni, | ||||
| 		}, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
| @@ -160,14 +160,16 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { | ||||
| 		serverName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         serverName, | ||||
| 			InsecureSkipVerify: option.SkipCertVerify, | ||||
| 			MinVersion:         tls.VersionTLS13, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) | ||||
| 		}, | ||||
| 		Fingerprint:    option.Fingerprint, | ||||
| 		CustomCA:       option.CustomCA, | ||||
| 		CustomCAString: option.CustomCAString, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -141,14 +141,16 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { | ||||
| 		serverName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         serverName, | ||||
| 			InsecureSkipVerify: option.SkipCertVerify, | ||||
| 			MinVersion:         tls.VersionTLS13, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) | ||||
| 		}, | ||||
| 		Fingerprint:    option.Fingerprint, | ||||
| 		CustomCA:       option.CustomCA, | ||||
| 		CustomCAString: option.CustomCAString, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -193,13 +193,14 @@ func (ss *Socks5) clientHandshakeContext(ctx context.Context, c net.Conn, addr s | ||||
| func NewSocks5(option Socks5Option) (*Socks5, error) { | ||||
| 	var tlsConfig *tls.Config | ||||
| 	if option.TLS { | ||||
| 		tlsConfig = &tls.Config{ | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				ServerName:         option.Server, | ||||
| 		} | ||||
|  | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
| @@ -100,14 +100,15 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C. | ||||
| 		} | ||||
|  | ||||
| 		wsOpts.TLS = true | ||||
| 		tlsConfig := &tls.Config{ | ||||
| 		wsOpts.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				NextProtos:         alpn, | ||||
| 				MinVersion:         tls.VersionTLS12, | ||||
| 				InsecureSkipVerify: t.option.SkipCertVerify, | ||||
| 				ServerName:         t.option.SNI, | ||||
| 		} | ||||
|  | ||||
| 		wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: t.option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -363,15 +364,15 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { | ||||
| 			return c, nil | ||||
| 		} | ||||
|  | ||||
| 		tlsConfig := &tls.Config{ | ||||
| 		tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 			TLSConfig: &tls.Config{ | ||||
| 				NextProtos:         option.ALPN, | ||||
| 				MinVersion:         tls.VersionTLS12, | ||||
| 				InsecureSkipVerify: option.SkipCertVerify, | ||||
| 				ServerName:         option.SNI, | ||||
| 		} | ||||
|  | ||||
| 		var err error | ||||
| 		tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) | ||||
| 			}, | ||||
| 			Fingerprint: option.Fingerprint, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|   | ||||
| @@ -161,17 +161,20 @@ func (t *Tuic) ProxyInfo() C.ProxyInfo { | ||||
| func NewTuic(option TuicOption) (*Tuic, error) { | ||||
| 	addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) | ||||
| 	serverName := option.Server | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 	if option.SNI != "" { | ||||
| 		serverName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         serverName, | ||||
| 			InsecureSkipVerify: option.SkipCertVerify, | ||||
| 			MinVersion:         tls.VersionTLS13, | ||||
| 	} | ||||
| 	if option.SNI != "" { | ||||
| 		tlsConfig.ServerName = option.SNI | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) | ||||
| 		}, | ||||
| 		Fingerprint:    option.Fingerprint, | ||||
| 		CustomCA:       option.CustomCA, | ||||
| 		CustomCAString: option.CustomCAString, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|   | ||||
| @@ -95,14 +95,15 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M | ||||
| 		} | ||||
| 		if v.option.TLS { | ||||
| 			wsOpts.TLS = true | ||||
| 			tlsConfig := &tls.Config{ | ||||
| 			wsOpts.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					MinVersion:         tls.VersionTLS12, | ||||
| 					ServerName:         host, | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					NextProtos:         []string{"http/1.1"}, | ||||
| 			} | ||||
|  | ||||
| 			wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @@ -498,10 +499,13 @@ func NewVless(option VlessOption) (*Vless, error) { | ||||
| 		} | ||||
| 		var tlsConfig *tls.Config | ||||
| 		if option.TLS { | ||||
| 			tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{ | ||||
| 			tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					ServerName:         v.option.ServerName, | ||||
| 			}, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|   | ||||
| @@ -123,13 +123,14 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M | ||||
|  | ||||
| 		if v.option.TLS { | ||||
| 			wsOpts.TLS = true | ||||
| 			tlsConfig := &tls.Config{ | ||||
| 			wsOpts.TLSConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					ServerName:         host, | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					NextProtos:         []string{"http/1.1"}, | ||||
| 			} | ||||
|  | ||||
| 			wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| @@ -501,10 +502,13 @@ func NewVmess(option VmessOption) (*Vmess, error) { | ||||
| 		} | ||||
| 		var tlsConfig *tls.Config | ||||
| 		if option.TLS { | ||||
| 			tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{ | ||||
| 			tlsConfig, err = ca.GetTLSConfig(ca.Option{ | ||||
| 				TLSConfig: &tls.Config{ | ||||
| 					InsecureSkipVerify: v.option.SkipCertVerify, | ||||
| 					ServerName:         v.option.ServerName, | ||||
| 			}, v.option.Fingerprint) | ||||
| 				}, | ||||
| 				Fingerprint: v.option.Fingerprint, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|   | ||||
| @@ -10,7 +10,9 @@ import ( | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/metacubex/mihomo/common/once" | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| ) | ||||
|  | ||||
| var globalCertPool *x509.CertPool | ||||
| @@ -65,18 +67,6 @@ func ResetCertificate() { | ||||
| 	initializeCertPool() | ||||
| } | ||||
|  | ||||
| func getCertPool() *x509.CertPool { | ||||
| 	if globalCertPool == nil { | ||||
| 		mutex.Lock() | ||||
| 		defer mutex.Unlock() | ||||
| 		if globalCertPool != nil { | ||||
| 			return globalCertPool | ||||
| 		} | ||||
| 		initializeCertPool() | ||||
| 	} | ||||
| 	return globalCertPool | ||||
| } | ||||
|  | ||||
| func GetCertPool(customCA string, customCAString string) (*x509.CertPool, error) { | ||||
| 	var certificate []byte | ||||
| 	var err error | ||||
| @@ -99,22 +89,41 @@ func GetCertPool(customCA string, customCAString string) (*x509.CertPool, error) | ||||
| 		} | ||||
| 		return certPool, nil | ||||
| 	} else { | ||||
| 		return getCertPool(), nil | ||||
| 		mutex.Lock() | ||||
| 		defer mutex.Unlock() | ||||
| 		if globalCertPool == nil { | ||||
| 			initializeCertPool() | ||||
| 		} | ||||
| 		return globalCertPool, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GetTLSConfig specified fingerprint, customCA and customCAString | ||||
| func GetTLSConfig(tlsConfig *tls.Config, fingerprint string, customCA string, customCAString string) (_ *tls.Config, err error) { | ||||
| type Option struct { | ||||
| 	TLSConfig      *tls.Config | ||||
| 	Fingerprint    string | ||||
| 	CustomCA       string | ||||
| 	CustomCAString string | ||||
| 	ZeroTrust      bool | ||||
| } | ||||
|  | ||||
| func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) { | ||||
| 	tlsConfig = opt.TLSConfig | ||||
| 	if tlsConfig == nil { | ||||
| 		tlsConfig = &tls.Config{} | ||||
| 	} | ||||
| 	tlsConfig.RootCAs, err = GetCertPool(customCA, customCAString) | ||||
| 	tlsConfig.Time = ntp.Now | ||||
|  | ||||
| 	if opt.ZeroTrust { | ||||
| 		tlsConfig.RootCAs = zeroTrustCertPool() | ||||
| 	} else { | ||||
| 		tlsConfig.RootCAs, err = GetCertPool(opt.CustomCA, opt.CustomCAString) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(fingerprint) > 0 { | ||||
| 		tlsConfig.VerifyPeerCertificate, err = NewFingerprintVerifier(fingerprint) | ||||
| 	if len(opt.Fingerprint) > 0 { | ||||
| 		tlsConfig.VerifyPeerCertificate, err = NewFingerprintVerifier(opt.Fingerprint) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -123,12 +132,12 @@ func GetTLSConfig(tlsConfig *tls.Config, fingerprint string, customCA string, cu | ||||
| 	return tlsConfig, nil | ||||
| } | ||||
|  | ||||
| // GetSpecifiedFingerprintTLSConfig specified fingerprint | ||||
| func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) (*tls.Config, error) { | ||||
| 	return GetTLSConfig(tlsConfig, fingerprint, "", "") | ||||
| var zeroTrustCertPool = once.OnceValue(func() *x509.CertPool { | ||||
| 	if len(_CaCertificates) != 0 { // always using embed cert first | ||||
| 		zeroTrustCertPool := x509.NewCertPool() | ||||
| 		if zeroTrustCertPool.AppendCertsFromPEM(_CaCertificates) { | ||||
| 			return zeroTrustCertPool | ||||
| 		} | ||||
|  | ||||
| func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { | ||||
| 	tlsConfig, _ = GetTLSConfig(tlsConfig, "", "", "") | ||||
| 	return tlsConfig | ||||
| 	} | ||||
| 	return nil // fallback to system pool | ||||
| }) | ||||
|   | ||||
| @@ -2,7 +2,6 @@ package http | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| @@ -28,11 +27,11 @@ func SetUA(UA string) { | ||||
| 	ua = UA | ||||
| } | ||||
|  | ||||
| func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { | ||||
| 	return HttpRequestWithProxy(ctx, url, method, header, body, "") | ||||
| func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader, options ...Option) (*http.Response, error) { | ||||
| 	opt := option{} | ||||
| 	for _, o := range options { | ||||
| 		o(&opt) | ||||
| 	} | ||||
|  | ||||
| func HttpRequestWithProxy(ctx context.Context, url, method string, header map[string][]string, body io.Reader, specialProxy string) (*http.Response, error) { | ||||
| 	method = strings.ToUpper(method) | ||||
| 	urlRes, err := URL.Parse(url) | ||||
| 	if err != nil { | ||||
| @@ -40,6 +39,10 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
| 	} | ||||
|  | ||||
| 	req, err := http.NewRequest(method, urlRes.String(), body) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	for k, v := range header { | ||||
| 		for _, v := range v { | ||||
| 			req.Header.Add(k, v) | ||||
| @@ -50,10 +53,6 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
| 		req.Header.Set("User-Agent", UA()) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if user := urlRes.User; user != nil { | ||||
| 		password, _ := user.Password() | ||||
| 		req.SetBasicAuth(user.Username(), password) | ||||
| @@ -61,6 +60,11 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
|  | ||||
| 	req = req.WithContext(ctx) | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(opt.caOption) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	transport := &http.Transport{ | ||||
| 		// from http.DefaultTransport | ||||
| 		DisableKeepAlives:     runtime.GOOS == "android", | ||||
| @@ -69,15 +73,34 @@ func HttpRequestWithProxy(ctx context.Context, url, method string, header map[st | ||||
| 		TLSHandshakeTimeout:   10 * time.Second, | ||||
| 		ExpectContinueTimeout: 1 * time.Second, | ||||
| 		DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { | ||||
| 			if conn, err := inner.HandleTcp(inner.GetTunnel(), address, specialProxy); err == nil { | ||||
| 			if conn, err := inner.HandleTcp(inner.GetTunnel(), address, opt.specialProxy); err == nil { | ||||
| 				return conn, nil | ||||
| 			} else { | ||||
| 				return dialer.DialContext(ctx, network, address) | ||||
| 			} | ||||
| 		}, | ||||
| 		TLSClientConfig: ca.GetGlobalTLSConfig(&tls.Config{}), | ||||
| 		TLSClientConfig: tlsConfig, | ||||
| 	} | ||||
|  | ||||
| 	client := http.Client{Transport: transport} | ||||
| 	return client.Do(req) | ||||
| } | ||||
|  | ||||
| type Option func(opt *option) | ||||
|  | ||||
| type option struct { | ||||
| 	specialProxy string | ||||
| 	caOption     ca.Option | ||||
| } | ||||
|  | ||||
| func WithSpecialProxy(name string) Option { | ||||
| 	return func(opt *option) { | ||||
| 		opt.specialProxy = name | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func WithCAOption(caOption ca.Option) Option { | ||||
| 	return func(opt *option) { | ||||
| 		opt.caOption = caOption | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -135,7 +135,7 @@ func (h *HTTPVehicle) Read(ctx context.Context, oldHash utils.HashType) (buf []b | ||||
| 			setIfNoneMatch = true | ||||
| 		} | ||||
| 	} | ||||
| 	resp, err := mihomoHttp.HttpRequestWithProxy(ctx, h.url, http.MethodGet, header, nil, h.proxy) | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, header, nil, mihomoHttp.WithSpecialProxy(h.proxy)) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|   | ||||
| @@ -15,6 +15,7 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/metacubex/mihomo/component/ca" | ||||
| 	mihomoHttp "github.com/metacubex/mihomo/component/http" | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	"github.com/metacubex/mihomo/constant/features" | ||||
| @@ -171,7 +172,7 @@ func (u *CoreUpdater) Update(currentExePath string, channel string, force bool) | ||||
| func (u *CoreUpdater) getLatestVersion(versionURL string) (version string, err error) { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) | ||||
| 	defer cancel() | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, nil, nil) | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, nil, nil, mihomoHttp.WithCAOption(ca.Option{ZeroTrust: true})) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| @@ -194,7 +195,7 @@ func (u *CoreUpdater) getLatestVersion(versionURL string) (version string, err e | ||||
| func (u *CoreUpdater) download(updateDir, packagePath, packageURL string) (err error) { | ||||
| 	ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) | ||||
| 	defer cancel() | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, nil, nil) | ||||
| 	resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, nil, nil, mihomoHttp.WithCAOption(ca.Option{ZeroTrust: true})) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("http request failed: %w", err) | ||||
| 	} | ||||
|   | ||||
| @@ -48,6 +48,13 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) | ||||
| 		network = "tcp" | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: c.Client.TLSConfig, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	addr := net.JoinHostPort(c.host, c.port) | ||||
| 	conn, err := c.dialer.DialContext(ctx, network, addr) | ||||
| 	if err != nil { | ||||
| @@ -66,7 +73,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) | ||||
| 	ch := make(chan result, 1) | ||||
| 	go func() { | ||||
| 		if strings.HasSuffix(c.Client.Net, "tls") { | ||||
| 			conn = tls.Client(conn, ca.GetGlobalTLSConfig(c.Client.TLSConfig)) | ||||
| 			conn = tls.Client(conn, tlsConfig) | ||||
| 		} | ||||
|  | ||||
| 		dConn := &D.Conn{ | ||||
|   | ||||
| @@ -397,12 +397,16 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp | ||||
| 		return transport, nil | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := ca.GetGlobalTLSConfig( | ||||
| 		&tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			InsecureSkipVerify:     doh.skipCertVerify, | ||||
| 			MinVersion:             tls.VersionTLS12, | ||||
| 			SessionTicketsDisabled: false, | ||||
| 		}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var nextProtos []string | ||||
| 	for _, v := range doh.httpVersions { | ||||
| 		nextProtos = append(nextProtos, string(v)) | ||||
|   | ||||
| @@ -331,15 +331,19 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn *quic.Conn, er | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := ca.GetGlobalTLSConfig( | ||||
| 		&tls.Config{ | ||||
| 	tlsConfig, err := ca.GetTLSConfig(ca.Option{ | ||||
| 		TLSConfig: &tls.Config{ | ||||
| 			ServerName:         host, | ||||
| 			InsecureSkipVerify: doq.skipCertVerify, | ||||
| 			NextProtos: []string{ | ||||
| 				NextProtoDQ, | ||||
| 			}, | ||||
| 			SessionTicketsDisabled: false, | ||||
| 		}, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	transport := quic.Transport{Conn: udp} | ||||
| 	transport.SetCreatedConn(true) // auto close conn | ||||
|   | ||||
| @@ -6,7 +6,7 @@ require ( | ||||
| 	github.com/bahlo/generic-list-go v0.2.0 | ||||
| 	github.com/coreos/go-iptables v0.8.0 | ||||
| 	github.com/dlclark/regexp2 v1.11.5 | ||||
| 	github.com/enfein/mieru/v3 v3.19.1 | ||||
| 	github.com/enfein/mieru/v3 v3.20.0 | ||||
| 	github.com/go-chi/chi/v5 v5.2.3 | ||||
| 	github.com/go-chi/render v1.0.3 | ||||
| 	github.com/gobwas/ws v1.4.0 | ||||
|   | ||||
| @@ -25,8 +25,8 @@ github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZ | ||||
| github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= | ||||
| github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= | ||||
| github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= | ||||
| github.com/enfein/mieru/v3 v3.19.1 h1:19b9kgFC7oJXX9RLEO5Pi1gO6yek5cWlpK7IJVUoE8I= | ||||
| github.com/enfein/mieru/v3 v3.19.1/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM= | ||||
| github.com/enfein/mieru/v3 v3.20.0 h1:1ob7pCIVSH5FYFAfYvim8isLW1vBOS4cFOUF9exJS38= | ||||
| github.com/enfein/mieru/v3 v3.20.0/go.mod h1:zJBUCsi5rxyvHM8fjFf+GLaEl4OEjjBXr1s5F6Qd3hM= | ||||
| github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358 h1:kXYqH/sL8dS/FdoFjr12ePjnLPorPo2FsnrHNuXSDyo= | ||||
| github.com/ericlagergren/aegis v0.0.0-20250325060835-cd0defd64358/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= | ||||
| github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= | ||||
|   | ||||
| @@ -20,6 +20,7 @@ import ( | ||||
| 	tlsC "github.com/metacubex/mihomo/component/tls" | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	"github.com/metacubex/mihomo/log" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/tunnel/statistic" | ||||
|  | ||||
| 	"github.com/go-chi/chi/v5" | ||||
| @@ -201,7 +202,7 @@ func startTLS(cfg *Config) { | ||||
| 		} | ||||
|  | ||||
| 		log.Infoln("RESTful API tls listening at: %s", l.Addr().String()) | ||||
| 		tlsConfig := &tlsC.Config{} | ||||
| 		tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 		tlsConfig.NextProtos = []string{"h2", "http/1.1"} | ||||
| 		tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} | ||||
|  | ||||
|   | ||||
| @@ -17,6 +17,7 @@ import ( | ||||
| 	C "github.com/metacubex/mihomo/constant" | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/anytls/padding" | ||||
| 	"github.com/metacubex/mihomo/transport/anytls/session" | ||||
|  | ||||
| @@ -42,7 +43,7 @@ func New(config LC.AnyTLSServer, tunnel C.Tunnel, additions ...inbound.Addition) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	if config.Certificate != "" && config.PrivateKey != "" { | ||||
| 		cert, err := ca.LoadTLSKeyPair(config.Certificate, config.PrivateKey, C.Path) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -12,6 +12,7 @@ import ( | ||||
| 	authStore "github.com/metacubex/mihomo/listener/auth" | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| ) | ||||
|  | ||||
| type Listener struct { | ||||
| @@ -65,7 +66,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
|  | ||||
| 	if config.Certificate != "" && config.PrivateKey != "" { | ||||
|   | ||||
| @@ -39,7 +39,7 @@ var userUUID = utils.NewUUIDV4().String() | ||||
| var tlsCertificate, tlsPrivateKey, tlsFingerprint, _ = ca.NewRandomTLSKeyPair(ca.KeyPairTypeP256) | ||||
| var tlsConfigCert, _ = tls.X509KeyPair([]byte(tlsCertificate), []byte(tlsPrivateKey)) | ||||
| var tlsConfig = &tls.Config{Certificates: []tls.Certificate{tlsConfigCert}, NextProtos: []string{"h2", "http/1.1"}} | ||||
| var tlsClientConfig, _ = ca.GetTLSConfig(nil, tlsFingerprint, "", "") | ||||
| var tlsClientConfig, _ = ca.GetTLSConfig(ca.Option{Fingerprint: tlsFingerprint}) | ||||
| var realityPrivateKey, realityPublickey string | ||||
| var realityDest = "itunes.apple.com" | ||||
| var realityShortid = "10f897e26c4b9478" | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import ( | ||||
| 	"github.com/metacubex/mihomo/listener/http" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/listener/socks" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/socks4" | ||||
| 	"github.com/metacubex/mihomo/transport/socks5" | ||||
| ) | ||||
| @@ -61,7 +62,7 @@ func NewWithConfig(config LC.AuthServer, tunnel C.Tunnel, additions ...inbound.A | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
|  | ||||
| 	if config.Certificate != "" && config.PrivateKey != "" { | ||||
|   | ||||
| @@ -20,6 +20,7 @@ import ( | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/log" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
|  | ||||
| 	"github.com/metacubex/sing-quic/hysteria2" | ||||
|  | ||||
| @@ -61,6 +62,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	tlsConfig := &tlsC.Config{ | ||||
| 		Time:       ntp.Now, | ||||
| 		MinVersion: tlsC.VersionTLS13, | ||||
| 	} | ||||
| 	tlsConfig.Certificates = []tlsC.Certificate{tlsC.UCertificate(cert)} | ||||
|   | ||||
| @@ -15,6 +15,7 @@ import ( | ||||
| 	LC "github.com/metacubex/mihomo/listener/config" | ||||
| 	"github.com/metacubex/mihomo/listener/reality" | ||||
| 	"github.com/metacubex/mihomo/listener/sing" | ||||
| 	"github.com/metacubex/mihomo/ntp" | ||||
| 	"github.com/metacubex/mihomo/transport/gun" | ||||
| 	"github.com/metacubex/mihomo/transport/vless/encryption" | ||||
| 	mihomoVMess "github.com/metacubex/mihomo/transport/vmess" | ||||
| @@ -75,7 +76,7 @@ func New(config LC.VlessServer, tunnel C.Tunnel, additions ...inbound.Addition) | ||||
| 		}() | ||||
| 	} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
| 	var httpServer http.Server | ||||
|  | ||||
|   | ||||
| @@ -76,7 +76,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) | ||||
|  | ||||
| 	sl = &Listener{false, config, nil, service} | ||||
|  | ||||
| 	tlsConfig := &tlsC.Config{} | ||||
| 	tlsConfig := &tlsC.Config{Time: ntp.Now} | ||||
| 	var realityBuilder *reality.Builder | ||||
| 	var httpServer http.Server | ||||
|  | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 github-action[bot]
					github-action[bot]