自建DNS增加解析测试

This commit is contained in:
刘祥超
2021-08-09 18:42:00 +08:00
parent 69c1d35406
commit 4d092f329b
13 changed files with 404 additions and 1 deletions

1
go.mod
View File

@@ -20,6 +20,5 @@ require (
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22 golang.org/x/sys v0.0.0-20210616094352-59db8d763f22
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
google.golang.org/grpc v1.38.0 google.golang.org/grpc v1.38.0
google.golang.org/protobuf v1.26.0
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776
) )

2
go.sum
View File

@@ -141,6 +141,7 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -164,6 +165,7 @@ golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

View File

@@ -404,6 +404,10 @@ func (this *RPCClient) NSRPC() pb.NSServiceClient {
return pb.NewNSServiceClient(this.pickConn()) return pb.NewNSServiceClient(this.pickConn())
} }
func (this *RPCClient) NSQuestionOptionRPC() pb.NSQuestionOptionServiceClient {
return pb.NewNSQuestionOptionServiceClient(this.pickConn())
}
func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient { func (this *RPCClient) MetricItemRPC() pb.MetricItemServiceClient {
return pb.NewMetricItemServiceClient(this.pickConn()) return pb.NewMetricItemServiceClient(this.pickConn())
} }

View File

@@ -0,0 +1,156 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/dns/domains/domainutils"
"github.com/TeaOSLab/EdgeCommon/pkg/dnsconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
"github.com/miekg/dns"
"net"
"regexp"
)
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("", "", "")
}
func (this *IndexAction) RunGet(params struct{}) {
// 集群列表
clustersResp, err := this.RPC().NSClusterRPC().FindAllEnabledNSClusters(this.AdminContext(), &pb.FindAllEnabledNSClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
var clusterMaps = []maps.Map{}
for _, cluster := range clustersResp.NsClusters {
if !cluster.IsOn {
continue
}
countNodesResp, err := this.RPC().NSNodeRPC().CountAllEnabledNSNodesMatch(this.AdminContext(), &pb.CountAllEnabledNSNodesMatchRequest{
NsClusterId: cluster.Id,
InstallState: 0,
ActiveState: 0,
Keyword: "",
})
if err != nil {
this.ErrorPage(err)
return
}
var countNodes = countNodesResp.Count
if countNodes <= 0 {
continue
}
clusterMaps = append(clusterMaps, maps.Map{
"id": cluster.Id,
"name": cluster.Name,
"countNodes": countNodes,
})
}
this.Data["clusters"] = clusterMaps
// 记录类型
this.Data["recordTypes"] = dnsconfigs.FindAllRecordTypeDefinitions()
this.Show()
}
func (this *IndexAction) RunPost(params struct {
NodeId int64
Domain string
Type string
Ip string
ClientIP string
Must *actions.Must
}) {
nodeResp, err := this.RPC().NSNodeRPC().FindEnabledNSNode(this.AdminContext(), &pb.FindEnabledNSNodeRequest{NsNodeId: params.NodeId})
if err != nil {
this.ErrorPage(err)
return
}
var node = nodeResp.NsNode
if node == nil {
this.Fail("找不到要测试的节点")
}
var isOk = false
var errMsg string
var isNetError = false
var result string
defer func() {
this.Data["isOk"] = isOk
this.Data["err"] = errMsg
this.Data["isNetErr"] = isNetError
this.Data["result"] = result
this.Success()
}()
if !domainutils.ValidateDomainFormat(params.Domain) {
errMsg = "域名格式错误"
return
}
recordType, ok := dns.StringToType[params.Type]
if !ok {
errMsg = "不支持此记录类型"
return
}
if len(params.ClientIP) > 0 && net.ParseIP(params.ClientIP) == nil {
errMsg = "客户端IP格式不正确"
return
}
var optionId int64
if len(params.ClientIP) > 0 {
optionResp, err := this.RPC().NSQuestionOptionRPC().CreateNSQuestionOption(this.AdminContext(), &pb.CreateNSQuestionOptionRequest{
Name: "setRemoteAddr",
ValuesJSON: maps.Map{"ip": params.ClientIP}.AsJSON(),
})
if err != nil {
this.ErrorPage(err)
return
}
optionId = optionResp.NsQuestionOptionId
defer func() {
_, err = this.RPC().NSQuestionOptionRPC().DeleteNSQuestionOption(this.AdminContext(), &pb.DeleteNSQuestionOptionRequest{NsQuestionOptionId: optionId})
if err != nil {
this.ErrorPage(err)
}
}()
}
c := new(dns.Client)
m := new(dns.Msg)
var domain = params.Domain + "."
if optionId > 0 {
domain = "$" + types.String(optionId) + "-" + domain
}
m.SetQuestion(domain, recordType)
r, _, err := c.Exchange(m, params.Ip+":53")
if err != nil {
errMsg = "解析过程中出错:" + err.Error()
// 是否为网络错误
if regexp.MustCompile(`timeout|connect`).MatchString(err.Error()) {
isNetError = true
}
return
}
result = r.String()
result = regexp.MustCompile(`\$\d+-`).ReplaceAllString(result, "")
isOk = true
}

View File

@@ -0,0 +1,20 @@
package test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeNS)).
Data("teaMenu", "ns").
Data("teaSubMenu", "test").
Prefix("/ns/test").
GetPost("", new(IndexAction)).
Post("/nodeOptions", new(NodeOptionsAction)).
EndAll()
})
}

