mirror of
				https://github.com/TeaOSLab/EdgeCommon.git
				synced 2025-11-04 05:00:24 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			263 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			263 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
						|
 | 
						|
package dnsconfigs
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"errors"
 | 
						|
	"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
 | 
						|
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
 | 
						|
	"github.com/iwind/TeaGo/maps"
 | 
						|
	"net"
 | 
						|
)
 | 
						|
 | 
						|
type RouteRangeType = string
 | 
						|
 | 
						|
const (
 | 
						|
	RouteRangeTypeIP     RouteRangeType = "ipRange" // IP范围
 | 
						|
	RouteRangeTypeCIDR   RouteRangeType = "cidr"    // CIDR
 | 
						|
	RouteRangeTypeRegion RouteRangeType = "region"  // 区域
 | 
						|
)
 | 
						|
 | 
						|
func AllRouteRangeTypes() []*shared.Definition {
 | 
						|
	return []*shared.Definition{
 | 
						|
		{
 | 
						|
			Name: "IP范围",
 | 
						|
			Code: RouteRangeTypeIP,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			Name: "CIDR",
 | 
						|
			Code: RouteRangeTypeCIDR,
 | 
						|
		},
 | 
						|
		{
 | 
						|
			Name: "区域",
 | 
						|
			Code: RouteRangeTypeRegion,
 | 
						|
		},
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// RouteRegionResolver 解析IP接口
 | 
						|
type RouteRegionResolver interface {
 | 
						|
	Resolve(ip net.IP) (countryId int64, provinceId int64, cityId int64, providerId int64)
 | 
						|
}
 | 
						|
 | 
						|
// RouteRangeInterface 线路范围接口
 | 
						|
type RouteRangeInterface interface {
 | 
						|
	// Init 初始化
 | 
						|
	Init() error
 | 
						|
 | 
						|
	// Contains 判断是否包含
 | 
						|
	Contains(ip net.IP) bool
 | 
						|
 | 
						|
	// SetRegionResolver 设置IP解析接口
 | 
						|
	SetRegionResolver(resolver RouteRegionResolver)
 | 
						|
 | 
						|
	// IsExcluding 是否为排除
 | 
						|
	IsExcluding() bool
 | 
						|
}
 | 
						|
 | 
						|
type BaseRouteRange struct {
 | 
						|
	IsReverse bool `json:"isReverse"`
 | 
						|
 | 
						|
	routeRegionResolver RouteRegionResolver
 | 
						|
}
 | 
						|
 | 
						|
func (this *BaseRouteRange) SetRegionResolver(resolver RouteRegionResolver) {
 | 
						|
	this.routeRegionResolver = resolver
 | 
						|
}
 | 
						|
 | 
						|
func (this *BaseRouteRange) IsExcluding() bool {
 | 
						|
	return this.IsReverse
 | 
						|
}
 | 
						|
 | 
						|
// RouteRangeIPRange IP范围配置
 | 
						|
// IPv4和IPv6不能混用
 | 
						|
type RouteRangeIPRange struct {
 | 
						|
	BaseRouteRange
 | 
						|
 | 
						|
	IPFrom string `json:"ipFrom"`
 | 
						|
	IPTo   string `json:"ipTo"`
 | 
						|
 | 
						|
	ipFromLong uint64
 | 
						|
	ipToLong   uint64
 | 
						|
 | 
						|
	ipVersion int // 4|6
 | 
						|
}
 | 
						|
 | 
						|
func (this *RouteRangeIPRange) Init() error {
 | 
						|
	var ipFrom = net.ParseIP(this.IPFrom)
 | 
						|
	var ipTo = net.ParseIP(this.IPTo)
 | 
						|
	if ipFrom == nil {
 | 
						|
		return errors.New("invalid ipFrom '" + this.IPFrom + "'")
 | 
						|
	}
 | 
						|
	if ipTo == nil {
 | 
						|
		return errors.New("invalid ipTo '" + this.IPTo + "'")
 | 
						|
	}
 | 
						|
 | 
						|
	var ipFromVersion = configutils.IPVersion(ipFrom)
 | 
						|
	var ipToVersion = configutils.IPVersion(ipTo)
 | 
						|
	if ipFromVersion != ipToVersion {
 | 
						|
		return errors.New("ipFrom and ipTo version are not same")
 | 
						|
	}
 | 
						|
	this.ipVersion = ipFromVersion
 | 
						|
 | 
						|
	this.ipFromLong = configutils.IP2Long(ipFrom)
 | 
						|
	this.ipToLong = configutils.IP2Long(ipTo)
 | 
						|
 | 
						|
	if this.ipFromLong > this.ipToLong {
 | 
						|
		this.ipFromLong, this.ipToLong = this.ipToLong, this.ipFromLong
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (this *RouteRangeIPRange) Contains(netIP net.IP) bool {
 | 
						|
	if len(netIP) == 0 {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	var version = configutils.IPVersion(netIP)
 | 
						|
	if version != this.ipVersion {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	var ipLong = configutils.IP2Long(netIP)
 | 
						|
	return ipLong >= this.ipFromLong && ipLong <= this.ipToLong
 | 
						|
}
 | 
						|
 | 
						|
// RouteRangeCIDR CIDR范围配置
 | 
						|
type RouteRangeCIDR struct {
 | 
						|
	BaseRouteRange
 | 
						|
 | 
						|
	CIDR string `json:"cidr"`
 | 
						|
 | 
						|
	cidr *net.IPNet
 | 
						|
}
 | 
						|
 | 
						|
func (this *RouteRangeCIDR) Init() error {
 | 
						|
	_, ipNet, err := net.ParseCIDR(this.CIDR)
 | 
						|
	if err != nil {
 | 
						|
		return errors.New("parse cidr failed: " + err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	this.cidr = ipNet
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (this *RouteRangeCIDR) Contains(netIP net.IP) bool {
 | 
						|
	if netIP == nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	if this.cidr == nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	return this.cidr.Contains(netIP)
 | 
						|
}
 | 
						|
 | 
						|
// RouteRangeRegion 区域范围
 | 
						|
// country:ID, province:ID, city:ID, isp:ID
 | 
						|
type RouteRangeRegion struct {
 | 
						|
	BaseRouteRange
 | 
						|
 | 
						|
	Regions []*routeRegion `json:"regions"`
 | 
						|
}
 | 
						|
 | 
						|
func (this *RouteRangeRegion) Init() error {
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (this *RouteRangeRegion) Contains(netIP net.IP) bool {
 | 
						|
	if this.routeRegionResolver == nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	if len(this.Regions) == 0 {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	countryId, provinceId, cityId, providerId := this.routeRegionResolver.Resolve(netIP)
 | 
						|
	if countryId <= 0 && provinceId <= 0 && cityId <= 0 && providerId <= 0 {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	for _, region := range this.Regions {
 | 
						|
		if region.Id <= 0 {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		switch region.Type {
 | 
						|
		case "country":
 | 
						|
			if region.Id == countryId {
 | 
						|
				return true
 | 
						|
			}
 | 
						|
		case "province":
 | 
						|
			if region.Id == provinceId {
 | 
						|
				return true
 | 
						|
			}
 | 
						|
		case "city":
 | 
						|
			if region.Id == cityId {
 | 
						|
				return true
 | 
						|
			}
 | 
						|
		case "isp":
 | 
						|
			if region.Id == providerId {
 | 
						|
				return true
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
type routeRegion struct {
 | 
						|
	Type string `json:"type"` // country|province|city|isp
 | 
						|
	Id   int64  `json:"id"`
 | 
						|
	Name string `json:"name"`
 | 
						|
}
 | 
						|
 | 
						|
// InitRangesFromJSON 从JSON中初始化线路范围
 | 
						|
func InitRangesFromJSON(rangesJSON []byte) (ranges []RouteRangeInterface, err error) {
 | 
						|
	if len(rangesJSON) == 0 {
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	var rangeMaps = []maps.Map{}
 | 
						|
	err = json.Unmarshal(rangesJSON, &rangeMaps)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	for _, rangeMap := range rangeMaps {
 | 
						|
		var rangeType = rangeMap.GetString("type")
 | 
						|
		paramsJSON, err := json.Marshal(rangeMap.Get("params"))
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		var r RouteRangeInterface
 | 
						|
 | 
						|
		switch rangeType {
 | 
						|
		case RouteRangeTypeIP:
 | 
						|
			r = &RouteRangeIPRange{}
 | 
						|
		case RouteRangeTypeCIDR:
 | 
						|
			r = &RouteRangeCIDR{}
 | 
						|
		case RouteRangeTypeRegion:
 | 
						|
			r = &RouteRangeRegion{}
 | 
						|
		default:
 | 
						|
			return nil, errors.New("invalid route line type '" + rangeType + "'")
 | 
						|
		}
 | 
						|
 | 
						|
		err = json.Unmarshal(paramsJSON, r)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		err = r.Init()
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
		ranges = append(ranges, r)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 |