mirror of
https://github.com/oneclickvirt/backtrace.git
synced 2025-04-21 03:32:07 +08:00
140 lines
3.6 KiB
Go
140 lines
3.6 KiB
Go
package backtrace
|
||
|
||
import (
|
||
"encoding/binary"
|
||
"fmt"
|
||
"net"
|
||
"strings"
|
||
|
||
. "github.com/oneclickvirt/defaultset"
|
||
"golang.org/x/net/icmp"
|
||
"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 (t *Tracer) serveIPv6(conn *ipv6.PacketConn) error {
|
||
defer conn.Close()
|
||
buf := make([]byte, 1500)
|
||
for {
|
||
n, _, from, err := conn.ReadFrom(buf)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
fromIP := from.(*net.IPAddr).IP
|
||
err = t.serveData(fromIP, buf[:n])
|
||
if err != nil {
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
|
||
// IPv6追踪函数
|
||
func traceIPv6(ch chan Result, i int, offset int) {
|
||
hops, err := Trace(net.ParseIP(ipv6s[i]))
|
||
if err != nil {
|
||
s := fmt.Sprintf("%v %-40s %v", ipv6Names[i], ipv6s[i], err)
|
||
ch <- Result{i + offset, s}
|
||
return
|
||
}
|
||
var asns []string
|
||
for _, h := range hops {
|
||
for _, n := range h.Nodes {
|
||
asn := ipAsn(n.IP.String())
|
||
if asn != "" {
|
||
asns = append(asns, asn)
|
||
}
|
||
}
|
||
}
|
||
// 处理路由信息
|
||
if asns != nil && len(asns) > 0 {
|
||
var tempText string
|
||
asns = removeDuplicates(asns)
|
||
tempText += fmt.Sprintf("%v ", ipv6Names[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...)
|
||
} else if hasAS4809 {
|
||
// 仅包含 AS4809 属于 CN2GIA
|
||
asns = append([]string{"AS4809a"}, asns...)
|
||
}
|
||
tempText += fmt.Sprintf("%-40s ", ipv6s[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 ", ipv6Names[i]) + fmt.Sprintf("%-40s ", ipv6s[i])) {
|
||
tempText += fmt.Sprintf("%v", Red("检测不到已知线路的ASN"))
|
||
}
|
||
ch <- Result{i + offset, tempText}
|
||
} else {
|
||
s := fmt.Sprintf("%v %-40s %v", ipv6Names[i], ipv6s[i], Red("检测不到回程路由节点的IP地址"))
|
||
ch <- Result{i + offset, s}
|
||
}
|
||
}
|