v1.5.1 增强程序稳定性
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
package teaconst
|
||||
|
||||
const (
|
||||
Version = "1.5.0"
|
||||
Version = "1.5.1"
|
||||
|
||||
ProductName = "Edge HTTPDNS"
|
||||
ProcessName = "edge-httpdns"
|
||||
|
||||
@@ -2,6 +2,7 @@ package nodes
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
@@ -46,7 +47,14 @@ func (n *HTTPDNSNode) Run() {
|
||||
return
|
||||
}
|
||||
|
||||
go n.start()
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE]goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
n.start()
|
||||
}()
|
||||
select {}
|
||||
}
|
||||
|
||||
@@ -108,6 +116,12 @@ func (n *HTTPDNSNode) listenSock() error {
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE]sock goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
|
||||
n.sock.OnCommand(func(cmd *gosock.Command) {
|
||||
switch cmd.Code {
|
||||
case "pid":
|
||||
@@ -152,12 +166,47 @@ func (n *HTTPDNSNode) start() {
|
||||
taskManager := NewTaskManager(n.quitCh, snapshotManager)
|
||||
resolveServer := NewResolveServer(n.quitCh, snapshotManager)
|
||||
|
||||
go snapshotManager.Start()
|
||||
go statusManager.Start()
|
||||
go taskManager.Start()
|
||||
go resolveServer.Start()
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE]snapshot goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
snapshotManager.Start()
|
||||
}()
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE]status goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
statusManager.Start()
|
||||
}()
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE]task goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
taskManager.Start()
|
||||
}()
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE]resolve goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
resolveServer.Start()
|
||||
}()
|
||||
|
||||
go NewUpgradeManager().Loop()
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE]upgrade goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
NewUpgradeManager().Loop()
|
||||
}()
|
||||
}
|
||||
|
||||
func (n *HTTPDNSNode) stop() {
|
||||
|
||||
@@ -166,7 +166,14 @@ func NewResolveServer(quitCh <-chan struct{}, snapshotManager *SnapshotManager)
|
||||
}
|
||||
|
||||
func (s *ResolveServer) Start() {
|
||||
go s.startAccessLogFlusher()
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE][resolve]access log flusher panic: %v", r))
|
||||
}
|
||||
}()
|
||||
s.startAccessLogFlusher()
|
||||
}()
|
||||
|
||||
// 1. Load initial certificate from file (fallback)
|
||||
if len(s.certFile) > 0 && len(s.keyFile) > 0 {
|
||||
@@ -323,6 +330,12 @@ func (s *ResolveServer) startListener(addr string) error {
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println(fmt.Sprintf("[HTTPDNS_NODE][resolve]serve goroutine panic: %v", r))
|
||||
}
|
||||
}()
|
||||
|
||||
if err := srv.Serve(tlsLn); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Println("[HTTPDNS_NODE][resolve]serve failed on", addr, ":", err.Error())
|
||||
}
|
||||
@@ -498,11 +511,18 @@ func (s *ResolveServer) handleResolve(writer http.ResponseWriter, request *http.
|
||||
clientIP := detectClientIP(request, query.Get("cip"))
|
||||
clientProfile := buildClientRouteProfile(clientIP)
|
||||
|
||||
// ECS 只使用可信来源的 IP(cip 参数或直连 RemoteAddr),
|
||||
// 不信任 X-Forwarded-For 等可被客户端伪造的转发头
|
||||
ecsIP := normalizeIPCandidate(query.Get("cip"))
|
||||
if len(ecsIP) == 0 {
|
||||
ecsIP = normalizeIPCandidate(request.RemoteAddr)
|
||||
}
|
||||
|
||||
clusterTTL := pickDefaultTTL(snapshot, loadedApp.App)
|
||||
rule, records, ttl := pickRuleRecords(loadedDomain.Rules, qtype, clientProfile, clusterTTL)
|
||||
if len(records) == 0 {
|
||||
// Fallback:回源上游 DNS 查询真实记录
|
||||
fallbackRecords, fallbackTTL, fallbackErr := fallbackResolve(domain, qtype)
|
||||
fallbackRecords, fallbackTTL, fallbackErr := fallbackResolve(domain, qtype, ecsIP, isMainlandChinaCountry(clientProfile.Country))
|
||||
if fallbackErr != nil || len(fallbackRecords) == 0 {
|
||||
errMsg := "未找到解析记录"
|
||||
if fallbackErr != nil {
|
||||
@@ -929,8 +949,49 @@ func pickRuleRecords(rules []*pb.HTTPDNSCustomRule, qtype string, profile *clien
|
||||
return bestRule, bestRecords, bestTTL
|
||||
}
|
||||
|
||||
// addECSOption 向 DNS 请求中设置 EDNS Client Subnet (ECS)。
|
||||
// 如果请求已携带 ECS 则覆盖(避免双 ECS 导致上游 malformed request)。
|
||||
func addECSOption(m *dns.Msg, clientIP string) {
|
||||
if len(clientIP) == 0 {
|
||||
return
|
||||
}
|
||||
ip := net.ParseIP(clientIP)
|
||||
if ip == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ecs := &dns.EDNS0_SUBNET{
|
||||
Code: dns.EDNS0SUBNET,
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
ecs.Family = 1 // IPv4
|
||||
ecs.SourceNetmask = 24
|
||||
ecs.Address = ip.To4()
|
||||
} else {
|
||||
ecs.Family = 2 // IPv6
|
||||
ecs.SourceNetmask = 56
|
||||
ecs.Address = ip
|
||||
}
|
||||
|
||||
opt := m.IsEdns0()
|
||||
if opt == nil {
|
||||
m.SetEdns0(4096, false)
|
||||
opt = m.IsEdns0()
|
||||
}
|
||||
if opt != nil {
|
||||
// 删除已有的 ECS option,避免出现双 EDNS0_SUBNET
|
||||
var filtered []dns.EDNS0
|
||||
for _, o := range opt.Option {
|
||||
if o.Option() != dns.EDNS0SUBNET {
|
||||
filtered = append(filtered, o)
|
||||
}
|
||||
}
|
||||
opt.Option = append(filtered, ecs)
|
||||
}
|
||||
}
|
||||
|
||||
// fallbackResolve 当无自定义规则命中时,回源上游 DNS 查询真实记录(对齐 EdgeDNS 做法)
|
||||
func fallbackResolve(domain string, qtype string) ([]*resolveRecord, int32, error) {
|
||||
func fallbackResolve(domain string, qtype string, clientIP string, isChina bool) ([]*resolveRecord, int32, error) {
|
||||
var dnsType uint16
|
||||
switch qtype {
|
||||
case "A":
|
||||
@@ -945,16 +1006,18 @@ func fallbackResolve(domain string, qtype string) ([]*resolveRecord, int32, erro
|
||||
m.SetQuestion(dns.Fqdn(domain), dnsType)
|
||||
m.RecursionDesired = true
|
||||
|
||||
// 优先使用本机 /etc/resolv.conf 中的 DNS 服务器(对齐 EdgeDNS)
|
||||
var upstream = "223.5.5.5:53"
|
||||
resolveConfig, confErr := dns.ClientConfigFromFile("/etc/resolv.conf")
|
||||
if confErr == nil && len(resolveConfig.Servers) > 0 {
|
||||
port := resolveConfig.Port
|
||||
if len(port) == 0 {
|
||||
port = "53"
|
||||
}
|
||||
server := resolveConfig.Servers[rands.Int(0, len(resolveConfig.Servers)-1)]
|
||||
upstream = server + ":" + port
|
||||
// 携带客户端真实 IP(ECS)向上游查询,确保 GeoIP 结果准确
|
||||
addECSOption(m, clientIP)
|
||||
|
||||
// 根据客户端 IP 地理位置选择上游 DNS
|
||||
// 中国大陆客户端 → 阿里 DNS(出口在中国,ECS + 出口双重匹配)
|
||||
// 海外客户端 → Google DNS(出口在海外)
|
||||
// 这样递归 DNS 出口和 ECS 子网指向同一区域,CDN 调度更准确
|
||||
var upstream string
|
||||
if isChina {
|
||||
upstream = "223.5.5.5:53"
|
||||
} else {
|
||||
upstream = "8.8.8.8:53"
|
||||
}
|
||||
|
||||
r, _, err := sharedRecursionDNSClient.Exchange(m, upstream)
|
||||
|
||||
@@ -91,6 +91,12 @@ func (this *UpgradeManager) Start() {
|
||||
log.Println("[UPGRADE_MANAGER]upgrade successfully")
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Println("[UPGRADE_MANAGER]goroutine panic:", r)
|
||||
}
|
||||
}()
|
||||
|
||||
err = this.restart()
|
||||
if err != nil {
|
||||
log.Println("[UPGRADE_MANAGER]" + err.Error())
|
||||
|
||||
@@ -14,5 +14,8 @@ func IP2Long(ip string) uint32 {
|
||||
if len(s) == 16 {
|
||||
return binary.BigEndian.Uint32(s[12:16])
|
||||
}
|
||||
if len(s) < 4 {
|
||||
return 0
|
||||
}
|
||||
return binary.BigEndian.Uint32(s)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user