Skip to content

Commit 69f4676

Browse files
author
wardlin
committed
update
0 parents  commit 69f4676

18 files changed

+2241
-0
lines changed

.gitignore

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
8+
# Test binary, built with `go test -c`
9+
*.test
10+
11+
# Output of the go coverage tool, specifically when used with LiteIDE
12+
*.out
13+
14+
# Dependency directories (remove the comment below to include it)
15+
# vendor/

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Mie~~~
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+124
Large diffs are not rendered by default.

go.mod

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module github.com/eaglesunshine/trace
2+
3+
go 1.16
4+
5+
require (
6+
github.com/sirupsen/logrus v1.8.1
7+
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d
8+
)

go.sum

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
2+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
4+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
5+
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
6+
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
7+
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
8+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
9+
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c=
10+
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
11+
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
12+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
13+
golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
14+
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
15+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
16+
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
17+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

icmp.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package ztrace
2+
3+
import (
4+
"encoding/binary"
5+
"net"
6+
"sync/atomic"
7+
"time"
8+
9+
"github.com/sirupsen/logrus"
10+
"golang.org/x/net/ipv4"
11+
)
12+
13+
func (t *TraceRoute) SendIPv4ICMP() {
14+
key := GetHash(t.netSrcAddr.To4(), t.netDstAddr.To4(), 65535, 65535, 1)
15+
db := NewStatsDB(key)
16+
17+
t.DB.Store(key, db)
18+
go db.Cache.Run()
19+
conn, err := net.ListenPacket("ip4:icmp", t.netSrcAddr.String())
20+
if err != nil {
21+
logrus.Error(err)
22+
return
23+
}
24+
defer conn.Close()
25+
26+
rSocket, err := ipv4.NewRawConn(conn)
27+
if err != nil {
28+
logrus.Error("can not create raw socket:", err)
29+
return
30+
}
31+
defer rSocket.Close()
32+
33+
id := uint16(1)
34+
mod := uint16(1 << 15)
35+
36+
for ttl := 1; ttl <= int(t.MaxTTL); ttl++ {
37+
hdr, payload := t.BuildIPv4ICMP(uint8(ttl), id, id, 0)
38+
rSocket.WriteTo(hdr, payload, nil)
39+
report := &SendMetric{
40+
FlowKey: key,
41+
ID: uint32(hdr.ID),
42+
TTL: uint8(ttl),
43+
TimeStamp: time.Now(),
44+
}
45+
t.SendChan <- report
46+
id = (id + 1) % mod
47+
48+
logrus.Info("send icmp ttl:", ttl)
49+
50+
//atomic.AddUint64(db.SendCnt, 1)
51+
}
52+
}
53+
54+
func (t *TraceRoute) ListenIPv4ICMP() {
55+
defer t.Stop()
56+
57+
laddr := &net.IPAddr{IP: t.netSrcAddr}
58+
59+
var err error
60+
t.recvICMPConn, err = net.ListenIP("ip4:icmp", laddr)
61+
62+
if err != nil {
63+
logrus.Error("bind failure:", err)
64+
return
65+
}
66+
defer t.recvICMPConn.Close()
67+
68+
//设置超时时间
69+
t.recvICMPConn.SetReadDeadline(time.Now().Add(t.Timeout))
70+
71+
for {
72+
if atomic.LoadInt32(t.stopSignal) == 1 {
73+
return
74+
}
75+
76+
buf := make([]byte, 1500)
77+
n, raddr, err := t.recvICMPConn.ReadFrom(buf)
78+
if err != nil {
79+
logrus.Error("recvICMPConn.ReadFrom failed:", err)
80+
return
81+
}
82+
83+
icmpType := buf[0]
84+
//logrus.Info(raddr, "|", icmpType, "|", n)
85+
86+
//TTL Exceeded or Port Unreachable
87+
if (icmpType == 11 || (icmpType == 3 && buf[1] == 3)) && (n >= 36) {
88+
id := binary.BigEndian.Uint16(buf[32:34])
89+
90+
dstip := net.IP(buf[24:28])
91+
srcip := net.IP(buf[20:24])
92+
93+
if dstip.Equal(t.netDstAddr) {
94+
key := GetHash(srcip, dstip, 65535, 65535, 1)
95+
96+
m := &RecvMetric{
97+
FlowKey: key,
98+
ID: uint32(id),
99+
RespAddr: raddr.String(),
100+
TimeStamp: time.Now(),
101+
}
102+
logrus.Info("recv icmp ttl:", id)
103+
104+
t.RecvChan <- m
105+
}
106+
}
107+
}
108+
109+
}

ipv6.go

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

0 commit comments

Comments
 (0)