mirror of
https://github.com/alibaba/higress.git
synced 2026-06-09 20:57:32 +08:00
Feat: Add ai-geoip wasm plugin to search the client's geographic information depending on the client ip address (#1172)
Co-authored-by: Kent Dong <ch3cho@qq.com> Co-authored-by: 澄潭 <zty98751@alibaba-inc.com>
This commit is contained in:
683844
plugins/wasm-go/extensions/geo-ip/generateCidr/ip.merge.txt
Normal file
683844
plugins/wasm-go/extensions/geo-ip/generateCidr/ip.merge.txt
Normal file
File diff suppressed because it is too large
Load Diff
160
plugins/wasm-go/extensions/geo-ip/generateCidr/ipRange2Cidr.go
Normal file
160
plugins/wasm-go/extensions/geo-ip/generateCidr/ipRange2Cidr.go
Normal file
@@ -0,0 +1,160 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
//"strconv"
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
//go:embed ip.merge.txt
|
||||
var geoipdata string
|
||||
|
||||
var CIDR2MASK = []uint32{
|
||||
0x00000000, 0x80000000, 0xC0000000, 0xE0000000, 0xF0000000, 0xF8000000,
|
||||
0xFC000000, 0xFE000000, 0xFF000000, 0xFF800000, 0xFFC00000, 0xFFE00000,
|
||||
0xFFF00000, 0xFFF80000, 0xFFFC0000, 0xFFFE0000, 0xFFFF0000, 0xFFFF8000,
|
||||
0xFFFFC000, 0xFFFFE000, 0xFFFFF000, 0xFFFFF800, 0xFFFFFC00, 0xFFFFFE00,
|
||||
0xFFFFFF00, 0xFFFFFF80, 0xFFFFFFC0, 0xFFFFFFE0, 0xFFFFFFF0, 0xFFFFFFF8,
|
||||
0xFFFFFFFC, 0xFFFFFFFE, 0xFFFFFFFF,
|
||||
}
|
||||
|
||||
func main() {
|
||||
outFile := "/data/geoCidr.txt"
|
||||
f, err := os.Create(outFile)
|
||||
if err != nil {
|
||||
log.Println("open file failed.", outFile, err)
|
||||
return
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
geoIpRows := strings.Split(geoipdata, "\n")
|
||||
for _, row := range geoIpRows {
|
||||
if row == "" {
|
||||
log.Println("this row is empty.")
|
||||
continue
|
||||
}
|
||||
|
||||
log.Println("geoip segment: ", row)
|
||||
tmpArr := strings.Split(row, "|")
|
||||
if len(tmpArr) < 7 {
|
||||
log.Println("geoIp row field number is less than 7 " + row)
|
||||
return
|
||||
}
|
||||
|
||||
sip := tmpArr[0]
|
||||
eip := tmpArr[1]
|
||||
country := tmpArr[2]
|
||||
province := tmpArr[4]
|
||||
city := tmpArr[5]
|
||||
isp := tmpArr[6]
|
||||
|
||||
if country == "0" {
|
||||
country = ""
|
||||
}
|
||||
if province == "0" {
|
||||
province = ""
|
||||
}
|
||||
if city == "0" {
|
||||
city = ""
|
||||
}
|
||||
if isp == "0" {
|
||||
isp = ""
|
||||
}
|
||||
|
||||
if err := parseGeoIpFile(sip, eip, country, province, city, isp, f); err != nil {
|
||||
log.Printf("parse geo ip file failed, error:%v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func range2cidrList(startIp string, endIp string) []string {
|
||||
cidrList := []string{}
|
||||
|
||||
start := uint32(ipToInt(startIp))
|
||||
beginStart := start
|
||||
end := uint32(ipToInt(endIp))
|
||||
for end >= start {
|
||||
maxSize := 32
|
||||
for maxSize > 0 {
|
||||
mask := CIDR2MASK[maxSize-1]
|
||||
maskedBase := start & mask
|
||||
|
||||
if maskedBase != start {
|
||||
break
|
||||
}
|
||||
|
||||
maxSize--
|
||||
}
|
||||
|
||||
x := math.Log2(float64(end - start + 1))
|
||||
maxDiff := 32 - int(math.Floor(x))
|
||||
if maxSize < maxDiff {
|
||||
maxSize = maxDiff
|
||||
}
|
||||
ipStr := intToIP(int(start))
|
||||
cidr := fmt.Sprintf("%s/%d", ipStr, maxSize)
|
||||
cidrList = append(cidrList, cidr)
|
||||
|
||||
start += uint32(math.Pow(2, float64(32-maxSize)))
|
||||
//avoid dead loop for 255.255.255.255
|
||||
if start < beginStart {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return cidrList
|
||||
}
|
||||
|
||||
func parseGeoIpFile(startIp string, endIp string, country string, province string, city string, isp string, f *os.File) error {
|
||||
cidrList := range2cidrList(startIp, endIp)
|
||||
for _, cidr := range cidrList {
|
||||
outRow := fmt.Sprintf("%s|%s|%s|%s|%s", cidr, country, province, city, isp)
|
||||
_, err := f.WriteString(outRow + "\n")
|
||||
if err != nil {
|
||||
log.Println("write string failed.", outRow, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ipToInt(ipStr string) int {
|
||||
ipSegs := strings.Split(ipStr, ".")
|
||||
var ipInt int = 0
|
||||
var pos uint = 24
|
||||
for _, ipSeg := range ipSegs {
|
||||
tempInt, _ := strconv.Atoi(ipSeg)
|
||||
tempInt = tempInt << pos
|
||||
ipInt = ipInt | tempInt
|
||||
pos -= 8
|
||||
}
|
||||
return ipInt
|
||||
}
|
||||
|
||||
func intToIP(ipInt int) string {
|
||||
ipSegs := make([]string, 4)
|
||||
var len int = len(ipSegs)
|
||||
buffer := bytes.NewBufferString("")
|
||||
for i := 0; i < len; i++ {
|
||||
tempInt := ipInt & 0xFF
|
||||
ipSegs[len-i-1] = strconv.Itoa(tempInt)
|
||||
ipInt = ipInt >> 8
|
||||
}
|
||||
for i := 0; i < len; i++ {
|
||||
buffer.WriteString(ipSegs[i])
|
||||
if i < len-1 {
|
||||
buffer.WriteString(".")
|
||||
}
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
//"strconv"
|
||||
_ "embed"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestRange2CidrList(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
startIp string
|
||||
endIp string
|
||||
want map[string]int
|
||||
}{
|
||||
{
|
||||
"test start ip with 0.0.0.0",
|
||||
"0.0.0.0",
|
||||
"1.0.0.255",
|
||||
map[string]int{
|
||||
"0.0.0.0/8": 1,
|
||||
"1.0.0.0/24": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
"test the same network segment",
|
||||
"1.0.1.0",
|
||||
"1.0.1.255",
|
||||
map[string]int{"1.0.1.0/24": 1},
|
||||
},
|
||||
{
|
||||
"test cross network segment",
|
||||
"1.0.1.0",
|
||||
"2.0.1.112",
|
||||
map[string]int{
|
||||
"1.0.1.0/24": 1,
|
||||
"1.0.2.0/23": 1,
|
||||
"1.0.4.0/22": 1,
|
||||
"1.0.8.0/21": 1,
|
||||
"1.0.16.0/20": 1,
|
||||
"1.0.32.0/19": 1,
|
||||
"1.0.64.0/18": 1,
|
||||
"1.0.128.0/17": 1,
|
||||
"1.1.0.0/16": 1,
|
||||
"1.2.0.0/15": 1,
|
||||
"1.4.0.0/14": 1,
|
||||
"1.8.0.0/13": 1,
|
||||
"1.16.0.0/12": 1,
|
||||
"1.32.0.0/11": 1,
|
||||
"1.64.0.0/10": 1,
|
||||
"1.128.0.0/9": 1,
|
||||
"2.0.0.0/24": 1,
|
||||
"2.0.1.0/26": 1,
|
||||
"2.0.1.64/27": 1,
|
||||
"2.0.1.96/28": 1,
|
||||
"2.0.1.112/32": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
"test end ip with 255.255.255.255",
|
||||
"224.0.0.0",
|
||||
"255.255.255.255",
|
||||
map[string]int{"224.0.0.0/3": 1},
|
||||
},
|
||||
{
|
||||
"test start ip is greater than end ip",
|
||||
"1.0.0.255",
|
||||
"1.0.0.0",
|
||||
map[string]int{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := range2cidrList(test.startIp, test.endIp)
|
||||
assert.Equal(t, len(test.want), len(actual), "")
|
||||
for _, v := range actual {
|
||||
if _, ok := test.want[v]; !ok {
|
||||
assert.Error(t, errors.New("not match"), "")
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user