Merge a6c7c736c2aa51ac451f5ef2f03166fe8ab0a746 into a947f3af6ec78a17d69c52bb07224506ee048428

This commit is contained in:
jose-C2OaWi 2023-12-04 15:44:38 +00:00 committed by GitHub
commit 543d70db3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 210 additions and 31 deletions

View File

@ -48,6 +48,7 @@ type InboundContext struct {
ProcessInfo *process.Info
QueryType uint16
FakeIP bool
IPCIDRMatchSource bool
// rule cache

View File

@ -128,5 +128,40 @@ func NewSTDClient(ctx context.Context, serverAddress string, options option.Outb
}
tlsConfig.RootCAs = certPool
}
if options.ClientAuth {
// explicitly call mutual verification
var cert []byte
var key []byte
if len(options.ClientCertificate) > 0 {
cert = []byte(strings.Join(options.ClientCertificate, "\n"))
} else if options.ClientCertificatePath != "" {
content, err := os.ReadFile(options.ClientCertificatePath)
if err != nil {
return nil, E.Cause(err, "read client certificate")
}
cert = content
}
if len(options.ClientKey) > 0 {
key = []byte(strings.Join(options.ClientKey, "\n"))
} else if options.ClientKeyPath != "" {
content, err := os.ReadFile(options.ClientKeyPath)
if err != nil {
return nil, E.Cause(err, "read client key")
}
key = content
}
if cert == nil {
return nil, E.New("missing client certificate")
} else if key == nil {
return nil, E.New("missing client key")
}
keyPair, err := tls.X509KeyPair(cert, key)
if err != nil {
return nil, E.New(err, "parse x509 key pair")
}
tlsConfig.Certificates = []tls.Certificate{keyPair}
}
return &STDClientConfig{&tlsConfig}, nil
}

View File

@ -3,6 +3,7 @@ package tls
import (
"context"
"crypto/tls"
"crypto/x509"
"net"
"os"
"strings"
@ -212,6 +213,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
}
var certificate []byte
var key []byte
var clientca []byte
if acmeService == nil {
if len(options.Certificate) > 0 {
certificate = []byte(strings.Join(options.Certificate, "\n"))
@ -249,6 +251,29 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
tlsConfig.Certificates = []tls.Certificate{keyPair}
}
}
if options.ClientAuth {
// require client authentication
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
if len(options.ClientCA) > 0 {
clientca = []byte(strings.Join(options.ClientCA, "\n"))
} else if options.ClientCAPath != "" {
content, err := os.ReadFile(options.ClientCAPath)
if err != nil {
return nil, E.Cause(err, "read client CA")
}
clientca = content
}
// add client ca certpool
if len(clientca) > 0 {
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(clientca) {
return nil, E.New("failed to parse client CA:\n\n", clientca)
}
tlsConfig.ClientCAs = certPool
}
} else {
tlsConfig.ClientAuth = tls.NoClientCert
}
return &STDServerConfig{
config: tlsConfig,
logger: logger,
@ -257,5 +282,6 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
key: key,
certificatePath: options.CertificatePath,
keyPath: options.KeyPath,
watcher: &fsnotify.Watcher{},
}, nil
}

View File

