mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-04-22 04:02:07 +08:00
fix: 进一步添加日志记录
This commit is contained in:
parent
fcc0403612
commit
341c21f1e5
@ -3,6 +3,7 @@ package backtrace
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@ -10,19 +11,19 @@ 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"
|
||||||
. "github.com/oneclickvirt/defaultset"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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.
|
||||||
@ -117,37 +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)
|
||||||
err = t.ipv6conn.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true)
|
err = t.ipv6conn.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if EnableLoger {
|
if EnableLoger {
|
||||||
InitLogger()
|
InitLogger()
|
||||||
defer Logger.Sync()
|
defer Logger.Sync()
|
||||||
Logger.Info("设置IPv6控制消息失败: " + err.Error())
|
Logger.Info("设置IPv6控制消息失败: " + err.Error())
|
||||||
}
|
}
|
||||||
t.ipv6conn.Close()
|
t.ipv6conn.Close()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
go t.serveIPv6(t.ipv6conn)
|
go t.serveIPv6(t.ipv6conn)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes listening socket.
|
// Close closes listening socket.
|
||||||
@ -178,89 +179,112 @@ 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
|
// 时间超过(这是traceroute的关键响应类型)
|
||||||
}
|
b = getReplyData(msg)
|
||||||
} else {
|
if len(b) < ipv6.HeaderLen {
|
||||||
// 原有的IPv4处理逻辑
|
if EnableLoger {
|
||||||
msg, err := icmp.ParseMessage(ProtocolICMP, b)
|
Logger.Warn("IPv6时间超过消息太短")
|
||||||
if err != nil {
|
}
|
||||||
return err
|
return errMessageTooShort
|
||||||
}
|
}
|
||||||
if msg.Type == ipv4.ICMPTypeEchoReply {
|
// 解析原始IPv6包头
|
||||||
echo := msg.Body.(*icmp.Echo)
|
if b[0]>>4 == ipv6.Version {
|
||||||
return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()})
|
ip, err := ipv6.ParseHeader(b)
|
||||||
}
|
if err != nil {
|
||||||
b = getReplyData(msg)
|
if EnableLoger {
|
||||||
if len(b) < ipv4.HeaderLen {
|
Logger.Warn("解析IPv6头部失败: " + err.Error())
|
||||||
return errMessageTooShort
|
}
|
||||||
}
|
return err
|
||||||
switch b[0] >> 4 {
|
}
|
||||||
case ipv4.Version:
|
if EnableLoger {
|
||||||
ip, err := ipv4.ParseHeader(b)
|
Logger.Info(fmt.Sprintf("处理IPv6时间超过: 目标=%v, FlowLabel=%d, HopLimit=%d",
|
||||||
if err != nil {
|
ip.Dst, ip.FlowLabel, ip.HopLimit))
|
||||||
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:
|
}
|
||||||
return errUnsupportedProtocol
|
} else {
|
||||||
}
|
// 原有的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 {
|
||||||
if EnableLoger {
|
if EnableLoger {
|
||||||
InitLogger()
|
InitLogger()
|
||||||
defer Logger.Sync()
|
defer Logger.Sync()
|
||||||
Logger.Info("发送IPv6请求失败: " + err.Error())
|
Logger.Info("发送IPv6请求失败: " + err.Error())
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("IPv6连接不可用")
|
return nil, errors.New("IPv6连接不可用")
|
||||||
} else {
|
} else {
|
||||||
// IPv4
|
// IPv4
|
||||||
b = newPacketV4(id, dst, ttl)
|
b = newPacketV4(id, dst, ttl)
|
||||||
_, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst})
|
_, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return req, nil
|
return req, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tracer) addSession(s *Session) {
|
func (t *Tracer) addSession(s *Session) {
|
||||||
@ -284,11 +308,41 @@ func (t *Tracer) removeSession(s *Session) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (t *Tracer) serveReply(dst net.IP, res *packet) error {
|
||||||
|
// t.mu.RLock()
|
||||||
|
// defer t.mu.RUnlock()
|
||||||
|
// a := t.sess[string(shortIP(dst))]
|
||||||
|
// for _, s := range a {
|
||||||
|
// s.handle(res)
|
||||||
|
// }
|
||||||
|
// return nil
|
||||||
|
// }
|
||||||
|
|
||||||
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
|
||||||
@ -348,16 +402,71 @@ func (s *Session) isDone(ttl int) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// func (s *Session) handle(res *packet) {
|
||||||
|
// now := res.Time
|
||||||
|
// n := 0
|
||||||
|
// var req *packet
|
||||||
|
// s.mu.Lock()
|
||||||
|
// for _, r := range s.probes {
|
||||||
|
// if now.Sub(r.Time) > s.t.Timeout {
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// if r.ID == res.ID {
|
||||||
|
// req = r
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
// s.probes[n] = r
|
||||||
|
// n++
|
||||||
|
// }
|
||||||
|
// s.probes = s.probes[:n]
|
||||||
|
// s.mu.Unlock()
|
||||||
|
// if req == nil {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// hops := req.TTL - res.TTL + 1
|
||||||
|
// if hops < 1 {
|
||||||
|
// hops = 1
|
||||||
|
// }
|
||||||
|
// select {
|
||||||
|
// case s.ch <- &Reply{
|
||||||
|
// IP: res.IP,
|
||||||
|
// RTT: res.Time.Sub(req.Time),
|
||||||
|
// Hops: hops,
|
||||||
|
// }:
|
||||||
|
// default:
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
func (s *Session) handle(res *packet) {
|
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 && res.ID == 0) {
|
||||||
|
if EnableLoger {
|
||||||
|
Logger.Info(fmt.Sprintf("找到匹配的探测包: ID=%d, TTL=%d", r.ID, r.TTL))
|
||||||
|
}
|
||||||
req = r
|
req = r
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -367,19 +476,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("发送响应到通道失败,通道已满")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user