This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
package dnsconfigs
// ClusterDNSConfig 集群的DNS设置
type ClusterDNSConfig struct {
CNAMERecords []string `yaml:"cnameRecords" json:"cnameRecords"` // 自动加入的CNAME
TTL int32 `yaml:"ttl" json:"ttl"` // 默认TTL各个DNS服务商对记录的TTL的限制各有不同
CNAMEAsDomain bool `yaml:"cnameAsDomain" json:"cnameAsDomain"` // 是否可以像域名一样直接访问CNAME
IncludingLnNodes bool `yaml:"includingLnNodes" json:"includingLnNodes"` // 是否包含Ln节点
NodesAutoSync bool `yaml:"nodesAutoSync" json:"nodesAutoSync"` // 是否自动同步节点状态
ServersAutoSync bool `yaml:"serversAutoSync" json:"serversAutoSync"` // 是否自动同步服务状态
}
func DefaultClusterDNSConfig() *ClusterDNSConfig {
return &ClusterDNSConfig{
CNAMEAsDomain: true,
IncludingLnNodes: true,
}
}

View File

@@ -0,0 +1,29 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnsconfigs
import (
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/iwind/TeaGo/types"
)
type DNSResolver struct {
Host string `json:"host"`
Port int `json:"port"`
Protocol string `json:"protocol"`
}
func (this *DNSResolver) Addr() string {
var port = this.Port
if port <= 0 {
// 暂时不支持DoH
// 实际应用中只支持udp
switch this.Protocol {
case "tls":
port = 853
default:
port = 53
}
}
return configutils.QuoteIP(this.Host) + ":" + types.String(port)
}

View File

@@ -0,0 +1,15 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
type NSAccessLogRef struct {
IsPrior bool `yaml:"isPrior" json:"isPrior"` // 是否覆盖
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
LogMissingDomains bool `yaml:"logMissingDomains" json:"logMissingDomains"` // 是否记录找不到的域名
MissingRecordsOnly bool `yaml:"missingRecordsOnly" json:"missingRecordsOnly"` // 只记录找不到解析记录的访问
}
func (this *NSAccessLogRef) Init() error {
return nil
}

View File

@@ -0,0 +1,60 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package dnsconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
type NSAnswerMode = string
const (
NSAnswerModeRandom NSAnswerMode = "random"
NSAnswerModeRoundRobin NSAnswerMode = "roundRobin"
)
const NSAnswerDefaultSize = 5
type NSAnswerConfig struct {
Mode NSAnswerMode `yaml:"mode" json:"mode"` // 记录回复模式
MaxSize int16 `yaml:"maxSize" json:"maxSize"` // 记录回复最大数量
}
func (this *NSAnswerConfig) IsSame(config2 *NSAnswerConfig) bool {
if config2 == nil {
return false
}
return this.Mode == config2.Mode &&
this.MaxSize == config2.MaxSize
}
func DefaultNSAnswerConfig() *NSAnswerConfig {
return &NSAnswerConfig{
Mode: NSAnswerModeRandom,
MaxSize: NSAnswerDefaultSize,
}
}
func FindAllNSAnswerModes() []*shared.Definition {
return []*shared.Definition{
{
Name: "随机",
Code: NSAnswerModeRandom,
Description: "有多个查询结果时,随机选取若干结果返回。",
},
{
Name: "轮询",
Code: NSAnswerModeRoundRobin,
Description: "有多个查询结果时,按顺序每次返回其中一个结果;在此模式下,记录权重将不会生效。",
},
}
}
func IsValidNSAnswerMode(mode string) bool {
for _, m := range FindAllNSAnswerModes() {
if m.Code == mode {
return true
}
}
return false
}

View File

@@ -0,0 +1,38 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
import "github.com/iwind/TeaGo/maps"
// 一组系统默认值
// 修改单个IP相关限制值时要考虑到NAT中每个IP会代表很多个主机并非1对1的关系
const (
DefaultMaxThreads = 20000 // 单节点最大线程数
DefaultMaxThreadsMin = 1000 // 单节点最大线程数最小值
DefaultMaxThreadsMax = 100_000 // 单节点最大线程数最大值
DefaultTCPMaxConnections = 100_000 // 单节点TCP最大连接数
DefaultTCPMaxConnectionsPerIP = 1000 // 单IP最大连接数
DefaultTCPMinConnectionsPerIP = 5 // 单IP最小连接数
DefaultTCPNewConnectionsMinutelyRate = 500 // 单IP连接速率限制按分钟
DefaultTCPNewConnectionsMinMinutelyRate = 3 // 单IP最小连接速率
DefaultTCPNewConnectionsSecondlyRate = 300 // 单IP连接速率限制按秒
DefaultTCPNewConnectionsMinSecondlyRate = 3 // 单IP最小连接速率
DefaultTCPLinger = 5 // 单节点TCP Linger值
DefaultTLSHandshakeTimeout = 3 // TLS握手超时时间
)
var DefaultConfigs = maps.Map{
"tcpMaxConnections": DefaultTCPMaxConnections,
"tcpMaxConnectionsPerIP": DefaultTCPMaxConnectionsPerIP,
"tcpMinConnectionsPerIP": DefaultTCPMinConnectionsPerIP,
"tcpNewConnectionsMinutelyRate": DefaultTCPNewConnectionsMinutelyRate,
"tcpNewConnectionsMinMinutelyRate": DefaultTCPNewConnectionsMinMinutelyRate,
"tcpNewConnectionsSecondlyRate": DefaultTCPNewConnectionsSecondlyRate,
"tcpNewConnectionsMinSecondlyRate": DefaultTCPNewConnectionsMinSecondlyRate,
}

View File

