/
main.go
106 lines (86 loc) · 3.05 KB
/
main.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
package main
import (
"fmt"
"os"
"net"
"time"
"golang.org/x/net/ipv4"
)
// Proto define udp protocol type
const (
Protocol = "udp4"
ICMP = "ip4:icmp"
LocalAddress = "0.0.0.0"
Port = 33434
BufferSize = 128
MaxTTL = 30
Deadline = 3
)
// Check for possible errors
func Check (err error) {
if err != nil {
panic (err.Error ())
}
}
// SendPacket to hostname with incremental ttl
func SendPacket (hostname string, addresses chan string, exit chan bool) {
remoteAddress, err := net.ResolveUDPAddr (Protocol, fmt.Sprintf ("%s:%d", hostname, Port))
Check (err)
conn, err := net.DialUDP (Protocol, nil, remoteAddress)
Check (err)
defer conn.Close ()
packet := ipv4.NewPacketConn (conn)
defer packet.Close ()
var ttl = 1
var output, destAddress string
for (destAddress != remoteAddress.IP.String () && ttl <= MaxTTL) {
packet.SetTTL (ttl)
begin := time.Now ()
buffer := make ([]byte, 0x00)
_, err := packet.Write (buffer) // write bytes through connected socket
Check (err)
destAddress = <- addresses //wait for routers response
rtt := time.Since (begin)
if destAddress == "" {
output = fmt.Sprintf ("%d\t%s\t%s\t%v", ttl, "*", "*", rtt)
} else {
output = fmt.Sprintf ("%d\t%s\t%v", ttl, destAddress, rtt)
}
fmt.Println (output)
ttl++
}
exit <- true
}
// ListenEcho from routers in path
func ListenEcho (addresses chan string) {
localAddress, err := net.ResolveIPAddr (ICMP, LocalAddress)
Check (err)
c, err := net.ListenIP (ICMP, localAddress)
Check (err)
c.SetReadDeadline (time.Now().Add (time.Second * Deadline))
defer c.Close ()
for {
buffer := make ([]byte, BufferSize)
bytesRead, remoteAddress, err := c.ReadFromIP (buffer)
if e, ok := err.(net.Error); ok && e.Timeout() {
// if err were a timeout we don't raise panic
c.SetReadDeadline (time.Now().Add (time.Second * Deadline))
addresses <- ""
continue
} else {
Check (err)
}
if bytesRead > 0 {
addresses <- remoteAddress.String ()
}
}
}
func main () {
if len (os.Args) <= 1 { return }
hostname := os.Args [1]
exit := make (chan bool)
addresses := make (chan string)
go ListenEcho (addresses)
go SendPacket (hostname, addresses, exit)
<- exit
}