Merge pull request #725 from Lvshujun0918/main

feat: skip dns local check
This commit is contained in:
samwafgo
2026-03-27 13:53:52 +08:00
committed by GitHub
8 changed files with 141 additions and 28 deletions
+6
View File
@@ -39,6 +39,9 @@ func (w *WafSslOrderApi) AddApi(c *gin.Context) {
var req request.WafSslorderaddReq
err := c.ShouldBindJSON(&req)
if err == nil {
if req.ApplyMethod != "dns01" {
req.SkipDNSVerify = 0
}
hostBean := wafHostService.GetDetailByCodeApi(req.HostCode)
if hostBean.Id == "" {
response.FailWithMessage("查找主机未找到", c)
@@ -178,6 +181,9 @@ func (w *WafSslOrderApi) ModifyApi(c *gin.Context) {
var req request.WafSslordereditReq
err := c.ShouldBindJSON(&req)
if err == nil {
if req.ApplyMethod != "dns01" {
req.SkipDNSVerify = 0
}
existingOrder := wafSslOrderService.GetDetailById(req.Id)
if existingOrder.Id == "" {
response.FailWithMessage("SSL订单不存在", c)
+2
View File
@@ -6,6 +6,7 @@ type WafSslorderaddReq struct {
HostCode string `json:"host_code"` //网站唯一码(主要键)
ApplyPlatform string `json:"apply_platform"` //申请平台
ApplyMethod string `json:"apply_method"` //申请方式http,dns
SkipDNSVerify int64 `json:"skip_dns_verify"` //dns01是否跳过本地DNS传播校验 0否 1是
ApplyDns string `json:"apply_dns"` //申请dns服务商
ApplyEmail string `json:"apply_email"` //申请邮箱
ApplyDomain string `json:"apply_domain"` //申请域名
@@ -16,6 +17,7 @@ type WafSslordereditReq struct {
HostCode string `json:"host_code"` //网站唯一码(主要键)
ApplyPlatform string `json:"apply_platform"` //申请平台
ApplyMethod string `json:"apply_method"` //申请方式http01,dns
SkipDNSVerify int64 `json:"skip_dns_verify"` //dns01是否跳过本地DNS传播校验 0否 1是
ApplyDns string `json:"apply_dns"` //申请dns服务商
ApplyEmail string `json:"apply_email"` //申请邮箱
ApplyDomain string `json:"apply_domain"` //申请域名
+1
View File
@@ -13,6 +13,7 @@ type SslOrder struct {
HostCode string `json:"host_code"` //网站唯一码(主要键)
ApplyPlatform string `json:"apply_platform"` //申请平台
ApplyMethod string `json:"apply_method"` //申请方式http01,dns
SkipDNSVerify int64 `json:"skip_dns_verify"` //dns01是否跳过本地DNS传播校验 0否 1是
ApplyDns string `json:"apply_dns"` //申请dns服务商
ApplyEmail string `json:"apply_email"` //申请邮箱
ApplyKey string `json:"apply_key"` //申请私钥
+4
View File
@@ -26,6 +26,7 @@ func (receiver *WafSSLOrderService) AddApi(req request.WafSslorderaddReq) (model
HostCode: req.HostCode,
ApplyPlatform: req.ApplyPlatform,
ApplyMethod: req.ApplyMethod,
SkipDNSVerify: req.SkipDNSVerify,
ApplyDns: req.ApplyDns,
ApplyDomain: req.ApplyDomain,
ApplyEmail: req.ApplyEmail,
@@ -43,6 +44,7 @@ func (receiver *WafSSLOrderService) ModifyApi(req request.WafSslordereditReq) er
"HostCode": req.HostCode,
"ApplyPlatform": req.ApplyPlatform,
"ApplyMethod": req.ApplyMethod,
"SkipDNSVerify": req.SkipDNSVerify,
"ApplyDns": req.ApplyDns,
"ApplyDomain": req.ApplyDomain,
"ApplyEmail": req.ApplyEmail,
@@ -108,6 +110,7 @@ func (receiver *WafSSLOrderService) ModifyById(sslOrder model.SslOrder) error {
"HostCode": sslOrder.HostCode,
"ApplyPlatform": sslOrder.ApplyPlatform,
"ApplyMethod": sslOrder.ApplyMethod,
"SkipDNSVerify": sslOrder.SkipDNSVerify,
"ApplyDns": sslOrder.ApplyDns,
"ApplyDomain": sslOrder.ApplyDomain,
"ApplyEmail": sslOrder.ApplyEmail,
@@ -145,6 +148,7 @@ func (receiver *WafSSLOrderService) RenewAdd(orderId string) (model.SslOrder, er
HostCode: order.HostCode,
ApplyPlatform: order.ApplyPlatform,
ApplyMethod: order.ApplyMethod,
SkipDNSVerify: order.SkipDNSVerify,
ApplyDns: order.ApplyDns,
ApplyDomain: order.ApplyDomain,
ApplyEmail: order.ApplyEmail,
+52 -16
View File
@@ -1,6 +1,7 @@
package ssl
import (
"SamWaf/common/zlog"
"SamWaf/model"
"SamWaf/utils"
"crypto"
@@ -14,10 +15,12 @@ import (
"fmt"
"net"
"strings"
"time"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/go-acme/lego/v4/certificate"
"github.com/go-acme/lego/v4/challenge"
"github.com/go-acme/lego/v4/challenge/dns01"
"github.com/go-acme/lego/v4/lego"
"github.com/go-acme/lego/v4/providers/dns/alidns"
"github.com/go-acme/lego/v4/providers/dns/baiducloud"
@@ -91,23 +94,25 @@ func RegistrationSSL(order model.SslOrder, savePath string, caServerAddress stri
// because we aren't running as root and can't bind a listener to port 80 and 443
// (used later when we attempt to pass challenges). Keep in mind that you still
// need to proxy challenge traffic to port 5002 and 5001.
if order.ApplyMethod == "http01" {
switch order.ApplyMethod {
case "http01":
provider, err := webroot.NewHTTPProvider(savePath)
if err != nil {
return order, err
}
err = client.Challenge.SetHTTP01Provider(provider)
} else if order.ApplyMethod == "dns01" {
case "dns01":
dnsProvider, err := GetDnsProvider(order.ApplyDns)
if err != nil {
zlog.Error(fmt.Sprintf("Failed to initialize DNS provider `%s`: %v", order.ApplyDns, err))
return order, err
}
err = client.Challenge.SetDNS01Provider(dnsProvider)
err = setDNS01ProviderWithRetry(client, dnsProvider, order.SkipDNSVerify)
if err != nil {
zlog.Error(fmt.Sprintf("Failed to set DNS-01 provider: %v", err))
}
}
if err != nil {
return order, err
}
// New users will need to register
var reg *registration.Resource
if applyPlatform == "zerossl" {
@@ -185,7 +190,6 @@ func RegistrationSSL(order model.SslOrder, savePath string, caServerAddress stri
}
// Each certificate comes back with the cert bytes, the bytes of the client's
// private key, and a certificate URL. SAVE THESE TO DISK.
fmt.Printf("%#v\n", certificates)
order.ResultPrivateKey = certificates.PrivateKey
order.ResultCertificate = certificates.Certificate
@@ -268,13 +272,13 @@ func ReNewSSL(order model.SslOrder, savePath string, caServerAddress string, app
} else if order.ApplyMethod == "dns01" {
dnsProvider, err := GetDnsProvider(order.ApplyDns)
if err != nil {
zlog.Error(fmt.Sprintf("Failed to initialize DNS provider `%s`: %v", order.ApplyDns, err))
return order, err
}
err = client.Challenge.SetDNS01Provider(dnsProvider)
}
if err != nil {
return order, err
err = setDNS01ProviderWithRetry(client, dnsProvider, order.SkipDNSVerify)
if err != nil {
zlog.Error(fmt.Sprintf("Failed to set DNS-01 provider: %v", err))
}
}
// New users will need to register
var reg *registration.Resource
@@ -363,7 +367,6 @@ func ReNewSSL(order model.SslOrder, savePath string, caServerAddress string, app
// Each certificate comes back with the cert bytes, the bytes of the client's
// private key, and a certificate URL. SAVE THESE TO DISK.
fmt.Printf("%#v\n", certificates)
order.ResultPrivateKey = certificates.PrivateKey
order.ResultCertificate = certificates.Certificate
@@ -429,15 +432,48 @@ func GetDnsProvider(dnsName string) (challenge.Provider, error) {
case "huaweicloud":
return huaweicloud.NewDNSProvider()
case "tencentcloud":
return tencentcloud.NewDNSProvider()
case "cloudflare":
return cloudflare.NewDNSProvider()
case "baiducloud":
return baiducloud.NewDNSProvider()
default:
return nil, fmt.Errorf("unrecognized DNS provider: %s", dnsName)
}
}
func setDNS01ProviderWithRetry(client *lego.Client, dnsProvider challenge.Provider, skipDNSVerify int64) error {
// 默认重试10次,每次间隔30秒
dnsPrecheckRetry := 10
dnsPrecheckRetryInterval := 30 * time.Second
// DNS 传播等待时间:300秒(3分钟)
propagationTimeout := 180 * time.Second
if skipDNSVerify == 1 {
// 跳过本地DNS传播校验:固定等待后直接通知CA进行验证
return client.Challenge.SetDNS01Provider(dnsProvider, dns01.PropagationWait(propagationTimeout, true))
}
// 默认执行本地DNS传播校验,并增加重试机制
return client.Challenge.SetDNS01Provider(dnsProvider,
dns01.WrapPreCheck(func(domain, fqdn, value string, check dns01.PreCheckFunc) (bool, error) {
var lastErr error
for i := 1; i <= dnsPrecheckRetry; i++ {
ok, err := check(fqdn, value)
if ok && err == nil {
return true, nil
}
lastErr = err
if i < dnsPrecheckRetry {
time.Sleep(dnsPrecheckRetryInterval)
}
}
if lastErr != nil {
return false, lastErr
}
return false, fmt.Errorf("dns propagation precheck failed after %d retries", dnsPrecheckRetry)
}),
)
}
+36
View File
@@ -718,6 +718,42 @@ func RunCoreDBMigrations(db *gorm.DB) error {
return nil
},
},
// 迁移20: 为 ssl_orders 表添加 skip_dns_verify 字段(DNS校验跳过开关)
{
ID: "202603250001_add_ssl_orders_skip_dns_verify",
Migrate: func(tx *gorm.DB) error {
zlog.Info("迁移 202603250001: 为 ssl_orders 表添加 skip_dns_verify 字段")
// 检查字段是否已存在
if tx.Migrator().HasColumn(&model.SslOrder{}, "skip_dns_verify") {
zlog.Info("skip_dns_verify 字段已存在,执行默认值回填")
if err := tx.Exec("UPDATE ssl_orders SET skip_dns_verify = 0 WHERE skip_dns_verify IS NULL").Error; err != nil {
zlog.Warn("回填 skip_dns_verify 默认值失败", "error", err.Error())
}
return nil
}
// 添加字段
if err := tx.Migrator().AddColumn(&model.SslOrder{}, "skip_dns_verify"); err != nil {
return fmt.Errorf("添加 skip_dns_verify 字段失败: %w", err)
}
// 为历史数据回填默认值 0(不跳过DNS校验)
if err := tx.Exec("UPDATE ssl_orders SET skip_dns_verify = 0 WHERE skip_dns_verify IS NULL").Error; err != nil {
zlog.Warn("设置 skip_dns_verify 默认值失败", "error", err.Error())
}
zlog.Info("skip_dns_verify 字段添加成功")
return nil
},
Rollback: func(tx *gorm.DB) error {
zlog.Info("回滚 202603250001: 删除 ssl_orders 表的 skip_dns_verify 字段")
if tx.Migrator().HasColumn(&model.SslOrder{}, "skip_dns_verify") {
return tx.Migrator().DropColumn(&model.SslOrder{}, "skip_dns_verify")
}
return nil
},
},
})
// 执行迁移
+1
View File
@@ -31,6 +31,7 @@ func (waf *WafEngine) ApplySSLOrder(chanType int, bean model.SslOrder) {
//加载环境变量
privateGroupName := bean.PrivateGroupName
privateGroupBelongCloud := bean.ApplyDns
zlog.Debug(fmt.Sprintf("Loading DNS provider env info - Group: `%s`, Cloud: `%s` for domain: %s", privateGroupName, privateGroupBelongCloud, bean.ApplyDomain))
//查询环境变量信息
wafssl.LoadDnsProviderEnvInfo(privateGroupName, privateGroupBelongCloud)
}
+39 -12
View File
@@ -11,19 +11,46 @@ import (
// LoadDnsProviderEnvInfo 初始化dns所需要的参数信息
func LoadDnsProviderEnvInfo(groupName string, belongCloud string) {
privateInfos, _, err := waf_service.WafPrivateInfoServiceApp.GetListByGroupAndBelongCloudPureApi(groupName, belongCloud)
if err == nil {
for _, info := range privateInfos {
err := os.Setenv(info.PrivateKey, info.PrivateValue)
if err != nil {
return
} else {
zlog.Info(fmt.Sprintf("Cloud `%s` Group `%s` ENV `%s` LOADED", belongCloud, groupName, info.PrivateKey))
}
}
// 清除旧的 DNS provider 相关环境变量,防止污染
dnsEnvKeys := []string{
// Tencent Cloud
"TENCENTCLOUD_SECRET_ID", "TENCENTCLOUD_SECRET_KEY", "TENCENTCLOUD_REGION",
// Alibaba Cloud
"ALICLOUD_ACCESS_KEY", "ALICLOUD_SECRET_KEY", "ALICLOUD_REGION_ID",
// Huawei Cloud
"HUAWEICLOUD_DOMAIN_NAME", "HUAWEICLOUD_ACCESS_KEY_ID", "HUAWEICLOUD_ACCESS_KEY_SECRET", "HUAWEICLOUD_REGION",
// Cloudflare
"CLOUDFLARE_API_TOKEN", "CLOUDFLARE_API_KEY", "CLOUDFLARE_ACCOUNT_ID",
// Baidu Cloud
"BAIDUCLOUD_ACCESS_KEY", "BAIDUCLOUD_SECRET_ACCESS_KEY", "BAIDUCLOUD_REGION",
}
for _, key := range dnsEnvKeys {
os.Unsetenv(key)
}
privateInfos, _, err := waf_service.WafPrivateInfoServiceApp.GetListByGroupAndBelongCloudPureApi(groupName, belongCloud)
if err != nil {
zlog.Error(fmt.Sprintf("Failed to load DNS provider env info for cloud `%s` group `%s`: %v", belongCloud, groupName, err))
return
}
if len(privateInfos) == 0 {
zlog.Warn(fmt.Sprintf("No DNS credentials found in DB for cloud `%s` group `%s` - DNS provider will have no auth", belongCloud, groupName))
return
}
for _, info := range privateInfos {
err := os.Setenv(info.PrivateKey, info.PrivateValue)
if err != nil {
zlog.Error(fmt.Sprintf("Failed to set env var `%s`: %v", info.PrivateKey, err))
return
}
zlog.Info(fmt.Sprintf("Cloud `%s` Group `%s` ENV `%s` LOADED", belongCloud, groupName, info.PrivateKey))
}
zlog.Info(fmt.Sprintf("Successfully loaded %d credentials for cloud `%s` group `%s`", len(privateInfos), belongCloud, groupName))
if global.GWAF_RELEASE == "false" {
fmt.Println("当前环境变量:")
zlog.Debug("Current DNS-related environment variables:")
for _, env := range os.Environ() {
parts := strings.SplitN(env, "=", 2)
key := parts[0]
@@ -31,7 +58,7 @@ func LoadDnsProviderEnvInfo(groupName string, belongCloud string) {
if len(parts) > 1 {
value = parts[1]
}
fmt.Printf("%s = %s\n", key, value)
zlog.Debug(fmt.Sprintf("%s = %s", key, value))
}
}
}