mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-25 01:51:29 +00:00
Add ACME DNS01 challenge support via libdns
This commit is contained in:
parent
c1ffcf365e
commit
d17e93384b
|
@ -9,10 +9,13 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
"github.com/caddyserver/certmagic"
|
"github.com/caddyserver/certmagic"
|
||||||
|
"github.com/libdns/alidns"
|
||||||
|
"github.com/libdns/cloudflare"
|
||||||
"github.com/mholt/acmez/acme"
|
"github.com/mholt/acmez/acme"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
@ -74,6 +77,21 @@ func startACME(ctx context.Context, options option.InboundACMEOptions) (*tls.Con
|
||||||
AltTLSALPNPort: int(options.AlternativeTLSPort),
|
AltTLSALPNPort: int(options.AlternativeTLSPort),
|
||||||
Logger: config.Logger,
|
Logger: config.Logger,
|
||||||
}
|
}
|
||||||
|
if dnsOptions := options.DNS01Challenge; dnsOptions != nil && dnsOptions.Provider != "" {
|
||||||
|
var solver certmagic.DNS01Solver
|
||||||
|
switch dnsOptions.Provider {
|
||||||
|
case C.DNSProviderAliDNS:
|
||||||
|
solver.DNSProvider = &alidns.Provider{
|
||||||
|
AccKeyID: dnsOptions.AliDNSOptions.AccessKeyID,
|
||||||
|
AccKeySecret: dnsOptions.AliDNSOptions.AccessKeySecret,
|
||||||
|
RegionID: dnsOptions.AliDNSOptions.RegionID,
|
||||||
|
}
|
||||||
|
case C.DNSProviderCloudflare:
|
||||||
|
solver.DNSProvider = &cloudflare.Provider{
|
||||||
|
APIToken: dnsOptions.CloudflareOptions.APIToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if options.ExternalAccount != nil && options.ExternalAccount.KeyID != "" {
|
if options.ExternalAccount != nil && options.ExternalAccount.KeyID != "" {
|
||||||
acmeConfig.ExternalAccount = (*acme.EAB)(options.ExternalAccount)
|
acmeConfig.ExternalAccount = (*acme.EAB)(options.ExternalAccount)
|
||||||
}
|
}
|
||||||
|
|
6
constant/dns.go
Normal file
6
constant/dns.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package constant
|
||||||
|
|
||||||
|
const (
|
||||||
|
DNSProviderAliDNS = "alidns"
|
||||||
|
DNSProviderCloudflare = "cloudflare"
|
||||||
|
)
|
31
docs/configuration/shared/dns01_challenge.md
Normal file
31
docs/configuration/shared/dns01_challenge.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
### Structure
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"provider": "",
|
||||||
|
|
||||||
|
... // Provider Fields
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Provider Fields
|
||||||
|
|
||||||
|
#### Alibaba Cloud DNS
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"provider": "alidns",
|
||||||
|
"access_key_id": "",
|
||||||
|
"access_key_secret": "",
|
||||||
|
"region_id": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Cloudflare
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"provider": "cloudflare",
|
||||||
|
"api_token": ""
|
||||||
|
}
|
||||||
|
```
|
31
docs/configuration/shared/dns01_challenge.zh.md
Normal file
31
docs/configuration/shared/dns01_challenge.zh.md
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
### 结构
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"provider": "",
|
||||||
|
|
||||||
|
... // 提供商字段
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 提供商字段
|
||||||
|
|
||||||
|
#### Alibaba Cloud DNS
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"provider": "alidns",
|
||||||
|
"access_key_id": "",
|
||||||
|
"access_key_secret": "",
|
||||||
|
"region_id": ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Cloudflare
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"provider": "cloudflare",
|
||||||
|
"api_token": ""
|
||||||
|
}
|
||||||
|
```
|
|
@ -25,7 +25,8 @@
|
||||||
"external_account": {
|
"external_account": {
|
||||||
"key_id": "",
|
"key_id": "",
|
||||||
"mac_key": ""
|
"mac_key": ""
|
||||||
}
|
},
|
||||||
|
"dns01_challenge": {}
|
||||||
},
|
},
|
||||||
"ech": {
|
"ech": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
@ -348,6 +349,12 @@ The key identifier.
|
||||||
|
|
||||||
The MAC key.
|
The MAC key.
|
||||||
|
|
||||||
|
#### dns01_challenge
|
||||||
|
|
||||||
|
ACME DNS01 challenge field. If configured, other challenge methods will be disabled.
|
||||||
|
|
||||||
|
See [DNS01 Challenge Fields](/configuration/shared/dns01_challenge) for details.
|
||||||
|
|
||||||
### Reality Fields
|
### Reality Fields
|
||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
|
@ -25,7 +25,8 @@
|
||||||
"external_account": {
|
"external_account": {
|
||||||
"key_id": "",
|
"key_id": "",
|
||||||
"mac_key": ""
|
"mac_key": ""
|
||||||
}
|
},
|
||||||
|
"dns01_challenge": {}
|
||||||
},
|
},
|
||||||
"ech": {
|
"ech": {
|
||||||
"enabled": false,
|
"enabled": false,
|
||||||
|
@ -339,6 +340,12 @@ EAB(外部帐户绑定)包含将 ACME 帐户绑定或映射到其他已知
|
||||||
|
|
||||||
MAC 密钥。
|
MAC 密钥。
|
||||||
|
|
||||||
|
#### dns01_challenge
|
||||||
|
|
||||||
|
ACME DNS01 验证字段。如果配置,将禁用其他验证方法。
|
||||||
|
|
||||||
|
参阅 [DNS01 验证字段](/configuration/shared/dns01_challenge)。
|
||||||
|
|
||||||
### Reality 字段
|
### Reality 字段
|
||||||
|
|
||||||
!!! warning ""
|
!!! warning ""
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -15,6 +15,8 @@ require (
|
||||||
github.com/go-chi/render v1.0.3
|
github.com/go-chi/render v1.0.3
|
||||||
github.com/gofrs/uuid/v5 v5.0.0
|
github.com/gofrs/uuid/v5 v5.0.0
|
||||||
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d
|
github.com/insomniacslk/dhcp v0.0.0-20230816195147-b3ca2534940d
|
||||||
|
github.com/libdns/alidns v1.0.3
|
||||||
|
github.com/libdns/cloudflare v0.1.0
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible
|
github.com/logrusorgru/aurora v2.0.3+incompatible
|
||||||
github.com/mholt/acmez v1.2.0
|
github.com/mholt/acmez v1.2.0
|
||||||
github.com/miekg/dns v1.1.55
|
github.com/miekg/dns v1.1.55
|
||||||
|
|
5
go.sum
5
go.sum
|
@ -68,6 +68,11 @@ github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZY
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/libdns/alidns v1.0.3 h1:LFHuGnbseq5+HCeGa1aW8awyX/4M2psB9962fdD2+yQ=
|
||||||
|
github.com/libdns/alidns v1.0.3/go.mod h1:e18uAG6GanfRhcJj6/tps2rCMzQJaYVcGKT+ELjdjGE=
|
||||||
|
github.com/libdns/cloudflare v0.1.0 h1:93WkJaGaiXCe353LHEP36kAWCUw0YjFqwhkBkU2/iic=
|
||||||
|
github.com/libdns/cloudflare v0.1.0/go.mod h1:a44IP6J1YH6nvcNl1PverfJviADgXUnsozR3a7vBKN8=
|
||||||
|
github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||||
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
||||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
||||||
|
|
|
@ -71,6 +71,7 @@ nav:
|
||||||
- Listen Fields: configuration/shared/listen.md
|
- Listen Fields: configuration/shared/listen.md
|
||||||
- Dial Fields: configuration/shared/dial.md
|
- Dial Fields: configuration/shared/dial.md
|
||||||
- TLS: configuration/shared/tls.md
|
- TLS: configuration/shared/tls.md
|
||||||
|
- DNS01 Challenge Fields: configuration/shared/dns01_challenge.md
|
||||||
- Multiplex: configuration/shared/multiplex.md
|
- Multiplex: configuration/shared/multiplex.md
|
||||||
- V2Ray Transport: configuration/shared/v2ray-transport.md
|
- V2Ray Transport: configuration/shared/v2ray-transport.md
|
||||||
- UDP over TCP: configuration/shared/udp-over-tcp.md
|
- UDP over TCP: configuration/shared/udp-over-tcp.md
|
||||||
|
@ -193,6 +194,7 @@ plugins:
|
||||||
Shared: 通用
|
Shared: 通用
|
||||||
Listen Fields: 监听字段
|
Listen Fields: 监听字段
|
||||||
Dial Fields: 拨号字段
|
Dial Fields: 拨号字段
|
||||||
|
DNS01 Challenge Fields: DNS01 验证字段
|
||||||
Multiplex: 多路复用
|
Multiplex: 多路复用
|
||||||
V2Ray Transport: V2Ray 传输层
|
V2Ray Transport: V2Ray 传输层
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/sagernet/sing-box/common/json"
|
||||||
|
C "github.com/sagernet/sing-box/constant"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
)
|
||||||
|
|
||||||
type InboundACMEOptions struct {
|
type InboundACMEOptions struct {
|
||||||
Domain Listable[string] `json:"domain,omitempty"`
|
Domain Listable[string] `json:"domain,omitempty"`
|
||||||
DataDirectory string `json:"data_directory,omitempty"`
|
DataDirectory string `json:"data_directory,omitempty"`
|
||||||
|
@ -11,9 +17,62 @@ type InboundACMEOptions struct {
|
||||||
AlternativeHTTPPort uint16 `json:"alternative_http_port,omitempty"`
|
AlternativeHTTPPort uint16 `json:"alternative_http_port,omitempty"`
|
||||||
AlternativeTLSPort uint16 `json:"alternative_tls_port,omitempty"`
|
AlternativeTLSPort uint16 `json:"alternative_tls_port,omitempty"`
|
||||||
ExternalAccount *ACMEExternalAccountOptions `json:"external_account,omitempty"`
|
ExternalAccount *ACMEExternalAccountOptions `json:"external_account,omitempty"`
|
||||||
|
DNS01Challenge *ACMEDNS01ChallengeOptions `json:"dns01_challenge,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ACMEExternalAccountOptions struct {
|
type ACMEExternalAccountOptions struct {
|
||||||
KeyID string `json:"key_id,omitempty"`
|
KeyID string `json:"key_id,omitempty"`
|
||||||
MACKey string `json:"mac_key,omitempty"`
|
MACKey string `json:"mac_key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type _ACMEDNS01ChallengeOptions struct {
|
||||||
|
Provider string `json:"provider,omitempty"`
|
||||||
|
AliDNSOptions ACMEDNS01AliDNSOptions `json:"-"`
|
||||||
|
CloudflareOptions ACMEDNS01CloudflareOptions `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ACMEDNS01ChallengeOptions _ACMEDNS01ChallengeOptions
|
||||||
|
|
||||||
|
func (o ACMEDNS01ChallengeOptions) MarshalJSON() ([]byte, error) {
|
||||||
|
var v any
|
||||||
|
switch o.Provider {
|
||||||
|
case C.DNSProviderAliDNS:
|
||||||
|
v = o.AliDNSOptions
|
||||||
|
case C.DNSProviderCloudflare:
|
||||||
|
v = o.CloudflareOptions
|
||||||
|
default:
|
||||||
|
return nil, E.New("unknown provider type: " + o.Provider)
|
||||||
|
}
|
||||||
|
return MarshallObjects((_ACMEDNS01ChallengeOptions)(o), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
|
err := json.Unmarshal(bytes, (*_ACMEDNS01ChallengeOptions)(o))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var v any
|
||||||
|
switch o.Provider {
|
||||||
|
case C.DNSProviderAliDNS:
|
||||||
|
v = &o.AliDNSOptions
|
||||||
|
case C.DNSProviderCloudflare:
|
||||||
|
v = &o.CloudflareOptions
|
||||||
|
default:
|
||||||
|
return E.New("unknown provider type: " + o.Provider)
|
||||||
|
}
|
||||||
|
err = UnmarshallExcluded(bytes, (*_ACMEDNS01ChallengeOptions)(o), v)
|
||||||
|
if err != nil {
|
||||||
|
return E.Cause(err, "DNS01 challenge options")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ACMEDNS01AliDNSOptions struct {
|
||||||
|
AccessKeyID string `json:"access_key_id,omitempty"`
|
||||||
|
AccessKeySecret string `json:"access_key_secret,omitempty"`
|
||||||
|
RegionID string `json:"region_id,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ACMEDNS01CloudflareOptions struct {
|
||||||
|
APIToken string `json:"api_token,omitempty"`
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue