2021-05-30 16:31:24 +08:00
|
|
|
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
|
|
|
|
|
|
|
|
|
package dnsconfigs
|
|
|
|
|
|
2022-06-28 20:26:44 +08:00
|
|
|
import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
|
|
|
|
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
|
|
|
|
|
"github.com/iwind/TeaGo/maps"
|
|
|
|
|
"net"
|
|
|
|
|
)
|
2021-06-01 16:43:13 +08:00
|
|
|
|
2021-05-30 16:31:24 +08:00
|
|
|
type RouteRangeType = string
|
|
|
|
|
|
|
|
|
|
const (
|
2022-06-28 20:26:44 +08:00
|
|
|
RouteRangeTypeIP RouteRangeType = "ipRange" // IP范围
|
|
|
|
|
RouteRangeTypeCIDR RouteRangeType = "cidr" // CIDR
|
|
|
|
|
RouteRangeTypeRegion RouteRangeType = "region" // 区域
|
2021-05-30 16:31:24 +08:00
|
|
|
)
|
|
|
|
|
|
2022-06-28 20:26:44 +08:00
|
|
|
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 线路范围接口
|
2021-06-01 16:43:13 +08:00
|
|
|
type RouteRangeInterface interface {
|
2022-06-28 20:26:44 +08:00
|
|
|
// Init 初始化
|
2021-06-01 16:43:13 +08:00
|
|
|
Init() error
|
2022-06-28 20:26:44 +08:00
|
|
|
|
|
|
|
|
// 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
|
2021-06-01 16:43:13 +08:00
|
|
|
}
|
|
|
|
|
|
2021-05-30 16:31:24 +08:00
|
|
|
// RouteRangeIPRange IP范围配置
|
2022-06-28 20:26:44 +08:00
|
|
|
// IPv4和IPv6不能混用
|
2021-05-30 16:31:24 +08:00
|
|
|
type RouteRangeIPRange struct {
|
2022-06-28 20:26:44 +08:00
|
|
|
BaseRouteRange
|
|
|
|
|
|
2021-05-30 16:31:24 +08:00
|
|
|
IPFrom string `json:"ipFrom"`
|
|
|
|
|
IPTo string `json:"ipTo"`
|
2021-06-01 16:43:13 +08:00
|
|
|
|
|
|
|
|
ipFromLong uint64
|
|
|
|
|
ipToLong uint64
|
2022-06-28 20:26:44 +08:00
|
|
|
|
|
|
|
|
ipVersion int // 4|6
|
2021-06-01 16:43:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *RouteRangeIPRange) Init() error {
|
2022-06-28 20:26:44 +08:00
|
|
|
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)
|
2021-06-01 16:43:13 +08:00
|
|
|
|
|
|
|
|
if this.ipFromLong > this.ipToLong {
|
|
|
|
|
this.ipFromLong, this.ipToLong = this.ipToLong, this.ipFromLong
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-28 20:26:44 +08:00
|
|
|
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
|
2021-05-30 16:31:24 +08:00
|
|
|
}
|