#!/bin/env ruby require 'timeout' require 'set' require 'socket' TRACEROUTE=`which traceroute`.chomp TIMES=3 TIMEOUT=60 def traceroute host `#{TRACEROUTE} -n #{host}` end class TraceViz def initialize(times,timeout) @times,@timeout = times,timeout @edges = Set.new @nodes = Set.new @targets = Set.new @this_host = Socket.gethostname @targets << @this_host end def trace host @times.times do |i| STDERR.puts "Trace ##{i+1} for #{host}" Timeout::timeout(@timeout) do process_trace(host,traceroute(host)) end rescue nil end end def process_trace host,trace @targets << host trace = [@this_host] + trace.collect do |line| line=line.split line[0].to_i > 0 && line[1] != "*" ? line[1] : nil end.compact trace << host trace.each {|h| @nodes << h } trace.each_cons(2) {|h1,h2| @edges << [h1,h2] } end def to_dot res = "digraph G {" @edges.each { |h1,h2| res << " \"#{h1}\"->\"#{h2}\"\n" } @nodes.each do |n| color = @targets.member?(n) ? "lightblue" : "lightgrey" res << " \"#{n}\" [style=filled fillcolor=#{color}]\n" end res << "}" end end tv = TraceViz.new(TIMES,TIMEOUT) ARGV.each {|host| tv.trace(host) } puts tv.to_dot