Files
EdgeCommon/pkg/dnsconfigs/route_ranges.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
}