Guest User

Untitled

a guest
Dec 10th, 2019
124
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