github.com/nxtrace/NTrace-core@v1.3.1-0.20240513132635-39169291e8c9/dn42/geofeed.go (about)

     1  package dn42
     2  
     3  import (
     4  	"encoding/csv"
     5  	"net"
     6  	"os"
     7  	"sort"
     8  
     9  	"github.com/spf13/viper"
    10  )
    11  
    12  type GeoFeedRow struct {
    13  	IPNet   *net.IPNet
    14  	CIDR    string
    15  	LtdCode string
    16  	ISO3166 string
    17  	City    string
    18  	ASN     string
    19  	IPWhois string
    20  }
    21  
    22  func GetGeoFeed(ip string) (GeoFeedRow, bool) {
    23  	rows, err := ReadGeoFeed()
    24  	if err != nil {
    25  		// 处理错误
    26  		panic(err)
    27  	}
    28  
    29  	row, find := FindGeoFeedRow(ip, rows)
    30  	return row, find
    31  
    32  }
    33  
    34  func ReadGeoFeed() ([]GeoFeedRow, error) {
    35  	path := viper.Get("geoFeedPath").(string)
    36  	f, err := os.Open(path)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	defer f.Close()
    41  
    42  	r := csv.NewReader(f)
    43  	rows, err := r.ReadAll()
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  
    48  	// 将 CSV 中的每一行转换为 GeoFeedRow 类型,并保存到 rowsSlice 中
    49  	var rowsSlice []GeoFeedRow
    50  	for _, row := range rows {
    51  		cidr := row[0] // 假设第一列是 CIDR 字段
    52  		_, ipnet, err := net.ParseCIDR(cidr)
    53  		if err != nil {
    54  			// 如果解析 CIDR 失败,跳过这一行
    55  			continue
    56  		}
    57  		if len(row) == 4 {
    58  			rowsSlice = append(rowsSlice, GeoFeedRow{
    59  				IPNet:   ipnet,
    60  				CIDR:    cidr,
    61  				LtdCode: row[1],
    62  				ISO3166: row[2],
    63  				City:    row[3],
    64  			})
    65  		} else {
    66  			rowsSlice = append(rowsSlice, GeoFeedRow{
    67  				IPNet:   ipnet,
    68  				CIDR:    cidr,
    69  				LtdCode: row[1],
    70  				ISO3166: row[2],
    71  				City:    row[3],
    72  				ASN:     row[4],
    73  				IPWhois: row[5],
    74  			})
    75  		}
    76  
    77  	}
    78  	// 根据 CIDR 范围从小到大排序,方便后面查找
    79  	sort.Slice(rowsSlice, func(i, j int) bool {
    80  		return rowsSlice[i].IPNet.Mask.String() > rowsSlice[j].IPNet.Mask.String()
    81  	})
    82  
    83  	return rowsSlice, nil
    84  }
    85  
    86  func FindGeoFeedRow(ipStr string, rows []GeoFeedRow) (GeoFeedRow, bool) {
    87  	ip := net.ParseIP(ipStr)
    88  	if ip == nil {
    89  		// 如果传入的 IP 无效,直接返回
    90  		return GeoFeedRow{}, false
    91  	}
    92  
    93  	// 遍历每个 CIDR 范围,找到第一个包含传入的 IP 的 CIDR
    94  	for _, row := range rows {
    95  		if row.IPNet.Contains(ip) {
    96  			return row, true
    97  		}
    98  	}
    99  
   100  	return GeoFeedRow{}, false
   101  }