View File

@@ -0,0 +1,59 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
package test
import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type NodeOptionsAction struct {
actionutils.ParentAction
}
func (this *NodeOptionsAction) RunPost(params struct {
ClusterId int64
}) {
nodesResp, err := this.RPC().NSNodeRPC().FindAllEnabledNSNodesWithNSClusterId(this.AdminContext(), &pb.FindAllEnabledNSNodesWithNSClusterIdRequest{NsClusterId: params.ClusterId})
if err != nil {
this.ErrorPage(err)
return
}
var nodeMaps = []maps.Map{}
for _, node := range nodesResp.NsNodes {
if !node.IsOn {
continue
}
addressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
NodeId: node.Id,
Role: nodeconfigs.NodeRoleDNS,
})
if err != nil {
this.ErrorPage(err)
return
}
var addresses = addressesResp.Addresses
if len(addresses) == 0 {
continue
}
var addrs = []string{}
for _, addr := range addresses {
if addr.CanAccess {
addrs = append(addrs, addr.Ip)
}
}
nodeMaps = append(nodeMaps, maps.Map{
"id": node.Id,
"name": node.Name,
"addrs": addrs,
})
}
this.Data["nodes"] = nodeMaps
this.Success()
}

View File

@@ -293,6 +293,11 @@ func (this *userMustAuth) modules(adminId int64) []maps.Map {
"url": "/ns/settings", "url": "/ns/settings",
"code": "setting", "code": "setting",
}, },
{
"name": "解析测试",
"url": "/ns/test",
"code": "test",
},
}, },
}, },
{ {

View File

@@ -51,6 +51,7 @@ import (
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/logs" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/clusters/logs"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/routes" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/routes"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/settings/accesslogs" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/settings/accesslogs"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/test"
_ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/users" _ "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/ns/users"
// 服务相关 // 服务相关

View File

@@ -0,0 +1,14 @@
pre.pre-box {
background: #eee;
padding: 1em;
}
.reasons {
margin-top: 0.3em;
}
.reasons ul {
margin: 0;
list-style: none;
padding: 0;
line-height: 1.8;
}
/*# sourceMappingURL=index.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,GAAG;EACF,gBAAA;EACA,YAAA;;AAGD;EACC,iBAAA;;AADD,QAGC;EACC,SAAA;EACA,gBAAA;EACA,UAAA;EACA,gBAAA","file":"index.css"}

View File

@@ -0,0 +1,76 @@
{$layout}
<form class="ui form" data-tea-action="$" data-tea-timeout="30" data-tea-before="before" data-tea-success="success" data-tea-done="done">
<table class="ui table definition selectable">
<tr>
<td>集群 *</td>
<td>
<select class="ui dropdown auto-width" name="clusterId" v-model="clusterId" @change="changeCluster">
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
</select>
<p class="comment">这里只列出有节点的集群。</p>
</td>
</tr>
<tr v-if="clusterId > 0">
<td>节点 *</td>
<td>
<select class="ui dropdown auto-width" name="nodeId" v-model="nodeId" @change="changeNode">
<option v-for="node in nodes" :value="node.id">{{node.name}}</option>
</select>
</td>
</tr>
<tr v-if="selectedNode != null">
<td>节点IP *</td>
<td>
<select class="ui dropdown auto-width" name="ip">
<option v-for="ip in selectedNode.addrs" :value="ip">{{ip}}</option>
</select>
</td>
</tr>
<tr>
<td class="title">域名 *</td>
<td>
<input type="text" name="domain" maxlength="200" ref="focus" placeholder="xxx.com"/>
<p class="comment">要解析的域名。</p>
</td>
</tr>
<tr>
<td>记录类型 *</td>
<td>
<select class="ui dropdown auto-width" name="type">
<option v-for="type in recordTypes" :value="type.type">{{type.type}}</option>
</select>
</td>
</tr>
<tr>
<td>模拟客户端IP</td>
<td>
<input type="text" name="clientIP" style="width: 12em" maxlength="128" placeholder="x.x.x.x"/>
<p class="comment">可选项用来模拟客户端IP。</p>
</td>
</tr>
<tr>
<td>解析结果</td>
<td>
<div v-if="result != null">
<span class="red" v-if="!result.isOk">{{result.err}}</span>
<div class="reasons" v-if="result.isNetErr">
可能的原因有:
<ul>
<li>1. DNS节点没有启动</li>
<li>2. DNS节点53/udp端口没有加入到节点防火墙规则或者其他安全策略中</li>
<li>3. DNS节点IP地址填写错误</li>
<li>4. 其他原因。</li>
</ul>
</div>
<div v-if="result.isOk">
<pre class="pre-box"><span class="green">{{result.result}}</span></pre>
</div>
</div>
</td>
</tr>
</table>
<submit-btn v-if="!isDoing">开始解析</submit-btn>
<button class="ui button disabled" type="button" v-if="isDoing">解析中...</button>
</form>

View File

@@ -0,0 +1,51 @@
Tea.context(function () {
this.clusterId = 0
if (this.clusters.length > 0) {
this.clusterId = this.clusters[0].id
this.$delay(function () {
this.changeCluster()
})
}
this.nodeId = 0
this.nodes = []
this.selectedNode = null
this.isDoing = false
this.result = null
this.before = function () {
this.isDoing = true
this.result = null
}
this.success = function (resp) {
this.result = resp.data
}
this.done = function () {
this.isDoing = false
}
this.changeCluster = function () {
this.nodeId = 0
this.$post(".nodeOptions")
.params({
clusterId: this.clusterId
})
.success(function (resp) {
this.nodes = resp.data.nodes
if (this.nodes.length > 0) {
this.nodeId = this.nodes[0].id
this.changeNode()
}
})
}
this.changeNode = function () {
let that = this
this.selectedNode = this.nodes.$find(function (k, v) {
return v.id == that.nodeId
})
}
})

View File

@@ -0,0 +1,15 @@
pre.pre-box {
background: #eee;
padding: 1em;
}
.reasons {
margin-top: 0.3em;
ul {
margin: 0;
list-style: none;
padding: 0;
line-height: 1.8;
}
}