1
0
Эх сурвалжийг харах

Fix geosite:ru rule (Normalization to RU vs lowercase ru) (#3971)

* Fix geosite:ru rule (Normalization to RU vs lowercase ru)

* fix
Troodi 1 өдөр өмнө
parent
commit
c2a2a36f56
3 өөрчлөгдсөн 75 нэмэгдсэн , 1 устгасан
  1. 1 1
      go.mod
  2. 56 0
      web/service/server.go
  3. 18 0
      web/web.go

+ 1 - 1
go.mod

@@ -26,6 +26,7 @@ require (
 	golang.org/x/sys v0.42.0
 	golang.org/x/sys v0.42.0
 	golang.org/x/text v0.35.0
 	golang.org/x/text v0.35.0
 	google.golang.org/grpc v1.80.0
 	google.golang.org/grpc v1.80.0
+	google.golang.org/protobuf v1.36.11
 	gorm.io/driver/sqlite v1.6.0
 	gorm.io/driver/sqlite v1.6.0
 	gorm.io/gorm v1.31.1
 	gorm.io/gorm v1.31.1
 )
 )
@@ -96,7 +97,6 @@ require (
 	golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
 	golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect
 	golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect
-	google.golang.org/protobuf v1.36.11 // indirect
 	gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 // indirect
 	gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0 // indirect
 	lukechampine.com/blake3 v1.4.1 // indirect
 	lukechampine.com/blake3 v1.4.1 // indirect
 )
 )

+ 56 - 0
web/service/server.go

@@ -34,6 +34,8 @@ import (
 	"github.com/shirou/gopsutil/v4/load"
 	"github.com/shirou/gopsutil/v4/load"
 	"github.com/shirou/gopsutil/v4/mem"
 	"github.com/shirou/gopsutil/v4/mem"
 	"github.com/shirou/gopsutil/v4/net"
 	"github.com/shirou/gopsutil/v4/net"
+	"github.com/xtls/xray-core/app/router"
+	"google.golang.org/protobuf/proto"
 )
 )
 
 
 // ProcessState represents the current state of a system process.
 // ProcessState represents the current state of a system process.
@@ -1055,6 +1057,48 @@ func (s *ServerService) IsValidGeofileName(filename string) bool {
 	return matched
 	return matched
 }
 }
 
 
+// NormalizeGeositeCountryCodes reads a geosite .dat file, uppercases all
+// country_code fields, and writes it back. This works around a case-sensitivity
+// mismatch in Xray-core: the router normalizes codes to uppercase before lookup,
+// but the find() function compares bytes case-sensitively. Some geosite.dat
+// providers (e.g. Loyalsoldier) store codes in lowercase, causing lookup failures.
+func NormalizeGeositeCountryCodes(path string) error {
+	data, err := os.ReadFile(path)
+	if err != nil {
+		return fmt.Errorf("failed to read geosite file %s: %w", path, err)
+	}
+
+	var list router.GeoSiteList
+	if err := proto.Unmarshal(data, &list); err != nil {
+		return fmt.Errorf("failed to parse geosite file %s: %w", path, err)
+	}
+
+	changed := false
+	for _, entry := range list.Entry {
+		upper := strings.ToUpper(entry.CountryCode)
+		if entry.CountryCode != upper {
+			entry.CountryCode = upper
+			changed = true
+		}
+	}
+
+	if !changed {
+		return nil
+	}
+
+	normalized, err := proto.Marshal(&list)
+	if err != nil {
+		return fmt.Errorf("failed to serialize normalized geosite file %s: %w", path, err)
+	}
+
+	if err := os.WriteFile(path, normalized, 0o644); err != nil {
+		return fmt.Errorf("failed to write normalized geosite file %s: %w", path, err)
+	}
+
+	logger.Infof("Normalized country codes to uppercase in %s (%d entries)", path, len(list.Entry))
+	return nil
+}
+
 func (s *ServerService) UpdateGeofile(fileName string) error {
 func (s *ServerService) UpdateGeofile(fileName string) error {
 	type geofileEntry struct {
 	type geofileEntry struct {
 		URL      string
 		URL      string
@@ -1146,12 +1190,22 @@ func (s *ServerService) UpdateGeofile(fileName string) error {
 
 
 	var errorMessages []string
 	var errorMessages []string
 
 
+	normalizeIfGeosite := func(destPath, name string) {
+		if strings.Contains(name, "geosite") {
+			if err := NormalizeGeositeCountryCodes(destPath); err != nil {
+				logger.Warningf("Failed to normalize geosite country codes in %s: %v", name, err)
+			}
+		}
+	}
+
 	if fileName == "" {
 	if fileName == "" {
 		// Download all geofiles
 		// Download all geofiles
 		for _, entry := range geofileAllowlist {
 		for _, entry := range geofileAllowlist {
 			destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
 			destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
 			if err := downloadFile(entry.URL, destPath); err != nil {
 			if err := downloadFile(entry.URL, destPath); err != nil {
 				errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
 				errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
+			} else {
+				normalizeIfGeosite(destPath, entry.FileName)
 			}
 			}
 		}
 		}
 	} else {
 	} else {
@@ -1159,6 +1213,8 @@ func (s *ServerService) UpdateGeofile(fileName string) error {
 		destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
 		destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
 		if err := downloadFile(entry.URL, destPath); err != nil {
 		if err := downloadFile(entry.URL, destPath); err != nil {
 			errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
 			errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
+		} else {
+			normalizeIfGeosite(destPath, entry.FileName)
 		}
 		}
 	}
 	}
 
 

+ 18 - 0
web/web.go

@@ -12,6 +12,7 @@ import (
 	"net"
 	"net"
 	"net/http"
 	"net/http"
 	"os"
 	"os"
+	"path/filepath"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
@@ -293,9 +294,26 @@ func (s *Server) initRouter() (*gin.Engine, error) {
 	return engine, nil
 	return engine, nil
 }
 }
 
 
+// normalizeExistingGeositeFiles normalizes country codes in all geosite .dat
+// files found in the bin directory so Xray-core can locate entries correctly.
+func normalizeExistingGeositeFiles() {
+	binDir := config.GetBinFolderPath()
+	matches, err := filepath.Glob(filepath.Join(binDir, "geosite*.dat"))
+	if err != nil {
+		logger.Warningf("Failed to glob geosite files: %v", err)
+		return
+	}
+	for _, path := range matches {
+		if err := service.NormalizeGeositeCountryCodes(path); err != nil {
+			logger.Warningf("Failed to normalize geosite country codes in %s: %v", path, err)
+		}
+	}
+}
+
 // startTask schedules background jobs (Xray checks, traffic jobs, cron
 // startTask schedules background jobs (Xray checks, traffic jobs, cron
 // jobs) which the panel relies on for periodic maintenance and monitoring.
 // jobs) which the panel relies on for periodic maintenance and monitoring.
 func (s *Server) startTask() {
 func (s *Server) startTask() {
+	normalizeExistingGeositeFiles()
 	s.customGeoService.EnsureOnStartup()
 	s.customGeoService.EnsureOnStartup()
 	err := s.xrayService.RestartXray(true)
 	err := s.xrayService.RestartXray(true)
 	if err != nil {
 	if err != nil {