@@ -0,0 +1,41 @@
// Copyright 2023 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package dnsconfigs
import (
"context"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
)
// NSDoHConfig DoH设置
type NSDoHConfig struct {
IsOn bool `yaml:"isOn" json:"isOn"` // 是否开启
Listen []*serverconfigs.NetworkAddressConfig `yaml:"listen" json:"listen"` // 绑定的网络地址
SSLPolicyRef *sslconfigs.SSLPolicyRef `yaml:"sslPolicyRef" json:"sslPolicyRef"`
SSLPolicy *sslconfigs.SSLPolicy `yaml:"sslPolicy" json:"sslPolicy"`
}
func NewNSDoHConfig() *NSDoHConfig {
return &NSDoHConfig{}
}
func (this *NSDoHConfig) Init() error {
for _, listen := range this.Listen {
err := listen.Init()
if err != nil {
return err
}
}
if this.SSLPolicy != nil {
err := this.SSLPolicy.Init(context.TODO())
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,55 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package dnsconfigs
import "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
// NSDomainStatus 域名状态
type NSDomainStatus = string
const (
NSDomainStatusNone NSDomainStatus = "none" // 初始状态
NSDomainStatusVerified NSDomainStatus = "verified" // 已验证
NSDomainStatusRejected NSDomainStatus = "rejected" // 已驳回(可以重新提交)
NSDomainStatusForbidden NSDomainStatus = "forbidden" // 已禁止(禁止继续使用此域名)
)
func FindAllNSDomainStatusList() []*shared.Definition {
return []*shared.Definition{
{
Name: "未验证",
Code: NSDomainStatusNone,
},
{
Name: "已验证",
Code: NSDomainStatusVerified,
},
{
Name: "已驳回",
Code: NSDomainStatusRejected,
},
{
Name: "已禁止",
Code: NSDomainStatusForbidden,
},
}
}
func NSDomainStatusIsValid(status string) bool {
for _, def := range FindAllNSDomainStatusList() {
if def.Code == status {
return true
}
}
return false
}
func NSDomainStatusName(status string) string {
for _, def := range FindAllNSDomainStatusList() {
if def.Code == status {
return def.Name
}
}
return ""
}

View File

@@ -0,0 +1,70 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
type KeyAlgorithmType = string
const (
KeyAlgorithmTypeHmacSHA1 KeyAlgorithmType = "hmac-sha1."
KeyAlgorithmTypeHmacSHA224 KeyAlgorithmType = "hmac-sha224."
KeyAlgorithmTypeHmacSHA256 KeyAlgorithmType = "hmac-sha256."
KeyAlgorithmTypeHmacSHA384 KeyAlgorithmType = "hmac-sha384."
KeyAlgorithmTypeHmacSHA512 KeyAlgorithmType = "hmac-sha512."
)
type KeyAlgorithmDefinition struct {
Name string `json:"name"`
Code string `json:"code"`
}
func FindAllKeyAlgorithmTypes() []*KeyAlgorithmDefinition {
return []*KeyAlgorithmDefinition{
{
Name: "HmacSHA1",
Code: KeyAlgorithmTypeHmacSHA1,
},
{
Name: "HmacSHA224",
Code: KeyAlgorithmTypeHmacSHA224,
},
{
Name: "HmacSHA256",
Code: KeyAlgorithmTypeHmacSHA256,
},
{
Name: "HmacSHA384",
Code: KeyAlgorithmTypeHmacSHA384,
},
{
Name: "HmacSHA512",
Code: KeyAlgorithmTypeHmacSHA512,
},
}
}
func FindKeyAlgorithmTypeName(algoType KeyAlgorithmType) string {
for _, def := range FindAllKeyAlgorithmTypes() {
if def.Code == algoType {
return def.Name
}
}
return ""
}
type NSKeySecretType = string
const (
NSKeySecretTypeClear NSKeySecretType = "clear"
NSKeySecretTypeBase64 NSKeySecretType = "base64"
)
func FindKeySecretTypeName(secretType NSKeySecretType) string {
switch secretType {
case NSKeySecretTypeClear:
return "明文"
case NSKeySecretTypeBase64:
return "BASE64"
}
return ""
}

View File

@@ -0,0 +1,116 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
import (
"context"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/ddosconfigs"
)
type NSNodeConfig struct {
Id int64 `yaml:"id" json:"id"`
IsPlus bool `yaml:"isPlus" json:"isPlus"`
NodeId string `yaml:"nodeId" json:"nodeId"`
Secret string `yaml:"secret" json:"secret"`
ClusterId int64 `yaml:"clusterId" json:"clusterId"`
AccessLogRef *NSAccessLogRef `yaml:"accessLogRef" json:"accessLogRef"`
RecursionConfig *NSRecursionConfig `yaml:"recursionConfig" json:"recursionConfig"`
DDoSProtection *ddosconfigs.ProtectionConfig `yaml:"ddosProtection" json:"ddosProtection"`
AllowedIPs []string `yaml:"allowedIPs" json:"allowedIPs"`
TimeZone string `yaml:"timeZone" json:"timeZone"` // 自动设置时区
Hosts []string `yaml:"hosts" json:"hosts"` // 主机名
Email string `yaml:"email" json:"email"`
SOA *NSSOAConfig `yaml:"soa" json:"soa"` // SOA配置
SOASerial uint32 `yaml:"soaSerial" json:"soaSerial"`
DetectAgents bool `yaml:"detectAgents" json:"detectAgents"` // 是否实时监测Agents
TCP *serverconfigs.TCPProtocolConfig `yaml:"tcp" json:"tcp"` // TCP配置
TLS *serverconfigs.TLSProtocolConfig `yaml:"tls" json:"tls"` // TLS配置
UDP *serverconfigs.UDPProtocolConfig `yaml:"udp" json:"udp"` // UDP配置
DoH *NSDoHConfig `yaml:"doh" json:"doh"` // DoH配置
Answer *NSAnswerConfig `yaml:"answer" json:"answer"` // 应答查询
APINodeAddrs []*serverconfigs.NetworkAddressConfig `yaml:"apiNodeAddrs" json:"apiNodeAddrs"`
paddedId string
}
func (this *NSNodeConfig) Init(ctx context.Context) error {
this.paddedId = fmt.Sprintf("%08d", this.Id)
// accessLog
if this.AccessLogRef != nil {
err := this.AccessLogRef.Init()
if err != nil {
return err
}
}
// 递归DNS
if this.RecursionConfig != nil {
err := this.RecursionConfig.Init()
if err != nil {
return err
}
}
// DDoS
if this.DDoSProtection != nil {
err := this.DDoSProtection.Init()
if err != nil {
return err
}
}
// tcp
if this.TCP != nil {
err := this.TCP.Init()
if err != nil {
return err
}
}
// tls
if this.TLS != nil {
err := this.TLS.Init(ctx)
if err != nil {
return err
}
}
// DoH
if this.DoH != nil {
err := this.DoH.Init()
if err != nil {
return err
}
}
// udp
if this.UDP != nil {
err := this.UDP.Init()
if err != nil {
return err
}
}
// api node addrs
if len(this.APINodeAddrs) > 0 {
for _, addr := range this.APINodeAddrs {
err := addr.Init()
if err != nil {
return err
}
}
}
return nil
}
func (this *NSNodeConfig) PaddedId() string {
return this.paddedId
}

View File

@@ -0,0 +1,33 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package dnsconfigs
type NSPlanConfig struct {
SupportCountryRoutes bool `json:"supportCountryRoutes"` // 支持全球国家/地区线路
SupportChinaProvinceRoutes bool `json:"supportChinaProvinceRoutes"` // 支持国内省份线路
SupportISPRoutes bool `json:"supportISPRoutes"` // 支持ISP运营商线路
SupportAgentRoutes bool `json:"supportAgentRoutes"` // 支持Agent线路
SupportPublicRoutes bool `json:"supportPublicRoutes"` // 支持系统管理员创建的公用线路
MaxCustomRoutes int32 `json:"maxCustomRoutes"` // 自定义的线路数量
MinTTL int32 `json:"minTTL"` // 最小TTL
MaxDomains int32 `json:"maxDomains"` // 域名数量
MaxRecordsPerDomain int32 `json:"maxRecordsPerDomain"` // 单域名记录数量
MaxLoadBalanceRecordsPerRecord int32 `json:"maxLoadBalanceRecordsPerRecord"` // 单记录负载均衡条数
SupportRecordStats bool `json:"supportRecordStats"` // 支持记录统计
SupportDomainAlias bool `json:"supportDomainAlias"` // 支持域名别名 TODO
SupportHealthCheck bool `json:"supportHealthCheck"` // 支持健康检查
SupportAPI bool `json:"supportAPI"` // 是否支持API操作 TODO
}
func DefaultNSPlanConfig() *NSPlanConfig {
return &NSPlanConfig{
SupportPublicRoutes: true,
SupportAgentRoutes: true,
}
}
func (this *NSPlanConfig) Init() error {
return nil
}

View File

@@ -0,0 +1,26 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnsconfigs
// NSRecordHealthCheckConfig 单个记录健康检查配置
type NSRecordHealthCheckConfig struct {
IsOn bool `json:"isOn"` // 是否启用
Port int32 `json:"port"` // 端口
TimeoutSeconds int `json:"timeoutSeconds"` // 超时秒数
CountUp int `json:"countUp"` // 连续上线次数
CountDown int `json:"countDown"` // 连续下线次数
}
func NewNSRecordHealthCheckConfig() *NSRecordHealthCheckConfig {
return &NSRecordHealthCheckConfig{
IsOn: false,
Port: 0,
TimeoutSeconds: 0,
CountUp: 0,
CountDown: 0,
}
}
func (this *NSRecordHealthCheckConfig) Init() error {
return nil
}

View File

@@ -0,0 +1,26 @@
// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package dnsconfigs
// NSRecordsHealthCheckConfig 记录健康检查整体配置
type NSRecordsHealthCheckConfig struct {
IsOn bool `json:"isOn"` // 是否启用
Port int32 `json:"port"` // 默认端口
TimeoutSeconds int `json:"timeoutSeconds"` // 默认超时秒数
CountUp int `json:"countUp"` // 默认连续上线次数
CountDown int `json:"countDown"` // 默认连续下线次数
}
func NewNSRecordsHealthCheckConfig() *NSRecordsHealthCheckConfig {
return &NSRecordsHealthCheckConfig{
IsOn: false,
Port: 80,
TimeoutSeconds: 5,
CountUp: 1,
CountDown: 3,
}
}
func (this *NSRecordsHealthCheckConfig) Init() error {
return nil
}

View File

@@ -0,0 +1,17 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
// NSRecursionConfig 递归DNS设置
type NSRecursionConfig struct {
IsOn bool `json:"isOn"`
Hosts []*DNSResolver `json:"hosts"`
UseLocalHosts bool `json:"useLocalHosts"` // 自动从本机读取DNS
AllowDomains []string `json:"allowDomains"`
DenyDomains []string `json:"denyDomains"`
}
func (this *NSRecursionConfig) Init() error {
return nil
}

View File

@@ -0,0 +1,282 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
import (
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/iputils"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/shared"
"github.com/iwind/TeaGo/maps"
"net"
)
type NSRouteRangeType = string
const (
NSRouteRangeTypeIP NSRouteRangeType = "ipRange" // IP范围
NSRouteRangeTypeCIDR NSRouteRangeType = "cidr" // CIDR
NSRouteRangeTypeRegion NSRouteRangeType = "region" // 区域
)
func AllNSRouteRangeTypes() []*shared.Definition {
return []*shared.Definition{
{
Name: "IP范围",
Code: NSRouteRangeTypeIP,
},
{
Name: "CIDR",
Code: NSRouteRangeTypeCIDR,
},
{
Name: "区域",
Code: NSRouteRangeTypeRegion,
},
}
}
// NSRouteRegionResolver 解析IP接口
type NSRouteRegionResolver interface {
Resolve(ip net.IP) (countryId int64, provinceId int64, cityId int64, providerId int64)
}
// NSRouteRangeInterface 线路范围接口
type NSRouteRangeInterface interface {
// Init 初始化
Init() error
// Contains 判断是否包含
Contains(ip net.IP) bool
// SetRegionResolver 设置IP解析接口
SetRegionResolver(resolver NSRouteRegionResolver)
// IsExcluding 是否为排除
IsExcluding() bool
}
type NSBaseRouteRange struct {
IsReverse bool `json:"isReverse"`
routeRegionResolver NSRouteRegionResolver
}
func (this *NSBaseRouteRange) SetRegionResolver(resolver NSRouteRegionResolver) {
this.routeRegionResolver = resolver
}
func (this *NSBaseRouteRange) IsExcluding() bool {
return this.IsReverse
}
// NSRouteRangeIPRange IP范围配置
// IPv4和IPv6不能混用
type NSRouteRangeIPRange struct {
NSBaseRouteRange
IPFrom string `json:"ipFrom"`
IPTo string `json:"ipTo"`
ipFrom iputils.IP
ipTo iputils.IP
ipVersion int // 4|6
}
func (this *NSRouteRangeIPRange) 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.ipFrom = iputils.NewIP(ipFrom)
this.ipTo = iputils.NewIP(ipTo)
if this.ipFrom.Compare(this.ipTo) > 0 {
this.ipFrom, this.ipTo = this.ipTo, this.ipFrom
}
return nil
}
func (this *NSRouteRangeIPRange) Contains(netIP net.IP) bool {
if len(netIP) == 0 {
return false
}
var version = configutils.IPVersion(netIP)
if version != this.ipVersion {
return false
}
return iputils.NewIP(netIP).Between(this.ipFrom, this.ipTo)
}
// NSRouteRangeCIDR CIDR范围配置
type NSRouteRangeCIDR struct {
NSBaseRouteRange
CIDR string `json:"cidr"`
cidr *net.IPNet
}
func (this *NSRouteRangeCIDR) Init() error {
_, ipNet, err := net.ParseCIDR(this.CIDR)
if err != nil {
return fmt.Errorf("parse cidr failed: %w", err)
}
this.cidr = ipNet
return nil
}
func (this *NSRouteRangeCIDR) Contains(netIP net.IP) bool {
if netIP == nil {
return false
}
if this.cidr == nil {
return false
}
return this.cidr.Contains(netIP)
}
// NSRouteRangeRegion 区域范围
// country:ID, province:ID, city:ID, isp:ID
type NSRouteRangeRegion struct {
NSBaseRouteRange
Regions []*RouteRegion `json:"regions"`
Connector string `json:"connector"` // AND | OR
}
func (this *NSRouteRangeRegion) Init() error {
return nil
}
func (this *NSRouteRangeRegion) 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
}
var matchAll = this.Connector == "AND"
for _, region := range this.Regions {
if region.Id <= 0 {
continue
}
switch region.Type {
case "country":
if region.Id == countryId {
if !matchAll {
return true
}
} else if matchAll {
return false
}
case "province":
if region.Id == provinceId {
if !matchAll {
return true
}
} else if matchAll {
return false
}
case "city":
if region.Id == cityId {
if !matchAll {
return true
}
} else if matchAll {
return false
}
case "provider":
if region.Id == providerId {
if !matchAll {
return true
}
} else if matchAll {
return false
}
}
}
return matchAll
}
type RouteRegion struct {
Type string `json:"type"` // country|province|city|isp
Id int64 `json:"id"`
Name string `json:"name"`
}
// InitNSRangesFromJSON 从JSON中初始化线路范围
func InitNSRangesFromJSON(rangesJSON []byte) (ranges []NSRouteRangeInterface, 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 NSRouteRangeInterface
switch rangeType {
case NSRouteRangeTypeIP:
r = &NSRouteRangeIPRange{}
case NSRouteRangeTypeCIDR:
r = &NSRouteRangeCIDR{}
case NSRouteRangeTypeRegion:
r = &NSRouteRangeRegion{}
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
}

View File

@@ -0,0 +1,135 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package dnsconfigs_test
import (
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/iwind/TeaGo/assert"
"net"
"testing"
)
func TestNSRouteRangeIPRange_Contains(t *testing.T) {
var a = assert.NewAssertion(t)
// ipv4
{
var r = &dnsconfigs.NSRouteRangeIPRange{
IPFrom: "192.168.1.100",
IPTo: "192.168.3.200",
}
err := r.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(r.Contains(net.ParseIP("aaa")))
a.IsTrue(r.Contains(net.ParseIP("192.168.1.200")))
a.IsTrue(r.Contains(net.ParseIP("192.168.3.200")))
a.IsFalse(r.Contains(net.ParseIP("192.168.4.1")))
a.IsFalse(r.Contains(net.ParseIP("::1")))
}
// ipv6
{
var prefix = "1:2:3:4:5:6"
var r = &dnsconfigs.NSRouteRangeIPRange{
IPFrom: prefix + ":1:8",
IPTo: prefix + ":5:10",
}
err := r.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(r.Contains(net.ParseIP("aaa")))
a.IsTrue(r.Contains(net.ParseIP(prefix + ":3:4")))
a.IsTrue(r.Contains(net.ParseIP(prefix + ":5:9")))
a.IsTrue(r.Contains(net.ParseIP(prefix + ":5:10")))
a.IsTrue(r.Contains(net.ParseIP(prefix + ":4:8")))
a.IsFalse(r.Contains(net.ParseIP(prefix + ":5:11")))
}
{
var r = &dnsconfigs.NSRouteRangeCIDR{
CIDR: "192.168.2.1/24",
}
err := r.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(r.Contains(net.ParseIP("aaa")))
a.IsTrue(r.Contains(net.ParseIP("192.168.2.1")))
a.IsTrue(r.Contains(net.ParseIP("192.168.2.254")))
a.IsTrue(r.Contains(net.ParseIP("192.168.2.100")))
a.IsFalse(r.Contains(net.ParseIP("192.168.3.1")))
a.IsFalse(r.Contains(net.ParseIP("192.168.1.1")))
}
// reverse ipv4
{
var r = &dnsconfigs.NSRouteRangeIPRange{
IPFrom: "192.168.1.100",
IPTo: "192.168.3.200",
}
err := r.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(r.Contains(net.ParseIP("aaa")))
a.IsTrue(r.Contains(net.ParseIP("192.168.1.200")))
a.IsTrue(r.Contains(net.ParseIP("192.168.3.200")))
a.IsFalse(r.Contains(net.ParseIP("192.168.4.1")))
}
// reverse cidr
{
var r = &dnsconfigs.NSRouteRangeCIDR{
CIDR: "192.168.2.1/24",
}
err := r.Init()
if err != nil {
t.Fatal(err)
}
a.IsFalse(r.Contains(net.ParseIP("aaa")))
a.IsTrue(r.Contains(net.ParseIP("192.168.2.1")))
a.IsTrue(r.Contains(net.ParseIP("192.168.2.254")))
a.IsTrue(r.Contains(net.ParseIP("192.168.2.100")))
a.IsFalse(r.Contains(net.ParseIP("192.168.3.1")))
a.IsFalse(r.Contains(net.ParseIP("192.168.1.1")))
}
}
type testNSIPResolver struct {
}
func (this *testNSIPResolver) Resolve(ip net.IP) (countryId int64, provinceId int64, cityId int64, providerId int64) {
return 1, 2, 3, 4
}
func TestNSRouteRangeRegion_Contains(t *testing.T) {
{
var r = &dnsconfigs.NSRouteRangeRegion{
Regions: nil,
Connector: "",
}
r.Regions = append(r.Regions, &dnsconfigs.RouteRegion{
Type: "country",
Id: 1,
Name: "1",
})
r.Regions = append(r.Regions, &dnsconfigs.RouteRegion{
Type: "province",
Id: 2,
Name: "2",
})
r.SetRegionResolver(&testNSIPResolver{})
err := r.Init()
if err != nil {
t.Fatal(err)
}
t.Log(r.Contains(net.ParseIP("1.1.1.1")))
r.Connector = "AND"
t.Log(r.Contains(net.ParseIP("1.1.1.1")))
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,87 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
import (
"strings"
"testing"
)
func TestRoutes(t *testing.T) {
// 检查代号是否有空,或者代号是否重复
var codeMap = map[string]bool{} // code => true
for _, routes := range [][]*Route{
AllDefaultChinaProvinceRoutes,
AllDefaultISPRoutes,
AllDefaultWorldRegionRoutes,
} {
for _, route := range routes {
if len(route.Name) == 0 {
t.Fatal("route name should not empty:", route)
}
if len(route.AliasNames) == 0 {
t.Fatal("route alias names should not empty:", route)
}
if len(route.Code) == 0 || route.Code == "world:" {
t.Fatal("route code should not empty:", route)
}
_, ok := codeMap[route.Code]
if ok {
t.Fatal("code duplicated:", route)
}
codeMap[route.Code] = true
if strings.HasPrefix(route.Code, "world:sp:") || (strings.HasPrefix(route.Code, "world:") && route.Code != "world:UAR" && len(route.Code) != 8) {
t.Log("no shorten code:", route)
}
}
}
}
func TestFindDefaultRoute(t *testing.T) {
t.Log(FindDefaultRoute("isp:china_unicom"))
t.Log(FindDefaultRoute("china:province:beijing"))
t.Log(FindDefaultRoute("world:CN"))
t.Log(FindDefaultRoute("world:US"))
}
func TestRoutes_Markdown(t *testing.T) {
var markdown = ""
for index, routes := range [][]*Route{
AllDefaultRoutes,
AllDefaultChinaProvinceRoutes,
AllDefaultISPRoutes,
AllDefaultWorldRegionRoutes,
} {
switch index {
case 0:
markdown += "## 默认线路\n"
case 1:
markdown += "## 中国省市\n"
case 2:
markdown += "## 运营商\n"
case 3:
markdown += "## 全球地区\n"
}
markdown += "| 名称 | 代号 |\n"
markdown += "|-----------|-----------|\n"
for _, route := range routes {
markdown += "| " + route.Name + " | " + route.Code + " |\n"
}
markdown += "\n"
}
t.Log(markdown)
}
func BenchmarkFindDefaultRoute(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = FindDefaultRoute("world:CN")
}
}

View File

@@ -0,0 +1,56 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package dnsconfigs
import (
"bytes"
"encoding/json"
)
func DefaultNSSOAConfig() *NSSOAConfig {
return &NSSOAConfig{
Hosts: nil, // TODO 暂时不实现
MName: "",
RName: "", // email address, john.doe@example.com => john\.doe.example.com
Serial: 0,
RefreshSeconds: 7200,
RetrySeconds: 3600,
ExpireSeconds: 1209600, // 14 days
MinimumTTL: 3600,
}
}
// NSSOAConfig 参考https://en.wikipedia.org/wiki/SOA_record
type NSSOAConfig struct {
Hosts []string `yaml:"hosts" json:"hosts"`
MName string `yaml:"mName" json:"mName"`
RName string `yaml:"rName" json:"rName"`
Serial uint32 `yaml:"serial" json:"serial"`
RefreshSeconds uint32 `yaml:"refreshSeconds" json:"refreshSeconds"`
RetrySeconds uint32 `yaml:"retrySeconds" json:"retrySeconds"`
ExpireSeconds uint32 `yaml:"expireSeconds" json:"expireSeconds"`
MinimumTTL uint32 `yaml:"minimumTTL" json:"minimumTTL"`
}
func (this *NSSOAConfig) Init() error {
return nil
}
func (this *NSSOAConfig) IsSame(config2 *NSSOAConfig) bool {
if config2 == nil {
return false
}
hostsJSON, _ := json.Marshal(this.Hosts)
host2JSON, _ := json.Marshal(config2.Hosts)
return ((len(this.Hosts) == 0 && len(config2.Hosts) == 0) || bytes.Equal(hostsJSON, host2JSON)) &&
this.MName == config2.MName &&
this.RName == config2.RName &&
this.RefreshSeconds == config2.RefreshSeconds &&
this.RetrySeconds == config2.RetrySeconds &&
this.ExpireSeconds == config2.ExpireSeconds &&
this.MinimumTTL == config2.MinimumTTL
}

View File

@@ -0,0 +1,9 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package dnsconfigs
// NSTSIGConfig 配置
type NSTSIGConfig struct {
IsOn bool `yaml:"isOn" json:"isOn"`
}

View File

@@ -0,0 +1,49 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package dnsconfigs
// NSDomainValidationConfig 域名校验设置
type NSDomainValidationConfig struct {
IsOn bool `yaml:"isOn" json:"isOn"` // 是否启用
Resolvers []*DNSResolver `yaml:"resolvers" json:"resolvers"` // 域名解析地址
}
func NewNSDomainValidationConfig() *NSDomainValidationConfig {
return &NSDomainValidationConfig{
IsOn: true,
Resolvers: []*DNSResolver{},
}
}
func NewNSUserConfig() *NSUserConfig {
return &NSUserConfig{
DefaultClusterId: 0,
DefaultPlanConfig: DefaultNSUserPlanConfig(),
DomainValidation: NewNSDomainValidationConfig(),
}
}
func DefaultNSUserPlanConfig() *NSPlanConfig {
return &NSPlanConfig{
SupportCountryRoutes: true,
SupportChinaProvinceRoutes: true,
SupportISPRoutes: true,
SupportAgentRoutes: true,
SupportPublicRoutes: true,
MaxCustomRoutes: 0,
MaxLoadBalanceRecordsPerRecord: 100,
MinTTL: 60,
MaxDomains: 100,
MaxRecordsPerDomain: 1000,
SupportRecordStats: true,
SupportDomainAlias: false,
SupportAPI: false,
}
}
type NSUserConfig struct {
DefaultClusterId int64 `json:"defaultClusterId"` // 默认部署到的集群
DefaultPlanConfig *NSPlanConfig `json:"defaultPlanConfig"` // 默认套餐设置
DomainValidation *NSDomainValidationConfig `json:"domainValidation"` // 域名验证设置
}

View File

@@ -0,0 +1,83 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package dnsconfigs
type RecordType = string
const (
RecordTypeA RecordType = "A"
RecordTypeCNAME RecordType = "CNAME"
RecordTypeAAAA RecordType = "AAAA"
RecordTypeNS RecordType = "NS"
RecordTypeMX RecordType = "MX"
RecordTypeSRV RecordType = "SRV"
RecordTypeTXT RecordType = "TXT"
RecordTypeCAA RecordType = "CAA"
RecordTypeSOA RecordType = "SOA"
)
type RecordTypeDefinition struct {
Type RecordType `json:"type"`
Description string `json:"description"`
CanDefine bool `json:"canDefine"` // 用户是否可以自定义
}
func FindAllRecordTypeDefinitions() []*RecordTypeDefinition {
return []*RecordTypeDefinition{
{
Type: RecordTypeA,
Description: "将域名指向一个IPV4地址",
CanDefine: true,
},
{
Type: RecordTypeCNAME,
Description: "将域名指向另外一个域名",
CanDefine: true,
},
{
Type: RecordTypeAAAA,
Description: "将域名指向一个IPV6地址",
CanDefine: true,
},
{
Type: RecordTypeNS,
Description: "将子域名指定其他DNS服务器解析",
CanDefine: false,
},
{
Type: RecordTypeSOA,
Description: "起始授权机构记录",
CanDefine: false,
},
{
Type: RecordTypeMX,
Description: "将域名指向邮件服务器地址",
CanDefine: true,
},
{
Type: RecordTypeSRV,
Description: "记录提供特定的服务的服务器",
CanDefine: true,
},
{
Type: RecordTypeTXT,
Description: "文本长度限制512通常做SPF记录或者校验域名所有者",
CanDefine: true,
},
{
Type: RecordTypeCAA,
Description: "CA证书颁发机构授权校验",
CanDefine: true,
},
}
}
func FindAllUserRecordTypeDefinitions() []*RecordTypeDefinition {
var result = []*RecordTypeDefinition{}
for _, r := range FindAllRecordTypeDefinitions() {
if r.CanDefine {
result = append(result, r)
}
}
return result
}