|
@@ -1,24 +1,80 @@
|
|
|
package option
|
|
|
|
|
|
-import "github.com/sagernet/sing/common/json/badoption"
|
|
|
+import (
|
|
|
+ "crypto/tls"
|
|
|
+ "encoding/json"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ E "github.com/sagernet/sing/common/exceptions"
|
|
|
+ "github.com/sagernet/sing/common/json/badoption"
|
|
|
+)
|
|
|
|
|
|
type InboundTLSOptions struct {
|
|
|
- Enabled bool `json:"enabled,omitempty"`
|
|
|
- ServerName string `json:"server_name,omitempty"`
|
|
|
- Insecure bool `json:"insecure,omitempty"`
|
|
|
- ALPN badoption.Listable[string] `json:"alpn,omitempty"`
|
|
|
- MinVersion string `json:"min_version,omitempty"`
|
|
|
- MaxVersion string `json:"max_version,omitempty"`
|
|
|
- CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"`
|
|
|
- Certificate badoption.Listable[string] `json:"certificate,omitempty"`
|
|
|
- CertificatePath string `json:"certificate_path,omitempty"`
|
|
|
- Key badoption.Listable[string] `json:"key,omitempty"`
|
|
|
- KeyPath string `json:"key_path,omitempty"`
|
|
|
- KernelTx bool `json:"kernel_tx,omitempty"`
|
|
|
- KernelRx bool `json:"kernel_rx,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 badoption.Listable[string] `json:"alpn,omitempty"`
|
|
|
+ MinVersion string `json:"min_version,omitempty"`
|
|
|
+ MaxVersion string `json:"max_version,omitempty"`
|
|
|
+ CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"`
|
|
|
+ CurvePreferences badoption.Listable[CurvePreference] `json:"curve_preferences,omitempty"`
|
|
|
+ Certificate badoption.Listable[string] `json:"certificate,omitempty"`
|
|
|
+ CertificatePath string `json:"certificate_path,omitempty"`
|
|
|
+ ClientAuthentication ClientAuthType `json:"client_authentication,omitempty"`
|
|
|
+ ClientCertificate badoption.Listable[string] `json:"client_certificate,omitempty"`
|
|
|
+ ClientCertificatePath badoption.Listable[string] `json:"client_certificate_path,omitempty"`
|
|
|
+ ClientCertificatePublicKeySHA256 badoption.Listable[[]byte] `json:"client_certificate_public_key_sha256,omitempty"`
|
|
|
+ Key badoption.Listable[string] `json:"key,omitempty"`
|
|
|
+ KeyPath string `json:"key_path,omitempty"`
|
|
|
+ KernelTx bool `json:"kernel_tx,omitempty"`
|
|
|
+ KernelRx bool `json:"kernel_rx,omitempty"`
|
|
|
+ ACME *InboundACMEOptions `json:"acme,omitempty"`
|
|
|
+ ECH *InboundECHOptions `json:"ech,omitempty"`
|
|
|
+ Reality *InboundRealityOptions `json:"reality,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+type ClientAuthType tls.ClientAuthType
|
|
|
+
|
|
|
+func (t ClientAuthType) MarshalJSON() ([]byte, error) {
|
|
|
+ var stringValue string
|
|
|
+ switch t {
|
|
|
+ case ClientAuthType(tls.NoClientCert):
|
|
|
+ stringValue = "no"
|
|
|
+ case ClientAuthType(tls.RequestClientCert):
|
|
|
+ stringValue = "request"
|
|
|
+ case ClientAuthType(tls.RequireAnyClientCert):
|
|
|
+ stringValue = "require-any"
|
|
|
+ case ClientAuthType(tls.VerifyClientCertIfGiven):
|
|
|
+ stringValue = "verify-if-given"
|
|
|
+ case ClientAuthType(tls.RequireAndVerifyClientCert):
|
|
|
+ stringValue = "require-and-verify"
|
|
|
+ default:
|
|
|
+ return nil, E.New("unknown client authentication type: ", int(t))
|
|
|
+ }
|
|
|
+ return json.Marshal(stringValue)
|
|
|
+}
|
|
|
+
|
|
|
+func (t *ClientAuthType) UnmarshalJSON(data []byte) error {
|
|
|
+ var stringValue string
|
|
|
+ err := json.Unmarshal(data, &stringValue)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ switch stringValue {
|
|
|
+ case "no":
|
|
|
+ *t = ClientAuthType(tls.NoClientCert)
|
|
|
+ case "request":
|
|
|
+ *t = ClientAuthType(tls.RequestClientCert)
|
|
|
+ case "require-any":
|
|
|
+ *t = ClientAuthType(tls.RequireAnyClientCert)
|
|
|
+ case "verify-if-given":
|
|
|
+ *t = ClientAuthType(tls.VerifyClientCertIfGiven)
|
|
|
+ case "require-and-verify":
|
|
|
+ *t = ClientAuthType(tls.RequireAndVerifyClientCert)
|
|
|
+ default:
|
|
|
+ return E.New("unknown client authentication type: ", stringValue)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
}
|
|
|
|
|
|
type InboundTLSOptionsContainer struct {
|
|
@@ -39,24 +95,26 @@ func (o *InboundTLSOptionsContainer) ReplaceInboundTLSOptions(options *InboundTL
|
|
|
}
|
|
|
|
|
|
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 badoption.Listable[string] `json:"alpn,omitempty"`
|
|
|
- MinVersion string `json:"min_version,omitempty"`
|
|
|
- MaxVersion string `json:"max_version,omitempty"`
|
|
|
- CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"`
|
|
|
- Certificate badoption.Listable[string] `json:"certificate,omitempty"`
|
|
|
- CertificatePath string `json:"certificate_path,omitempty"`
|
|
|
- Fragment bool `json:"fragment,omitempty"`
|
|
|
- FragmentFallbackDelay badoption.Duration `json:"fragment_fallback_delay,omitempty"`
|
|
|
- RecordFragment bool `json:"record_fragment,omitempty"`
|
|
|
- KernelTx bool `json:"kernel_tx,omitempty"`
|
|
|
- KernelRx bool `json:"kernel_rx,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 badoption.Listable[string] `json:"alpn,omitempty"`
|
|
|
+ MinVersion string `json:"min_version,omitempty"`
|
|
|
+ MaxVersion string `json:"max_version,omitempty"`
|
|
|
+ CipherSuites badoption.Listable[string] `json:"cipher_suites,omitempty"`
|
|
|
+ CurvePreferences badoption.Listable[CurvePreference] `json:"curve_preferences,omitempty"`
|
|
|
+ Certificate badoption.Listable[string] `json:"certificate,omitempty"`
|
|
|
+ CertificatePath string `json:"certificate_path,omitempty"`
|
|
|
+ CertificatePublicKeySHA256 badoption.Listable[[]byte] `json:"certificate_public_key_sha256,omitempty"`
|
|
|
+ Fragment bool `json:"fragment,omitempty"`
|
|
|
+ FragmentFallbackDelay badoption.Duration `json:"fragment_fallback_delay,omitempty"`
|
|
|
+ RecordFragment bool `json:"record_fragment,omitempty"`
|
|
|
+ KernelTx bool `json:"kernel_tx,omitempty"`
|
|
|
+ KernelRx bool `json:"kernel_rx,omitempty"`
|
|
|
+ ECH *OutboundECHOptions `json:"ech,omitempty"`
|
|
|
+ UTLS *OutboundUTLSOptions `json:"utls,omitempty"`
|
|
|
+ Reality *OutboundRealityOptions `json:"reality,omitempty"`
|
|
|
}
|
|
|
|
|
|
type OutboundTLSOptionsContainer struct {
|
|
@@ -76,6 +134,58 @@ func (o *OutboundTLSOptionsContainer) ReplaceOutboundTLSOptions(options *Outboun
|
|
|
o.TLS = options
|
|
|
}
|
|
|
|
|
|
+type CurvePreference tls.CurveID
|
|
|
+
|
|
|
+const (
|
|
|
+ CurveP256 = 23
|
|
|
+ CurveP384 = 24
|
|
|
+ CurveP521 = 25
|
|
|
+ X25519 = 29
|
|
|
+ X25519MLKEM768 = 4588
|
|
|
+)
|
|
|
+
|
|
|
+func (c CurvePreference) MarshalJSON() ([]byte, error) {
|
|
|
+ var stringValue string
|
|
|
+ switch c {
|
|
|
+ case CurvePreference(CurveP256):
|
|
|
+ stringValue = "P256"
|
|
|
+ case CurvePreference(CurveP384):
|
|
|
+ stringValue = "P384"
|
|
|
+ case CurvePreference(CurveP521):
|
|
|
+ stringValue = "P521"
|
|
|
+ case CurvePreference(X25519):
|
|
|
+ stringValue = "X25519"
|
|
|
+ case CurvePreference(X25519MLKEM768):
|
|
|
+ stringValue = "X25519MLKEM768"
|
|
|
+ default:
|
|
|
+ return nil, E.New("unknown curve id: ", int(c))
|
|
|
+ }
|
|
|
+ return json.Marshal(stringValue)
|
|
|
+}
|
|
|
+
|
|
|
+func (c *CurvePreference) UnmarshalJSON(data []byte) error {
|
|
|
+ var stringValue string
|
|
|
+ err := json.Unmarshal(data, &stringValue)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ switch strings.ToUpper(stringValue) {
|
|
|
+ case "P256":
|
|
|
+ *c = CurvePreference(CurveP256)
|
|
|
+ case "P384":
|
|
|
+ *c = CurvePreference(CurveP384)
|
|
|
+ case "P521":
|
|
|
+ *c = CurvePreference(CurveP521)
|
|
|
+ case "X25519":
|
|
|
+ *c = CurvePreference(X25519)
|
|
|
+ case "X25519MLKEM768":
|
|
|
+ *c = CurvePreference(X25519MLKEM768)
|
|
|
+ default:
|
|
|
+ return E.New("unknown curve name: ", stringValue)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
type InboundRealityOptions struct {
|
|
|
Enabled bool `json:"enabled,omitempty"`
|
|
|
Handshake InboundRealityHandshakeOptions `json:"handshake,omitempty"`
|