Files
linkmaster-node/internal/handler/dns.go
2025-11-21 19:17:38 +08:00

147 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handler
import (
"encoding/base64"
"fmt"
"net"
"os/exec"
"strings"
"time"
"github.com/gin-gonic/gin"
)
func handleDns(c *gin.Context, url string, params map[string]interface{}) {
// 获取seq参数
seq := ""
if seqVal, ok := params["seq"].(string); ok {
seq = seqVal
}
// 获取dig类型参数
digType := ""
if dt, ok := params["dt"].(string); ok {
digType = dt
}
// 获取DNS服务器参数
dnsServer := ""
if ds, ok := params["ds"].(string); ok {
dnsServer = ds
}
// 解析URL提取hostname
hostname := url
if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
parts := strings.Split(url, "//")
if len(parts) > 1 {
hostParts := strings.Split(parts[1], "/")
hostname = hostParts[0]
if idx := strings.Index(hostname, ":"); idx != -1 {
hostname = hostname[:idx]
}
}
}
// 准备结果
result := map[string]interface{}{
"seq": seq,
"type": "ceDns",
"requrl": hostname,
"ips": []interface{}{},
}
// 构建dig命令
args := []string{hostname}
if digType != "" {
args = append([]string{"-t", digType}, args...)
}
if dnsServer != "" {
args = append([]string{"@" + dnsServer}, args...)
}
cmd := exec.Command("dig", args...)
output, err := cmd.CombinedOutput()
outputStr := string(output)
// 编码完整输出为base64header字段
result["header"] = base64.StdEncoding.EncodeToString([]byte(outputStr))
if err != nil {
result["error"] = err.Error()
c.JSON(200, result)
return
}
// 解析dig输出
lines := strings.Split(outputStr, "\n")
inAnswerSection := false
ipList := make([]map[string]interface{}, 0)
for _, line := range lines {
line = strings.TrimSpace(line)
if strings.Contains(line, "ANSWER SECTION") {
inAnswerSection = true
continue
}
if inAnswerSection {
if line == "" {
break
}
// 解析dig输出行格式如example.com. 300 IN A 192.168.1.1
// 或者www.baidu.com. 1038 IN CNAME www.a.shifen.com.
parts := strings.Fields(line)
if len(parts) >= 5 {
// parts[3] 是 "IN" (record type)parts[4] 是记录类型 (A, AAAA, CNAME等)
recordClass := parts[4] // A, AAAA, CNAME等
recordValue := ""
if len(parts) > 5 {
recordValue = strings.Join(parts[5:], " ")
// 移除CNAME值末尾的点如果有
recordValue = strings.TrimSuffix(recordValue, ".")
}
// 处理A、AAAA和CNAME记录
if recordClass == "A" || recordClass == "AAAA" || recordClass == "CNAME" {
recordItem := map[string]interface{}{
"url": strings.TrimSuffix(parts[0], "."), // 移除域名末尾的点
"type": recordClass,
"ip": recordValue, // CNAME记录中ip字段存储的是CNAME值
}
ipList = append(ipList, recordItem)
}
}
}
}
// 如果没有从dig输出解析到IP尝试使用net.LookupIP
if len(ipList) == 0 {
start := time.Now()
ips, err := net.LookupIP(hostname)
lookupTime := time.Since(start)
if err == nil {
for _, ip := range ips {
ipType := "A"
if ip.To4() == nil {
ipType = "AAAA"
}
ipItem := map[string]interface{}{
"url": hostname,
"type": ipType,
"ip": ip.String(),
}
ipList = append(ipList, ipItem)
}
// 更新header包含lookup时间信息
lookupInfo := fmt.Sprintf("Lookup time: %v\n", lookupTime)
result["header"] = base64.StdEncoding.EncodeToString([]byte(outputStr + lookupInfo))
} else {
result["error"] = err.Error()
}
}
result["ips"] = ipList
c.JSON(200, result)
}