summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorinsomniacslk <insomniacslk@users.noreply.github.com>2016-02-24 18:09:16 +0000
committerinsomniacslk <insomniacslk@users.noreply.github.com>2016-02-24 18:09:16 +0000
commit389d5d632e055ad64725e6ba8b92b2ed61c0cab5 (patch)
treeb9c46488c2d3c289ee92ed1147461e4465445a05
parent229d8166ab0c298be16590a4a3d448996dcc10cf (diff)
parentc39b1c2d6fa150b36a7a57829be4f1fc31a74aee (diff)
downloadfbtracert-389d5d632e055ad64725e6ba8b92b2ed61c0cab5.zip
fbtracert-389d5d632e055ad64725e6ba8b92b2ed61c0cab5.tar.gz
fbtracert-389d5d632e055ad64725e6ba8b92b2ed61c0cab5.tar.bz2
Merge pull request #2 from virtuallynathan/master
gofmt / golint / minor code changes
-rw-r--r--main.go178
-rw-r--r--tcp.go28
2 files changed, 91 insertions, 115 deletions
diff --git a/main.go b/main.go
index 527199a..30b0a13 100644
--- a/main.go
+++ b/main.go
@@ -13,33 +13,33 @@ import (
"encoding/json"
"flag"
"fmt"
- "github.com/golang/glog"
- "github.com/olekukonko/tablewriter"
"math/rand"
"net"
"os"
- "runtime"
"syscall"
"time"
+
+ "github.com/golang/glog"
+ "github.com/olekukonko/tablewriter"
)
//
// Command line flags
//
-var maxTtl *int = flag.Int("maxTtl", 30, "The maximum ttl to use")
-var minTtl *int = flag.Int("minTtl", 1, "The ttl to start at")
-var maxSrcPorts *int = flag.Int("maxSrcPorts", 256, "The maximum number of source ports to use")
-var maxTime *int = flag.Int("maxTime", 60, "The time to run the process for")
-var targetPort *int = flag.Int("targetPort", 22, "The target port to trace to")
-var probeRate *int = flag.Int("probeRate", 96, "The probe rate per ttl layer")
-var tosValue *int = flag.Int("tosValue", 140, "The TOS/TC to use in probes")
-var numResolvers *int = flag.Int("numResolvers", 32, "The number of DNS resolver goroutines")
-var addrFamily *string = flag.String("addrFamily", "ip4", "The address family (ip4/ip6) to use for testing")
-var maxColumns *int = flag.Int("maxColumns", 4, "Maximum number of columns in report tables")
-var showAll *bool = flag.Bool("showAll", false, "Show all paths, regardless of loss detection")
-var srcAddr *string = flag.String("srcAddr", "", "The source address for pings, default to auto-discover")
-var jsonOutput *bool = flag.Bool("jsonOutput", false, "Output raw JSON data")
-var baseSrcPort *int = flag.Int("baseSrcPort", 32768, "The base source port to start probing from")
+var maxTTL = flag.Int("maxTTL", 30, "The maximum ttl to use")
+var minTTL = flag.Int("minTTL", 1, "The ttl to start at")
+var maxSrcPorts = flag.Int("maxSrcPorts", 256, "The maximum number of source ports to use")
+var maxTime = flag.Int("maxTime", 60, "The time to run the process for")
+var targetPort = flag.Int("targetPort", 22, "The target port to trace to")
+var probeRate = flag.Int("probeRate", 96, "The probe rate per ttl layer")
+var tosValue = flag.Int("tosValue", 140, "The TOS/TC to use in probes")
+var numResolvers = flag.Int("numResolvers", 32, "The number of DNS resolver goroutines")
+var addrFamily = flag.String("addrFamily", "ip4", "The address family (ip4/ip6) to use for testing")
+var maxColumns = flag.Int("maxColumns", 4, "Maximum number of columns in report tables")
+var showAll = flag.Bool("showAll", false, "Show all paths, regardless of loss detection")
+var srcAddr = flag.String("srcAddr", "", "The source address for pings, default to auto-discover")
+var jsonOutput = flag.Bool("jsonOutput", false, "Output raw JSON data")
+var baseSrcPort = flag.Int("baseSrcPort", 32768, "The base source port to start probing from")
//
// Discover the source address for pinging
@@ -68,50 +68,40 @@ func getSourceAddr(af string, srcAddr string) (*net.IP, error) {
return nil, fmt.Errorf("Could not find a source address in af %s", af)
}
-//
// Resolve given hostname/address in the given address family
-//
func resolveName(dest string, af string) (*net.IP, error) {
addr, err := net.ResolveIPAddr(af, dest)
return &addr.IP, err
}
-//
-// Probe specification, emitted by sender
-//
+// Probe is emitted by sender
type Probe struct {
srcPort int
ttl int
}
-//
-// Emitted by IcmpReceiver
-//
-type IcmpResponse struct {
+// ICMPResponse is emitted by ICMPReceiver
+type ICMPResponse struct {
Probe
fromAddr *net.IP
fromName string
rtt uint32
}
-//
-// Emitted by TcpReceiver
-//
-type TcpResponse struct {
+// TCPResponse is emitted by TCPReceiver
+type TCPResponse struct {
Probe
rtt uint32
}
-//
-// Feed on TCP RST messages we receive from the end host; we use lots of parameters to check if the incoming packet
-// is actually a response to our probe. We create TcpResponse structs and emit them on the output channel
-//
-func TcpReceiver(done <-chan struct{}, af string, targetAddr string, probePortStart, probePortEnd, targetPort, maxTtl int) (chan interface{}, error) {
+// TCPReceiver Feeds on TCP RST messages we receive from the end host; we use lots of parameters to check if the incoming packet
+// is actually a response to our probe. We create TCPResponse structs and emit them on the output channel
+func TCPReceiver(done <-chan struct{}, af string, targetAddr string, probePortStart, probePortEnd, targetPort, maxTTL int) (chan interface{}, error) {
var recvSocket int
var err error
var ipHdrSize int
- glog.V(2).Infoln("TcpReceiver starting...")
+ glog.V(2).Infoln("TCPReceiver starting...")
// create the socket
switch {
@@ -131,11 +121,11 @@ func TcpReceiver(done <-chan struct{}, af string, targetAddr string, probePortSt
return nil, err
}
- // we'll be writing the TcpResponse structs to this channel
+ // we'll be writing the TCPResponse structs to this channel
out := make(chan interface{})
// IP + TCP header, this channel is fed from the socket
- recv := make(chan TcpResponse)
+ recv := make(chan TCPResponse)
go func() {
const tcpHdrSize int = 20
packet := make([]byte, ipHdrSize+tcpHdrSize)
@@ -153,7 +143,7 @@ func TcpReceiver(done <-chan struct{}, af string, targetAddr string, probePortSt
}
// is that from the target port we expect?
- tcpHdr := parseTcpHeader(packet[ipHdrSize:n])
+ tcpHdr := parseTCPHeader(packet[ipHdrSize:n])
if int(tcpHdr.Source) != targetPort {
continue
}
@@ -181,7 +171,7 @@ func TcpReceiver(done <-chan struct{}, af string, targetAddr string, probePortSt
ackNum := tcpHdr.AckNum - 1
ttl := int(ackNum >> 24)
- if ttl > maxTtl || ttl < 1 {
+ if ttl > maxTTL || ttl < 1 {
continue
}
@@ -195,7 +185,7 @@ func TcpReceiver(done <-chan struct{}, af string, targetAddr string, probePortSt
continue
}
- recv <- TcpResponse{Probe: Probe{srcPort: int(tcpHdr.Destination), ttl: ttl}, rtt: now - ts}
+ recv <- TCPResponse{Probe: Probe{srcPort: int(tcpHdr.Destination), ttl: ttl}, rtt: now - ts}
}
}()
@@ -207,7 +197,7 @@ func TcpReceiver(done <-chan struct{}, af string, targetAddr string, probePortSt
case response := <-recv:
out <- response
case <-done:
- glog.V(2).Infoln("TcpReceiver terminating...")
+ glog.V(2).Infoln("TCPReceiver terminating...")
return
}
}
@@ -216,14 +206,12 @@ func TcpReceiver(done <-chan struct{}, af string, targetAddr string, probePortSt
return out, nil
}
-//
-// This runs on its own collecting Icmp responses until its explicitly told to stop
-//
-func IcmpReceiver(done <-chan struct{}, af string) (chan interface{}, error) {
+// ICMPReceiver runs on its own collecting ICMP responses until its explicitly told to stop
+func ICMPReceiver(done <-chan struct{}, af string) (chan interface{}, error) {
var recvSocket int
var err error
- var outerIpHdrSize int
- var innerIpHdrSize int
+ var outerIPHdrSize int
+ var innerIPHdrSize int
var icmpMsgType byte
const (
@@ -235,17 +223,17 @@ func IcmpReceiver(done <-chan struct{}, af string) (chan interface{}, error) {
case af == "ip4":
recvSocket, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP)
// IPv4 raw socket always prepend the transport IPv4 header
- outerIpHdrSize = 20
+ outerIPHdrSize = 20
// the size of the original IPv4 header that was on the TCP packet sent out
- innerIpHdrSize = 20
+ innerIPHdrSize = 20
// hardcoded: time to live exceeded
icmpMsgType = 11
case af == "ip6":
recvSocket, err = syscall.Socket(syscall.AF_INET6, syscall.SOCK_RAW, syscall.IPPROTO_ICMPV6)
// IPv6 raw socket does not prepend the original transport IPv6 header
- outerIpHdrSize = 0
+ outerIPHdrSize = 0
// this is the size of IPv6 header of the original TCP packet we used in the probes
- innerIpHdrSize = 40
+ innerIPHdrSize = 40
// time to live exceeded
icmpMsgType = 3
}
@@ -254,28 +242,28 @@ func IcmpReceiver(done <-chan struct{}, af string) (chan interface{}, error) {
return nil, err
}
- glog.V(2).Infoln("IcmpReceiver is starting...")
+ glog.V(2).Infoln("ICMPReceiver is starting...")
recv := make(chan interface{})
go func() {
// TODO: remove hardcode; 20 bytes for IP header, 8 bytes for ICMP header, 8 bytes for TCP header
- packet := make([]byte, outerIpHdrSize+icmpHdrSize+innerIpHdrSize+tcpHdrSize)
+ packet := make([]byte, outerIPHdrSize+icmpHdrSize+innerIPHdrSize+tcpHdrSize)
for {
n, from, err := syscall.Recvfrom(recvSocket, packet, 0)
if err != nil {
break
}
// extract the 8 bytes of the original TCP header
- if n < outerIpHdrSize+icmpHdrSize+innerIpHdrSize+tcpHdrSize {
+ if n < outerIPHdrSize+icmpHdrSize+innerIPHdrSize+tcpHdrSize {
continue
}
// not ttl exceeded
- if packet[outerIpHdrSize] != icmpMsgType || packet[outerIpHdrSize+1] != 0 {
+ if packet[outerIPHdrSize] != icmpMsgType || packet[outerIPHdrSize+1] != 0 {
continue
}
- glog.V(4).Infof("Received icmp response message %d: %x\n", len(packet), packet)
- tcpHdr := parseTcpHeader(packet[outerIpHdrSize+icmpHdrSize+innerIpHdrSize : n])
+ glog.V(4).Infof("Received ICMP response message %d: %x\n", len(packet), packet)
+ tcpHdr := parseTCPHeader(packet[outerIPHdrSize+icmpHdrSize+innerIPHdrSize : n])
var fromAddr net.IP
@@ -293,7 +281,7 @@ func IcmpReceiver(done <-chan struct{}, af string) (chan interface{}, error) {
ts := tcpHdr.SeqNum & 0x00ffffff
// scale the current time
now := uint32(time.Now().UnixNano()/(1000*1000)) & 0x00ffffff
- recv <- IcmpResponse{Probe: Probe{srcPort: int(tcpHdr.Source), ttl: ttl}, fromAddr: &fromAddr, rtt: now - ts}
+ recv <- ICMPResponse{Probe: Probe{srcPort: int(tcpHdr.Source), ttl: ttl}, fromAddr: &fromAddr, rtt: now - ts}
}
}()
@@ -303,11 +291,11 @@ func IcmpReceiver(done <-chan struct{}, af string) (chan interface{}, error) {
defer close(out)
for {
select {
- // read Icmp struct
+ // read ICMP struct
case response := <-recv:
out <- response
case <-done:
- glog.V(2).Infoln("IcmpReceiver done")
+ glog.V(2).Infoln("ICMPReceiver done")
return
}
}
@@ -316,10 +304,8 @@ func IcmpReceiver(done <-chan struct{}, af string) (chan interface{}, error) {
return out, nil
}
-//
-// Resolve names in incoming IcmpResponse messages
+// Resolver resolves names in incoming ICMPResponse messages
// Everything else is passed through as is
-//
func Resolver(input chan interface{}) (chan interface{}, error) {
out := make(chan interface{})
go func() {
@@ -327,8 +313,8 @@ func Resolver(input chan interface{}) (chan interface{}, error) {
for val := range input {
switch val.(type) {
- case IcmpResponse:
- resp := val.(IcmpResponse)
+ case ICMPResponse:
+ resp := val.(ICMPResponse)
names, err := net.LookupAddr(resp.fromAddr.String())
if err != nil {
resp.fromName = "?"
@@ -344,11 +330,9 @@ func Resolver(input chan interface{}) (chan interface{}, error) {
return out, nil
}
-//
-// Generate TCP SYN packet probes with given TTL at given packet per second rate
+// Sender generates TCP SYN packet probes with given TTL at given packet per second rate
// The packet descriptions are published to the output channel as Probe messages
// As a side effect, the packets are injected into raw socket
-//
func Sender(done <-chan struct{}, srcAddr *net.IP, af, dest string, dstPort, baseSrcPort, maxSrcPorts, maxIters, ttl, pps, tos int) (chan interface{}, error) {
var err error
@@ -427,7 +411,7 @@ func Sender(done <-chan struct{}, srcAddr *net.IP, af, dest string, dstPort, bas
probe := Probe{srcPort: srcPort, ttl: ttl}
now := uint32(time.Now().UnixNano()/(1000*1000)) & 0x00ffffff
seqNum := ((uint32(ttl) & 0xff) << 24) | (now & 0x00ffffff)
- packet := makeTcpHeader(af, srcAddr, dstAddr, srcPort, dstPort, seqNum)
+ packet := makeTCPHeader(af, srcAddr, dstAddr, srcPort, dstPort, seqNum)
switch {
case af == "ip4":
@@ -510,16 +494,16 @@ func isLossy(hitRates []float64) bool {
//
// print the paths reported as having losses
//
-func printLossyPaths(sent, rcvd map[int] /* src port */ []int, hops map[int] /* src port */ []string, maxColumns, maxTtl int) {
+func printLossyPaths(sent, rcvd map[int] /* src port */ []int, hops map[int] /* src port */ []string, maxColumns, maxTTL int) {
var allPorts []int
- for srcPort, _ := range hops {
+ for srcPort := range hops {
allPorts = append(allPorts, srcPort)
}
// split in multiple tables to fit the columns on the screen
for i := 0; i < len(allPorts)/maxColumns; i++ {
- data := make([][]string, maxTtl)
+ data := make([][]string, maxTTL)
table := tablewriter.NewWriter(os.Stdout)
header := []string{"TTL"}
@@ -534,7 +518,7 @@ func printLossyPaths(sent, rcvd map[int] /* src port */ []int, hops map[int] /*
table.SetHeader(header)
- for ttl := 0; ttl < maxTtl-1; ttl++ {
+ for ttl := 0; ttl < maxTTL-1; ttl++ {
data[ttl] = make([]string, 2*(maxOffset-i*maxColumns)+1)
data[ttl][0] = fmt.Sprintf("%d", ttl+1)
for j, srcPort := range allPorts[i*maxColumns : maxOffset] {
@@ -552,9 +536,7 @@ func printLossyPaths(sent, rcvd map[int] /* src port */ []int, hops map[int] /*
}
}
-//
-// Define a JSON report from go/fbtracert
-//
+// Report defines a JSON report from go/fbtracert
type Report struct {
// The path map
Paths map[string] /* srcPort */ []string /* path hops */
@@ -575,7 +557,7 @@ func newReport() (report Report) {
//
// Raw Json output for external program to analyze
//
-func printLossyPathsJson(sent, rcvd map[int] /* src port */ []int, hops map[int] /* src port */ []string, maxTtl int) {
+func printLossyPathsJSON(sent, rcvd map[int] /* src port */ []int, hops map[int] /* src port */ []string, maxTTL int) {
var report = newReport()
for srcPort, path := range hops {
@@ -593,8 +575,6 @@ func printLossyPathsJson(sent, rcvd map[int] /* src port */ []int, hops map[int]
}
func main() {
- runtime.GOMAXPROCS(runtime.NumCPU())
-
flag.Parse()
if flag.Arg(0) == "" {
fmt.Fprintf(os.Stderr, "Must specify a target\n")
@@ -622,12 +602,12 @@ func main() {
fmt.Fprintf(os.Stderr, "Use '-logtostderr=true' cmd line option to see GLOG output\n")
// this will catch senders quitting - we have one sender per ttl
- senderDone := make([]chan struct{}, *maxTtl)
- for ttl := *minTtl; ttl <= *maxTtl; ttl++ {
+ senderDone := make([]chan struct{}, *maxTTL)
+ for ttl := *minTTL; ttl <= *maxTTL; ttl++ {
senderDone[ttl-1] = make(chan struct{})
c, err := Sender(senderDone[ttl-1], source, *addrFamily, target, *targetPort, *baseSrcPort, *maxSrcPorts, numIters, ttl, *probeRate, *tosValue)
if err != nil {
- glog.Fatalf("Failed to start sender for ttl %d, %s\n", ttl, err)
+ glog.Fatalf("Failed to start sender for ttl %d, %s\n -- are you running with the correct privileges?", ttl, err)
return
}
probes = append(probes, c)
@@ -636,15 +616,15 @@ func main() {
// channel to tell receivers to stop
recvDone := make(chan struct{})
- // collect icmp unreachable messages for our probes
- icmpResp, err := IcmpReceiver(recvDone, *addrFamily)
+ // collect ICMP unreachable messages for our probes
+ icmpResp, err := ICMPReceiver(recvDone, *addrFamily)
if err != nil {
return
}
// collect TCP RST's from the target
targetAddr, err := resolveName(target, *addrFamily)
- tcpResp, err := TcpReceiver(recvDone, *addrFamily, targetAddr.String(), *baseSrcPort, *baseSrcPort+*maxSrcPorts, *targetPort, *maxTtl)
+ tcpResp, err := TCPReceiver(recvDone, *addrFamily, targetAddr.String(), *baseSrcPort, *baseSrcPort+*maxSrcPorts, *targetPort, *maxTTL)
if err != nil {
return
}
@@ -669,12 +649,12 @@ func main() {
hops := make(map[int] /*src Port */ []string /* hop name */)
for srcPort := *baseSrcPort; srcPort < *baseSrcPort+*maxSrcPorts; srcPort++ {
- sent[srcPort] = make([]int, *maxTtl)
- rcvd[srcPort] = make([]int, *maxTtl)
- hops[srcPort] = make([]string, *maxTtl)
- //hops[srcPort][*maxTtl-1] = target
+ sent[srcPort] = make([]int, *maxTTL)
+ rcvd[srcPort] = make([]int, *maxTTL)
+ hops[srcPort] = make([]string, *maxTTL)
+ //hops[srcPort][*maxTTL-1] = target
- for i := 0; i < *maxTtl; i++ {
+ for i := 0; i < *maxTTL; i++ {
hops[srcPort][i] = "?"
}
}
@@ -697,13 +677,13 @@ func main() {
var names []string
// src ports that changed their paths in process of tracing
- var flappedPorts map[int]bool = make(map[int]bool)
+ var flappedPorts = make(map[int]bool)
- lastClosed := *maxTtl
+ lastClosed := *maxTTL
for val := range merge(resolved...) {
switch val.(type) {
- case IcmpResponse:
- resp := val.(IcmpResponse)
+ case ICMPResponse:
+ resp := val.(ICMPResponse)
rcvd[resp.srcPort][resp.ttl-1]++
currName := hops[resp.srcPort][resp.ttl-1]
if currName != "?" && currName != resp.fromName {
@@ -715,8 +695,8 @@ func main() {
// XXX: we may have duplicates, which is OK,
// but not very efficient
names = append(names, resp.fromName)
- case TcpResponse:
- resp := val.(TcpResponse)
+ case TCPResponse:
+ resp := val.(TCPResponse)
// stop all senders sending above this ttl, since they are not needed
// XXX: this is not always optimal, i.e. we may receive TCP RST for
// a port mapped to a short WAN path, and it would tell us to terminate
@@ -737,7 +717,7 @@ func main() {
for srcPort, hopVector := range hops {
for i := range hopVector {
// truncate lists once we hit the target name
- if hopVector[i] == target && i < *maxTtl-1 {
+ if hopVector[i] == target && i < *maxTTL-1 {
sent[srcPort] = sent[srcPort][:i+1]
rcvd[srcPort] = rcvd[srcPort][:i+1]
hopVector = hopVector[:i+1]
@@ -783,7 +763,7 @@ func main() {
if len(lossyPathHops) > 0 {
if *jsonOutput {
- printLossyPathsJson(lossyPathSent, lossyPathRcvd, lossyPathHops, lastClosed+1)
+ printLossyPathsJSON(lossyPathSent, lossyPathRcvd, lossyPathHops, lastClosed+1)
} else {
printLossyPaths(lossyPathSent, lossyPathRcvd, lossyPathHops, *maxColumns, lastClosed+1)
}
diff --git a/tcp.go b/tcp.go
index 9514bea..87cfc33 100644
--- a/tcp.go
+++ b/tcp.go
@@ -27,10 +27,8 @@ const (
URG = 1 << 5
)
-//
-// Define the TCP header struct
-//
-type TcpHeader struct {
+// TCPHeader defines the TCP header struct
+type TCPHeader struct {
Source uint16
Destination uint16
SeqNum uint32
@@ -46,8 +44,8 @@ type TcpHeader struct {
//
// create & serialize a TCP header, compute and fill in the checksum (v4/v6)
//
-func makeTcpHeader(af string, srcAddr, dstAddr *net.IP, srcPort, dstPort int, ts uint32) []byte {
- tcpHeader := TcpHeader{
+func makeTCPHeader(af string, srcAddr, dstAddr *net.IP, srcPort, dstPort int, ts uint32) []byte {
+ TCPHeader := TCPHeader{
Source: uint16(srcPort), // Random ephemeral port
Destination: uint16(dstPort),
SeqNum: ts,
@@ -61,15 +59,15 @@ func makeTcpHeader(af string, srcAddr, dstAddr *net.IP, srcPort, dstPort int, ts
}
// temporary bytes for checksum
- bytes := tcpHeader.Serialize()
- tcpHeader.Checksum = tcpChecksum(af, bytes, srcAddr, dstAddr)
+ bytes := TCPHeader.Serialize()
+ TCPHeader.Checksum = tcpChecksum(af, bytes, srcAddr, dstAddr)
- return tcpHeader.Serialize()
+ return TCPHeader.Serialize()
}
-// Parse packet into TcpHeader structure
-func parseTcpHeader(data []byte) *TcpHeader {
- var tcp TcpHeader
+// Parse packet into TCPHeader structure
+func parseTCPHeader(data []byte) *TCPHeader {
+ var tcp TCPHeader
r := bytes.NewReader(data)
@@ -96,10 +94,8 @@ func parseTcpHeader(data []byte) *TcpHeader {
return &tcp
}
-//
-// Emit raw bytes for the header
-//
-func (tcp *TcpHeader) Serialize() []byte {
+// Serialize emits raw bytes for the header
+func (tcp *TCPHeader) Serialize() []byte {
buf := new(bytes.Buffer)
binary.Write(buf, binary.BigEndian, tcp.Source)