mirror of
https://github.com/nadoo/glider.git
synced 2026-06-26 16:40:12 +08:00
111 lines
2.6 KiB
Go
111 lines
2.6 KiB
Go
package anytls
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"errors"
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/nadoo/glider/proxy"
|
|
)
|
|
|
|
type AnyTLS struct {
|
|
dialer proxy.Dialer
|
|
proxy proxy.Proxy
|
|
|
|
addr string
|
|
password string
|
|
serverName string
|
|
skipVerify bool
|
|
certFile string
|
|
keyFile string
|
|
tlsConfig *tls.Config
|
|
|
|
synackTimeout time.Duration
|
|
padding paddingScheme
|
|
}
|
|
|
|
func NewAnyTLS(s string, d proxy.Dialer, p proxy.Proxy) (*AnyTLS, error) {
|
|
u, err := url.Parse(s)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("[anytls] parse url err: %s", err)
|
|
}
|
|
query := u.Query()
|
|
a := &AnyTLS{
|
|
dialer: d,
|
|
proxy: p,
|
|
addr: u.Host,
|
|
password: u.User.Username(),
|
|
serverName: query.Get("serverName"),
|
|
skipVerify: query.Get("skipVerify") == "true",
|
|
certFile: query.Get("cert"),
|
|
keyFile: query.Get("key"),
|
|
synackTimeout: 10 * time.Second,
|
|
}
|
|
if a.password == "" {
|
|
return nil, errors.New("[anytls] password must be specified")
|
|
}
|
|
if a.addr != "" {
|
|
if _, port, _ := net.SplitHostPort(a.addr); port == "" {
|
|
a.addr = net.JoinHostPort(a.addr, "443")
|
|
}
|
|
if a.serverName == "" {
|
|
a.serverName = a.addr[:strings.LastIndex(a.addr, ":")]
|
|
}
|
|
}
|
|
if timeout := query.Get("synackTimeout"); timeout != "" {
|
|
d, err := time.ParseDuration(timeout)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("[anytls] invalid synackTimeout: %s", err)
|
|
}
|
|
a.synackTimeout = d
|
|
}
|
|
if scheme := query.Get("paddingScheme"); scheme != "" {
|
|
a.padding, err = parsePaddingScheme(scheme)
|
|
} else {
|
|
a.padding, err = parsePaddingScheme(defaultPaddingScheme)
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("[anytls] invalid padding scheme: %s", err)
|
|
}
|
|
return a, nil
|
|
}
|
|
|
|
func (s *AnyTLS) Addr() string {
|
|
if s.addr == "" && s.dialer != nil {
|
|
return s.dialer.Addr()
|
|
}
|
|
return s.addr
|
|
}
|
|
|
|
func loadClientTLSConfig(serverName, certFile string, skipVerify bool) (*tls.Config, error) {
|
|
conf := &tls.Config{ServerName: serverName, InsecureSkipVerify: skipVerify, MinVersion: tls.VersionTLS12}
|
|
if certFile != "" {
|
|
certData, err := os.ReadFile(certFile)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("[anytls] read cert file error: %s", err)
|
|
}
|
|
certPool := x509.NewCertPool()
|
|
if !certPool.AppendCertsFromPEM(certData) {
|
|
return nil, fmt.Errorf("[anytls] can not append cert file: %s", certFile)
|
|
}
|
|
conf.RootCAs = certPool
|
|
}
|
|
return conf, nil
|
|
}
|
|
|
|
func init() {
|
|
proxy.AddUsage("anytls", `
|
|
AnyTLS client scheme:
|
|
anytls://password@host:port[?serverName=SERVERNAME][&skipVerify=true][&cert=PATH][&synackTimeout=10s]
|
|
|
|
AnyTLS server scheme:
|
|
anytls://password@host:port?cert=PATH&key=PATH
|
|
`)
|
|
}
|