v2raya: backport memory fix for GeoIP parser

Fixes: #30285
Reported-by: ALOKY <ajm1055@uomustansiriyah.edu.iq>
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen committed 2026-10-10 10:57:44 +08:00
1 parent dbd1a89a05
commit ff50e2db0c
2 files changed
+133 -1

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=v2rayA
PKG_VERSION:=2.2.7.5
PKG_RELEASE:=1
PKG_RELEASE:=2
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/v2rayA/v2rayA/tar.gz/v$(PKG_VERSION)?
@@ -0,0 +1,132 @@
From 43b6e55b67bb6cfa7bf1ca1305b47e8b113eaef5 Mon Sep 17 00:00:00 2001
From: ALOKY <ajm1055@uomustansiriyah.edu.iq>
Date: Sun, 16 Aug 2026 15:34:30 +0300
Subject: [PATCH] reduce GeoIP parser memory usage
Decode one GeoIP entry at a time and cache successful results.
Signed-off-by: ALOKY <ajm1055@uomustansiriyah.edu.iq>
---
service/common/parseGeoIP/parser.go | 87 +++++++++++++++++++++++++----
1 file changed, 77 insertions(+), 10 deletions(-)
--- a/common/parseGeoIP/parser.go
+++ b/common/parseGeoIP/parser.go
@@ -5,31 +5,91 @@ import (
"net"
"os"
"strings"
+ "sync"
"github.com/v2rayA/v2rayA/core/v2ray/asset"
+ "google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
)
-func Parser(filename string, countryCode string) ([]string, []string, error) {
- var ipv4List []string
- var ipv6List []string
- var geoIpProto GeoIPList
+type parserResult struct {
+ ipv4 []string
+ ipv6 []string
+}
+type parserCacheKey struct {
+ path string
+ size int64
+ modTime int64
+ countryCode string
+}
+
+var parserCache sync.Map
+
+func Parser(filename string, countryCode string) ([]string, []string, error) {
realpath, err := asset.GetV2rayLocationAsset(filename)
if err != nil {
- return ipv4List, ipv6List, err
+ return nil, nil, err
}
+ info, err := os.Stat(realpath)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ cacheKey := parserCacheKey{
+ path: realpath,
+ size: info.Size(),
+ modTime: info.ModTime().UnixNano(),
+ countryCode: countryCode,
+ }
+ if cached, ok := parserCache.Load(cacheKey); ok {
+ result := cached.(parserResult)
+ return result.ipv4, result.ipv6, nil
+ }
+
data, err := os.ReadFile(realpath)
if err != nil {
- return ipv4List, ipv6List, err
+ return nil, nil, err
}
- if err := proto.Unmarshal(data, &geoIpProto); err != nil {
+ ipv4List, ipv6List, err := parseGeoIP(data, countryCode)
+ if err != nil {
return ipv4List, ipv6List, err
}
- for _, geo := range geoIpProto.Entry {
- if geo.CountryCode == countryCode {
+ parserCache.Store(cacheKey, parserResult{ipv4: ipv4List, ipv6: ipv6List})
+ return ipv4List, ipv6List, nil
+}
+
+func parseGeoIP(data []byte, countryCode string) ([]string, []string, error) {
+ var ipv4List []string
+ var ipv6List []string
+
+ // GeoIPList contains repeated GeoIP messages in field 1. Decoding the
+ // complete list expands a roughly 22 MiB asset to hundreds of MiB in
+ // memory. Decode one entry at a time and stop at the requested country.
+ for len(data) > 0 {
+ number, wireType, n := protowire.ConsumeTag(data)
+ if n < 0 {
+ return ipv4List, ipv6List, protowire.ParseError(n)
+ }
+ data = data[n:]
+
+ if number == 1 && wireType == protowire.BytesType {
+ entryData, consumed := protowire.ConsumeBytes(data)
+ if consumed < 0 {
+ return ipv4List, ipv6List, protowire.ParseError(consumed)
+ }
+ data = data[consumed:]
+
+ var geo GeoIP
+ if err := proto.Unmarshal(entryData, &geo); err != nil {
+ return ipv4List, ipv6List, err
+ }
+ if geo.CountryCode != countryCode {
+ continue
+ }
+
for _, c := range geo.Cidr {
ip := net.IP(c.Ip)
if strings.Contains(ip.String(), ":") {
@@ -42,8 +102,15 @@ func Parser(filename string, countryCode
ipv4List = append(ipv4List, fmt.Sprintf("%s/%d", ip.String(), c.Prefix))
}
}
- break
+ return ipv4List, ipv6List, nil
+ }
+
+ consumed := protowire.ConsumeFieldValue(number, wireType, data)
+ if consumed < 0 {
+ return ipv4List, ipv6List, protowire.ParseError(consumed)
}
+ data = data[consumed:]
}
+
return ipv4List, ipv6List, nil
}