فهرست منبع

feat(service): 增加对国际域名 (IDN) 的支持

- 在 WafFormatterService 中添加 ConvertToPunycodeIfIDN 方法,用于判断域名是否为 IDN 并转换为 Punycode
- 在 WebForwardingService 中使用 ConvertToPunycodeIfIDN 方法处理请求域名,确保对 IDN 的正确支持
- 引入 idna 和 strings 包以支持 IDN转换和字符串比较
fusu 1 ماه پیش
والد
کامیت
6c98712ff3
2فایلهای تغییر یافته به همراه28 افزوده شده و 1 حذف شده
  1. 22 0
      internal/service/wafformatter.go
  2. 6 1
      internal/service/webforwarding.go

+ 22 - 0
internal/service/wafformatter.go

@@ -10,11 +10,13 @@ import (
 	"github.com/go-nunu/nunu-layout-advanced/pkg/rabbitmq"
 	amqp "github.com/rabbitmq/amqp091-go"
 	"go.uber.org/zap"
+	"golang.org/x/net/idna"
 	"golang.org/x/net/publicsuffix"
 	"golang.org/x/sync/errgroup"
 	"net"
 	"slices"
 	"strconv"
+	"strings"
 )
 
 type WafFormatterService interface {
@@ -33,6 +35,8 @@ type WafFormatterService interface {
 	AddOrigin(ctx context.Context, req v1.WebJson) (int64, error)
 	// 获取ip数量等于1的源站过白ip
 	WashDelIps(ctx context.Context, ips []string) ([]string, error)
+	// 判断域名是否是IDN,如果是,转换为 Punycode
+	ConvertToPunycodeIfIDN(ctx context.Context,domain string) (isIDN bool, punycodeDomain string, err error)
 }
 func NewWafFormatterService(
     service *Service,
@@ -471,4 +475,22 @@ func (s *wafFormatterService) WashDelIps(ctx context.Context, ips []string) ([]s
 	}
 
 	return ipsToDelist, nil
+}
+
+// 判断域名是否为 中文域名,如果是,转换为 Punycode
+func (s *wafFormatterService) ConvertToPunycodeIfIDN(ctx context.Context,domain string) (isIDN bool, punycodeDomain string, err error) {
+	// 使用 idna.ToASCII 将域名转换为 Punycode。
+	// 这个函数同时会根据 IDNA 规范验证域名的合法性。
+	punycodeDomain, err = idna.ToASCII(domain)
+	if err != nil {
+		// 如果转换出错,说明域名格式不符合 IDNA 标准。
+		return false, "", fmt.Errorf("域名 '%s' 格式无效: %v", domain, err)
+	}
+
+	// 判断是否为 IDN 的关键:
+	// 比较转换后的 Punycode 域名和原始域名(忽略大小写)。
+	// 如果不相等,说明原始域名包含非 ASCII 字符,即为 IDN。
+	isIDN = !strings.EqualFold(domain, punycodeDomain)
+
+	return isIDN, punycodeDomain, nil
 }

+ 6 - 1
internal/service/webforwarding.go

@@ -206,8 +206,13 @@ func (s *webForwardingService) prepareWafData(ctx context.Context, req *v1.WebFo
 	var serverName []serverNames
 	var serverJson []byte
 	if req.WebForwardingData.Domain != "" {
+
+		_, punyDomain, err := s.wafformatter.ConvertToPunycodeIfIDN(ctx,req.WebForwardingData.Domain)
+		if err != nil {
+			return RequireResponse{}, v1.Website{}, err
+		}
 		serverName = append(serverName, serverNames{
-			ServerNames: req.WebForwardingData.Domain,
+			ServerNames: punyDomain,
 			Type: "full",
 		})
 		serverJson, err = json.Marshal(serverName)