Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTroodi <troodi@bk.ru>2026-04-19 22:44:51 +0300
committerGitHub <noreply@github.com>2026-04-19 22:44:51 +0300
commitc2a2a36f5685bd90ce1a9eb8b1b09c5dd24bf6c2 (patch)
tree84cb50241417c24e96172918e9072fb6e3d6b23f /web/service
parente986a133f80b6b1fb231887806f4853edd540d7b (diff)
Fix geosite:ru rule (Normalization to RU vs lowercase ru) (#3971)
* Fix geosite:ru rule (Normalization to RU vs lowercase ru) * fix
Diffstat (limited to 'web/service')
-rw-r--r--web/service/server.go56
1 files changed, 56 insertions, 0 deletions
diff --git a/web/service/server.go b/web/service/server.go
index 2e0b34b8..6685ceab 100644
--- a/web/service/server.go
+++ b/web/service/server.go
@@ -34,6 +34,8 @@ import (
"github.com/shirou/gopsutil/v4/load"
"github.com/shirou/gopsutil/v4/mem"
"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.
@@ -1055,6 +1057,48 @@ func (s *ServerService) IsValidGeofileName(filename string) bool {
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 {
type geofileEntry struct {
URL string
@@ -1146,12 +1190,22 @@ func (s *ServerService) UpdateGeofile(fileName string) error {
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 == "" {
// Download all geofiles
for _, entry := range geofileAllowlist {
destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
if err := downloadFile(entry.URL, destPath); err != nil {
errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
+ } else {
+ normalizeIfGeosite(destPath, entry.FileName)
}
}
} else {
@@ -1159,6 +1213,8 @@ func (s *ServerService) UpdateGeofile(fileName string) error {
destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
if err := downloadFile(entry.URL, destPath); err != nil {
errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
+ } else {
+ normalizeIfGeosite(destPath, entry.FileName)
}
}