@ -12,6 +12,9 @@
"certificate_path": "",
"key": [],
"key_path": "",
"clientAuth": false,
"clientCA": [],
"clientCA_path": "",
"acme": {
"domain": [],
"data_directory": "",
@ -64,8 +67,13 @@
"min_version": "",
"max_version": "",
"cipher_suites": [],
"certificate": "",
"certificate": [],
"certificate_path": "",
"clientAuth": false,
"client_key": [],
"client_key_path": "",
"client_certificate": [],
"client_certificate_path": "",
"ech": {
"enabled": false,
"pq_signature_schemes_enabled": false,
@ -189,6 +197,46 @@ The server private key line array, in PEM format.
The path to the server private key, in PEM format.
#### clientAuth
Enable TLS Client Authentication
#### clientCA
==Server only==
The server's client CA Certificate line array, in PEM format.
#### clientCA_path
==Server only==
The path to the server's client CA certificate, in PEM format.
#### client_certificate
==Client only==
The client certificate line array, in PEM format.
#### certificate_path
==Client only==
The path to the client certificate, in PEM format.
#### client_key
==Client only==
The client private key line array, in PEM format.
#### client_key_path
==Client only==
The path to the client private, in PEM format.
## Custom TLS support
!!! info "QUIC support"
@ -237,7 +285,7 @@ It is recommended to match the parameters of `sing-box generate ech-keypair`.
Disables adaptive sizing of TLS records.
When true, the largest possible TLS record size is always used.
When true, the largest possible TLS record size is always used.
When false, the size of TLS records may be adjusted in an attempt to improve latency.
#### key
@ -385,4 +433,4 @@ Check disabled if empty.
### Reload
For server configuration, certificate, key and ECH key will be automatically reloaded if modified.
For server configuration, certificate, key and ECH key will be automatically reloaded if modified.

View File

@ -12,6 +12,9 @@
"certificate_path": "",
"key": [],
"key_path": "",
"clientAuth": false,
"clientCA": [],
"clientCA_path": "",
"acme": {
"domain": [],
"data_directory": "",
@ -66,6 +69,11 @@
"cipher_suites": [],
"certificate": [],
"certificate_path": "",
"clientAuth": false,
"client_key": [],
"client_key_path": "",
"client_certificate": [],
"client_certificate_path": "",
"ech": {
"enabled": false,
"pq_signature_schemes_enabled": false,
@ -189,6 +197,46 @@ TLS 版本值:
服务器 PEM 私钥路径。
#### clientAuth
启用客户端验证
#### clientCA
==仅服务器==
服务器 PEM 验证客户端 CA 证书行数组
#### clientCA_path
==仅服务器==
服务器 PEM 验证客户端 CA 证书路径
#### client_certificate
==仅客户端==
客户端 PEM 证书行数组。
#### certificate_path
==仅客户端==
客户端 PEM 证书路径。
#### client_key
==仅客户端==
客户端 PEM 私钥行数组。
#### client_key_path
==仅客户端==
客户端 PEM 私钥路径。
#### utls
==仅客户端==
@ -373,4 +421,4 @@ ACME DNS01 验证字段。如果配置,将禁用其他验证方法。
### 重载
对于服务器配置,如果修改,证书和密钥将自动重新加载。
对于服务器配置,如果修改,证书和密钥将自动重新加载。

View File

@ -1,36 +1,45 @@
package option
type InboundTLSOptions struct {
Enabled bool `json:"enabled,omitempty"`
ServerName string `json:"server_name,omitempty"`
Insecure bool `json:"insecure,omitempty"`
ALPN Listable[string] `json:"alpn,omitempty"`
MinVersion string `json:"min_version,omitempty"`
MaxVersion string `json:"max_version,omitempty"`
CipherSuites Listable[string] `json:"cipher_suites,omitempty"`
Certificate Listable[string] `json:"certificate,omitempty"`
CertificatePath string `json:"certificate_path,omitempty"`
Key Listable[string] `json:"key,omitempty"`
KeyPath string `json:"key_path,omitempty"`
ACME *InboundACMEOptions `json:"acme,omitempty"`
ECH *InboundECHOptions `json:"ech,omitempty"`
Reality *InboundRealityOptions `json:"reality,omitempty"`
Enabled bool `json:"enabled,omitempty"`
ServerName string `json:"server_name,omitempty"`
Insecure bool `json:"insecure,omitempty"`
ALPN Listable[string] `json:"alpn,omitempty"`
MinVersion string `json:"min_version,omitempty"`
MaxVersion string `json:"max_version,omitempty"`
CipherSuites Listable[string] `json:"cipher_suites,omitempty"`
Certificate Listable[string] `json:"certificate,omitempty"`
CertificatePath string `json:"certificate_path,omitempty"`
Key Listable[string] `json:"key,omitempty"`
KeyPath string `json:"key_path,omitempty"`
ClientAuth bool `json:"clientAuth,omitempty"`
// , Requireandverify
ClientCA Listable[string] `json:"clientCA,omitempty"`
ClientCAPath string `json:"clientCA_path,omitempty"`
ACME *InboundACMEOptions `json:"acme,omitempty"`
ECH *InboundECHOptions `json:"ech,omitempty"`
Reality *InboundRealityOptions `json:"reality,omitempty"`
}
type OutboundTLSOptions struct {
Enabled bool `json:"enabled,omitempty"`
DisableSNI bool `json:"disable_sni,omitempty"`
ServerName string `json:"server_name,omitempty"`
Insecure bool `json:"insecure,omitempty"`
ALPN Listable[string] `json:"alpn,omitempty"`
MinVersion string `json:"min_version,omitempty"`
MaxVersion string `json:"max_version,omitempty"`
CipherSuites Listable[string] `json:"cipher_suites,omitempty"`
Certificate Listable[string] `json:"certificate,omitempty"`
CertificatePath string `json:"certificate_path,omitempty"`
ECH *OutboundECHOptions `json:"ech,omitempty"`
UTLS *OutboundUTLSOptions `json:"utls,omitempty"`
Reality *OutboundRealityOptions `json:"reality,omitempty"`
Enabled bool `json:"enabled,omitempty"`
DisableSNI bool `json:"disable_sni,omitempty"`
ServerName string `json:"server_name,omitempty"`
Insecure bool `json:"insecure,omitempty"`
ALPN Listable[string] `json:"alpn,omitempty"`
MinVersion string `json:"min_version,omitempty"`
MaxVersion string `json:"max_version,omitempty"`
CipherSuites Listable[string] `json:"cipher_suites,omitempty"`
Certificate Listable[string] `json:"certificate,omitempty"`
CertificatePath string `json:"certificate_path,omitempty"`
ClientAuth bool `json:"clientAuth,omitempty"`
ClientKey Listable[string] `json:"client_key,omitempty"`
ClientKeyPath string `json:"client_key_path,omitempty"`
ClientCertificate Listable[string] `json:"client_certificate,omitempty"`
ClientCertificatePath string `json:"client_certificate_path,omitempty"`
ECH *OutboundECHOptions `json:"ech,omitempty"`
UTLS *OutboundUTLSOptions `json:"utls,omitempty"`
Reality *OutboundRealityOptions `json:"reality,omitempty"`
}
type InboundRealityOptions struct {

View File

@ -597,6 +597,18 @@ func (r *Router) Start() error {
return nil
}
func (r *Router) PostStart() error {
if len(r.ruleSets) > 0 {
for i, ruleSet := range r.ruleSets {
err := ruleSet.PostStart()
if err != nil {
return E.Cause(err, "post start rule-set[", i, "]")
}
}
}
return nil
}
func (r *Router) Close() error {
monitor := taskmonitor.New(r.logger, C.DefaultStopTimeout)
var err error