mirror of
				https://github.com/oneclickvirt/backtrace.git
				synced 2025-11-04 07:42:37 +08:00 
			
		
		
		
	feat: 添加IPV6路由追踪包的构建逻辑
This commit is contained in:
		
							parent
							
								
									7a644b403e
								
							
						
					
					
						commit
						b93b8fbb4a
					
				
							
								
								
									
										30
									
								
								bk/asn.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								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"
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								bk/ipv6_asn.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								bk/ipv6_asn.go
									
									
									
									
									
										Normal file
									
								
							@ -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 ""
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -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) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										119
									
								
								bk/trace_ipv6.go
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								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...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user