SHARE
TWEET

Untitled

a guest Dec 10th, 2019 104 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package main
  2.  
  3. import (
  4.     "errors"
  5.     "flag"
  6.     "fmt"
  7.     c "github.com/fatih/color"
  8.     trace "github.com/pl0th/go-traceroute"
  9.     "golang.org/x/net/icmp"
  10.     "golang.org/x/net/ipv4"
  11.     "golang.org/x/net/ipv6"
  12.     "math/rand"
  13.     "net"
  14.     "strconv"
  15.     "time"
  16. )
  17.  
  18.  
  19. type TraceData struct {
  20.     Hops    [][]Hop
  21.     Dest    net.IP
  22.     Timeout time.Duration
  23.     Tries   int
  24.     MaxTTL  int
  25.     Port    int
  26.     Proto   string
  27.     IPv     string
  28. }
  29.  
  30. // Hop represents a path between a source and a destination.
  31. type Hop struct {
  32.     TryNumber int
  33.     TTL       int
  34.     AddrIP    net.IP
  35.     AddrDNS   []string //net.IPAddr
  36.     Latency   time.Duration
  37.     Err       error
  38. }
  39.  
  40. // Exec returns TraceData with initialized Hops and inserts the IP version into the protocol
  41. func Exec(dest net.IP, timeout time.Duration, tries int, maxTTL int, proto string, port int) (data TraceData) {
  42.     data = TraceData{
  43.         Hops:    make([][]Hop, tries),
  44.         Dest:    dest,
  45.         Timeout: timeout,
  46.         Tries:   tries,
  47.         MaxTTL:  maxTTL,
  48.         Port:    port,
  49.         Proto:   proto,
  50.     }
  51.     if dest.To4() == nil {
  52.         data.IPv = "6"
  53.     } else {
  54.         data.IPv = "4"
  55.     }
  56.     return
  57. }
  58.  
  59. // Next executes the doHop method for every try.
  60. func (data *TraceData) Next() (err error) {
  61.     ttl := len(data.Hops[0]) + 1
  62.     if ttl > data.MaxTTL {
  63.         return errors.New("Maximum TTL reached")
  64.     }
  65.     for try := 0; try < data.Tries; try++ {
  66.         currentHop, err := doHop(ttl, data.Dest, data.Timeout, data.Proto, data.Port, data.IPv)
  67.         if err != nil {
  68.             return err
  69.         }
  70.         if currentHop.Err == nil {
  71.             currentHop.AddrDNS, _ = net.LookupAddr(currentHop.AddrIP.String()) // maybe use memoization
  72.         }
  73.         currentHop.TryNumber = try
  74.         data.Hops[try] = append(data.Hops[try], currentHop)
  75.     }
  76.     return
  77. }
  78.  
  79. func doHop(ttl int, dest net.IP, timeout time.Duration, proto string, port int, ipv string) (currentHop Hop, err error) {
  80.     var destString string
  81.     if port == 0 {
  82.         destString = dest.String()
  83.     } else {
  84.         destString = dest.String() + ":" + strconv.Itoa(port)
  85.     }
  86.     req := []byte{}
  87.     dialProto := proto
  88.  
  89.     if proto == "udp" {
  90.         req = []byte("TABS")
  91.         dialProto += ipv
  92.     } else if proto == "icmp" {
  93.         dialProto = "ip" + ipv + ":" + proto
  94.     } else {
  95.         return currentHop, errors.New("protocol not implemented")
  96.     }
  97.  
  98.     conn, err := net.Dial(dialProto, destString)
  99.     if err != nil {
  100.         return
  101.     }
  102.     defer conn.Close()
  103.  
  104.     listenAddress := "0.0.0.0"
  105.  
  106.     if ipv == "4" {
  107.         newConn := ipv4.NewConn(conn)
  108.         if err = newConn.SetTTL(ttl); err != nil {
  109.             return
  110.         }
  111.         if proto == "icmp" {
  112.             req, err = createICMPEcho(ipv4.ICMPTypeEcho)
  113.             if err != nil {
  114.                 return
  115.             }
  116.         }
  117.     } else if ipv == "6" {
  118.         listenAddress = "::0"
  119.         newConn := ipv6.NewConn(conn)
  120.         if err = newConn.SetHopLimit(ttl); err != nil {
  121.             return
  122.         }
  123.         if proto == "icmp" {
  124.             req, err = createICMPEcho(ipv6.ICMPTypeEchoRequest)
  125.             if err != nil {
  126.                 return
  127.             }
  128.         }
  129.     }
  130.  
  131.     packetConn, err := icmp.ListenPacket("ip"+ipv+":"+"icmp", listenAddress)
  132.     if err != nil {
  133.         return
  134.     }
  135.     defer packetConn.Close()
  136.  
  137.     start := time.Now()
  138.     _, err = conn.Write(req)
  139.  
  140.     if err != nil {
  141.         return
  142.     }
  143.     if err = packetConn.SetDeadline(time.Now().Add(timeout)); err != nil {
  144.         return
  145.     }
  146.  
  147.     readBytes := make([]byte, 1500)                     // 1500 Bytes ethernet MTU
  148.     _, sAddr, connErr := packetConn.ReadFrom(readBytes) // first return value (Code) might be useful
  149.  
  150.     latency := time.Since(start)
  151.  
  152.     currentHop = Hop{
  153.         TTL:     ttl,
  154.         Latency: latency,
  155.         Err:     connErr,
  156.     }
  157.  
  158.     if connErr == nil {
  159.         currentHop.AddrIP = net.ParseIP(sAddr.String())
  160.         if currentHop.AddrIP == nil {
  161.             currentHop.Err = errors.New("timeout reached")
  162.         }
  163.     }
  164.  
  165.     return currentHop, err
  166. }
  167.  
  168. // All executes all doHops for all tries.
  169. func (data *TraceData) All() (err error) {
  170.     for try := 0; try < data.Tries; try++ {
  171.         for ttl := 1; ttl <= data.MaxTTL; ttl++ {
  172.             currentHop, err := doHop(ttl, data.Dest, data.Timeout, data.Proto, data.Port, data.IPv)
  173.             if err != nil {
  174.                 return err
  175.             }
  176.             if currentHop.Err == nil {
  177.                 currentHop.AddrDNS, _ = net.LookupAddr(currentHop.AddrIP.String()) // maybe use memoization
  178.             }
  179.             currentHop.TryNumber = try
  180.             data.Hops[try] = append(data.Hops[try], currentHop)
  181.             if currentHop.Err == nil && data.Dest.Equal(currentHop.AddrIP) {
  182.                 break
  183.             }
  184.         }
  185.     }
  186.     return
  187. }
  188.  
  189. func createICMPEcho(ICMPTypeEcho icmp.Type) (req []byte, err error) {
  190.     echo := icmp.Message{
  191.         Type: ICMPTypeEcho, Code: 0,
  192.         Body: &icmp.Echo{
  193.             ID:   rand.Int(),
  194.             Seq:  1, // TODO Sequence should be incremented every Hop & the id should be changed on every try(not random but different)
  195.             Data: []byte("TABS"),
  196.         }}
  197.  
  198.     req, err = echo.Marshal(nil)
  199.     return
  200. }
  201.  
  202. var(
  203.     host = flag.String("h","www.google.com","")
  204.     ttl = flag.Int("T", 64, "")
  205.     timeout = flag.Float64("t", 3, "")
  206.     tries = flag.Int("tr",3, "")
  207.     colour = flag.Bool("c",true, "")
  208. )
  209.  
  210.  
  211. var usage = ``
  212.  
  213. func main() {
  214.     //app.Flags = []fmt.Flag{
  215.     //  cli.IntFlag{
  216.     //      Name:  "ttl, T",
  217.     //      Value: 64,
  218.     //      Usage: "sets the max. TTL value",
  219.     //  },
  220.     //  cli.Float64Flag{
  221.     //      Name:  "timeout, o",
  222.     //      Value: 3,
  223.     //      Usage: "sets the timeout for the icmp echo request in seconds",
  224.     //  },
  225.     //  cli.IntFlag{
  226.     //      Name:  "tries, t",
  227.     //      Value: 3,
  228.     //      Usage: "sets the amount of tries",
  229.     //  },
  230.     //  cli.StringFlag{
  231.     //      Name:  "protocol, P",
  232.     //      Value: "icmp",
  233.     //      Usage: "sets the request protocol",
  234.     //  },
  235.     //  cli.IntFlag{
  236.     //      Name:  "port, p",
  237.     //      Value: 33434,
  238.     //      Usage: "sets the port for udp requests",
  239.     //  },
  240.     //  cli.BoolFlag{
  241.     //      Name:        "colour, c",
  242.     //      Usage:       "disables colour",
  243.     //      Destination: &c.NoColor,
  244.     //  },
  245.     //}
  246.  
  247.  
  248.     flag.Usage = func() {
  249.         fmt.Printf(usage)
  250.     }
  251.     flag.Parse()
  252.  
  253.  
  254.  
  255.     ip := net.ParseIP(*host)
  256.     if ip == nil {
  257.         ips, err := net.LookupIP(*host)
  258.         if err != nil || len(ips) == 0 {
  259.             c.Yellow("Please provide a valid IP address or fqdn")
  260.             return
  261.         }
  262.         ip = ips[0]
  263.     }
  264.  
  265.     traceData := trace.TraceData{}
  266.     traceData = trace.Exec(ip, time.Duration((*timeout)*float64(time.Second.Nanoseconds())), *tries, *ttl, "icmp", 0)
  267.     hops := make([][]printData, 0)
  268.     err := traceData.Next()
  269.     Loop:
  270.         for idxTry := 0; err == nil; err = traceData.Next() {
  271.             usedIPs := make(map[string][]time.Duration)
  272.             hops = append(hops, make([]printData, 0))
  273.             for idx := 0; idx < traceData.Tries; idx++ {
  274.                 hop := traceData.Hops[idx][len(hops)-1]
  275.                 if len(hop.AddrDNS) == 0 {
  276.                     traceData.Hops[idx][len(hops)-1].AddrDNS = append(hop.AddrDNS, "no dns entry found")
  277.                 }
  278.  
  279.                 usedIPs[hop.AddrIP.String()] = append(usedIPs[hop.AddrIP.String()], hop.Latency)
  280.                 hops[len(hops)-1] = append(hops[len(hops)-1], printData{[]time.Duration{hop.Latency}, 1, hop})
  281.             }
  282.             for idx := 0; idx < traceData.Tries; idx++ {
  283.                 hop := traceData.Hops[idx][len(hops)-1]
  284.                 if _, ok := usedIPs[hop.AddrIP.String()]; ok {
  285.                     addrString := fmt.Sprintf("%v (%v) ", c.YellowString(hop.AddrIP.String()), c.CyanString(hop.AddrDNS[0]))
  286.                     if hop.AddrIP == nil {
  287.                         addrString = c.RedString("no response ")
  288.                     }
  289.  
  290.                     fmt.Printf("%v: %v", idxTry, addrString)
  291.                     for _, lat := range usedIPs[hop.AddrIP.String()] {
  292.                         latString, formString := lat.String(), ""
  293.                         if lat > time.Second {
  294.                             formString = fmt.Sprintf("%v ", latString[:4]+latString[len(latString)-1:])
  295.                         } else if lat < time.Millisecond && lat > time.Nanosecond {
  296.                             formString = fmt.Sprintf("%v ", latString[:4]+latString[len(latString)-3:])
  297.                         } else {
  298.                             formString = fmt.Sprintf("%v ", latString[:4]+latString[len(latString)-2:])
  299.                         }
  300.                         fmt.Printf(c.MagentaString(formString)) //┬Ás
  301.                     }
  302.                     fmt.Println()
  303.                 }
  304.                 delete(usedIPs, hop.AddrIP.String())
  305.                 if traceData.Dest.Equal(hop.AddrIP) && traceData.Tries == idx+1 {
  306.                     break Loop
  307.                 }
  308.             }
  309.             idxTry++
  310.         }
  311.         if err != nil {
  312.             c.Yellow("Please make sure you run this command as root")
  313.             return
  314.         }
  315.         return
  316. }
  317.  
  318. type printData struct {
  319.     latencies []time.Duration
  320.     count     int
  321.     trace.Hop
  322. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top