mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-04-22 04:02:07 +08:00
Compare commits
6 Commits
466c8dbe5d
...
f1ccde0ea9
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f1ccde0ea9 | ||
![]() |
4caf507831 | ||
![]() |
ddc2f9b401 | ||
![]() |
93434aeda1 | ||
![]() |
341c21f1e5 | ||
![]() |
fcc0403612 |
2
.github/workflows/main.yaml
vendored
2
.github/workflows/main.yaml
vendored
@ -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
|
||||||
|
@ -19,9 +19,11 @@
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
|
- [ ] 增加IPV6路由能力检测
|
||||||
|
- [ ] 兼容额外的ICMP地址获取,若当前目标IP无法查询路由尝试额外的IP地址
|
||||||
|
- [ ] 重复检测同一段路由,避免结果不可复现
|
||||||
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段)
|
- [ ] 自动检测汇聚层,裁剪结果不输出汇聚层后的线路(区分境内外段)
|
||||||
- [ ] 添加对主流ISP的POP点检测,区分国际互联能力
|
- [ ] 添加对主流ISP的POP点检测,区分国际互联能力
|
||||||
- [ ] 增加IPV6路由能力检测,兼容额外的ICMP地址获取,每日更新
|
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
|
126
bk/asn.go
126
bk/asn.go
@ -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)
|
||||||
|
@ -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"
|
||||||
@ -132,6 +134,16 @@ func (t *Tracer) init() {
|
|||||||
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)
|
||||||
|
err = t.ipv6conn.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true)
|
||||||
|
if err != nil {
|
||||||
|
if EnableLoger {
|
||||||
|
InitLogger()
|
||||||
|
defer Logger.Sync()
|
||||||
|
Logger.Info("设置IPv6控制消息失败: " + err.Error())
|
||||||
|
}
|
||||||
|
t.ipv6conn.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
go t.serveIPv6(t.ipv6conn)
|
go t.serveIPv6(t.ipv6conn)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -171,25 +183,46 @@ func (t *Tracer) serveData(from net.IP, b []byte) error {
|
|||||||
// IPv6处理
|
// IPv6处理
|
||||||
msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, b)
|
msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if EnableLoger {
|
||||||
|
Logger.Warn("解析IPv6 ICMP消息失败: " + err.Error())
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// 记录所有收到的消息类型,帮助调试
|
||||||
|
if EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("收到IPv6 ICMP消息: 类型=%v, 代码=%v", msg.Type, msg.Code))
|
||||||
|
}
|
||||||
|
// 处理不同类型的ICMP消息
|
||||||
if msg.Type == ipv6.ICMPTypeEchoReply {
|
if msg.Type == ipv6.ICMPTypeEchoReply {
|
||||||
echo := msg.Body.(*icmp.Echo)
|
if echo, ok := msg.Body.(*icmp.Echo); ok {
|
||||||
|
if EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("处理IPv6回显应答: ID=%d, Seq=%d", echo.ID, echo.Seq))
|
||||||
|
}
|
||||||
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
|
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
|
||||||
}
|
}
|
||||||
|
} else if msg.Type == ipv6.ICMPTypeTimeExceeded {
|
||||||
b = getReplyData(msg)
|
b = getReplyData(msg)
|
||||||
if len(b) < ipv6.HeaderLen {
|
if len(b) < ipv6.HeaderLen {
|
||||||
|
if EnableLoger {
|
||||||
|
Logger.Warn("IPv6时间超过消息太短")
|
||||||
|
}
|
||||||
return errMessageTooShort
|
return errMessageTooShort
|
||||||
}
|
}
|
||||||
switch b[0] >> 4 {
|
// 解析原始IPv6包头
|
||||||
case ipv6.Version:
|
if b[0]>>4 == ipv6.Version {
|
||||||
ip, err := ipv6.ParseHeader(b)
|
ip, err := ipv6.ParseHeader(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if EnableLoger {
|
||||||
|
Logger.Warn("解析IPv6头部失败: " + err.Error())
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("处理IPv6时间超过: 目标=%v, FlowLabel=%d, HopLimit=%d",
|
||||||
|
ip.Dst, ip.FlowLabel, ip.HopLimit))
|
||||||
|
}
|
||||||
return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, time.Now()})
|
return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, time.Now()})
|
||||||
default:
|
}
|
||||||
return errUnsupportedProtocol
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 原有的IPv4处理逻辑
|
// 原有的IPv4处理逻辑
|
||||||
@ -216,6 +249,7 @@ func (t *Tracer) serveData(from net.IP, b []byte) error {
|
|||||||
return errUnsupportedProtocol
|
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) {
|
||||||
@ -224,18 +258,23 @@ func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) {
|
|||||||
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 {
|
||||||
|
if EnableLoger {
|
||||||
|
InitLogger()
|
||||||
|
defer Logger.Sync()
|
||||||
|
Logger.Info("发送IPv6请求失败: " + err.Error())
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("IPv6 connection not available")
|
return nil, errors.New("IPv6连接不可用")
|
||||||
} else {
|
} else {
|
||||||
// IPv4
|
// IPv4
|
||||||
b = newPacketV4(id, dst, ttl)
|
b = newPacketV4(id, dst, ttl)
|
||||||
@ -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("发送响应到通道失败,通道已满")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
125
bk/trace_ipv4.go
125
bk/trace_ipv4.go
@ -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}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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]))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user