Compare commits

...

6 Commits

Author SHA1 Message Date
spiritlhl
f1ccde0ea9 feat: 更新todo需求 2025-04-08 14:29:25 +00:00
spiritlhl
4caf507831 fix: 对齐V4和V6的输出 2025-04-08 14:22:56 +00:00
spiritlhl
ddc2f9b401 fix: 减少无效日志输出,对齐V4和V6的输出 2025-04-08 14:18:20 +00:00
spiritlhl
93434aeda1 fix: 修复IPV6包头识别 2025-04-08 14:05:47 +00:00
spiritlhl
341c21f1e5 fix: 进一步添加日志记录 2025-04-08 13:54:11 +00:00
spiritlhl
fcc0403612 fix: 添加ipv6的hop日志记录 2025-04-08 13:37:54 +00:00
6 changed files with 348 additions and 257 deletions

View File

@ -36,7 +36,7 @@ jobs:
echo "Deleting asset with ID: $asset" echo "Deleting asset with ID: $asset"
curl -X DELETE -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/oneclickvirt/backtrace/releases/assets/$asset" curl -X DELETE -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" "https://api.github.com/repos/oneclickvirt/backtrace/releases/assets/$asset"
done done
sleep 60 sleep 30
release-binary: release-binary:
name: Release Go Binary name: Release Go Binary

View File

@ -19,9 +19,11 @@
## TODO ## TODO
- [ ] 增加IPV6路由能力检测
- [ ] 兼容额外的ICMP地址获取若当前目标IP无法查询路由尝试额外的IP地址
- [ ] 重复检测同一段路由,避免结果不可复现
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段) - [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段)
- [ ] 添加对主流ISP的POP点检测区分国际互联能力 - [ ] 添加对主流ISP的POP点检测区分国际互联能力
- [ ] 增加IPV6路由能力检测兼容额外的ICMP地址获取每日更新
## 使用 ## 使用

126
bk/asn.go
View File

