Skip to content

Commit

Permalink
Init mtr
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Foerster <tim.foerster@hetzner.de>
  • Loading branch information
tonobo committed Dec 14, 2017
0 parents commit 7338b3f
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 0 deletions.
53 changes: 53 additions & 0 deletions icmp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"net"
"time"

"golang.org/x/net/icmp"
"golang.org/x/net/ipv4"
)

type ICMPReturn struct {
Success bool
Addr string
Elapsed time.Duration
}

func Icmp(localAddr string, dst net.Addr, ttl, pid int, timeout time.Duration) (hop ICMPReturn, err error) {
hop.Success = false
start := time.Now()
c, err := icmp.ListenPacket("ip4:icmp", localAddr)
if err != nil {
return hop, err
}
defer c.Close()
c.IPv4PacketConn().SetTTL(ttl)
c.SetDeadline(time.Now().Add(timeout))
wm := icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: pid, Seq: 1,
Data: []byte(""),
},
}
wb, err := wm.Marshal(nil)
if err != nil {
return hop, err
}

if _, err := c.WriteTo(wb, dst); err != nil {
return hop, err
}

rb := make([]byte, 1500)
_, peer, err := c.ReadFrom(rb)
if err != nil {
return hop, err
}
elapsed := time.Since(start)
hop.Elapsed = elapsed
hop.Addr = peer.String()
hop.Success = true
return hop, err
}
152 changes: 152 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package main

import (
"container/ring"
"fmt"
"net"
"os"
"sync"
"time"
)

var (
MAX_HOPS = 64
RING_BUFFER_SIZE = 8
)

func main() {
fmt.Println("Start:", time.Now())
m := NewMTR("8.8.8.8")
m.Run()
m.Run()
m.Run()
m.Render()
}

type HopStatistic struct {
Sent int
Last ICMPReturn
Best ICMPReturn
Worst ICMPReturn
SumElapsed time.Duration
Lost int
Packets *ring.Ring
}

func (h *HopStatistic) Render(ttl int) {
failedCounter := 0
successCounter := 0
h.Packets.Do(func(f interface{}) {
if f == nil {
return
}
if !f.(ICMPReturn).Success {
failedCounter++
} else {
successCounter++
}
})
addr := "???"
if h.Last.Addr != "" {
addr = h.Last.Addr
}
avg := 0.0
if !(h.Sent-h.Lost == 0) {
avg = h.SumElapsed.Seconds() * 1000 / float64(h.Sent-h.Lost)
}
fmt.Printf("%3d:|-- %-20s %5.1f%% %4d %6.1f %6.1f %6.1f %6.1f\n",
ttl,
addr,
float32(h.Lost)/float32(h.Sent)*100.0,
h.Sent,
h.Last.Elapsed.Seconds()*1000,
avg,
h.Best.Elapsed.Seconds()*1000,
h.Worst.Elapsed.Seconds()*1000,
)
}

type MTR struct {
mutex *sync.RWMutex
Address string `json:"destination"`
Statistic map[int]*HopStatistic `json:"statistic"`
}

func NewMTR(addr string) *MTR {
return &MTR{
Address: addr,
mutex: &sync.RWMutex{},
Statistic: map[int]*HopStatistic{},
}
}

func (m *MTR) registerStatistic(ttl int, r ICMPReturn) {
if m.Statistic[ttl] == nil {
m.Statistic[ttl] = &HopStatistic{
Sent: 1,
Last: r,
Best: r,
Worst: r,
Lost: 0,
SumElapsed: r.Elapsed,
Packets: ring.New(RING_BUFFER_SIZE),
}
if !r.Success {
m.Statistic[ttl].Lost++
}
m.Statistic[ttl].Packets.Value = r
return
}
s := m.Statistic[ttl]
s.Packets = s.Packets.Next()
s.Packets.Value = r
s.Sent++
s.SumElapsed = r.Elapsed + s.SumElapsed
if !r.Success {
m.Statistic[ttl].Lost++
}
s.Last = r
if s.Best.Elapsed > r.Elapsed {
s.Best = r
}
if s.Worst.Elapsed < r.Elapsed {
s.Worst = r
}
}

func (m *MTR) Render() {
fmt.Printf("HOP: %-20s %5s%% %4s %6s %6s %6s %6s\n", "Address", "Loss", "Sent", "Last", "Avg", "Best", "Worst")
for i := 1; i <= len(m.Statistic); i++ {
m.mutex.RLock()
m.Statistic[i].Render(i)
m.mutex.RUnlock()
}
}

func (m *MTR) Run() {
ipAddr := net.IPAddr{IP: net.ParseIP(m.Address)}
pid := os.Getpid() & 0xffff
timeout := 500 * time.Millisecond
ttlDoubleBump := false

for ttl := 1; ttl < 64; ttl++ {
hopReturn, err := Icmp("0.0.0.0", &ipAddr, ttl, pid, timeout)
if err != nil || !hopReturn.Success {
if ttlDoubleBump {
break
}
m.mutex.Lock()
m.registerStatistic(ttl, hopReturn)
m.mutex.Unlock()
ttlDoubleBump = true
continue
}
ttlDoubleBump = false
m.mutex.Lock()
m.registerStatistic(ttl, hopReturn)
m.mutex.Unlock()
if hopReturn.Addr == m.Address {
break
}
}
}

0 comments on commit 7338b3f

Please sign in to comment.