diff --git a/bk/asn.go b/bk/asn.go index 6677001..cc4ec62 100644 --- a/bk/asn.go +++ b/bk/asn.go @@ -14,19 +14,30 @@ type Result struct { } var ( - ips = []string{ + ipv4s = []string{ // "219.141.136.12", "202.106.50.1", "219.141.140.10", "202.106.195.68", "221.179.155.161", "202.96.209.133", "210.22.97.1", "211.136.112.200", "58.60.188.222", "210.21.196.6", "120.196.165.24", "61.139.2.69", "119.6.6.6", "211.137.96.205", } - names = []string{ + ipv6s = []string{ + "2408:80f0:4100:2005::10", // 北京电信 IPv6 + "2408:8000:1010:1::6", // 北京联通 IPv6 + "2409:8000:1003:5::5", // 北京移动 IPv6 + "2408:8026:1:1::6", // 上海联通 IPv6 + "2409:8089:1020:50::6", // 上海移动 IPv6 + } + ipv4Names = []string{ "北京电信", "北京联通", "北京移动", "上海电信", "上海联通", "上海移动", "广州电信", "广州联通", "广州移动", "成都电信", "成都联通", "成都移动", } + ipv6Names = []string{ + "北京电信v6", "北京联通v6", "北京移动v6", + "上海联通v6", "上海移动v6", + } m = map[string]string{ // [] 前的字符串个数,中文占2个字符串 "AS23764": "电信CTGNET [精品线路]", @@ -56,9 +67,9 @@ func removeDuplicates(elements []string) []string { } func trace(ch chan Result, i int) { - hops, err := Trace(net.ParseIP(ips[i])) + hops, err := Trace(net.ParseIP(ipv4s[i])) if err != nil { - s := fmt.Sprintf("%v %-15s %v", names[i], ips[i], err) + s := fmt.Sprintf("%v %-15s %v", ipv4Names[i], ipv4s[i], err) ch <- Result{i, s} return } @@ -75,7 +86,7 @@ func trace(ch chan Result, i int) { if asns != nil && len(asns) > 0 { var tempText string asns = removeDuplicates(asns) - tempText += fmt.Sprintf("%v ", names[i]) + tempText += fmt.Sprintf("%v ", ipv4Names[i]) hasAS4134 := false hasAS4809 := false for _, asn := range asns { @@ -94,7 +105,7 @@ func trace(ch chan Result, i int) { // 仅包含 AS4809 属于 CN2GIA asns = append([]string{"AS4809a"}, asns...) } - tempText += fmt.Sprintf("%-15s ", ips[i]) + tempText += fmt.Sprintf("%-15s ", ipv4s[i]) for _, asn := range asns { asnDescription := m[asn] switch asn { @@ -128,17 +139,20 @@ func trace(ch chan Result, i int) { } } } - if tempText == (fmt.Sprintf("%v ", names[i]) + fmt.Sprintf("%-15s ", ips[i])) { + if tempText == (fmt.Sprintf("%v ", ipv4Names[i]) + fmt.Sprintf("%-15s ", ipv4s[i])) { tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN")) } ch <- Result{i, tempText} } else { - s := fmt.Sprintf("%v %-15s %v", names[i], ips[i], Red("检测不到回程路由节点的IP地址")) + s := fmt.Sprintf("%v %-15s %v", ipv4Names[i], ipv4s[i], Red("检测不到回程路由节点的IP地址")) ch <- Result{i, s} } } func ipAsn(ip string) string { + if strings.Contains(ip, ":") { + return ipv6Asn(ip) + } switch { case strings.HasPrefix(ip, "59.43"): return "AS4809" diff --git a/bk/backtrace.go b/bk/backtrace.go index b23ae61..79f33e6 100644 --- a/bk/backtrace.go +++ b/bk/backtrace.go @@ -6,24 +6,30 @@ import ( ) func BackTrace() { - var ( - s [12]string // 对应 ips 目标地址数量 - c = make(chan Result) - t = time.After(time.Second * 10) - ) - for i := range ips { - go trace(c, i) - } + // 获取IP地址数量 + ipCount := len(ipv4s) + var ( + s = make([]string, ipCount) // 动态分配切片大小 + c = make(chan Result) + t = time.After(time.Second * 10) + ) + for i := range ipv4s { + go trace(c, i) + } + loop: - for range s { - select { - case o := <-c: - s[o.i] = o.s - case <-t: - break loop - } - } - for _, r := range s { - fmt.Println(r) - } + for range s { + select { + case o := <-c: + s[o.i] = o.s + case <-t: + break loop + } + } + + for _, r := range s { + if r != "" { + fmt.Println(r) + } + } } diff --git a/bk/ipv6_asn.go b/bk/ipv6_asn.go new file mode 100644 index 0000000..74f3252 --- /dev/null +++ b/bk/ipv6_asn.go @@ -0,0 +1,40 @@ +package backtrace + +import ( + "strings" +) + +// 识别IPv6地址的ASN +func ipv6Asn(ip string) string { + switch { + // 电信CN2GIA + case strings.HasPrefix(ip, "2408:80"): + return "AS4809a" + // 电信CN2GT + case strings.HasPrefix(ip, "2408:8000"): + return "AS4809b" + // 电信163 + case strings.HasPrefix(ip, "240e:") || strings.HasPrefix(ip, "2408:8"): + return "AS4134" + // 联通9929 + case strings.HasPrefix(ip, "2408:8026:"): + return "AS9929" + // 联通4837 + case strings.HasPrefix(ip, "2408:8000:"): + return "AS4837" + // 移动CMIN2 + case strings.HasPrefix(ip, "2409:8880:"): + return "AS58807" + // 移动CMI + case strings.HasPrefix(ip, "2409:8000:") || strings.HasPrefix(ip, "2409:"): + return "AS9808" + // 移动CMI + case strings.HasPrefix(ip, "2407:") || strings.HasPrefix(ip, "2401:"): + return "AS58453" + // 电信CTGNET + case strings.HasPrefix(ip, "2402:0:") || strings.HasPrefix(ip, "2400:8:"): + return "AS23764" + default: + return "" + } +} diff --git a/bk/trace_common.go b/bk/trace_common.go index e91917a..1367c8b 100644 --- a/bk/trace_common.go +++ b/bk/trace_common.go @@ -17,11 +17,11 @@ import ( // DefaultConfig is the default configuration for Tracer. var DefaultConfig = Config{ - Delay: 50 * time.Millisecond, - Timeout: 500 * time.Millisecond, - MaxHops: 15, - Count: 1, - Networks: []string{"ip4:icmp", "ip4:ip"}, + Delay: 50 * time.Millisecond, + Timeout: 500 * time.Millisecond, + MaxHops: 15, + Count: 1, + Networks: []string{"ip4:icmp", "ip4:ip", "ip6:ipv6-icmp", "ip6:ip"}, } // DefaultTracer is a tracer with DefaultConfig. @@ -126,17 +126,6 @@ func (t *Tracer) init() { } } } - // 初始化IPv6 ICMP连接 - c, err := net.ListenPacket("ip6:ipv6-icmp", "") - if err == nil { - p := ipv6.NewPacketConn(c) - if err := p.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true); err == nil { - t.ipv6conn = p - go t.serveIPv6(p) - } else { - c.Close() - } - } } // Close closes listening socket. @@ -167,55 +156,73 @@ func (t *Tracer) serve(conn *net.IPConn) error { } func (t *Tracer) serveData(from net.IP, b []byte) error { - if from.To4() == nil { - // TODO: implement ProtocolIPv6ICMP - return errUnsupportedProtocol - } - now := time.Now() - 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, 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, now}) - case ipv6.Version: - ip, err := ipv6.ParseHeader(b) - if err != nil { - return err - } - return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, now}) - default: - return errUnsupportedProtocol - } + if from.To4() == nil { + // IPv6 处理 + msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, b) + if err != nil { + return err + } + if msg.Type == ipv6.ICMPTypeEchoReply { + echo := msg.Body.(*icmp.Echo) + return t.serveReply(from, &packet{from, uint16(echo.ID), 1, time.Now()}) + } + b = getReplyData(msg) + if len(b) < ipv6.HeaderLen { + return errMessageTooShort + } + switch b[0] >> 4 { + case ipv6.Version: + ip, err := ipv6.ParseHeader(b) + if err != nil { + return err + } + return t.serveReply(ip.Dst, &packet{from, uint16(ip.FlowLabel), ip.HopLimit, 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 + } + } } func (t *Tracer) sendRequest(dst net.IP, ttl int) (*packet, error) { - if dst.To4() == nil { - // IPv6 - return t.sendRequestV6(dst, ttl) - } - // Ipv4 - id := uint16(atomic.AddUint32(&t.seq, 1)) - b := newPacketV4(id, dst, ttl) - req := &packet{dst, id, ttl, time.Now()} - _, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst}) - if err != nil { - return nil, err - } - return req, nil + id := uint16(atomic.AddUint32(&t.seq, 1)) + var b []byte + if dst.To4() == nil { + // IPv6 + b = newPacketV6(id, dst, ttl) + } else { + // IPv4 + b = newPacketV4(id, dst, ttl) + } + req := &packet{dst, id, ttl, time.Now()} + _, err := t.conn.WriteToIP(b, &net.IPAddr{IP: dst}) + if err != nil { + return nil, err + } + return req, nil } func (t *Tracer) addSession(s *Session) { diff --git a/bk/trace_ipv6.go b/bk/trace_ipv6.go index e26065e..22d1d48 100644 --- a/bk/trace_ipv6.go +++ b/bk/trace_ipv6.go @@ -2,124 +2,29 @@ package backtrace import ( "net" - "sync/atomic" - "time" "golang.org/x/net/icmp" "golang.org/x/net/ipv6" ) -func newPacketV6(id uint16, dst net.IP, ttl int) ([]byte, error) { - // 创建ICMPv6 Echo请求消息 +func newPacketV6(id uint16, dst net.IP, ttl int) []byte { msg := icmp.Message{ Type: ipv6.ICMPTypeEchoRequest, - Code: 0, Body: &icmp.Echo{ - ID: int(id), - Seq: int(id), - Data: []byte("TRACEROUTE"), + ID: int(id), + Seq: int(id), }, } - - // 直接序列化ICMPv6消息 - // 第一个参数是协议号,对于ICMPv6应该是58 - return msg.Marshal(nil) -} - -func (t *Tracer) sendRequestV6(dst net.IP, ttl int) (*packet, error) { - id := uint16(atomic.AddUint32(&t.seq, 1)) - // 创建ICMPv6消息 - msg := icmp.Message{ - Type: ipv6.ICMPTypeEchoRequest, - Code: 0, - Body: &icmp.Echo{ - ID: int(id), - Seq: int(id), - Data: []byte("TRACEROUTE"), - }, + p, _ := msg.Marshal(nil) + ip := &ipv6.Header{ + Version: ipv6.Version, + NextHeader: ProtocolIPv6ICMP, + HopLimit: ttl, + Dst: dst, } - // 序列化ICMPv6消息 - b, err := msg.Marshal(nil) + buf, err := ip.Marshal() //TODO 修复 if err != nil { - return nil, err - } - // 获取底层连接 - ipv6Conn, err := t.getIPv6Conn() - if err != nil { - return nil, err - } - // 设置IPv6数据包的跳数限制(TTL) - if err := ipv6Conn.SetHopLimit(ttl); err != nil { - return nil, err - } - // 发送数据包 - if _, err := ipv6Conn.WriteTo(b, nil, &net.IPAddr{IP: dst}); err != nil { - return nil, err - } - // 创建一个数据包记录,用于后续匹配回复 - req := &packet{dst, id, ttl, time.Now()} - return req, nil -} - -// getIPv6Conn 获取IPv6的PacketConn接口 -func (t *Tracer) getIPv6Conn() (*ipv6.PacketConn, error) { - if t.ipv6conn != nil { - return t.ipv6conn, nil - } - // 创建一个UDP连接 - c, err := net.ListenPacket("udp6", "::") - if err != nil { - return nil, err - } - // 将其包装为IPv6 PacketConn - p := ipv6.NewPacketConn(c) - // 设置控制消息 - if err := p.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagSrc|ipv6.FlagDst|ipv6.FlagInterface, true); err != nil { - c.Close() - return nil, err - } - t.ipv6conn = p - return p, nil -} - -func (t *Tracer) serveIPv6(conn *ipv6.PacketConn) error { - defer conn.Close() - buf := make([]byte, 1500) - for { - n, cm, src, err := conn.ReadFrom(buf) - if err != nil { - return err - } - // 从控制消息中获取跳数限制 - hopLimit := 0 - if cm != nil { - hopLimit = cm.HopLimit - } - // 解析ICMP消息 - msg, err := icmp.ParseMessage(ProtocolIPv6ICMP, buf[:n]) - if err != nil { - continue - } - // 根据消息类型处理 - switch msg.Type { - case ipv6.ICMPTypeEchoReply: - echo := msg.Body.(*icmp.Echo) - t.serveReply(src.(*net.IPAddr).IP, &packet{src.(*net.IPAddr).IP, uint16(echo.ID), hopLimit, time.Now()}) - case ipv6.ICMPTypeTimeExceeded: - // 处理超时消息,获取原始数据包 - data := msg.Body.(*icmp.TimeExceeded).Data - // 尝试提取嵌入的原始Echo请求 - if len(data) < 8 { // 至少需要IPv6头部前8个字节 - continue - } - // 跳过IPv6头部和ICMPv6头部,简化处理,实际可能需要更复杂的解析 - innerMsg, err := icmp.ParseMessage(ProtocolIPv6ICMP, data[48:]) - if err != nil { - continue - } - if echo, ok := innerMsg.Body.(*icmp.Echo); ok { - t.serveReply(src.(*net.IPAddr).IP, &packet{src.(*net.IPAddr).IP, uint16(echo.ID), hopLimit, time.Now()}) - } - } + return nil } + return append(buf, p...) }