-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathipv6.go
134 lines (102 loc) · 2.86 KB
/
ipv6.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package ztrace
import (
"fmt"
"math/rand"
"net"
"runtime"
"time"
"github.com/sirupsen/logrus"
"golang.org/x/net/icmp"
"golang.org/x/net/ipv6"
)
func (t *TraceRoute) TraceIpv6ICMP() (err error) {
defer func() {
if e := recover(); e != nil {
logrus.Error(e)
buf := make([]byte, 64<<10)
buf = buf[:runtime.Stack(buf, false)]
err = fmt.Errorf("errgroup: panic recovered: %s\n %s", e, buf)
}
}()
var dst net.IPAddr
if _, err := t.dnsResolve(t.Dest, &dst); err != nil {
logrus.Error("TraceIpv6ICMP failed:", err)
return err
}
icmp6Sock, err := net.ListenPacket("ip6:ipv6-icmp", t.SrcAddr)
if err != nil {
logrus.Error("Could not set a listening ICMP6 socket: ", err)
return err
}
defer icmp6Sock.Close()
ipv6Sock := ipv6.NewPacketConn(icmp6Sock)
defer ipv6Sock.Close()
if err := ipv6Sock.SetControlMessage(ipv6.FlagHopLimit|ipv6.FlagDst|ipv6.FlagInterface|ipv6.FlagSrc, true); err != nil {
logrus.Error("Could not set options on the ipv6 socket: ", err)
return err
}
icmp6Echo := icmp.Message{
Type: ipv6.ICMPTypeEchoRequest, Code: 0, Body: &icmp.Echo{ID: rand.Int(), Data: []byte("")},
}
buf := make([]byte, 1500)
isDest := false
for i := 1; i <= int(t.MaxTTL); i++ {
hopData := HopData{
Hop: i,
}
for j := 0; j < t.Count; j++ {
icmp6Echo.Body.(*icmp.Echo).Seq = i
buffer, err := icmp6Echo.Marshal(nil)
if err != nil {
logrus.Error("Could not serialize the ICMP6 echo request: ", err)
return err
}
if err := ipv6Sock.SetHopLimit(i); err != nil {
logrus.Error("Could not set the HopLimit field: ", err)
return err
}
timeNow := time.Now()
if _, err := ipv6Sock.WriteTo(buffer, nil, &dst); err != nil {
logrus.Error("Could not send the ICMP6 echo packet: ", err)
return err
}
if err := ipv6Sock.SetReadDeadline(time.Now().Add(t.Timeout)); err != nil {
logrus.Error("Could not set the read timeout on the ipv6 socket: ", err)
return err
}
n, _, node, err := ipv6Sock.ReadFrom(buf)
hop := map[string]interface{}{}
if err == nil {
answer, err := icmp.ParseMessage(58, buf[:n])
if err != nil {
logrus.Error("Could not parse the ICMP6 packet from: ", node.String())
return err
}
timeCost := time.Since(timeNow)
if answer.Type == ipv6.ICMPTypeTimeExceeded {
hop = map[string]interface{}{
"rtt": fmt.Sprintf("%s", timeCost),
"saddr": node.String(),
}
hopData.Details = append(hopData.Details, hop)
} else if answer.Type == ipv6.ICMPTypeEchoReply {
hop = map[string]interface{}{
"rtt": fmt.Sprintf("%s", timeCost),
"saddr": node.String(),
}
hopData.Details = append(hopData.Details, hop)
t.LastArrived += 1
if t.LastArrived == t.Count {
isDest = true
break
}
}
}
}
t.Hops = append(t.Hops, hopData)
if isDest {
break
}
}
return nil
}