mirror of
				https://github.com/TeaOSLab/EdgeCommon.git
				synced 2025-11-04 21:50:26 +08:00 
			
		
		
		
	更好地支持IPv6
This commit is contained in:
		@@ -1,41 +1,10 @@
 | 
				
			|||||||
package configutils
 | 
					package configutils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/binary"
 | 
					 | 
				
			||||||
	"math/big"
 | 
					 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IPString2Long 将IP转换为整型
 | 
					 | 
				
			||||||
// 注意IPv6没有顺序
 | 
					 | 
				
			||||||
func IPString2Long(ip string) uint64 {
 | 
					 | 
				
			||||||
	if len(ip) == 0 {
 | 
					 | 
				
			||||||
		return 0
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	var netIP = net.ParseIP(ip)
 | 
					 | 
				
			||||||
	if len(netIP) == 0 {
 | 
					 | 
				
			||||||
		return 0
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return IP2Long(netIP)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IP2Long 将IP对象转换为整型
 | 
					 | 
				
			||||||
func IP2Long(netIP net.IP) uint64 {
 | 
					 | 
				
			||||||
	if len(netIP) == 0 {
 | 
					 | 
				
			||||||
		return 0
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var b4 = netIP.To4()
 | 
					 | 
				
			||||||
	if b4 != nil {
 | 
					 | 
				
			||||||
		return uint64(binary.BigEndian.Uint32(b4.To4()))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var i = big.NewInt(0)
 | 
					 | 
				
			||||||
	i.SetBytes(netIP.To16())
 | 
					 | 
				
			||||||
	return i.Uint64()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// IsIPv4 检查是否为IPv4
 | 
					// IsIPv4 检查是否为IPv4
 | 
				
			||||||
func IsIPv4(netIP net.IP) bool {
 | 
					func IsIPv4(netIP net.IP) bool {
 | 
				
			||||||
	if len(netIP) == 0 {
 | 
						if len(netIP) == 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@
 | 
				
			|||||||
package configutils_test
 | 
					package configutils_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
 | 
				
			||||||
	"github.com/iwind/TeaGo/assert"
 | 
						"github.com/iwind/TeaGo/assert"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
@@ -16,12 +15,6 @@ func TestParseCIDR(t *testing.T) {
 | 
				
			|||||||
	t.Log(configutils.ParseCIDR("192.168.1.1/16"))
 | 
						t.Log(configutils.ParseCIDR("192.168.1.1/16"))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestIPString2Long(t *testing.T) {
 | 
					 | 
				
			||||||
	for _, ip := range []string{"127.0.0.1", "192.168.1.100", "::1", "fd00:6868:6868:0:10ac:d056:3bf6:7452", "fd00:6868:6868:0:10ac:d056:3bf6:7453", "2001:0db8:85a3:0000:0000:8a2e:0370:7334", "wrong ip"} {
 | 
					 | 
				
			||||||
		t.Log(fmt.Sprintf("%42s", ip), "=>", configutils.IPString2Long(ip))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestIsIPv4(t *testing.T) {
 | 
					func TestIsIPv4(t *testing.T) {
 | 
				
			||||||
	t.Log(configutils.IsIPv4(net.ParseIP("192.168.1.100")))
 | 
						t.Log(configutils.IsIPv4(net.ParseIP("192.168.1.100")))
 | 
				
			||||||
	t.Log(configutils.IsIPv4(net.ParseIP("::1")))
 | 
						t.Log(configutils.IsIPv4(net.ParseIP("::1")))
 | 
				
			||||||
@@ -40,7 +33,6 @@ func TestIPVersion(t *testing.T) {
 | 
				
			|||||||
	a.IsTrue(configutils.IPVersion(net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")) == 6)
 | 
						a.IsTrue(configutils.IPVersion(net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")) == 6)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestQuoteIP(t *testing.T) {
 | 
					func TestQuoteIP(t *testing.T) {
 | 
				
			||||||
	t.Log(configutils.QuoteIP(configutils.QuoteIP("2001:da8:22::10")))
 | 
						t.Log(configutils.QuoteIP(configutils.QuoteIP("2001:da8:22::10")))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								pkg/iplibrary/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								pkg/iplibrary/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1 +1,2 @@
 | 
				
			|||||||
*-plus.db
 | 
					*-plus.db
 | 
				
			||||||
 | 
					internal-ip-library-test.db
 | 
				
			||||||
@@ -33,7 +33,7 @@ func InitDefault() error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var library = NewIPLibrary()
 | 
						var library = NewIPLibrary()
 | 
				
			||||||
	err := library.InitFromData(ipLibraryData, "")
 | 
						err := library.InitFromData(ipLibraryData, "", ReaderVersionV1)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -66,18 +66,18 @@ func LookupIPSummaries(ipList []string) map[string]string /** ip => summary **/
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type IPLibrary struct {
 | 
					type IPLibrary struct {
 | 
				
			||||||
	reader *Reader
 | 
						reader ReaderInterface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewIPLibrary() *IPLibrary {
 | 
					func NewIPLibrary() *IPLibrary {
 | 
				
			||||||
	return &IPLibrary{}
 | 
						return &IPLibrary{}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewIPLibraryWithReader(reader *Reader) *IPLibrary {
 | 
					func NewIPLibraryWithReader(reader ReaderInterface) *IPLibrary {
 | 
				
			||||||
	return &IPLibrary{reader: reader}
 | 
						return &IPLibrary{reader: reader}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *IPLibrary) InitFromData(data []byte, password string) error {
 | 
					func (this *IPLibrary) InitFromData(data []byte, password string, version ReaderVersion) error {
 | 
				
			||||||
	if len(data) == 0 || this.reader != nil {
 | 
						if len(data) == 0 || this.reader != nil {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -99,7 +99,12 @@ func (this *IPLibrary) InitFromData(data []byte, password string) error {
 | 
				
			|||||||
		_ = gzipReader.Close()
 | 
							_ = gzipReader.Close()
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	libReader, err := NewReader(gzipReader)
 | 
						var libReader ReaderInterface
 | 
				
			||||||
 | 
						if version == ReaderVersionV2 {
 | 
				
			||||||
 | 
							libReader, err = NewReaderV2(gzipReader)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							libReader, err = NewReaderV1(gzipReader)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,7 +15,7 @@ import (
 | 
				
			|||||||
func TestIPLibrary_Init(t *testing.T) {
 | 
					func TestIPLibrary_Init(t *testing.T) {
 | 
				
			||||||
	var lib = iplibrary.NewIPLibrary()
 | 
						var lib = iplibrary.NewIPLibrary()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
 | 
						err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "", iplibrary.ReaderVersionV1)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -38,7 +38,7 @@ func TestIPLibrary_Lookup(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var before = time.Now()
 | 
						var before = time.Now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
 | 
						err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "", iplibrary.ReaderVersionV1)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -69,7 +69,7 @@ func TestIPLibrary_Lookup(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestIPLibrary_LookupIP(t *testing.T) {
 | 
					func TestIPLibrary_LookupIP(t *testing.T) {
 | 
				
			||||||
	var lib = iplibrary.NewIPLibrary()
 | 
						var lib = iplibrary.NewIPLibrary()
 | 
				
			||||||
	err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
 | 
						err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "", iplibrary.ReaderVersionV1)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -88,7 +88,7 @@ func TestIPLibrary_LookupIP(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestIPLibrary_LookupIP_Summary(t *testing.T) {
 | 
					func TestIPLibrary_LookupIP_Summary(t *testing.T) {
 | 
				
			||||||
	var lib = iplibrary.NewIPLibrary()
 | 
						var lib = iplibrary.NewIPLibrary()
 | 
				
			||||||
	err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
 | 
						err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "", iplibrary.ReaderVersionV1)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -123,7 +123,7 @@ func TestIPLibrary_LookupIPSummaries(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func BenchmarkIPLibrary_Lookup(b *testing.B) {
 | 
					func BenchmarkIPLibrary_Lookup(b *testing.B) {
 | 
				
			||||||
	var lib = iplibrary.NewIPLibrary()
 | 
						var lib = iplibrary.NewIPLibrary()
 | 
				
			||||||
	err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "")
 | 
						err := lib.InitFromData(iplibrary.DefaultIPLibraryData(), "", iplibrary.ReaderVersionV1)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		b.Fatal(err)
 | 
							b.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,20 +6,34 @@ import (
 | 
				
			|||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ipv4Item struct {
 | 
					type ipv4ItemV1 struct {
 | 
				
			||||||
	IPFrom uint32
 | 
						IPFrom uint32
 | 
				
			||||||
	IPTo   uint32
 | 
						IPTo   uint32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Region *ipRegion
 | 
						Region *ipRegion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ipv6Item struct {
 | 
					type ipv6ItemV1 struct {
 | 
				
			||||||
	IPFrom uint64
 | 
						IPFrom uint64
 | 
				
			||||||
	IPTo   uint64
 | 
						IPTo   uint64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	Region *ipRegion
 | 
						Region *ipRegion
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ipv4ItemV2 struct {
 | 
				
			||||||
 | 
						IPFrom [4]byte
 | 
				
			||||||
 | 
						IPTo   [4]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Region *ipRegion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ipv6ItemV2 struct {
 | 
				
			||||||
 | 
						IPFrom [16]byte
 | 
				
			||||||
 | 
						IPTo   [16]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Region *ipRegion
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ipRegion struct {
 | 
					type ipRegion struct {
 | 
				
			||||||
	CountryId  uint16
 | 
						CountryId  uint16
 | 
				
			||||||
	ProvinceId uint16
 | 
						ProvinceId uint16
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,12 @@ package iplibrary
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"runtime"
 | 
						"runtime"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
@@ -21,8 +23,8 @@ type Reader struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	regionMap map[string]*ipRegion // 缓存重复的区域用来节约内存
 | 
						regionMap map[string]*ipRegion // 缓存重复的区域用来节约内存
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ipV4Items []ipv4Item
 | 
						ipV4Items []ipv4ItemV1
 | 
				
			||||||
	ipV6Items []ipv6Item
 | 
						ipV6Items []ipv6ItemV1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lastIPFrom     uint64
 | 
						lastIPFrom     uint64
 | 
				
			||||||
	lastCountryId  uint16
 | 
						lastCountryId  uint16
 | 
				
			||||||
@@ -32,16 +34,16 @@ type Reader struct {
 | 
				
			|||||||
	lastProviderId uint16
 | 
						lastProviderId uint16
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewReader 创建新Reader对象
 | 
					// NewReaderV1 创建新Reader对象
 | 
				
			||||||
func NewReader(reader io.Reader) (*Reader, error) {
 | 
					func NewReaderV1(reader io.Reader) (*Reader, error) {
 | 
				
			||||||
	var libReader = &Reader{
 | 
						var libReader = &Reader{
 | 
				
			||||||
		regionMap: map[string]*ipRegion{},
 | 
							regionMap: map[string]*ipRegion{},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if runtime.NumCPU() >= 4 /** CPU数量较多的通常有着大内存 **/ {
 | 
						if runtime.NumCPU() >= 4 /** CPU数量较多的通常有着大内存 **/ {
 | 
				
			||||||
		libReader.ipV4Items = make([]ipv4Item, 0, 6_000_000)
 | 
							libReader.ipV4Items = make([]ipv4ItemV1, 0, 6_000_000)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		libReader.ipV4Items = make([]ipv4Item, 0, 600_000)
 | 
							libReader.ipV4Items = make([]ipv4ItemV1, 0, 600_000)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := libReader.load(reader)
 | 
						err := libReader.load(reader)
 | 
				
			||||||
@@ -131,7 +133,7 @@ func (this *Reader) Lookup(ip net.IP) *QueryResult {
 | 
				
			|||||||
		return &QueryResult{}
 | 
							return &QueryResult{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var ipLong = configutils.IP2Long(ip)
 | 
						var ipLong = this.ip2long(ip)
 | 
				
			||||||
	var isV4 = configutils.IsIPv4(ip)
 | 
						var isV4 = configutils.IsIPv4(ip)
 | 
				
			||||||
	var resultItem any
 | 
						var resultItem any
 | 
				
			||||||
	if isV4 {
 | 
						if isV4 {
 | 
				
			||||||
@@ -170,11 +172,11 @@ func (this *Reader) Meta() *Meta {
 | 
				
			|||||||
	return this.meta
 | 
						return this.meta
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *Reader) IPv4Items() []ipv4Item {
 | 
					func (this *Reader) IPv4Items() []ipv4ItemV1 {
 | 
				
			||||||
	return this.ipV4Items
 | 
						return this.ipV4Items
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *Reader) IPv6Items() []ipv6Item {
 | 
					func (this *Reader) IPv6Items() []ipv6ItemV1 {
 | 
				
			||||||
	return this.ipV6Items
 | 
						return this.ipV6Items
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -304,13 +306,13 @@ func (this *Reader) parseLine(line []byte) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if version == "4" {
 | 
						if version == "4" {
 | 
				
			||||||
		this.ipV4Items = append(this.ipV4Items, ipv4Item{
 | 
							this.ipV4Items = append(this.ipV4Items, ipv4ItemV1{
 | 
				
			||||||
			IPFrom: uint32(ipFrom),
 | 
								IPFrom: uint32(ipFrom),
 | 
				
			||||||
			IPTo:   uint32(ipTo),
 | 
								IPTo:   uint32(ipTo),
 | 
				
			||||||
			Region: region,
 | 
								Region: region,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		this.ipV6Items = append(this.ipV6Items, ipv6Item{
 | 
							this.ipV6Items = append(this.ipV6Items, ipv6ItemV1{
 | 
				
			||||||
			IPFrom: ipFrom,
 | 
								IPFrom: ipFrom,
 | 
				
			||||||
			IPTo:   ipTo,
 | 
								IPTo:   ipTo,
 | 
				
			||||||
			Region: region,
 | 
								Region: region,
 | 
				
			||||||
@@ -328,3 +330,18 @@ func (this *Reader) decodeUint64(s string) uint64 {
 | 
				
			|||||||
	i, _ := strconv.ParseUint(s, 10, 64)
 | 
						i, _ := strconv.ParseUint(s, 10, 64)
 | 
				
			||||||
	return i
 | 
						return i
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *Reader) ip2long(netIP net.IP) uint64 {
 | 
				
			||||||
 | 
						if len(netIP) == 0 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var b4 = netIP.To4()
 | 
				
			||||||
 | 
						if b4 != nil {
 | 
				
			||||||
 | 
							return uint64(binary.BigEndian.Uint32(b4.To4()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var i = big.NewInt(0)
 | 
				
			||||||
 | 
						i.SetBytes(netIP.To16())
 | 
				
			||||||
 | 
						return i.Uint64()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,10 +9,12 @@ import (
 | 
				
			|||||||
	"io"
 | 
						"io"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"path/filepath"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type FileReader struct {
 | 
					type FileReader struct {
 | 
				
			||||||
	rawReader *Reader
 | 
						rawReader ReaderInterface
 | 
				
			||||||
	//password  string
 | 
						//password  string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -25,10 +27,15 @@ func NewFileReader(path string, password string) (*FileReader, error) {
 | 
				
			|||||||
		_ = fp.Close()
 | 
							_ = fp.Close()
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return NewFileDataReader(fp, password)
 | 
						var version = ReaderVersionV1
 | 
				
			||||||
 | 
						if strings.HasSuffix(filepath.Base(path), ".v2.db") {
 | 
				
			||||||
 | 
							version = ReaderVersionV2
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NewFileDataReader(fp, password, version)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewFileDataReader(dataReader io.Reader, password string) (*FileReader, error) {
 | 
					func NewFileDataReader(dataReader io.Reader, password string, readerVersion ReaderVersion) (*FileReader, error) {
 | 
				
			||||||
	if len(password) > 0 {
 | 
						if len(password) > 0 {
 | 
				
			||||||
		data, err := io.ReadAll(dataReader)
 | 
							data, err := io.ReadAll(dataReader)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -48,7 +55,12 @@ func NewFileDataReader(dataReader io.Reader, password string) (*FileReader, erro
 | 
				
			|||||||
		return nil, fmt.Errorf("create gzip reader failed: %w", err)
 | 
							return nil, fmt.Errorf("create gzip reader failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reader, err := NewReader(gzReader)
 | 
						var reader ReaderInterface
 | 
				
			||||||
 | 
						if readerVersion == ReaderVersionV2 {
 | 
				
			||||||
 | 
							reader, err = NewReaderV2(gzReader)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							reader, err = NewReaderV1(gzReader)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -59,13 +71,13 @@ func NewFileDataReader(dataReader io.Reader, password string) (*FileReader, erro
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *FileReader) Meta() *Meta {
 | 
					func (this *FileReader) Meta() *Meta {
 | 
				
			||||||
	return this.rawReader.meta
 | 
						return this.rawReader.Meta()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *FileReader) Lookup(ip net.IP) *QueryResult {
 | 
					func (this *FileReader) Lookup(ip net.IP) *QueryResult {
 | 
				
			||||||
	return this.rawReader.Lookup(ip)
 | 
						return this.rawReader.Lookup(ip)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *FileReader) RawReader() *Reader {
 | 
					func (this *FileReader) RawReader() ReaderInterface {
 | 
				
			||||||
	return this.rawReader
 | 
						return this.rawReader
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,12 +6,13 @@ import (
 | 
				
			|||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
 | 
				
			||||||
	"github.com/iwind/TeaGo/maps"
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						stringutil "github.com/iwind/TeaGo/utils/string"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNewFileReader(t *testing.T) {
 | 
					func TestNewFileReader(t *testing.T) {
 | 
				
			||||||
	reader, err := iplibrary.NewFileReader("./ip-20c1461c.db", "123456")
 | 
						reader, err := iplibrary.NewFileReader("./default_ip_library_plus_test.go", stringutil.Md5("123456"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										18
									
								
								pkg/iplibrary/reader_interface.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								pkg/iplibrary/reader_interface.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iplibrary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "net"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ReaderVersion = int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						ReaderVersionV1 ReaderVersion = 0
 | 
				
			||||||
 | 
						ReaderVersionV2 ReaderVersion = 2
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ReaderInterface interface {
 | 
				
			||||||
 | 
						Meta() *Meta
 | 
				
			||||||
 | 
						Lookup(ip net.IP) *QueryResult
 | 
				
			||||||
 | 
						Destroy()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -213,13 +213,21 @@ func (this *QueryResult) RegionSummary() string {
 | 
				
			|||||||
func (this *QueryResult) realCountryId() uint16 {
 | 
					func (this *QueryResult) realCountryId() uint16 {
 | 
				
			||||||
	if this.item != nil {
 | 
						if this.item != nil {
 | 
				
			||||||
		switch item := this.item.(type) {
 | 
							switch item := this.item.(type) {
 | 
				
			||||||
		case *ipv4Item:
 | 
							case *ipv4ItemV1:
 | 
				
			||||||
			return item.Region.CountryId
 | 
								return item.Region.CountryId
 | 
				
			||||||
		case ipv4Item:
 | 
							case ipv4ItemV1:
 | 
				
			||||||
			return item.Region.CountryId
 | 
								return item.Region.CountryId
 | 
				
			||||||
		case *ipv6Item:
 | 
							case *ipv6ItemV1:
 | 
				
			||||||
			return item.Region.CountryId
 | 
								return item.Region.CountryId
 | 
				
			||||||
		case ipv6Item:
 | 
							case ipv6ItemV1:
 | 
				
			||||||
 | 
								return item.Region.CountryId
 | 
				
			||||||
 | 
							case *ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.CountryId
 | 
				
			||||||
 | 
							case ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.CountryId
 | 
				
			||||||
 | 
							case *ipv6ItemV2:
 | 
				
			||||||
 | 
								return item.Region.CountryId
 | 
				
			||||||
 | 
							case ipv6ItemV2:
 | 
				
			||||||
			return item.Region.CountryId
 | 
								return item.Region.CountryId
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -230,13 +238,21 @@ func (this *QueryResult) realCountryId() uint16 {
 | 
				
			|||||||
func (this *QueryResult) realProvinceId() uint16 {
 | 
					func (this *QueryResult) realProvinceId() uint16 {
 | 
				
			||||||
	if this.item != nil {
 | 
						if this.item != nil {
 | 
				
			||||||
		switch item := this.item.(type) {
 | 
							switch item := this.item.(type) {
 | 
				
			||||||
		case *ipv4Item:
 | 
							case *ipv4ItemV1:
 | 
				
			||||||
			return item.Region.ProvinceId
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
		case ipv4Item:
 | 
							case ipv4ItemV1:
 | 
				
			||||||
			return item.Region.ProvinceId
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
		case *ipv6Item:
 | 
							case *ipv6ItemV1:
 | 
				
			||||||
			return item.Region.ProvinceId
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
		case ipv6Item:
 | 
							case ipv6ItemV1:
 | 
				
			||||||
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
 | 
							case *ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
 | 
							case ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
 | 
							case *ipv6ItemV2:
 | 
				
			||||||
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
 | 
							case ipv6ItemV2:
 | 
				
			||||||
			return item.Region.ProvinceId
 | 
								return item.Region.ProvinceId
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -247,13 +263,21 @@ func (this *QueryResult) realProvinceId() uint16 {
 | 
				
			|||||||
func (this *QueryResult) realCityId() uint32 {
 | 
					func (this *QueryResult) realCityId() uint32 {
 | 
				
			||||||
	if this.item != nil {
 | 
						if this.item != nil {
 | 
				
			||||||
		switch item := this.item.(type) {
 | 
							switch item := this.item.(type) {
 | 
				
			||||||
		case *ipv4Item:
 | 
							case *ipv4ItemV1:
 | 
				
			||||||
			return item.Region.CityId
 | 
								return item.Region.CityId
 | 
				
			||||||
		case ipv4Item:
 | 
							case ipv4ItemV1:
 | 
				
			||||||
			return item.Region.CityId
 | 
								return item.Region.CityId
 | 
				
			||||||
		case *ipv6Item:
 | 
							case *ipv6ItemV1:
 | 
				
			||||||
			return item.Region.CityId
 | 
								return item.Region.CityId
 | 
				
			||||||
		case ipv6Item:
 | 
							case ipv6ItemV1:
 | 
				
			||||||
 | 
								return item.Region.CityId
 | 
				
			||||||
 | 
							case *ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.CityId
 | 
				
			||||||
 | 
							case ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.CityId
 | 
				
			||||||
 | 
							case *ipv6ItemV2:
 | 
				
			||||||
 | 
								return item.Region.CityId
 | 
				
			||||||
 | 
							case ipv6ItemV2:
 | 
				
			||||||
			return item.Region.CityId
 | 
								return item.Region.CityId
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -264,13 +288,21 @@ func (this *QueryResult) realCityId() uint32 {
 | 
				
			|||||||
func (this *QueryResult) realTownId() uint32 {
 | 
					func (this *QueryResult) realTownId() uint32 {
 | 
				
			||||||
	if this.item != nil {
 | 
						if this.item != nil {
 | 
				
			||||||
		switch item := this.item.(type) {
 | 
							switch item := this.item.(type) {
 | 
				
			||||||
		case *ipv4Item:
 | 
							case *ipv4ItemV1:
 | 
				
			||||||
			return item.Region.TownId
 | 
								return item.Region.TownId
 | 
				
			||||||
		case ipv4Item:
 | 
							case ipv4ItemV1:
 | 
				
			||||||
			return item.Region.TownId
 | 
								return item.Region.TownId
 | 
				
			||||||
		case *ipv6Item:
 | 
							case *ipv6ItemV1:
 | 
				
			||||||
			return item.Region.TownId
 | 
								return item.Region.TownId
 | 
				
			||||||
		case ipv6Item:
 | 
							case ipv6ItemV1:
 | 
				
			||||||
 | 
								return item.Region.TownId
 | 
				
			||||||
 | 
							case *ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.TownId
 | 
				
			||||||
 | 
							case ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.TownId
 | 
				
			||||||
 | 
							case *ipv6ItemV2:
 | 
				
			||||||
 | 
								return item.Region.TownId
 | 
				
			||||||
 | 
							case ipv6ItemV2:
 | 
				
			||||||
			return item.Region.TownId
 | 
								return item.Region.TownId
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -281,13 +313,21 @@ func (this *QueryResult) realTownId() uint32 {
 | 
				
			|||||||
func (this *QueryResult) realProviderId() uint16 {
 | 
					func (this *QueryResult) realProviderId() uint16 {
 | 
				
			||||||
	if this.item != nil {
 | 
						if this.item != nil {
 | 
				
			||||||
		switch item := this.item.(type) {
 | 
							switch item := this.item.(type) {
 | 
				
			||||||
		case *ipv4Item:
 | 
							case *ipv4ItemV1:
 | 
				
			||||||
			return item.Region.ProviderId
 | 
								return item.Region.ProviderId
 | 
				
			||||||
		case ipv4Item:
 | 
							case ipv4ItemV1:
 | 
				
			||||||
			return item.Region.ProviderId
 | 
								return item.Region.ProviderId
 | 
				
			||||||
		case *ipv6Item:
 | 
							case *ipv6ItemV1:
 | 
				
			||||||
			return item.Region.ProviderId
 | 
								return item.Region.ProviderId
 | 
				
			||||||
		case ipv6Item:
 | 
							case ipv6ItemV1:
 | 
				
			||||||
 | 
								return item.Region.ProviderId
 | 
				
			||||||
 | 
							case *ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.ProviderId
 | 
				
			||||||
 | 
							case ipv4ItemV2:
 | 
				
			||||||
 | 
								return item.Region.ProviderId
 | 
				
			||||||
 | 
							case *ipv6ItemV2:
 | 
				
			||||||
 | 
								return item.Region.ProviderId
 | 
				
			||||||
 | 
							case ipv6ItemV2:
 | 
				
			||||||
			return item.Region.ProviderId
 | 
								return item.Region.ProviderId
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestNewReader(t *testing.T) {
 | 
					func TestNewReader(t *testing.T) {
 | 
				
			||||||
	var buf = &bytes.Buffer{}
 | 
						var buf = &bytes.Buffer{}
 | 
				
			||||||
	var writer = iplibrary.NewWriter(buf, &iplibrary.Meta{
 | 
						var writer = iplibrary.NewWriterV1(buf, &iplibrary.Meta{
 | 
				
			||||||
		Author: "GoEdge <https://goedge.cn>",
 | 
							Author: "GoEdge <https://goedge.cn>",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,7 +63,7 @@ func TestNewReader(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	var stat = &runtime.MemStats{}
 | 
						var stat = &runtime.MemStats{}
 | 
				
			||||||
	runtime.ReadMemStats(stat)
 | 
						runtime.ReadMemStats(stat)
 | 
				
			||||||
	reader, err := iplibrary.NewReader(buf)
 | 
						reader, err := iplibrary.NewReaderV2(buf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var stat2 = &runtime.MemStats{}
 | 
						var stat2 = &runtime.MemStats{}
 | 
				
			||||||
	runtime.ReadMemStats(stat2)
 | 
						runtime.ReadMemStats(stat2)
 | 
				
			||||||
@@ -115,7 +115,7 @@ func BenchmarkNewReader(b *testing.B) {
 | 
				
			|||||||
	runtime.GOMAXPROCS(1)
 | 
						runtime.GOMAXPROCS(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var buf = &bytes.Buffer{}
 | 
						var buf = &bytes.Buffer{}
 | 
				
			||||||
	var writer = iplibrary.NewWriter(buf, &iplibrary.Meta{
 | 
						var writer = iplibrary.NewWriterV1(buf, &iplibrary.Meta{
 | 
				
			||||||
		Author: "GoEdge <https://goedge.cn>",
 | 
							Author: "GoEdge <https://goedge.cn>",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -135,7 +135,7 @@ func BenchmarkNewReader(b *testing.B) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	reader, err := iplibrary.NewReader(buf)
 | 
						reader, err := iplibrary.NewReaderV2(buf)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		b.Fatal(err)
 | 
							b.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										360
									
								
								pkg/iplibrary/reader_v2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										360
									
								
								pkg/iplibrary/reader_v2.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,360 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iplibrary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
						"sort"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ReaderV2 IP库Reader V2
 | 
				
			||||||
 | 
					type ReaderV2 struct {
 | 
				
			||||||
 | 
						meta *Meta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						regionMap map[string]*ipRegion // 缓存重复的区域用来节约内存
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ipV4Items []ipv4ItemV2
 | 
				
			||||||
 | 
						ipV6Items []ipv6ItemV2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lastCountryId  uint16
 | 
				
			||||||
 | 
						lastProvinceId uint16
 | 
				
			||||||
 | 
						lastCityId     uint32
 | 
				
			||||||
 | 
						lastTownId     uint32
 | 
				
			||||||
 | 
						lastProviderId uint16
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewReaderV2 创建新Reader对象
 | 
				
			||||||
 | 
					func NewReaderV2(reader io.Reader) (*ReaderV2, error) {
 | 
				
			||||||
 | 
						var libReader = &ReaderV2{
 | 
				
			||||||
 | 
							regionMap: map[string]*ipRegion{},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if runtime.NumCPU() >= 4 /** CPU数量较多的通常有着大内存 **/ {
 | 
				
			||||||
 | 
							libReader.ipV4Items = make([]ipv4ItemV2, 0, 6_000_000)
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							libReader.ipV4Items = make([]ipv4ItemV2, 0, 600_000)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := libReader.load(reader)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return libReader, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 从Reader中加载数据
 | 
				
			||||||
 | 
					func (this *ReaderV2) load(reader io.Reader) error {
 | 
				
			||||||
 | 
						var buf = make([]byte, 1024)
 | 
				
			||||||
 | 
						var metaLine []byte
 | 
				
			||||||
 | 
						var metaLineFound = false
 | 
				
			||||||
 | 
						var dataBuf = []byte{}
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							n, err := reader.Read(buf)
 | 
				
			||||||
 | 
							if n > 0 {
 | 
				
			||||||
 | 
								var data = buf[:n]
 | 
				
			||||||
 | 
								dataBuf = append(dataBuf, data...)
 | 
				
			||||||
 | 
								if metaLineFound {
 | 
				
			||||||
 | 
									left, err := this.parse(dataBuf)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									dataBuf = left
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									var index = bytes.IndexByte(dataBuf, '\n')
 | 
				
			||||||
 | 
									if index > 0 {
 | 
				
			||||||
 | 
										metaLine = dataBuf[:index]
 | 
				
			||||||
 | 
										dataBuf = dataBuf[index+1:]
 | 
				
			||||||
 | 
										metaLineFound = true
 | 
				
			||||||
 | 
										var meta = &Meta{}
 | 
				
			||||||
 | 
										err = json.Unmarshal(metaLine, &meta)
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											return err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										meta.Init()
 | 
				
			||||||
 | 
										this.meta = meta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										left, err := this.parse(dataBuf)
 | 
				
			||||||
 | 
										if err != nil {
 | 
				
			||||||
 | 
											return err
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										dataBuf = left
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								if err != io.EOF {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(this.ipV4Items, func(i, j int) bool {
 | 
				
			||||||
 | 
							var from0 = this.ipV4Items[i].IPFrom
 | 
				
			||||||
 | 
							var to0 = this.ipV4Items[i].IPTo
 | 
				
			||||||
 | 
							var from1 = this.ipV4Items[j].IPFrom
 | 
				
			||||||
 | 
							var to1 = this.ipV4Items[j].IPTo
 | 
				
			||||||
 | 
							if from0 == from1 {
 | 
				
			||||||
 | 
								return bytes.Compare(to0[:], to1[:]) < 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return bytes.Compare(from0[:], from1[:]) < 0
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sort.Slice(this.ipV6Items, func(i, j int) bool {
 | 
				
			||||||
 | 
							var from0 = this.ipV6Items[i].IPFrom
 | 
				
			||||||
 | 
							var to0 = this.ipV6Items[i].IPTo
 | 
				
			||||||
 | 
							var from1 = this.ipV6Items[j].IPFrom
 | 
				
			||||||
 | 
							var to1 = this.ipV6Items[j].IPTo
 | 
				
			||||||
 | 
							if from0 == from1 {
 | 
				
			||||||
 | 
								return bytes.Compare(to0[:], to1[:]) < 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return bytes.Compare(from0[:], from1[:]) < 0
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 清理内存
 | 
				
			||||||
 | 
						this.regionMap = nil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ReaderV2) Lookup(ip net.IP) *QueryResult {
 | 
				
			||||||
 | 
						if ip == nil {
 | 
				
			||||||
 | 
							return &QueryResult{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var isV4 = ip.To4() != nil
 | 
				
			||||||
 | 
						var resultItem any
 | 
				
			||||||
 | 
						if isV4 {
 | 
				
			||||||
 | 
							sort.Search(len(this.ipV4Items), func(i int) bool {
 | 
				
			||||||
 | 
								var item = this.ipV4Items[i]
 | 
				
			||||||
 | 
								if bytes.Compare(item.IPFrom[:], ip) <= 0 {
 | 
				
			||||||
 | 
									if bytes.Compare(item.IPTo[:], ip) >= 0 {
 | 
				
			||||||
 | 
										resultItem = item
 | 
				
			||||||
 | 
										return false
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							sort.Search(len(this.ipV6Items), func(i int) bool {
 | 
				
			||||||
 | 
								var item = this.ipV6Items[i]
 | 
				
			||||||
 | 
								if bytes.Compare(item.IPFrom[:], ip) <= 0 {
 | 
				
			||||||
 | 
									if bytes.Compare(item.IPTo[:], ip) >= 0 {
 | 
				
			||||||
 | 
										resultItem = item
 | 
				
			||||||
 | 
										return false
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return false
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &QueryResult{
 | 
				
			||||||
 | 
							item: resultItem,
 | 
				
			||||||
 | 
							meta: this.meta,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ReaderV2) Meta() *Meta {
 | 
				
			||||||
 | 
						return this.meta
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ReaderV2) IPv4Items() []ipv4ItemV2 {
 | 
				
			||||||
 | 
						return this.ipV4Items
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ReaderV2) IPv6Items() []ipv6ItemV2 {
 | 
				
			||||||
 | 
						return this.ipV6Items
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ReaderV2) Destroy() {
 | 
				
			||||||
 | 
						this.meta = nil
 | 
				
			||||||
 | 
						this.regionMap = nil
 | 
				
			||||||
 | 
						this.ipV4Items = nil
 | 
				
			||||||
 | 
						this.ipV6Items = nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 分析数据
 | 
				
			||||||
 | 
					func (this *ReaderV2) parse(data []byte) (left []byte, err error) {
 | 
				
			||||||
 | 
						if len(data) == 0 {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for {
 | 
				
			||||||
 | 
							if len(data) == 0 {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var offset int
 | 
				
			||||||
 | 
							if data[0] == '|' {
 | 
				
			||||||
 | 
								offset = 1 + 8 + 1
 | 
				
			||||||
 | 
							} else if data[0] == '4' {
 | 
				
			||||||
 | 
								offset = 2 + 8 + 1
 | 
				
			||||||
 | 
							} else if data[0] == '6' {
 | 
				
			||||||
 | 
								offset = 2 + 32 + 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var index = bytes.IndexByte(data[offset:], '\n')
 | 
				
			||||||
 | 
							if index >= 0 {
 | 
				
			||||||
 | 
								index += offset
 | 
				
			||||||
 | 
								var line = data[:index]
 | 
				
			||||||
 | 
								err = this.parseLine(line)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								data = data[index+1:]
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								left = data
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 单行分析
 | 
				
			||||||
 | 
					func (this *ReaderV2) parseLine(line []byte) error {
 | 
				
			||||||
 | 
						if len(line) == 0 {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const maxPieces = 8
 | 
				
			||||||
 | 
						var pieces []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var offset int
 | 
				
			||||||
 | 
						if line[0] == '|' {
 | 
				
			||||||
 | 
							offset = 1 + 8 + 1
 | 
				
			||||||
 | 
							pieces = append(pieces, "", string(line[1:5]), string(line[5:9]))
 | 
				
			||||||
 | 
						} else if line[0] == '4' {
 | 
				
			||||||
 | 
							offset = 2 + 8 + 1
 | 
				
			||||||
 | 
							pieces = append(pieces, "", string(line[2:6]), string(line[6:10]))
 | 
				
			||||||
 | 
						} else if line[0] == '6' {
 | 
				
			||||||
 | 
							offset = 2 + 32 + 1
 | 
				
			||||||
 | 
							pieces = append(pieces, "6", string(line[2:18]), string(line[18:34]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pieces = append(pieces, strings.Split(string(line[offset:]), "|")...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var countPieces = len(pieces)
 | 
				
			||||||
 | 
						if countPieces < maxPieces { // 补足一行
 | 
				
			||||||
 | 
							for i := 0; i < maxPieces-countPieces; i++ {
 | 
				
			||||||
 | 
								pieces = append(pieces, "")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if countPieces > maxPieces {
 | 
				
			||||||
 | 
							return errors.New("invalid ip definition '" + string(line) + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var version = pieces[0]
 | 
				
			||||||
 | 
						if len(version) == 0 {
 | 
				
			||||||
 | 
							version = "4"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if version != "4" && version != "6" {
 | 
				
			||||||
 | 
							return errors.New("invalid ip version '" + string(line) + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// ip range
 | 
				
			||||||
 | 
						var ipFromV4 [4]byte
 | 
				
			||||||
 | 
						var ipToV4 [4]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var ipFromV6 [16]byte
 | 
				
			||||||
 | 
						var ipToV6 [16]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if version == "6" {
 | 
				
			||||||
 | 
							ipFromV6 = [16]byte([]byte(pieces[1]))
 | 
				
			||||||
 | 
							ipToV6 = [16]byte([]byte(pieces[2]))
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ipFromV4 = [4]byte([]byte(pieces[1]))
 | 
				
			||||||
 | 
							ipToV4 = [4]byte([]byte(pieces[2]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// country
 | 
				
			||||||
 | 
						var countryId uint16
 | 
				
			||||||
 | 
						if pieces[3] == "+" {
 | 
				
			||||||
 | 
							countryId = this.lastCountryId
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							countryId = uint16(this.decodeUint64(pieces[3]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastCountryId = countryId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var provinceId uint16
 | 
				
			||||||
 | 
						if pieces[4] == "+" {
 | 
				
			||||||
 | 
							provinceId = this.lastProvinceId
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							provinceId = uint16(this.decodeUint64(pieces[4]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastProvinceId = provinceId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// city
 | 
				
			||||||
 | 
						var cityId uint32
 | 
				
			||||||
 | 
						if pieces[5] == "+" {
 | 
				
			||||||
 | 
							cityId = this.lastCityId
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							cityId = uint32(this.decodeUint64(pieces[5]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastCityId = cityId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// town
 | 
				
			||||||
 | 
						var townId uint32
 | 
				
			||||||
 | 
						if pieces[6] == "+" {
 | 
				
			||||||
 | 
							townId = this.lastTownId
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							townId = uint32(this.decodeUint64(pieces[6]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastTownId = townId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// provider
 | 
				
			||||||
 | 
						var providerId uint16
 | 
				
			||||||
 | 
						if pieces[7] == "+" {
 | 
				
			||||||
 | 
							providerId = this.lastProviderId
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							providerId = uint16(this.decodeUint64(pieces[7]))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastProviderId = providerId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var hash = HashRegion(countryId, provinceId, cityId, townId, providerId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						region, ok := this.regionMap[hash]
 | 
				
			||||||
 | 
						if !ok {
 | 
				
			||||||
 | 
							region = &ipRegion{
 | 
				
			||||||
 | 
								CountryId:  countryId,
 | 
				
			||||||
 | 
								ProvinceId: provinceId,
 | 
				
			||||||
 | 
								CityId:     cityId,
 | 
				
			||||||
 | 
								TownId:     townId,
 | 
				
			||||||
 | 
								ProviderId: providerId,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							this.regionMap[hash] = region
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if version == "4" {
 | 
				
			||||||
 | 
							this.ipV4Items = append(this.ipV4Items, ipv4ItemV2{
 | 
				
			||||||
 | 
								IPFrom: ipFromV4,
 | 
				
			||||||
 | 
								IPTo:   ipToV4,
 | 
				
			||||||
 | 
								Region: region,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							this.ipV6Items = append(this.ipV6Items, ipv6ItemV2{
 | 
				
			||||||
 | 
								IPFrom: ipFromV6,
 | 
				
			||||||
 | 
								IPTo:   ipToV6,
 | 
				
			||||||
 | 
								Region: region,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *ReaderV2) decodeUint64(s string) uint64 {
 | 
				
			||||||
 | 
						if this.meta != nil && this.meta.Version == Version2 {
 | 
				
			||||||
 | 
							i, _ := strconv.ParseUint(s, 32, 64)
 | 
				
			||||||
 | 
							return i
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						i, _ := strconv.ParseUint(s, 10, 64)
 | 
				
			||||||
 | 
						return i
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -214,7 +214,12 @@ func (this *Updater) Loop() error {
 | 
				
			|||||||
func (this *Updater) loadFile(fp *os.File) error {
 | 
					func (this *Updater) loadFile(fp *os.File) error {
 | 
				
			||||||
	this.source.LogInfo("load ip library from '" + fp.Name() + "' ...")
 | 
						this.source.LogInfo("load ip library from '" + fp.Name() + "' ...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fileReader, err := NewFileDataReader(fp, "")
 | 
						var version = ReaderVersionV1
 | 
				
			||||||
 | 
						if strings.HasSuffix(fp.Name(), ".v2.db") {
 | 
				
			||||||
 | 
							version = ReaderVersionV2
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fileReader, err := NewFileDataReader(fp, "", version)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return fmt.Errorf("load ip library from reader failed: %w", err)
 | 
							return fmt.Errorf("load ip library from reader failed: %w", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,42 +3,19 @@
 | 
				
			|||||||
package iplibrary
 | 
					package iplibrary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"crypto/md5"
 | 
						"encoding/binary"
 | 
				
			||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
 | 
				
			||||||
	"hash"
 | 
					 | 
				
			||||||
	"io"
 | 
						"io"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
	"net"
 | 
						"net"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type hashWriter struct {
 | 
					type WriterV1 struct {
 | 
				
			||||||
	rawWriter io.Writer
 | 
					 | 
				
			||||||
	hash      hash.Hash
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func newHashWriter(writer io.Writer) *hashWriter {
 | 
					 | 
				
			||||||
	return &hashWriter{
 | 
					 | 
				
			||||||
		rawWriter: writer,
 | 
					 | 
				
			||||||
		hash:      md5.New(),
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (this *hashWriter) Write(p []byte) (n int, err error) {
 | 
					 | 
				
			||||||
	n, err = this.rawWriter.Write(p)
 | 
					 | 
				
			||||||
	this.hash.Write(p)
 | 
					 | 
				
			||||||
	return
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (this *hashWriter) Sum() string {
 | 
					 | 
				
			||||||
	return fmt.Sprintf("%x", this.hash.Sum(nil))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Writer struct {
 | 
					 | 
				
			||||||
	writer *hashWriter
 | 
						writer *hashWriter
 | 
				
			||||||
	meta   *Meta
 | 
						meta   *Meta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -50,21 +27,21 @@ type Writer struct {
 | 
				
			|||||||
	lastProviderId int64
 | 
						lastProviderId int64
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewWriter(writer io.Writer, meta *Meta) *Writer {
 | 
					func NewWriterV1(writer io.Writer, meta *Meta) *WriterV1 {
 | 
				
			||||||
	if meta == nil {
 | 
						if meta == nil {
 | 
				
			||||||
		meta = &Meta{}
 | 
							meta = &Meta{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	meta.Version = Version2
 | 
						meta.Version = Version2
 | 
				
			||||||
	meta.CreatedAt = time.Now().Unix()
 | 
						meta.CreatedAt = time.Now().Unix()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var libWriter = &Writer{
 | 
						var libWriter = &WriterV1{
 | 
				
			||||||
		writer: newHashWriter(writer),
 | 
							writer: newHashWriter(writer),
 | 
				
			||||||
		meta:   meta,
 | 
							meta:   meta,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return libWriter
 | 
						return libWriter
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *Writer) WriteMeta() error {
 | 
					func (this *WriterV1) WriteMeta() error {
 | 
				
			||||||
	metaJSON, err := json.Marshal(this.meta)
 | 
						metaJSON, err := json.Marshal(this.meta)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -77,7 +54,7 @@ func (this *Writer) WriteMeta() error {
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *Writer) Write(ipFrom string, ipTo string, countryId int64, provinceId int64, cityId int64, townId int64, providerId int64) error {
 | 
					func (this *WriterV1) Write(ipFrom string, ipTo string, countryId int64, provinceId int64, cityId int64, townId int64, providerId int64) error {
 | 
				
			||||||
	// validate IP
 | 
						// validate IP
 | 
				
			||||||
	var fromIP = net.ParseIP(ipFrom)
 | 
						var fromIP = net.ParseIP(ipFrom)
 | 
				
			||||||
	if fromIP == nil {
 | 
						if fromIP == nil {
 | 
				
			||||||
@@ -100,11 +77,14 @@ func (this *Writer) Write(ipFrom string, ipTo string, countryId int64, provinceI
 | 
				
			|||||||
		pieces = append(pieces, "")
 | 
							pieces = append(pieces, "")
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		pieces = append(pieces, "6")
 | 
							pieces = append(pieces, "6")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// we do NOT support v6 yet
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 1
 | 
						// 1
 | 
				
			||||||
	var fromIPLong = configutils.IP2Long(fromIP)
 | 
						var fromIPLong = this.ip2long(fromIP)
 | 
				
			||||||
	var toIPLong = configutils.IP2Long(toIP)
 | 
						var toIPLong = this.ip2long(toIP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if toIPLong < fromIPLong {
 | 
						if toIPLong < fromIPLong {
 | 
				
			||||||
		fromIPLong, toIPLong = toIPLong, fromIPLong
 | 
							fromIPLong, toIPLong = toIPLong, fromIPLong
 | 
				
			||||||
@@ -193,10 +173,25 @@ func (this *Writer) Write(ipFrom string, ipTo string, countryId int64, provinceI
 | 
				
			|||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *Writer) Sum() string {
 | 
					func (this *WriterV1) Sum() string {
 | 
				
			||||||
	return this.writer.Sum()
 | 
						return this.writer.Sum()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (this *Writer) formatUint64(i uint64) string {
 | 
					func (this *WriterV1) formatUint64(i uint64) string {
 | 
				
			||||||
	return strconv.FormatUint(i, 32)
 | 
						return strconv.FormatUint(i, 32)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *WriterV1) ip2long(netIP net.IP) uint64 {
 | 
				
			||||||
 | 
						if len(netIP) == 0 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var b4 = netIP.To4()
 | 
				
			||||||
 | 
						if b4 != nil {
 | 
				
			||||||
 | 
							return uint64(binary.BigEndian.Uint32(b4.To4()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var i = big.NewInt(0)
 | 
				
			||||||
 | 
						i.SetBytes(netIP.To16())
 | 
				
			||||||
 | 
						return i.Uint64()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ type FileWriter struct {
 | 
				
			|||||||
	gzWriter *gzip.Writer
 | 
						gzWriter *gzip.Writer
 | 
				
			||||||
	password string
 | 
						password string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rawWriter *Writer
 | 
						rawWriter WriterInterface
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewFileWriter(path string, meta *Meta, password string) (*FileWriter, error) {
 | 
					func NewFileWriter(path string, meta *Meta, password string) (*FileWriter, error) {
 | 
				
			||||||
@@ -29,7 +29,7 @@ func NewFileWriter(path string, meta *Meta, password string) (*FileWriter, error
 | 
				
			|||||||
	var writer = &FileWriter{
 | 
						var writer = &FileWriter{
 | 
				
			||||||
		fp:        fp,
 | 
							fp:        fp,
 | 
				
			||||||
		gzWriter:  gzWriter,
 | 
							gzWriter:  gzWriter,
 | 
				
			||||||
		rawWriter: NewWriter(gzWriter, meta),
 | 
							rawWriter: NewWriterV1(gzWriter, meta),
 | 
				
			||||||
		password:  password,
 | 
							password:  password,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return writer, nil
 | 
						return writer, nil
 | 
				
			||||||
@@ -64,11 +64,13 @@ func (this *FileWriter) Close() error {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if len(data) > 0 {
 | 
							if len(data) > 0 {
 | 
				
			||||||
			encodedData, err := NewEncrypt().Encode(data, this.password)
 | 
								encodedData, encodeErr := NewEncrypt().Encode(data, this.password)
 | 
				
			||||||
			if err != nil {
 | 
								if encodeErr != nil {
 | 
				
			||||||
				return err
 | 
									return encodeErr
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								_ = os.Remove(filePath)
 | 
				
			||||||
			err = os.WriteFile(filePath, encodedData, 0666)
 | 
								err = os.WriteFile(filePath, encodedData, 0666)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,13 +6,14 @@ import (
 | 
				
			|||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
 | 
				
			||||||
	"github.com/iwind/TeaGo/rands"
 | 
						"github.com/iwind/TeaGo/rands"
 | 
				
			||||||
	"github.com/iwind/TeaGo/types"
 | 
						"github.com/iwind/TeaGo/types"
 | 
				
			||||||
 | 
						stringutil "github.com/iwind/TeaGo/utils/string"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNewFileWriter(t *testing.T) {
 | 
					func TestNewFileWriter(t *testing.T) {
 | 
				
			||||||
	writer, err := iplibrary.NewFileWriter("./internal-ip-library-test.db", &iplibrary.Meta{
 | 
						writer, err := iplibrary.NewFileWriter("./internal-ip-library-test.db", &iplibrary.Meta{
 | 
				
			||||||
		Author: "GoEdge",
 | 
							Author: "GoEdge",
 | 
				
			||||||
	}, "")
 | 
						}, stringutil.Md5("123456"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								pkg/iplibrary/writer_interface.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								pkg/iplibrary/writer_interface.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iplibrary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WriterInterface interface {
 | 
				
			||||||
 | 
						WriteMeta() error
 | 
				
			||||||
 | 
						Write(ipFrom string, ipTo string, countryId int64, provinceId int64, cityId int64, townId int64, providerId int64) error
 | 
				
			||||||
 | 
						Sum() string
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										190
									
								
								pkg/iplibrary/writer_v2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								pkg/iplibrary/writer_v2.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,190 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iplibrary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"crypto/md5"
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"errors"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"hash"
 | 
				
			||||||
 | 
						"io"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type hashWriter struct {
 | 
				
			||||||
 | 
						rawWriter io.Writer
 | 
				
			||||||
 | 
						hash      hash.Hash
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func newHashWriter(writer io.Writer) *hashWriter {
 | 
				
			||||||
 | 
						return &hashWriter{
 | 
				
			||||||
 | 
							rawWriter: writer,
 | 
				
			||||||
 | 
							hash:      md5.New(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *hashWriter) Write(p []byte) (n int, err error) {
 | 
				
			||||||
 | 
						n, err = this.rawWriter.Write(p)
 | 
				
			||||||
 | 
						this.hash.Write(p)
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *hashWriter) Sum() string {
 | 
				
			||||||
 | 
						return fmt.Sprintf("%x", this.hash.Sum(nil))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type WriterV2 struct {
 | 
				
			||||||
 | 
						writer *hashWriter
 | 
				
			||||||
 | 
						meta   *Meta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						lastCountryId  int64
 | 
				
			||||||
 | 
						lastProvinceId int64
 | 
				
			||||||
 | 
						lastCityId     int64
 | 
				
			||||||
 | 
						lastTownId     int64
 | 
				
			||||||
 | 
						lastProviderId int64
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewWriterV2(writer io.Writer, meta *Meta) *WriterV2 {
 | 
				
			||||||
 | 
						if meta == nil {
 | 
				
			||||||
 | 
							meta = &Meta{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						meta.Version = Version2
 | 
				
			||||||
 | 
						meta.CreatedAt = time.Now().Unix()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var libWriter = &WriterV2{
 | 
				
			||||||
 | 
							writer: newHashWriter(writer),
 | 
				
			||||||
 | 
							meta:   meta,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return libWriter
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *WriterV2) WriteMeta() error {
 | 
				
			||||||
 | 
						metaJSON, err := json.Marshal(this.meta)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err = this.writer.Write(metaJSON)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err = this.writer.Write([]byte("\n"))
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *WriterV2) Write(ipFrom string, ipTo string, countryId int64, provinceId int64, cityId int64, townId int64, providerId int64) error {
 | 
				
			||||||
 | 
						// validate IP
 | 
				
			||||||
 | 
						var fromIP = net.ParseIP(ipFrom)
 | 
				
			||||||
 | 
						if fromIP == nil {
 | 
				
			||||||
 | 
							return errors.New("invalid 'ipFrom': '" + ipFrom + "'")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var fromIsIPv4 = fromIP.To4() != nil
 | 
				
			||||||
 | 
						var toIP = net.ParseIP(ipTo)
 | 
				
			||||||
 | 
						if toIP == nil {
 | 
				
			||||||
 | 
							return errors.New("invalid 'ipTo': " + ipTo)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						var toIsIPv4 = toIP.To4() != nil
 | 
				
			||||||
 | 
						if fromIsIPv4 != toIsIPv4 {
 | 
				
			||||||
 | 
							return errors.New("'ipFrom(" + ipFrom + ")' and 'ipTo(" + ipTo + ")' should have the same IP version")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pieces = []string{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 0
 | 
				
			||||||
 | 
						if fromIsIPv4 {
 | 
				
			||||||
 | 
							pieces = append(pieces, "")
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pieces = append(pieces, "6")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 1
 | 
				
			||||||
 | 
						if bytes.Compare(fromIP, toIP) > 0 {
 | 
				
			||||||
 | 
							fromIP, toIP = toIP, fromIP
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if fromIsIPv4 {
 | 
				
			||||||
 | 
							pieces = append(pieces, string(fromIP.To4())+string(toIP.To4()))
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pieces = append(pieces, string(fromIP.To16())+string(toIP.To16()))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2
 | 
				
			||||||
 | 
						if countryId > 0 {
 | 
				
			||||||
 | 
							if countryId == this.lastCountryId {
 | 
				
			||||||
 | 
								pieces = append(pieces, "+")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								pieces = append(pieces, this.formatUint64(uint64(countryId)))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pieces = append(pieces, "")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastCountryId = countryId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 3
 | 
				
			||||||
 | 
						if provinceId > 0 {
 | 
				
			||||||
 | 
							if provinceId == this.lastProvinceId {
 | 
				
			||||||
 | 
								pieces = append(pieces, "+")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								pieces = append(pieces, this.formatUint64(uint64(provinceId)))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pieces = append(pieces, "")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastProvinceId = provinceId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 4
 | 
				
			||||||
 | 
						if cityId > 0 {
 | 
				
			||||||
 | 
							if cityId == this.lastCityId {
 | 
				
			||||||
 | 
								pieces = append(pieces, "+")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								pieces = append(pieces, this.formatUint64(uint64(cityId)))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pieces = append(pieces, "")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastCityId = cityId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 5
 | 
				
			||||||
 | 
						if townId > 0 {
 | 
				
			||||||
 | 
							if townId == this.lastTownId {
 | 
				
			||||||
 | 
								pieces = append(pieces, "+")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								pieces = append(pieces, this.formatUint64(uint64(townId)))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pieces = append(pieces, "")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastTownId = townId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 6
 | 
				
			||||||
 | 
						if providerId > 0 {
 | 
				
			||||||
 | 
							if providerId == this.lastProviderId {
 | 
				
			||||||
 | 
								pieces = append(pieces, "+")
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								pieces = append(pieces, this.formatUint64(uint64(providerId)))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							pieces = append(pieces, "")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						this.lastProviderId = providerId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err := this.writer.Write([]byte(strings.TrimRight(strings.Join(pieces, "|"), "|")))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_, err = this.writer.Write([]byte("\n"))
 | 
				
			||||||
 | 
						return err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *WriterV2) Sum() string {
 | 
				
			||||||
 | 
						return this.writer.Sum()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *WriterV2) formatUint64(i uint64) string {
 | 
				
			||||||
 | 
						return strconv.FormatUint(i, 32)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -5,12 +5,14 @@ package iplibrary_test
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/logs"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNewWriter(t *testing.T) {
 | 
					func TestNewWriter(t *testing.T) {
 | 
				
			||||||
 | 
						//write
 | 
				
			||||||
	var buf = &bytes.Buffer{}
 | 
						var buf = &bytes.Buffer{}
 | 
				
			||||||
	var writer = iplibrary.NewWriter(buf, &iplibrary.Meta{
 | 
						var writer = iplibrary.NewWriterV1(buf, &iplibrary.Meta{
 | 
				
			||||||
		Author: "GoEdge <https://goedge.cn>",
 | 
							Author: "GoEdge <https://goedge.cn>",
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,6 +41,27 @@ func TestNewWriter(t *testing.T) {
 | 
				
			|||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = writer.Write("10.0.0.1", "10.0.0.2", 101, 201, 301, 401, 501)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = writer.Write("10.0.0.3", "10.0.0.4", 101, 201, 301, 401, 501)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t.Log(buf.String())
 | 
						t.Log(buf.String())
 | 
				
			||||||
	t.Log("sum:", writer.Sum())
 | 
						t.Log("sum:", writer.Sum())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// read
 | 
				
			||||||
 | 
						reader, err := iplibrary.NewReaderV2(buf)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						logs.PrintAsJSON(reader.IPv4Items(), t)
 | 
				
			||||||
 | 
						logs.PrintAsJSON(reader.IPv6Items(), t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_ = reader
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										216
									
								
								pkg/iputils/ip.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								pkg/iputils/ip.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iputils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/binary"
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
						"math/big"
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type IP struct {
 | 
				
			||||||
 | 
						rawIP  net.IP
 | 
				
			||||||
 | 
						bigInt *big.Int
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var uint32BigInt = big.NewInt(int64(math.MaxUint32))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ParseIP(ipString string) IP {
 | 
				
			||||||
 | 
						return NewIP(net.ParseIP(ipString))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewIP(rawIP net.IP) IP {
 | 
				
			||||||
 | 
						if rawIP == nil {
 | 
				
			||||||
 | 
							return IP{}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rawIP.To4() == nil {
 | 
				
			||||||
 | 
							var bigInt = big.NewInt(0)
 | 
				
			||||||
 | 
							bigInt.SetBytes(rawIP.To16())
 | 
				
			||||||
 | 
							bigInt.Add(bigInt, uint32BigInt)
 | 
				
			||||||
 | 
							return IP{
 | 
				
			||||||
 | 
								rawIP:  rawIP,
 | 
				
			||||||
 | 
								bigInt: bigInt,
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return IP{
 | 
				
			||||||
 | 
							rawIP: rawIP,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsIPv4(ipString string) bool {
 | 
				
			||||||
 | 
						var rawIP = net.ParseIP(ipString)
 | 
				
			||||||
 | 
						return rawIP != nil && rawIP.To4() != nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsIPv6(ipString string) bool {
 | 
				
			||||||
 | 
						var rawIP = net.ParseIP(ipString)
 | 
				
			||||||
 | 
						return rawIP != nil && rawIP.To4() == nil && rawIP.To16() != nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func CompareLong(i1 string, i2 string) int {
 | 
				
			||||||
 | 
						if i1 == "" {
 | 
				
			||||||
 | 
							i1 = "0"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if i2 == "" {
 | 
				
			||||||
 | 
							i2 = "0"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var l = len(i1) - len(i2)
 | 
				
			||||||
 | 
						if l > 0 {
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if l < 0 {
 | 
				
			||||||
 | 
							return -1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if i1 > i2 {
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if i1 < i2 {
 | 
				
			||||||
 | 
							return -1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var bigIntPool = &sync.Pool{
 | 
				
			||||||
 | 
						New: func() any {
 | 
				
			||||||
 | 
							return big.NewInt(0)
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ToLong(ip string) string {
 | 
				
			||||||
 | 
						var rawIP = net.ParseIP(ip)
 | 
				
			||||||
 | 
						if rawIP == nil {
 | 
				
			||||||
 | 
							return "0"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var i4 = rawIP.To4()
 | 
				
			||||||
 | 
						if i4 != nil {
 | 
				
			||||||
 | 
							return strconv.FormatUint(uint64(binary.BigEndian.Uint32(i4)), 10)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var bigInt = bigIntPool.Get().(*big.Int)
 | 
				
			||||||
 | 
						bigInt.SetBytes(rawIP.To16())
 | 
				
			||||||
 | 
						bigInt.Add(bigInt, uint32BigInt)
 | 
				
			||||||
 | 
						var s = bigInt.String()
 | 
				
			||||||
 | 
						bigIntPool.Put(bigInt)
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ToHex(ip string) string {
 | 
				
			||||||
 | 
						var rawIP = net.ParseIP(ip)
 | 
				
			||||||
 | 
						if rawIP == nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if rawIP.To4() != nil {
 | 
				
			||||||
 | 
							return fmt.Sprintf("%x", rawIP.To4())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return fmt.Sprintf("%x", rawIP.To16())
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func ToLittleLong(ip string) string {
 | 
				
			||||||
 | 
						var rawIP = net.ParseIP(ip)
 | 
				
			||||||
 | 
						if rawIP == nil {
 | 
				
			||||||
 | 
							return "0"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var i4 = rawIP.To4()
 | 
				
			||||||
 | 
						if i4 != nil {
 | 
				
			||||||
 | 
							return strconv.FormatUint(uint64(binary.BigEndian.Uint32(i4)), 10)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var bigInt = bigIntPool.Get().(*big.Int)
 | 
				
			||||||
 | 
						bigInt.SetBytes(rawIP.To16())
 | 
				
			||||||
 | 
						var s = bigInt.String()
 | 
				
			||||||
 | 
						bigIntPool.Put(bigInt)
 | 
				
			||||||
 | 
						return s
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) ToLong() string {
 | 
				
			||||||
 | 
						if this.rawIP == nil {
 | 
				
			||||||
 | 
							return "0"
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if this.bigInt != nil {
 | 
				
			||||||
 | 
							return this.bigInt.String()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return strconv.FormatUint(uint64(binary.BigEndian.Uint32(this.rawIP.To4())), 10)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) Mod(d int) int {
 | 
				
			||||||
 | 
						if this.rawIP == nil {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if this.bigInt != nil {
 | 
				
			||||||
 | 
							return int(this.bigInt.Mod(this.bigInt, big.NewInt(int64(d))).Int64())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return int(binary.BigEndian.Uint32(this.rawIP.To4()) % uint32(d))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) Compare(anotherIP IP) int {
 | 
				
			||||||
 | 
						if this.rawIP == nil {
 | 
				
			||||||
 | 
							if anotherIP.rawIP == nil {
 | 
				
			||||||
 | 
								return 0
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return -1
 | 
				
			||||||
 | 
						} else if anotherIP.rawIP == nil {
 | 
				
			||||||
 | 
							return 1
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if this.bigInt != nil {
 | 
				
			||||||
 | 
							if anotherIP.bigInt == nil {
 | 
				
			||||||
 | 
								return 1 // IPv6 always greater than IPv4
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return this.bigInt.Cmp(anotherIP.bigInt)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if anotherIP.bigInt == nil {
 | 
				
			||||||
 | 
							var i1 = binary.BigEndian.Uint32(this.rawIP.To4())
 | 
				
			||||||
 | 
							var i2 = binary.BigEndian.Uint32(anotherIP.rawIP.To4())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if i1 > i2 {
 | 
				
			||||||
 | 
								return 1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if i1 < i2 {
 | 
				
			||||||
 | 
								return -1
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return -1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) Between(ipFrom IP, ipTo IP) bool {
 | 
				
			||||||
 | 
						return ipFrom.Compare(this) <= 0 && ipTo.Compare(this) >= 0
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) IsIPv4() bool {
 | 
				
			||||||
 | 
						return this.rawIP != nil && this.bigInt == nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) IsIPv6() bool {
 | 
				
			||||||
 | 
						return this.bigInt != nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) IsValid() bool {
 | 
				
			||||||
 | 
						return this.rawIP != nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) Raw() net.IP {
 | 
				
			||||||
 | 
						return this.rawIP
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this IP) String() string {
 | 
				
			||||||
 | 
						if this.rawIP == nil {
 | 
				
			||||||
 | 
							return ""
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.rawIP.String()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										230
									
								
								pkg/iputils/ip_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								pkg/iputils/ip_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,230 @@
 | 
				
			|||||||
 | 
					// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package iputils_test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/iputils"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/assert"
 | 
				
			||||||
 | 
						"runtime"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIP_ParseIP(t *testing.T) {
 | 
				
			||||||
 | 
						var a = assert.NewAssertion(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i = iputils.ParseIP("127.0.0.1")
 | 
				
			||||||
 | 
							a.IsTrue(i.IsIPv4())
 | 
				
			||||||
 | 
							a.IsFalse(i.IsIPv6())
 | 
				
			||||||
 | 
							a.IsTrue(i.IsValid())
 | 
				
			||||||
 | 
							a.IsTrue(iputils.IsIPv4("127.0.0.1"))
 | 
				
			||||||
 | 
							a.IsFalse(iputils.IsIPv6("127.0.0.1"))
 | 
				
			||||||
 | 
							t.Log(i.String(), i.ToLong())
 | 
				
			||||||
 | 
							t.Log("raw:", i.Raw())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i = iputils.ParseIP("0.0.0.1")
 | 
				
			||||||
 | 
							a.IsTrue(i.IsIPv4())
 | 
				
			||||||
 | 
							a.IsFalse(i.IsIPv6())
 | 
				
			||||||
 | 
							t.Log(i.String(), i.ToLong())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for j := 0; j < 3; j++ /** repeat test **/ {
 | 
				
			||||||
 | 
							var i = iputils.ParseIP("::1")
 | 
				
			||||||
 | 
							a.IsFalse(i.IsIPv4())
 | 
				
			||||||
 | 
							a.IsTrue(i.IsIPv6())
 | 
				
			||||||
 | 
							a.IsTrue(i.IsValid())
 | 
				
			||||||
 | 
							t.Log(i.String(), i.ToLong())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var i = iputils.ParseIP("2001:db8:0:1::1:101")
 | 
				
			||||||
 | 
								t.Log(i.String(), i.ToLong())
 | 
				
			||||||
 | 
								a.IsFalse(i.IsIPv4())
 | 
				
			||||||
 | 
								a.IsTrue(i.IsIPv6())
 | 
				
			||||||
 | 
								a.IsFalse(iputils.IsIPv4("2001:db8:0:1::1:101"))
 | 
				
			||||||
 | 
								a.IsTrue(iputils.IsIPv6("2001:db8:0:1::1:101"))
 | 
				
			||||||
 | 
								a.IsTrue(i.IsValid())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var i = iputils.ParseIP("2001:db8:0:1::1:102")
 | 
				
			||||||
 | 
								t.Log(i.String(), i.ToLong())
 | 
				
			||||||
 | 
								a.IsFalse(i.IsIPv4())
 | 
				
			||||||
 | 
								a.IsTrue(i.IsIPv6())
 | 
				
			||||||
 | 
								a.IsTrue(i.IsValid())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var i = iputils.ParseIP("2001:db8:0:1::2:101")
 | 
				
			||||||
 | 
								t.Log(i.String(), i.ToLong())
 | 
				
			||||||
 | 
								a.IsFalse(i.IsIPv4())
 | 
				
			||||||
 | 
								a.IsTrue(i.IsIPv6())
 | 
				
			||||||
 | 
								a.IsTrue(i.IsValid())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i = iputils.ParseIP("WRONG IP")
 | 
				
			||||||
 | 
							t.Log(i.String(), i.ToLong())
 | 
				
			||||||
 | 
							a.IsFalse(i.IsIPv4())
 | 
				
			||||||
 | 
							a.IsFalse(i.IsIPv6())
 | 
				
			||||||
 | 
							a.IsFalse(i.IsValid())
 | 
				
			||||||
 | 
							a.IsFalse(iputils.IsIPv4("WRONG IP"))
 | 
				
			||||||
 | 
							a.IsFalse(iputils.IsIPv6("WRONG IP"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIP_Mod(t *testing.T) {
 | 
				
			||||||
 | 
						for _, ip := range []string{
 | 
				
			||||||
 | 
							"127.0.0.1",
 | 
				
			||||||
 | 
							"::1",
 | 
				
			||||||
 | 
							"2001:db8:0:1::1:101",
 | 
				
			||||||
 | 
							"2001:db8:0:1::1:102",
 | 
				
			||||||
 | 
							"WRONG IP",
 | 
				
			||||||
 | 
						} {
 | 
				
			||||||
 | 
							var i = iputils.ParseIP(ip)
 | 
				
			||||||
 | 
							t.Log(ip, "=>", i.ToLong(), "=>", i.Mod(5))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIP_Compare(t *testing.T) {
 | 
				
			||||||
 | 
						var a = assert.NewAssertion(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("127.0.0.1")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("127.0.0.1")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == 0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("127.0.0.1")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("127.0.0.2")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == -1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("127.0.0.2")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("127.0.0.1")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == 1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("2001:db8:0:1::101")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("127.0.0.1")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == 1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("127.0.0.1")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("2001:db8:0:1::101")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == -1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("2001:db8:0:1::101")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("2001:db8:0:1::101")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == 0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("2001:db8:0:1::101")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("2001:db8:0:1::102")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == -1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("2001:db8:0:1::102")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("2001:db8:0:1::101")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == 1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							var i1 = iputils.ParseIP("2001:db8:0:1::2:100")
 | 
				
			||||||
 | 
							var i2 = iputils.ParseIP("2001:db8:0:1::1:101")
 | 
				
			||||||
 | 
							a.IsTrue(i1.Compare(i2) == 1)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIP_Between(t *testing.T) {
 | 
				
			||||||
 | 
						var a = assert.NewAssertion(t)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.ParseIP("127.0.0.2").Between(iputils.ParseIP("127.0.0.1"), iputils.ParseIP("127.0.0.3")))
 | 
				
			||||||
 | 
						a.IsTrue(iputils.ParseIP("127.0.0.1").Between(iputils.ParseIP("127.0.0.1"), iputils.ParseIP("127.0.0.3")))
 | 
				
			||||||
 | 
						a.IsFalse(iputils.ParseIP("127.0.0.2").Between(iputils.ParseIP("127.0.0.3"), iputils.ParseIP("127.0.0.4")))
 | 
				
			||||||
 | 
						a.IsFalse(iputils.ParseIP("127.0.0.5").Between(iputils.ParseIP("127.0.0.3"), iputils.ParseIP("127.0.0.4")))
 | 
				
			||||||
 | 
						a.IsFalse(iputils.ParseIP("127.0.0.2").Between(iputils.ParseIP("127.0.0.3"), iputils.ParseIP("127.0.0.1")))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIP_ToLong(t *testing.T) {
 | 
				
			||||||
 | 
						for _, ip := range []string{
 | 
				
			||||||
 | 
							"127.0.0.1",
 | 
				
			||||||
 | 
							"192.168.1.100",
 | 
				
			||||||
 | 
							"::1",
 | 
				
			||||||
 | 
							"fd00:6868:6868:0:10ac:d056:3bf6:7452",
 | 
				
			||||||
 | 
							"fd00:6868:6868:0:10ac:d056:3bf6:7453",
 | 
				
			||||||
 | 
							"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
 | 
				
			||||||
 | 
							"2001:db8:0:1::101",
 | 
				
			||||||
 | 
							"2001:db8:0:2::101",
 | 
				
			||||||
 | 
							"wrong ip",
 | 
				
			||||||
 | 
						} {
 | 
				
			||||||
 | 
							var goIP = iputils.ParseIP(ip)
 | 
				
			||||||
 | 
							t.Log(ip, "=>", "\n", goIP.String(), "\n", "=>", "\n", "long1:", goIP.ToLong(), "\n", "long2:", iputils.ToLong(ip), "\n", "little long:", iputils.ToLittleLong(ip))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIP_CompareLong(t *testing.T) {
 | 
				
			||||||
 | 
						var a = assert.NewAssertion(t)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.CompareLong("1", "2") == -1)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.CompareLong("11", "2") == 1)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.CompareLong("11", "22") == -1)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.CompareLong("22", "101") == -1)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.CompareLong("33", "22") == 1)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.CompareLong("101", "22") == 1)
 | 
				
			||||||
 | 
						a.IsTrue(iputils.CompareLong("22", "22") == 0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestIP_Memory(t *testing.T) {
 | 
				
			||||||
 | 
						var list []iputils.IP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var stat1 = &runtime.MemStats{}
 | 
				
			||||||
 | 
						runtime.ReadMemStats(stat1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < 1_000_000; i++ {
 | 
				
			||||||
 | 
							list = append(list, iputils.ParseIP("fd00:6868:6868:0:10ac:d056:3bf6:7452"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//runtime.GC()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var stat2 = &runtime.MemStats{}
 | 
				
			||||||
 | 
						runtime.ReadMemStats(stat2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						t.Log((stat2.Alloc-stat1.Alloc)>>10, "KB", (stat2.HeapInuse-stat1.HeapInuse)>>10, "KB")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// hold the memory
 | 
				
			||||||
 | 
						for _, v := range list {
 | 
				
			||||||
 | 
							_ = v
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func BenchmarkParse(b *testing.B) {
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							iputils.ParseIP("fd00:6868:6868:0:10ac:d056:3bf6:7452")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func BenchmarkToLongV4(b *testing.B) {
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							iputils.ToLong("192.168.2.100")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func BenchmarkToLongV6(b *testing.B) {
 | 
				
			||||||
 | 
						runtime.GOMAXPROCS(1)
 | 
				
			||||||
 | 
						b.ReportAllocs()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < b.N; i++ {
 | 
				
			||||||
 | 
							iputils.ToLong("fd00:6868:6868:0:10ac:d056:3bf6:7452")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user