Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 78 additions & 4 deletions component/geodata/utils.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package geodata

import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"strings"

"github.com/metacubex/mihomo/common/singleflight"
Expand Down Expand Up @@ -50,14 +54,84 @@ func SetSiteMatcher(newMatcher string) {
}
}

func verifyGeodataReader(r io.Reader, fileSize int64) error {
if fileSize == 0 {
return fmt.Errorf("invalid geodata file: empty file")
}

br := bufio.NewReader(r)
var pos int64
var b [1]byte

for pos < fileSize {
// Each top-level entry starts with 0x0A (protobuf field 1, wire type 2).
if _, err := io.ReadFull(br, b[:]); err != nil {
return fmt.Errorf("invalid geodata file: %w", err)
}
pos++
if b[0] != 0x0A {
return fmt.Errorf("invalid geodata file: unexpected byte 0x%02X at offset %d", b[0], pos-1)
}

// Decode the entry length varint.
var entryLen uint64
var shift uint
for {
if _, err := io.ReadFull(br, b[:]); err != nil {
return fmt.Errorf("invalid geodata file: truncated varint at offset %d: %w", pos, err)
}
pos++
entryLen |= uint64(b[0]&0x7F) << shift
if b[0] < 0x80 {
break
}
shift += 7
if shift >= 64 {
return fmt.Errorf("invalid geodata file: varint overflow at offset %d", pos)
}
}

if entryLen == 0 {
return fmt.Errorf("invalid geodata file: zero-length entry at offset %d", pos)
}

if _, err := io.CopyN(io.Discard, br, int64(entryLen)); err != nil {
return fmt.Errorf("invalid geodata file: truncated entry at offset %d: %w", pos, err)
}
pos += int64(entryLen)
}

if pos != fileSize {
return fmt.Errorf("invalid geodata file: truncated (last entry ends at %d, file size %d)", pos, fileSize)
}

return nil
}

func verifyGeodataFile(path string) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()

info, err := f.Stat()
if err != nil {
return err
}
return verifyGeodataReader(f, info.Size())
}

func VerifyGeodataBytes(data []byte) error {
return verifyGeodataReader(bytes.NewReader(data), int64(len(data)))
}

func Verify(name string) error {
switch name {
case C.GeositeName:
_, err := LoadGeoSiteMatcher("CN")
return err
return verifyGeodataFile(C.Path.GeoSite())
case C.GeoipName:
_, err := LoadGeoIPMatcher("CN")
return err
return verifyGeodataFile(C.Path.GeoIP())
default:
return fmt.Errorf("not support name")
}
Expand Down
13 changes: 4 additions & 9 deletions component/updater/update_geo.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/metacubex/mihomo/common/atomic"
"github.com/metacubex/mihomo/common/utils"
"github.com/metacubex/mihomo/component/geodata"
_ "github.com/metacubex/mihomo/component/geodata/standard"
"github.com/metacubex/mihomo/component/mmdb"
"github.com/metacubex/mihomo/component/resource"
C "github.com/metacubex/mihomo/constant"
Expand Down Expand Up @@ -107,8 +106,6 @@ func UpdateASN() (err error) {
}

func UpdateGeoIp() (err error) {
geoLoader, err := geodata.GetGeoDataLoader("standard")

vehicle := resource.NewHTTPVehicle(geodata.GeoIpUrl(), C.Path.GeoIP(), "", nil, defaultHttpTimeout, 0)
var oldHash utils.HashType
if buf, err := os.ReadFile(vehicle.Path()); err == nil {
Expand All @@ -125,8 +122,8 @@ func UpdateGeoIp() (err error) {
return fmt.Errorf("can't download GeoIP database file: no data")
}

if _, err = geoLoader.LoadIPByBytes(data, "cn"); err != nil {
return fmt.Errorf("invalid GeoIP database file: %s", err)
if err = geodata.VerifyGeodataBytes(data); err != nil {
return fmt.Errorf("invalid GeoIP database file: %w", err)
}

defer geodata.ClearGeoIPCache()
Expand All @@ -137,8 +134,6 @@ func UpdateGeoIp() (err error) {
}

func UpdateGeoSite() (err error) {
geoLoader, err := geodata.GetGeoDataLoader("standard")

vehicle := resource.NewHTTPVehicle(geodata.GeoSiteUrl(), C.Path.GeoSite(), "", nil, defaultHttpTimeout, 0)
var oldHash utils.HashType
if buf, err := os.ReadFile(vehicle.Path()); err == nil {
Expand All @@ -155,8 +150,8 @@ func UpdateGeoSite() (err error) {
return fmt.Errorf("can't download GeoSite database file: no data")
}

if _, err = geoLoader.LoadSiteByBytes(data, "cn"); err != nil {
return fmt.Errorf("invalid GeoSite database file: %s", err)
if err = geodata.VerifyGeodataBytes(data); err != nil {
return fmt.Errorf("invalid GeoSite database file: %w", err)
}

defer geodata.ClearGeoSiteCache()
Expand Down
Loading