@ -1,11 +1,7 @@
package backtrace package backtrace
import ( import (
"fmt"
"net"
"strings" "strings"
. "github.com/oneclickvirt/defaultset"
) )
type Result struct { type Result struct {
@ -72,128 +68,6 @@ func removeDuplicates(elements []string) []string {
return result // 返回去重后的结果切片 return result // 返回去重后的结果切片
} }
// trace IPv4追踪函数
func trace(ch chan Result, i int) {
if EnableLoger {
InitLogger()
defer Logger.Sync()
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", ipv4Names[i], ipv4s[i]))
}
hops, err := Trace(net.ParseIP(ipv4s[i]))
if err != nil {
s := fmt.Sprintf("%v %-15s %v", ipv4Names[i], ipv4s[i], err)
if EnableLoger {
Logger.Error(fmt.Sprintf("追踪 %s (%s) 失败: %v", ipv4Names[i], ipv4s[i], err))
}
ch <- Result{i, s}
return
}
// 记录每个hop的信息
if EnableLoger {
for hopNum, hop := range hops {
for nodeNum, node := range hop.Nodes {
Logger.Info(fmt.Sprintf("追踪 %s (%s) - Hop %d, Node %d: %s (RTT: %v)",
ipv4Names[i], ipv4s[i], hopNum+1, nodeNum+1, node.IP.String(), node.RTT))
}
}
}
var asns []string
for _, h := range hops {
for _, n := range h.Nodes {
asn := ipAsn(n.IP.String())
if asn != "" {
asns = append(asns, asn)
if EnableLoger {
Logger.Info(fmt.Sprintf("IP %s 对应的ASN: %s", n.IP.String(), asn))
}
}
}
}
// 处理CN2不同路线的区别
if asns != nil && len(asns) > 0 {
var tempText string
asns = removeDuplicates(asns)
tempText += fmt.Sprintf("%v ", ipv4Names[i])
hasAS4134 := false
hasAS4809 := false
for _, asn := range asns {
if asn == "AS4134" {
hasAS4134 = true
}
if asn == "AS4809" {
hasAS4809 = true
}
}
// 判断是否包含 AS4134 和 AS4809
if hasAS4134 && hasAS4809 {
// 同时包含 AS4134 和 AS4809 属于 CN2GT
asns = append([]string{"AS4809b"}, asns...)
if EnableLoger {
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GT", ipv4Names[i], ipv4s[i]))
}
} else if hasAS4809 {
// 仅包含 AS4809 属于 CN2GIA
asns = append([]string{"AS4809a"}, asns...)
if EnableLoger {
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GIA", ipv4Names[i], ipv4s[i]))
}
}
tempText += fmt.Sprintf("%-15s ", ipv4s[i])
for _, asn := range asns {
asnDescription := m[asn]
switch asn {
case "":
continue
case "AS4809": // 被 AS4809a 和 AS4809b 替代了
continue
case "AS9929":
if !strings.Contains(tempText, asnDescription) {
tempText += DarkGreen(asnDescription) + " "
}
case "AS4809a":
if !strings.Contains(tempText, asnDescription) {
tempText += DarkGreen(asnDescription) + " "
}
case "AS23764":
if !strings.Contains(tempText, asnDescription) {
tempText += DarkGreen(asnDescription) + " "
}
case "AS4809b":
if !strings.Contains(tempText, asnDescription) {
tempText += Green(asnDescription) + " "
}
case "AS58807":
if !strings.Contains(tempText, asnDescription) {
tempText += Green(asnDescription) + " "
}
default:
if !strings.Contains(tempText, asnDescription) {
tempText += White(asnDescription) + " "
}
}
}
if tempText == (fmt.Sprintf("%v ", ipv4Names[i]) + fmt.Sprintf("%-15s ", ipv4s[i])) {
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
if EnableLoger {
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到已知线路的ASN", ipv4Names[i], ipv4s[i]))
}
}
if EnableLoger {
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,结果: %s", ipv4Names[i], ipv4s[i], tempText))
}
ch <- Result{i, tempText}
} else {
s := fmt.Sprintf("%v %-15s %v", ipv4Names[i], ipv4s[i], Red("检测不到回程路由节点的IP地址"))
if EnableLoger {
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IP地址", ipv4Names[i], ipv4s[i]))
}
ch <- Result{i, s}
}
}
func ipAsn(ip string) string { func ipAsn(ip string) string {
if strings.Contains(ip, ":") { if strings.Contains(ip, ":") {
return ipv6Asn(ip) return ipv6Asn(ip)

View File

@ -3,6 +3,7 @@ package backtrace
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"net" "net"
"sort" "sort"
"strings" "strings"
@ -10,6 +11,7 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
. "github.com/oneclickvirt/defaultset"
"golang.org/x/net/icmp" "golang.org/x/net/icmp"
"golang.org/x/net/ipv4" "golang.org/x/net/ipv4"
"golang.org/x/net/ipv6" "golang.org/x/net/ipv6"
@ -17,11 +19,11 @@ import (
// DefaultConfig is the default configuration for Tracer. // DefaultConfig is the default configuration for Tracer.
var DefaultConfig = Config{ var DefaultConfig = Config{
Delay: 50 * time.Millisecond, Delay: 50 * time.Millisecond,
Timeout: 500 * time.Millisecond, Timeout: 500 * time.Millisecond,
MaxHops: 15, MaxHops: 15,
Count: 1, Count: 1,
Networks: []string{"ip4:icmp", "ip4:ip", "ip6:ipv6-icmp", "ip6:ip"}, Networks: []string{"ip4:icmp", "ip4:ip", "ip6:ipv6-icmp", "ip6:ip"},
} }
// DefaultTracer is a tracer with DefaultConfig. // DefaultTracer is a tracer with DefaultConfig.
@ -116,27 +118,37 @@ func (t *Tracer) NewSession(ip net.IP) (*Session, error) {
} }
func (t *Tracer) init() { func (t *Tracer) init() {
// 初始化IPv4连接 // 初始化IPv4连接
for _, network := range t.Networks { for _, network := range t.Networks {
if strings.HasPrefix(network, "ip4") { if strings.HasPrefix(network, "ip4") {
t.conn, t.err = t.listen(network, t.Addr) t.conn, t.err = t.listen(network, t.Addr)
if t.err == nil { if t.err == nil {
go t.serve(t.conn) go t.serve(t.conn)
break break
} }
} }
} }
// 初始化IPv6连接 // 初始化IPv6连接
for _, network := range t.Networks { for _, network := range t.Networks {
if strings.HasPrefix(network, "ip6") { if strings.HasPrefix(network, "ip6") {
conn, err := net.ListenIP(network, t.Addr) conn, err := net.ListenIP(network, t.Addr)
if err == nil { if err == nil {
t.ipv6conn = ipv6.NewPacketConn(conn) t.ipv6conn = ipv6.NewPacketConn(conn)
go t.serveIPv6(t.ipv6conn) err = t.ipv6conn.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true)
break if err != nil {
} if EnableLoger {
} InitLogger()
} defer Logger.Sync()
Logger.Info("设置IPv6控制消息失败: " + err.Error())
}
t.ipv6conn.Close()
continue
}
go t.serveIPv6(t.ipv6conn)
break
}
}
}
} }
// Close closes listening socket. // Close closes listening socket.
@ -167,84 +179,111 @@ func (t *Tracer) serve(conn *net.IPConn) error {
} }
func (t *Tracer) serveData(from net.IP, b []byte) error { func (t *Tracer) serveData(from net.IP, b []byte) error {
if from.To4() == nil { if from.To4() == nil {
// IPv6 处理 // IPv6处理
msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, b) msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, b)
if err != nil { if err != nil {
return err if EnableLoger {
} Logger.Warn("解析IPv6 ICMP消息失败: " + err.Error())
if msg.Type == ipv6.ICMPTypeEchoReply { }
echo := msg.Body.(*icmp.Echo) return err
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()}) }
} // 记录所有收到的消息类型,帮助调试
b = getReplyData(msg) if EnableLoger {
if len(b) < ipv6.HeaderLen { Logger.Info(fmt.Sprintf("收到IPv6 ICMP消息: 类型=%v, 代码=%v", msg.Type, msg.Code))
return errMessageTooShort }
} // 处理不同类型的ICMP消息
switch b[0] >> 4 { if msg.Type == ipv6.ICMPTypeEchoReply {
case ipv6.Version: if echo, ok := msg.Body.(*icmp.Echo); ok {
ip, err := ipv6.ParseHeader(b) if EnableLoger {
if err != nil { Logger.Info(fmt.Sprintf("处理IPv6回显应答: ID=%d, Seq=%d", echo.ID, echo.Seq))
return err }
} return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, time.Now()}) }
default: } else if msg.Type == ipv6.ICMPTypeTimeExceeded {
return errUnsupportedProtocol b = getReplyData(msg)
} if len(b) < ipv6.HeaderLen {
} else { if EnableLoger {
// 原有的IPv4处理逻辑 Logger.Warn("IPv6时间超过消息太短")
msg, err := icmp.ParseMessage(ProtocolICMP, b) }
if err != nil { return errMessageTooShort
return err }
} // 解析原始IPv6包头
if msg.Type == ipv4.ICMPTypeEchoReply { if b[0]>>4 == ipv6.Version {
echo := msg.Body.(*icmp.Echo) ip, err := ipv6.ParseHeader(b)
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()}) if err != nil {
} if EnableLoger {
b = getReplyData(msg) Logger.Warn("解析IPv6头部失败: " + err.Error())
if len(b) < ipv4.HeaderLen { }
return errMessageTooShort return err
} }
switch b[0] >> 4 { if EnableLoger {
case ipv4.Version: Logger.Info(fmt.Sprintf("处理IPv6时间超过: 目标=%v, FlowLabel=%d, HopLimit=%d",
ip, err := ipv4.ParseHeader(b) ip.Dst, ip.FlowLabel, ip.HopLimit))
if err != nil { }
return err return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, time.Now()})
} }
return t.serveReply(ip.Dst, &packet{from, uint16(ip.ID), ip.TTL, time.Now()}) }
default: } else {
return errUnsupportedProtocol // 原有的IPv4处理逻辑
} msg, err := icmp.ParseMessage(ProtocolICMP, b)
} if err != nil {
return err
}
if msg.Type == ipv4.ICMPTypeEchoReply {
echo := msg.Body.(*icmp.Echo)
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
}
b = getReplyData(msg)
if len(b) < ipv4.HeaderLen {
return errMessageTooShort
}
switch b[0] >> 4 {
case ipv4.Version:
ip, err := ipv4.ParseHeader(b)
if err != nil {
return err
}
return t.serveReply(ip.Dst, &packet{from, uint16(ip.ID), ip.TTL, time.Now()})
default:
return errUnsupportedProtocol
}
}
return nil
} }
func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) { func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) {
id := uint16(atomic.AddUint32(&t.seq, 1)) id := uint16(atomic.AddUint32(&t.seq, 1))
var b []byte var b []byte
req := &packet{dst, id, ttl, time.Now()} req := &packet{dst, id, ttl, time.Now()}
if dst.To4() == nil { if dst.To4() == nil {
// IPv6 // IPv6
b = newPacketV6(id, dst, ttl) b := newPacketV6(id, dst, ttl)
if t.ipv6conn != nil { if t.ipv6conn != nil {
cm := &ipv6.ControlMessage{ cm := &ipv6.ControlMessage{
HopLimit: ttl, HopLimit: ttl,
} }
_, err := t.ipv6conn.WriteTo(b, cm, &net.IPAddr{IP: dst}) _, err := t.ipv6conn.WriteTo(b, cm, &net.IPAddr{IP: dst})
if err != nil { if err != nil {
return nil, err if EnableLoger {
} InitLogger()
return req, nil defer Logger.Sync()
} Logger.Info("发送IPv6请求失败: " + err.Error())
return nil, errors.New("IPv6 connection not available") }
} else { return nil, err
// IPv4 }
b = newPacketV4(id, dst, ttl) return req, nil
_, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst}) }
if err != nil { return nil, errors.New("IPv6连接不可用")
return nil, err } else {
} // IPv4
return req, nil b = newPacketV4(id, dst, ttl)
} _, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst})
if err != nil {
return nil, err
}
return req, nil
}
} }
func (t *Tracer) addSession(s *Session) { func (t *Tracer) addSession(s *Session) {
@ -269,10 +308,30 @@ func (t *Tracer) removeSession(s *Session) {
} }
func (t *Tracer) serveReply(dst net.IP, res *packet) error { func (t *Tracer) serveReply(dst net.IP, res *packet) error {
if EnableLoger {
Logger.Info(fmt.Sprintf("处理回复: 目标=%v, 来源=%v, ID=%d, TTL=%d",
dst, res.IP, res.ID, res.TTL))
}
// 确保使用正确的IP格式进行查找
shortDst := shortIP(dst)
t.mu.RLock() t.mu.RLock()
defer t.mu.RUnlock() defer t.mu.RUnlock()
a := t.sess[string(shortIP(dst))] // // 调试输出会话信息
// if EnableLoger && len(t.sess) > 0 {
// for ip, sessions := range t.sess {
// Logger.Info(fmt.Sprintf("会话信息: IP=%v, 会话数=%d",
// net.IP([]byte(ip)), len(sessions)))
// }
// }
// 查找对应的会话
a := t.sess[string(shortDst)]
if len(a) == 0 && EnableLoger {
Logger.Warn(fmt.Sprintf("找不到目标IP=%v的会话", dst))
}
for _, s := range a { for _, s := range a {
if EnableLoger {
Logger.Info(fmt.Sprintf("处理会话响应: 会话目标=%v", s.ip))
}
s.handle(res) s.handle(res)
} }
return nil return nil
@ -336,12 +395,32 @@ func (s *Session) handle(res *packet) {
now := res.Time now := res.Time
n := 0 n := 0
var req *packet var req *packet
if EnableLoger {
Logger.Info(fmt.Sprintf("处理会话响应: 会话目标=%v, 响应源=%v, ID=%d, TTL=%d",
s.ip, res.IP, res.ID, res.TTL))
}
s.mu.Lock() s.mu.Lock()
// // 打印出所有待处理的探测包
// if EnableLoger && len(s.probes) > 0 {
// Logger.Info(fmt.Sprintf("当前会话有 %d 个待处理的探测包", len(s.probes)))
// for i, probe := range s.probes {
// Logger.Info(fmt.Sprintf("探测包 #%d: ID=%d, TTL=%d, 时间=%v",
// i, probe.ID, probe.TTL, probe.Time))
// }
// }
// 查找匹配的请求包
for _, r := range s.probes { for _, r := range s.probes {
if now.Sub(r.Time) > s.t.Timeout { if now.Sub(r.Time) > s.t.Timeout {
// if EnableLoger {
// Logger.Info(fmt.Sprintf("探测包超时: ID=%d, TTL=%d", r.ID, r.TTL))
// }
continue continue
} }
if r.ID == res.ID { // 对于IPv6 松散匹配
if r.ID == res.ID || res.IP.To4() == nil {
if EnableLoger {
Logger.Info(fmt.Sprintf("找到匹配的探测包: ID=%d, TTL=%d", r.ID, r.TTL))
}
req = r req = r
continue continue
} }
@ -351,19 +430,32 @@ func (s *Session) handle(res *packet) {
s.probes = s.probes[:n] s.probes = s.probes[:n]
s.mu.Unlock() s.mu.Unlock()
if req == nil { if req == nil {
if EnableLoger {
Logger.Warn(fmt.Sprintf("未找到匹配的探测包: 响应ID=%d", res.ID))
}
return return
} }
hops := req.TTL - res.TTL + 1 hops := req.TTL - res.TTL + 1
if hops < 1 { if hops < 1 {
hops = 1 hops = 1
} }
if EnableLoger {
Logger.Info(fmt.Sprintf("创建响应: IP=%v, RTT=%v, Hops=%d",
res.IP, res.Time.Sub(req.Time), hops))
}
select { select {
case s.ch <- &Reply{ case s.ch <- &Reply{
IP: res.IP, IP: res.IP,
RTT: res.Time.Sub(req.Time), RTT: res.Time.Sub(req.Time),
Hops: hops, Hops: hops,
}: }:
if EnableLoger {
Logger.Info("响应已发送到通道")
}
default: default:
if EnableLoger {
Logger.Warn("发送响应到通道失败,通道已满")
}
} }
} }

View File

@ -1,8 +1,11 @@
package backtrace package backtrace
import ( import (
"fmt"
"net" "net"
"strings"
. "github.com/oneclickvirt/defaultset"
"golang.org/x/net/icmp" "golang.org/x/net/icmp"
"golang.org/x/net/ipv4" "golang.org/x/net/ipv4"
) )
@ -33,3 +36,125 @@ func newPacketV4(id uint16, dst net.IP, ttl int) []byte {
} }
return append(buf, p...) return append(buf, p...)
} }
// trace IPv4追踪函数
func trace(ch chan Result, i int) {
if EnableLoger {
InitLogger()
defer Logger.Sync()
Logger.Info(fmt.Sprintf("开始追踪 %s (%s)", ipv4Names[i], ipv4s[i]))
}
hops, err := Trace(net.ParseIP(ipv4s[i]))
if err != nil {
s := fmt.Sprintf("%v %-15s %v", ipv4Names[i], ipv4s[i], err)
if EnableLoger {
Logger.Error(fmt.Sprintf("追踪 %s (%s) 失败: %v", ipv4Names[i], ipv4s[i], err))
}
ch <- Result{i, s}
return
}
// 记录每个hop的信息
if EnableLoger {
for hopNum, hop := range hops {
for nodeNum, node := range hop.Nodes {
Logger.Info(fmt.Sprintf("追踪 %s (%s) - Hop %d, Node %d: %s (RTT: %v)",
ipv4Names[i], ipv4s[i], hopNum+1, nodeNum+1, node.IP.String(), node.RTT))
}
}
}
var asns []string
for _, h := range hops {
for _, n := range h.Nodes {
asn := ipAsn(n.IP.String())
if asn != "" {
asns = append(asns, asn)
if EnableLoger {
Logger.Info(fmt.Sprintf("IP %s 对应的ASN: %s", n.IP.String(), asn))
}
}
}
}
// 处理CN2不同路线的区别
if asns != nil && len(asns) > 0 {
var tempText string
asns = removeDuplicates(asns)
tempText += fmt.Sprintf("%v ", ipv4Names[i])
hasAS4134 := false
hasAS4809 := false
for _, asn := range asns {
if asn == "AS4134" {
hasAS4134 = true
}
if asn == "AS4809" {
hasAS4809 = true
}
}
// 判断是否包含 AS4134 和 AS4809
if hasAS4134 && hasAS4809 {
// 同时包含 AS4134 和 AS4809 属于 CN2GT
asns = append([]string{"AS4809b"}, asns...)
if EnableLoger {
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GT", ipv4Names[i], ipv4s[i]))
}
} else if hasAS4809 {
// 仅包含 AS4809 属于 CN2GIA
asns = append([]string{"AS4809a"}, asns...)
if EnableLoger {
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GIA", ipv4Names[i], ipv4s[i]))
}
}
tempText += fmt.Sprintf("%-24s ", ipv4s[i])
for _, asn := range asns {
asnDescription := m[asn]
switch asn {
case "":
continue
case "AS4809": // 被 AS4809a 和 AS4809b 替代了
continue
case "AS9929":
if !strings.Contains(tempText, asnDescription) {
tempText += DarkGreen(asnDescription) + " "
}
case "AS4809a":
if !strings.Contains(tempText, asnDescription) {
tempText += DarkGreen(asnDescription) + " "
}
case "AS23764":
if !strings.Contains(tempText, asnDescription) {
tempText += DarkGreen(asnDescription) + " "
}
case "AS4809b":
if !strings.Contains(tempText, asnDescription) {
tempText += Green(asnDescription) + " "
}
case "AS58807":
if !strings.Contains(tempText, asnDescription) {
tempText += Green(asnDescription) + " "
}
default:
if !strings.Contains(tempText, asnDescription) {
tempText += White(asnDescription) + " "
}
}
}
if tempText == (fmt.Sprintf("%v ", ipv4Names[i]) + fmt.Sprintf("%-15s ", ipv4s[i])) {
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
if EnableLoger {
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到已知线路的ASN", ipv4Names[i], ipv4s[i]))
}
}
if EnableLoger {
Logger.Info(fmt.Sprintf("%s (%s) 追踪完成,结果: %s", ipv4Names[i], ipv4s[i], tempText))
}
ch <- Result{i, tempText}
} else {
s := fmt.Sprintf("%v %-15s %v", ipv4Names[i], ipv4s[i], Red("检测不到回程路由节点的IP地址"))
if EnableLoger {
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IP地址", ipv4Names[i], ipv4s[i]))
}
ch <- Result{i, s}
}
}

View File

@ -1,7 +1,6 @@
package backtrace package backtrace
import ( import (
"encoding/binary"
"fmt" "fmt"
"net" "net"
"strings" "strings"
@ -12,44 +11,43 @@ import (
) )
func newPacketV6(id uint16, dst net.IP, ttl int) []byte { func newPacketV6(id uint16, dst net.IP, ttl int) []byte {
// 创建ICMP消息回显请求 // 使用ipv6包的Echo请求
msg := icmp.Message{ msg := icmp.Message{
Type: ipv6.ICMPTypeEchoRequest, Type: ipv6.ICMPTypeEchoRequest,
Code: 0,
Body: &icmp.Echo{ Body: &icmp.Echo{
ID: int(id), ID: int(id),
Seq: int(id), Seq: int(id),
Data: []byte("HELLO-R-U-THERE"),
}, },
} }
// 序列化ICMP消息 // 序列化ICMP消息
icmpData, _ := msg.Marshal(nil) icmpBytes, _ := msg.Marshal(nil)
// 手动创建原始IPv6数据包头部 return icmpBytes
ipHeaderBytes := make([]byte, ipv6.HeaderLen)
// 设置版本和流量类别(第一个字节)
ipHeaderBytes[0] = (ipv6.Version << 4)
// 设置下一个头部(协议)
ipHeaderBytes[6] = ProtocolIPv6ICMP
// 设置跳数限制
ipHeaderBytes[7] = byte(ttl)
// 设置有效载荷长度2字节字段
binary.BigEndian.PutUint16(ipHeaderBytes[4:6], uint16(len(icmpData)))
// 设置目标地址最后16个字节
copy(ipHeaderBytes[24:40], dst.To16())
// 合并头部和ICMP数据
return append(ipHeaderBytes, icmpData...)
} }
func (t *Tracer) serveIPv6(conn *ipv6.PacketConn) error { func (t *Tracer) serveIPv6(conn *ipv6.PacketConn) error {
if EnableLoger {
InitLogger()
defer Logger.Sync()
}
defer conn.Close() defer conn.Close()
buf := make([]byte, 1500) buf := make([]byte, 1500)
for { for {
n, _, from, err := conn.ReadFrom(buf) n, cm, src, err := conn.ReadFrom(buf)
if err != nil { if err != nil {
if EnableLoger {
Logger.Error("读取IPv6响应失败: " + err.Error())
}
return err return err
} }
fromIP := from.(*net.IPAddr).IP if EnableLoger {
Logger.Info(fmt.Sprintf("收到IPv6响应: 来源=%v, 跳数=%d", src, cm.HopLimit))
}
fromIP := src.(*net.IPAddr).IP
err = t.serveData(fromIP, buf[:n]) err = t.serveData(fromIP, buf[:n])
if err != nil { if err != nil && EnableLoger {
continue Logger.Warn("处理IPv6数据失败: " + err.Error())
} }
} }
} }
@ -63,7 +61,7 @@ func traceIPv6(ch chan Result, i int, offset int) {
} }
hops, err := Trace(net.ParseIP(ipv6s[i])) hops, err := Trace(net.ParseIP(ipv6s[i]))
if err != nil { if err != nil {
s := fmt.Sprintf("%v %-40s %v", ipv6Names[i], ipv6s[i], err) s := fmt.Sprintf("%v %-24s %v", ipv6Names[i], ipv6s[i], err)
if EnableLoger { if EnableLoger {
Logger.Error(fmt.Sprintf("追踪 %s (%s) 失败: %v", ipv6Names[i], ipv6s[i], err)) Logger.Error(fmt.Sprintf("追踪 %s (%s) 失败: %v", ipv6Names[i], ipv6s[i], err))
} }
@ -120,7 +118,7 @@ func traceIPv6(ch chan Result, i int, offset int) {
Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GIA", ipv6Names[i], ipv6s[i])) Logger.Info(fmt.Sprintf("%s (%s) 线路识别为: CN2GIA", ipv6Names[i], ipv6s[i]))
} }
} }
tempText += fmt.Sprintf("%-40s ", ipv6s[i]) tempText += fmt.Sprintf("%-24s ", ipv6s[i])
for _, asn := range asns { for _, asn := range asns {
asnDescription := m[asn] asnDescription := m[asn]
switch asn { switch asn {
@ -166,7 +164,7 @@ func traceIPv6(ch chan Result, i int, offset int) {
} }
ch <- Result{i + offset, tempText} ch <- Result{i + offset, tempText}
} else { } else {
s := fmt.Sprintf("%v %-40s %v", ipv6Names[i], ipv6s[i], Red("检测不到回程路由节点的IP地址")) s := fmt.Sprintf("%v %-24s %v", ipv6Names[i], ipv6s[i], Red("检测不到回程路由节点的IP地址"))
if EnableLoger { if EnableLoger {
Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IP地址", ipv6Names[i], ipv6s[i])) Logger.Warn(fmt.Sprintf("%s (%s) 检测不到回程路由节点的IP地址", ipv6Names[i], ipv6s[i]))
} }