diff --git a/bk/trace_common.go b/bk/trace_common.go index 149ff4d..0c998d7 100644 --- a/bk/trace_common.go +++ b/bk/trace_common.go @@ -13,6 +13,7 @@ import ( "golang.org/x/net/icmp" "golang.org/x/net/ipv4" "golang.org/x/net/ipv6" + . "github.com/oneclickvirt/defaultset" ) // DefaultConfig is the default configuration for Tracer. @@ -132,6 +133,16 @@ func (t *Tracer) init() { conn, err := net.ListenIP(network, t.Addr) if err == nil { 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) break } @@ -224,18 +235,23 @@ func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) { req := &packet{dst, id, ttl, time.Now()} if dst.To4() == nil { // IPv6 - b = newPacketV6(id, dst, ttl) + b := newPacketV6(id, dst, ttl) if t.ipv6conn != nil { cm := &ipv6.ControlMessage{ HopLimit: ttl, } _, err := t.ipv6conn.WriteTo(b, cm, &net.IPAddr{IP: dst}) if err != nil { + if EnableLoger { + InitLogger() + defer Logger.Sync() + Logger.Info("发送IPv6请求失败: " + err.Error()) + } return nil, err } return req, nil } - return nil, errors.New("IPv6 connection not available") + return nil, errors.New("IPv6连接不可用") } else { // IPv4 b = newPacketV4(id, dst, ttl) diff --git a/bk/trace_ipv6.go b/bk/trace_ipv6.go index 5aa6b46..2babcbe 100644 --- a/bk/trace_ipv6.go +++ b/bk/trace_ipv6.go @@ -1,7 +1,6 @@ package backtrace import ( - "encoding/binary" "fmt" "net" "strings" @@ -11,45 +10,71 @@ import ( "golang.org/x/net/ipv6" ) +// func newPacketV6(id uint16, dst net.IP, ttl int) []byte { +// // 创建ICMP消息(回显请求) +// msg := icmp.Message{ +// Type: ipv6.ICMPTypeEchoRequest, +// Body: &icmp.Echo{ +// ID: int(id), +// Seq: int(id), +// }, +// } +// // 序列化ICMP消息 +// icmpData, _ := msg.Marshal(nil) +// // 手动创建原始IPv6数据包头部 +// 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 newPacketV6(id uint16, dst net.IP, ttl int) []byte { - // 创建ICMP消息(回显请求) + // 使用ipv6包的Echo请求 msg := icmp.Message{ Type: ipv6.ICMPTypeEchoRequest, + Code: 0, Body: &icmp.Echo{ - ID: int(id), - Seq: int(id), + ID: int(id), + Seq: int(id), + Data: []byte("HELLO-R-U-THERE"), }, } // 序列化ICMP消息 - icmpData, _ := msg.Marshal(nil) - // 手动创建原始IPv6数据包头部 - 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...) + icmpBytes, _ := msg.Marshal(nil) + return icmpBytes } func (t *Tracer) serveIPv6(conn *ipv6.PacketConn) error { + if EnableLoger { + InitLogger() + defer Logger.Sync() + } defer conn.Close() buf := make([]byte, 1500) for { - n, _, from, err := conn.ReadFrom(buf) + n, cm, src, err := conn.ReadFrom(buf) if err != nil { + if EnableLoger { + Logger.Error("读取IPv6响应失败: " + err.Error()) + } 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]) - if err != nil { - continue + if err != nil && EnableLoger { + Logger.Warn("处理IPv6数据失败: " + err.Error()) } } }