Skip to content

Commit

Permalink
Fix Meta-geoip convert
Browse files Browse the repository at this point in the history
  • Loading branch information
H1JK committed Feb 15, 2024
1 parent 9d94005 commit 474a473
Showing 1 changed file with 73 additions and 19 deletions.
92 changes: 73 additions & 19 deletions convert/v2ray_ip.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package convert

import (
"fmt"
"io"
"net"
"net/netip"
"strings"

"github.com/metacubex/geo/encoding/v2raygeo"
Expand All @@ -11,6 +13,8 @@ import (
"github.com/maxmind/mmdbwriter/inserter"
"github.com/maxmind/mmdbwriter/mmdbtype"
"github.com/sagernet/sing/common"
"golang.org/x/exp/constraints"
"golang.org/x/exp/slices"
)

func V2RayIPToSing(geoipList []*v2raygeo.GeoIP, output io.Writer) error {
Expand Down Expand Up @@ -62,33 +66,83 @@ func V2RayIPToMetaV0(geoipList []*v2raygeo.GeoIP, output io.Writer) error {
return err
}

included := make([]netip.Prefix, 0, 4*len(geoipList))
codeMap := make(map[netip.Prefix][]string, 4*len(geoipList))
for _, geoipEntry := range geoipList {
code := strings.ToLower(geoipEntry.CountryCode)
for _, cidrEntry := range geoipEntry.Cidr {
ipAddress := net.IP(cidrEntry.Ip)
if ip4 := ipAddress.To4(); ip4 != nil {
ipAddress = ip4
addr, ok := netip.AddrFromSlice(cidrEntry.Ip)
if !ok {
return fmt.Errorf("bad IP address: %v", cidrEntry.Ip)
}
ipNet := net.IPNet{
IP: ipAddress,
Mask: net.CIDRMask(int(cidrEntry.Prefix), len(ipAddress)*8),
addr = addr.Unmap()
prefix := netip.PrefixFrom(addr, int(cidrEntry.Prefix))
included = append(included, prefix)
codeMap[prefix] = append(codeMap[prefix], code)
}
}
included = common.Uniq(included)
slices.SortFunc(included, func(a, b netip.Prefix) int {
// sort in ascending order
return cmpCompare(a.Bits(), b.Bits())
})

for _, prefix := range included {
ipAddress := net.IP(prefix.Addr().AsSlice())
ipNet := net.IPNet{
IP: ipAddress,
Mask: net.CIDRMask(prefix.Bits(), len(ipAddress)*8),
}
codes := codeMap[prefix]
_, record := writer.Get(ipAddress)
switch typedRecord := record.(type) {
case nil:
if len(codes) == 1 {
record = mmdbtype.String(codes[0])
} else {
record = mmdbtype.Slice(common.Map(codes, func(it string) mmdbtype.DataType {
return mmdbtype.String(it)
}))
}
_, record := writer.Get(ipAddress)
switch typedRecord := record.(type) {
case nil:
record = mmdbtype.String(strings.ToLower(geoipEntry.CountryCode))
case mmdbtype.String:
record = mmdbtype.Slice{record, mmdbtype.String(strings.ToLower(geoipEntry.CountryCode))}
case mmdbtype.Slice:
record = append(typedRecord, mmdbtype.String(strings.ToLower(geoipEntry.CountryCode)))
default:
panic("bad record type")
case mmdbtype.String:
recordSlice := make(mmdbtype.Slice, 0, 1+len(codes))
recordSlice = append(recordSlice, typedRecord)
for _, code := range codes {
recordSlice = append(recordSlice, mmdbtype.String(code))
}
err = writer.Insert(&ipNet, record)
if err != nil {
return err
recordSlice = common.Uniq(recordSlice)
if len(recordSlice) == 1 {
record = recordSlice[0]
} else {
record = recordSlice
}
case mmdbtype.Slice:
recordSlice := typedRecord
for _, code := range codes {
recordSlice = append(recordSlice, mmdbtype.String(code))
}
recordSlice = common.Uniq(recordSlice)
record = recordSlice
default:
panic("bad record type")
}
err = writer.Insert(&ipNet, record)
if err != nil {
return err
}
}

return common.Error(writer.WriteTo(output))
}

// cmpCompare is a copy of cmp.Compare from the Go 1.21 release.
// T cannot be float types.
func cmpCompare[T constraints.Ordered](x, y T) int {
if x < y {
return -1
}
if x > y {
return +1
}
return 0
}

0 comments on commit 474a473

Please sign in to comment.