mirror of
https://github.com/e1732a364fed/v2ray_simple.git
synced 2025-12-24 13:27:56 +08:00
修订代码,文档,示例;支持客户端证书和CA.
This commit is contained in:
8
.gitignore
vendored
8
.gitignore
vendored
@@ -14,4 +14,10 @@ geosite
|
||||
vs_log*
|
||||
cert.pem
|
||||
cert.key
|
||||
BUILD_VERSION
|
||||
ca.key
|
||||
ca.crt
|
||||
BUILD_VERSION
|
||||
client.crt
|
||||
client.csr
|
||||
client.key
|
||||
.vscode
|
||||
|
||||
@@ -225,6 +225,9 @@ func mainFunc() (result int) {
|
||||
ce.Write(zap.String("dir", wdir))
|
||||
}
|
||||
}
|
||||
if ce := utils.CanLogDebug("All Given Flags"); ce != nil {
|
||||
ce.Write(zap.Any("flags", utils.GivenFlagKVs()))
|
||||
}
|
||||
|
||||
if loadConfigErr != nil && !isFlexible() {
|
||||
|
||||
|
||||
@@ -73,6 +73,10 @@ utls = true #是否使用 utls 来应用 chrome指纹进行伪装
|
||||
|
||||
# 如果要使用 websocket/grpc ,则 客户端和服务端 都要配置 advancedLayer 和 path
|
||||
|
||||
# 下面cert和key用于 "客户端证书", 小白可以无视,高级玩家可以用, 详见 vlesss.server.toml
|
||||
#cert = "client.crt"
|
||||
#key = "client.key"
|
||||
|
||||
# advancedLayer = "ws" # 也可为 grpc 或 quic
|
||||
# path = "/ohmygod_verysimple_is_very_simple" # ws的path和 grpc的serviceName 都在这个path里填写, 为了防探测这里越长越随机越好
|
||||
|
||||
|
||||
@@ -9,13 +9,25 @@ version = 0
|
||||
insecure = true
|
||||
fallback = ":80" # 默认回落地址.ip必须是本机ip(可以省略ip而只写端口,程序会默认补全127.0.0.1), 或者unix domain socket的文件名/路径, 或者 udp://127.0.0.1:80 这种url格式。 (用udp以试图回落到 nginx的 无tls 的 udp的 http3 服务端口,适用于 quic的情况)
|
||||
|
||||
#cert = "cert.pem" # 这里既可以默认放在程序本身目录下,也可以指定完整路径
|
||||
#key = "cert.key" # 如果 cert和key中 有一项没给出, 或者文件不存在, 就会自动在内存中生成随机证书,
|
||||
cert = "cert.pem" # 这里既可以默认放在程序本身目录下,也可以指定完整路径
|
||||
key = "cert.key" # 如果 cert和key中 有一项没给出, 或者文件不存在, 就会自动在内存中生成随机证书,
|
||||
|
||||
# 我们作为示例, 就直接随机证书了, 避免很多小白 共同使用相同的证书 导致被 审查者 察觉.
|
||||
|
||||
#xver = 1 # 可选, 高级用法, 小白不用管. 若为1或者2, 则监听 PROXY protocol, 用于nginx等回落到 verysimple. 实际上目前无论给出的是1还是2, 都会同时监听 v1和v2. 不过这只是目前代码的实现而已, 也许未来会改动, 所以你还是确定选用一个版本.
|
||||
|
||||
# ca = "ca.crt" # 用于验证客户端证书
|
||||
|
||||
# 生成ca的命令:
|
||||
# openssl ecparam -genkey -name prime256v1 -out ca.key
|
||||
# openssl req -new -x509 -days 365 -sha256 -key ca.key -out ca.crt #会提示让你输入 CountryName 等信息。
|
||||
|
||||
# 用ca生成客户端key和crt
|
||||
# openssl ecparam -genkey -name prime256v1 -out client.key
|
||||
# openssl req -new -key client.key -out client.csr #会提示 让你输入 CountryName 等信息。
|
||||
# openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
|
||||
|
||||
# 之后 client.key 和 client.crt 就是我们要的 客户端证书。 注意 上面的openssl 生成 crt 的两个命令 要使用 -sha256参数, 因为默认的sha1已经不安全, 在go1.18中被废弃了。
|
||||
|
||||
[[dial]]
|
||||
protocol = "direct"
|
||||
|
||||
@@ -14,7 +14,15 @@ const (
|
||||
// real nginx response, curl -iv --raw 127.0.0.1/not_exist_path > response
|
||||
Err404response_nginx = "HTTP/1.1 404 Not Found\r\nServer: nginx/1.21.5\r\nDate: Sat, 02 Jan 2006 15:04:05 MST\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Length: 19\r\nConnection: keep-alive\r\nCache-Control: no-cache, no-store, no-transform, must-revalidate, private, max-age=0\r\nExpires: Thu, 01 Jan 1970 08:00:00 AWST\r\nPragma: no-cache\r\nVary: Origin\r\nX-Content-Type-Options: nosniff\r\n\r\n404 page not found"
|
||||
|
||||
/* real nginx response, set nginx config like:
|
||||
location / {
|
||||
return 403;
|
||||
}
|
||||
|
||||
*/
|
||||
Err403response_nginx = `HTTP/1.1 403 Forbidden\r\nServer: nginx/1.14.2\r\nDate: Sat, 07 May 2022 07:03:47 GMT\r\nContent-Type: text/html\r\nContent-Length: 169\r\nConnection: keep-alive\r\n\r\n<html>\r\n<head><title>403 Forbidden</title></head>\r\n<body bgcolor="white">\r\n<center><h1>403 Forbidden</h1></center>\r\n<hr><center>nginx/1.14.2</center>\r\n</body>\r\n</html>\r\n`
|
||||
|
||||
//备注,vim中, "\r" 显示为 ^M, 输入它是用 ctrl + V + M
|
||||
)
|
||||
|
||||
var nginxTimezone = time.FixedZone("GMT", 0)
|
||||
|
||||
@@ -39,9 +39,9 @@ func LoadMaxmindGeoipFile(fn string) {
|
||||
if fn == "" { //因为 GeoipFileName 是公有变量,所以可能会被设成""
|
||||
return
|
||||
}
|
||||
bs, e := os.ReadFile(fn)
|
||||
bs, e := os.ReadFile(utils.GetFilePath(fn))
|
||||
if e != nil {
|
||||
log.Println("LoadMaxmindGeoipFile err", e)
|
||||
log.Printf("LoadMaxmindGeoipFile err, %s\n", e.Error())
|
||||
return
|
||||
}
|
||||
loadMaxmindGeoipBytes(bs)
|
||||
|
||||
@@ -318,20 +318,42 @@ func (b *Base) InitAdvLayer() {
|
||||
Headers = dc.HttpHeader
|
||||
}
|
||||
|
||||
advClient, err := creator.NewClientFromConf(&advLayer.Conf{
|
||||
var tConf *tls.Config
|
||||
if creator.IsSuper() {
|
||||
|
||||
tConf = &tls.Config{
|
||||
InsecureSkipVerify: dc.Insecure,
|
||||
NextProtos: dc.Alpn,
|
||||
ServerName: dc.Host,
|
||||
}
|
||||
|
||||
if dc.TLSCert != "" && dc.TLSKey != "" {
|
||||
certArray, err := tlsLayer.GetCertArrayFromFile(dc.TLSCert, dc.TLSKey)
|
||||
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load client cert file failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.Certificates = certArray
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
aConf := &advLayer.Conf{
|
||||
Path: dc.Path,
|
||||
Host: dc.Host,
|
||||
IsEarly: dc.IsEarly,
|
||||
Addr: ad,
|
||||
Headers: Headers,
|
||||
Xver: dc.Xver,
|
||||
TlsConf: &tls.Config{
|
||||
InsecureSkipVerify: dc.Insecure,
|
||||
NextProtos: dc.Alpn,
|
||||
ServerName: dc.Host,
|
||||
},
|
||||
Extra: dc.Extra,
|
||||
})
|
||||
TlsConf: tConf,
|
||||
Extra: dc.Extra,
|
||||
}
|
||||
|
||||
advClient, err := creator.NewClientFromConf(aConf)
|
||||
if err != nil {
|
||||
|
||||
if ce := utils.CanLogErr("InitAdvLayer client failed "); ce != nil {
|
||||
@@ -357,18 +379,38 @@ func (b *Base) InitAdvLayer() {
|
||||
|
||||
var certArray []tls.Certificate
|
||||
|
||||
if lc.TLSCert != "" && lc.TLSKey != "" {
|
||||
certArray, err = tlsLayer.GetCertArrayFromFile(lc.TLSCert, lc.TLSKey)
|
||||
if creator.IsSuper() {
|
||||
if lc.TLSCert != "" && lc.TLSKey != "" {
|
||||
certArray, err = tlsLayer.GetCertArrayFromFile(lc.TLSCert, lc.TLSKey)
|
||||
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
|
||||
if ce := utils.CanLogErr("can't create tls cert"); ce != nil {
|
||||
ce.Write(zap.String("cert", lc.TLSCert), zap.String("key", lc.TLSKey), zap.Error(err))
|
||||
if ce := utils.CanLogErr("can't create tls cert"); ce != nil {
|
||||
ce.Write(zap.String("cert", lc.TLSCert), zap.String("key", lc.TLSKey), zap.Error(err))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
tConf := &tls.Config{
|
||||
InsecureSkipVerify: lc.Insecure,
|
||||
NextProtos: lc.Alpn,
|
||||
ServerName: lc.Host,
|
||||
Certificates: certArray,
|
||||
}
|
||||
|
||||
if lc.CA != "" {
|
||||
certPool, err := tlsLayer.LoadCA(lc.CA)
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load CA failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.ClientCAs = certPool
|
||||
tConf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
|
||||
advSer, err := creator.NewServerFromConf(&advLayer.Conf{
|
||||
@@ -378,13 +420,8 @@ func (b *Base) InitAdvLayer() {
|
||||
Xver: lc.Xver,
|
||||
Addr: ad,
|
||||
Headers: Headers,
|
||||
TlsConf: &tls.Config{
|
||||
InsecureSkipVerify: lc.Insecure,
|
||||
NextProtos: lc.Alpn,
|
||||
ServerName: lc.Host,
|
||||
Certificates: certArray,
|
||||
},
|
||||
Extra: lc.Extra,
|
||||
TlsConf: tConf,
|
||||
Extra: lc.Extra,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
|
||||
@@ -9,32 +9,51 @@ import (
|
||||
|
||||
// CommonConf is the common part of ListenConf and DialConf.
|
||||
type CommonConf struct {
|
||||
Tag string `toml:"tag"` //可选
|
||||
Protocol string `toml:"protocol"` //代理层; 约定,如果一个Protocol尾缀去掉了's'后仍然是一个有效协议,则该协议使用了 tls。这种方法继承自 v2simple,适合极简模式
|
||||
Uuid string `toml:"uuid"` //代理层用户的唯一标识,视代理层协议而定,一般使用uuid,但trojan协议是随便的.
|
||||
Host string `toml:"host"` //ip 或域名. 若unix domain socket 则为文件路径
|
||||
IP string `toml:"ip"` //给出Host后,该项可以省略; 既有Host又有ip的情况比较适合cdn
|
||||
Port int `toml:"port"` //若Network不为 unix , 则port项必填
|
||||
Version int `toml:"version"` //可选
|
||||
Tag string `toml:"tag"` //可选
|
||||
|
||||
Extra map[string]any `toml:"extra"` //用于包含任意其它数据.虽然本包自己定义的协议肯定都是已知的,但是如果其他人使用了本包的话,那就有可能添加一些 新协议 特定的数据.
|
||||
|
||||
/////////////////// 网络层 ///////////////////
|
||||
|
||||
Host string `toml:"host"` //ip 或域名. 若unix domain socket 则为文件路径
|
||||
IP string `toml:"ip"` //给出Host后,该项可以省略; 既有Host又有ip的情况比较适合cdn
|
||||
|
||||
/////////////////// 传输层 ///////////////////
|
||||
|
||||
Network string `toml:"network"` //传输层协议; 默认使用tcp, network可选值为 tcp, udp, unix; 理论上来说应该用 transportLayer,但是怕小白不懂,所以使用 network作为名称。而且也不算错,因为go的net包 也是用 network来指示 传输层/网络层协议的. 比如 net.Listen()第一个参数可以用 ip, tcp, udp 等。
|
||||
|
||||
Sockopt *netLayer.Sockopt `toml:"sockopt"` //可选
|
||||
Xver int `toml:"xver"` //可选,只能为0/1/2. 若不为0, 则使用 PROXY protocol 协议头.
|
||||
|
||||
Port int `toml:"port"` //若Network不为 unix , 则port项必填
|
||||
|
||||
Xver int `toml:"xver"` //可选,只能为0/1/2. 若不为0, 则使用 PROXY protocol 协议头.
|
||||
|
||||
/////////////////// tls层 ///////////////////
|
||||
|
||||
TLS bool `toml:"tls"` //tls层; 可选. 如果不使用 's' 后缀法,则还可以配置这一项来更清晰第标明使用tls
|
||||
Insecure bool `toml:"insecure"` //tls 是否安全
|
||||
Alpn []string `toml:"alpn"`
|
||||
|
||||
TLSCert string `toml:"cert"` //可选
|
||||
TLSKey string `toml:"key"` //可选
|
||||
|
||||
/////////////////// http层 ///////////////////
|
||||
|
||||
HttpHeader *httpLayer.HeaderPreset `toml:"header"` //http伪装头; 可选
|
||||
|
||||
AdvancedLayer string `toml:"advancedLayer"` //高级层; 可不填
|
||||
|
||||
IsEarly bool `toml:"early"` //是否启用 0-rtt
|
||||
|
||||
Path string `toml:"path"` //ws 的path 或 grpc的 serviceName。为了简便我们在同一位置给出.
|
||||
|
||||
Extra map[string]any `toml:"extra"` //用于包含任意其它数据.虽然本包自己定义的协议肯定都是已知的,但是如果其他人使用了本包的话,那就有可能添加一些 新协议 特定的数据.
|
||||
/////////////////// 高级层 ///////////////////
|
||||
|
||||
AdvancedLayer string `toml:"advancedLayer"` //高级层; 可选
|
||||
IsEarly bool `toml:"early"` //是否启用 0-rtt
|
||||
|
||||
/////////////////// 代理层 ///////////////////
|
||||
|
||||
Protocol string `toml:"protocol"` //代理层; 约定,如果一个Protocol尾缀去掉了's'后仍然是一个有效协议,则该协议使用了 tls。这种方法继承自 v2simple,适合极简模式
|
||||
Uuid string `toml:"uuid"` //代理层用户的唯一标识,视代理层协议而定,一般使用uuid,但trojan协议是随便的.
|
||||
Version int `toml:"version"` //可选,代理层协议版本号,vless v1 要用到。
|
||||
|
||||
}
|
||||
|
||||
func (cc *CommonConf) GetAddrStr() string {
|
||||
@@ -78,9 +97,10 @@ func (cc *CommonConf) GetAddrStrForListenOrDial() string {
|
||||
// CommonConf.Host , CommonConf.IP, CommonConf.Port is the addr and port for listening
|
||||
type ListenConf struct {
|
||||
CommonConf
|
||||
Fallback any `toml:"fallback"` //可选,默认回落的地址,一般可为 ip:port,数字port or unix socket的文件名
|
||||
TLSCert string `toml:"cert"`
|
||||
TLSKey string `toml:"key"`
|
||||
|
||||
CA string `toml:"ca"` //可选,用于 验证"客户端证书"
|
||||
|
||||
Fallback any `toml:"fallback"` //可选,默认回落的地址,一般可为 ip:port,数字port or unix socket的文件名
|
||||
|
||||
//noroute 意味着 传入的数据 不会被分流,一定会被转发到默认的 dial
|
||||
// 这一项是针对 分流功能的. 如果不设noroute, 则所有listen 得到的流量都会被 试图 进行分流
|
||||
|
||||
@@ -155,7 +155,7 @@ Comparison
|
||||
|
||||
与本作架构对立的架构是 支持转发链 或者说 “链式转发” 的架构,如gost。
|
||||
|
||||
实际上 v2ray的架构 更接近 gost 这种架构。本作的架构比较独特。
|
||||
实际上 v2ray的架构 更接近 gost 这种架构, 而本作的架构比较独特。
|
||||
|
||||
目前本作架构基本上无法实现链式转发,如果要支持,要进行一些重构。应该是可以做到的。
|
||||
*/
|
||||
|
||||
@@ -55,7 +55,15 @@ func prepareTLS_forClient(com BaseInterface, dc *DialConf) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
clic.Tls_c = tlsLayer.NewClient(dc.Host, dc.Insecure, dc.Utls, alpnList)
|
||||
var certConf *tlsLayer.CertConf
|
||||
if dc.TLSCert != "" && dc.TLSKey != "" {
|
||||
certConf = &tlsLayer.CertConf{
|
||||
CertFile: dc.TLSCert,
|
||||
KeyFile: dc.TLSKey,
|
||||
}
|
||||
}
|
||||
|
||||
clic.Tls_c = tlsLayer.NewClient(dc.Host, dc.Insecure, dc.Utls, alpnList, certConf)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -69,7 +77,10 @@ func prepareTLS_forServer(com BaseInterface, lc *ListenConf) error {
|
||||
|
||||
alpnList := updateAlpnListByAdvLayer(com, lc.Alpn)
|
||||
|
||||
tlsserver, err := tlsLayer.NewServer(lc.Host, lc.TLSCert, lc.TLSKey, lc.Insecure, alpnList)
|
||||
tlsserver, err := tlsLayer.NewServer(lc.Host, &tlsLayer.CertConf{
|
||||
CertFile: lc.TLSCert, KeyFile: lc.TLSKey, CA: lc.CA,
|
||||
}, lc.Insecure, alpnList)
|
||||
|
||||
if err == nil {
|
||||
serc.Tls_s = tlsserver
|
||||
} else {
|
||||
@@ -93,7 +104,7 @@ func prepareTLS_forProxyCommon_withURL(u *url.URL, isclient bool, com BaseInterf
|
||||
useUtls := utlsStr != "" && utlsStr != "false" && utlsStr != "0"
|
||||
|
||||
if cc != nil {
|
||||
cc.Tls_c = tlsLayer.NewClient(u.Host, insecure, useUtls, nil)
|
||||
cc.Tls_c = tlsLayer.NewClient(u.Host, insecure, useUtls, nil, nil)
|
||||
|
||||
}
|
||||
|
||||
@@ -104,7 +115,9 @@ func prepareTLS_forProxyCommon_withURL(u *url.URL, isclient bool, com BaseInterf
|
||||
hostAndPort := u.Host
|
||||
sni, _, _ := net.SplitHostPort(hostAndPort)
|
||||
|
||||
tlsserver, err := tlsLayer.NewServer(sni, certFile, keyFile, insecure, nil)
|
||||
tlsserver, err := tlsLayer.NewServer(sni, &tlsLayer.CertConf{
|
||||
CertFile: certFile, KeyFile: keyFile,
|
||||
}, insecure, nil)
|
||||
if err == nil {
|
||||
if cc != nil {
|
||||
cc.Tls_s = tlsserver
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package tlsLayer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
mathrand "math/rand"
|
||||
|
||||
"crypto/ecdsa"
|
||||
@@ -19,6 +21,29 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var ErrCAFileWrong = errors.New("ca file is somehow wrong")
|
||||
|
||||
type CertConf struct {
|
||||
CA string
|
||||
CertFile, KeyFile string
|
||||
}
|
||||
|
||||
func LoadCA(caFile string) (cp *x509.CertPool, err error) {
|
||||
if caFile == "" {
|
||||
err = utils.ErrNilParameter
|
||||
return
|
||||
}
|
||||
cp = x509.NewCertPool()
|
||||
data, err := ioutil.ReadFile(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !cp.AppendCertsFromPEM(data) {
|
||||
return nil, ErrCAFileWrong
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//使用 ecc p256 方式生成证书
|
||||
func GenerateRandomeCert_Key() (certPEM []byte, keyPEM []byte) {
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ type Client struct {
|
||||
alpnList []string
|
||||
}
|
||||
|
||||
func NewClient(host string, insecure bool, use_uTls bool, alpnList []string) *Client {
|
||||
func NewClient(host string, insecure bool, use_uTls bool, alpnList []string, certConf *CertConf) *Client {
|
||||
|
||||
c := &Client{
|
||||
use_uTls: use_uTls,
|
||||
@@ -29,21 +29,56 @@ func NewClient(host string, insecure bool, use_uTls bool, alpnList []string) *Cl
|
||||
c.alpnList = alpnList
|
||||
|
||||
if use_uTls {
|
||||
c.uTlsConfig = utls.Config{
|
||||
tConf := utls.Config{
|
||||
InsecureSkipVerify: insecure,
|
||||
ServerName: host,
|
||||
NextProtos: alpnList,
|
||||
}
|
||||
|
||||
if certConf != nil {
|
||||
certArray, err := GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load client cert file failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
var array []utls.Certificate
|
||||
|
||||
for _, c := range certArray {
|
||||
|
||||
array = append(array, *(*utls.Certificate)(unsafe.Pointer(&c)))
|
||||
}
|
||||
|
||||
tConf.Certificates = array
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
c.uTlsConfig = tConf
|
||||
|
||||
if ce := utils.CanLogInfo("using utls and Chrome fingerprint for"); ce != nil {
|
||||
ce.Write(zap.String("host", host))
|
||||
}
|
||||
} else {
|
||||
c.tlsConfig = &tls.Config{
|
||||
tConf := &tls.Config{
|
||||
InsecureSkipVerify: insecure,
|
||||
ServerName: host,
|
||||
NextProtos: alpnList,
|
||||
}
|
||||
if certConf != nil {
|
||||
certArray, err := GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load client cert file failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.Certificates = certArray
|
||||
|
||||
}
|
||||
}
|
||||
c.tlsConfig = tConf
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/e1732a364fed/v2ray_simple/utils"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/exp/slices"
|
||||
)
|
||||
|
||||
@@ -14,12 +15,17 @@ type Server struct {
|
||||
}
|
||||
|
||||
//如 certFile, keyFile 有一项没给出,则会自动生成随机证书
|
||||
func NewServer(host, certFile, keyFile string, isInsecure bool, alpnList []string) (*Server, error) {
|
||||
func NewServer(host string, certConf *CertConf, isInsecure bool, alpnList []string) (*Server, error) {
|
||||
|
||||
certArray, err := GetCertArrayFromFile(certFile, keyFile)
|
||||
var certArray []tls.Certificate
|
||||
var err error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if certConf != nil {
|
||||
certArray, err = GetCertArrayFromFile(certConf.CertFile, certConf.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
//发现服务端必须给出 http/1.1 等,否则不会协商出这个alpn,而我们为了回落,是需要协商出所有可能需要的 alpn的。
|
||||
@@ -38,13 +44,29 @@ func NewServer(host, certFile, keyFile string, isInsecure bool, alpnList []strin
|
||||
}
|
||||
}
|
||||
|
||||
tConf := &tls.Config{
|
||||
InsecureSkipVerify: isInsecure,
|
||||
ServerName: host,
|
||||
Certificates: certArray,
|
||||
NextProtos: alpnList,
|
||||
}
|
||||
|
||||
if certConf != nil {
|
||||
if certConf.CA != "" {
|
||||
certPool, err := LoadCA(certConf.CA)
|
||||
if err != nil {
|
||||
if ce := utils.CanLogErr("load CA failed"); ce != nil {
|
||||
ce.Write(zap.Error(err))
|
||||
}
|
||||
} else {
|
||||
tConf.ClientCAs = certPool
|
||||
tConf.ClientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
tlsConfig: &tls.Config{
|
||||
InsecureSkipVerify: isInsecure,
|
||||
ServerName: host,
|
||||
Certificates: certArray,
|
||||
NextProtos: alpnList,
|
||||
},
|
||||
tlsConfig: tConf,
|
||||
}
|
||||
|
||||
return s, nil
|
||||
|
||||
@@ -46,6 +46,16 @@ func ParseFlags() {
|
||||
GivenFlags = GetGivenFlags()
|
||||
}
|
||||
|
||||
//return kv pairs for GivenFlags
|
||||
func GivenFlagKVs() (r map[string]string) {
|
||||
r = map[string]string{}
|
||||
|
||||
for k, f := range GivenFlags {
|
||||
r[k] = f.Value.String()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//移除 = "" 和 = false 的项
|
||||
func GetPurgedTomlStr(v any) (string, error) {
|
||||
buf := GetBuf()
|
||||
|
||||
Reference in New Issue
Block a user