-
Notifications
You must be signed in to change notification settings - Fork 4
/
traceroute.go
101 lines (89 loc) · 2.16 KB
/
traceroute.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
package mtr
import (
"syscall"
"time"
)
func Traceroute(dest [4]byte, options *TracerouteOptions, c ...chan TracerouteHop) (result TracerouteResult, err error) {
result.Hops = []TracerouteHop{}
result.DestAddress = dest
destAddr := AddressString(dest)
socketAddr, err := LocalAddr()
if err != nil {
return
}
timeoutMs := (int64)(options.TimeoutMs())
tv := syscall.NsecToTimeval(1000 * 1000 * timeoutMs)
var p = make([]byte, options.PacketSize())
retry := 0
succ := false
sntCount := options.SntSize()
retryCount := options.Retries()
for ttl := 1; ttl < options.MaxHops(); ttl++ {
if ttl >= 10 && retry > 1 {
sntCount = options.SntSize() / retry
retryCount = options.Retries() / 2
if sntCount < 2 {
sntCount = 2
}
}
hop := TracerouteHop{TTL: ttl}
failSum := 0
allTime := time.Duration(0) * time.Second
firstReturn := true
for i := 0; i < sntCount; i++ {
singleHop, err := Udp(socketAddr, dest, ttl, options.Port(), tv, p)
if err != nil {
failSum++
continue
}
hop.LastTime = singleHop.Elapsed
allTime += singleHop.Elapsed
if firstReturn {
hop.Address = singleHop.Addr
hop.BestTime = singleHop.Elapsed
hop.WrstTime = singleHop.Elapsed
firstReturn = false
} else {
if singleHop.Elapsed > hop.WrstTime {
hop.WrstTime = singleHop.Elapsed
} else if singleHop.Elapsed < hop.BestTime {
hop.BestTime = singleHop.Elapsed
}
}
if singleHop.Addr == destAddr {
succ = true
}
}
if failSum == sntCount {
hop.Success = false
retry++
if retry >= retryCount {
closeNotify(c)
return result, nil
}
continue
}
retry = 0
hop.AvgTime = time.Duration((int64)(allTime/time.Microsecond)/(int64)(sntCount-failSum)) * time.Microsecond
hop.Loss = float32(failSum) / float32(sntCount) * 100
hop.Success = true
result.Hops = append(result.Hops, hop)
notify(hop, c)
if succ {
closeNotify(c)
return result, nil
}
}
closeNotify(c)
return result, nil
}
func notify(hop TracerouteHop, channels []chan TracerouteHop) {
for _, c := range channels {
c <- hop
}
}
func closeNotify(channels []chan TracerouteHop) {
for _, c := range channels {
close(c)
}
}