Module: EM::TracerouteHandler

Defined in:
lib/emtraceroute/handler.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#deferredObject (readonly)

Returns the value of attribute deferred.



2
3
4
# File 'lib/emtraceroute/handler.rb', line 2

def deferred
  @deferred
end

Instance Method Details

#hop_found(hop, ip, icmp) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/emtraceroute/handler.rb', line 63

def hop_found(hop, ip, icmp)
  hop.remote_ip = ip
  hop.remote_icmp = icmp

  if ip && icmp
    hop.found = Time.now.to_f

    if @settings.fetch "geoip_lookup"

      url = "http://freegeoip.net/json/#{ip.src}"

      page = open(url).read
      d = JSON.load page

      hop.location = [d["country_name"], d["region_name"], d["city"]].select do |s|
        s && !(s.empty?)
      end.join(", ").encode("utf-8")
    end
  end

  ttl = hop.ttl + 1
  tail = @hops.last(2)
  if  tail.size == 2 && tail.first.remote_ip == ip ||
      (ttl > (@settings.fetch("max_hops", 30) + 1))
    done = true
  else
    done = false
  end

  unless done
    if(cb = @settings.fetch "hop_callback")
      cb.call(hop)
    end
  end

  unless @waiting
    if @deferred
      @deferred.set_deferred_status :succeeded, @hops
      @deferred = nil
    end
    EM.stop
  else
    @out_queue << EM::Traceroute::Hop.new(@target, ttl)
  end
rescue
  detach
end

#hop_timeout(*ign) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/emtraceroute/handler.rb', line 111

def hop_timeout *ign
  hop = @hops.last
  unless hop.found
    if hop.tries < @settings.fetch("max_tries")
      # retry
      @out_queue << hop
    else
      # give up and move forward
      hop_found(hop, nil, nil)
    end
  end
end

#initialize(target, settings) ⇒ Object



3
4
5
6
# File 'lib/emtraceroute/handler.rb', line 3

def initialize target, settings
  @target = target
  @settings = settings
end

#notify_readableObject



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/emtraceroute/handler.rb', line 19

def notify_readable
  return if !@waiting || @hops.empty?

  pkt = @io.recv(4096)

  # disassemble ip header
  ip = Iphdr.disassemble(pkt[0..19])
  unless ip.proto != Socket::IPPROTO_ICMP
    found = false
    
    # disassemble icmp header
    icmp = Icmphdr.disassemble(pkt[20..27])
    if icmp.type == 0 && icmp.id == @hops.last.icmp.id
      found = true
    elsif icmp.type == 11
      # disassemble referenced ip header
      ref =  Iphdr.disassemble(pkt[28..47])
      found = true if ref.dst == @target
    end

    @waiting = false if ip.src == @target

    hop_found(@hops.last, ip, icmp) if found
  end
end

#notify_writableObject



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/emtraceroute/handler.rb', line 45

def notify_writable
  if @waiting && !(@out_queue.empty?)
    hop = @out_queue.shift
    pkt = hop.pkt
    if  @hops.empty? || !(@hops.empty?) && hop.ttl != @hops.last.ttl
      @hops << hop
    end
    sockaddr = Socket.sockaddr_in(0, hop.ip.dst)
    @io.send(pkt, 0, sockaddr)

    timeout = @settings.fetch('timeout')
    EM.add_timer(timeout) { hop_timeout }
  end
end

#post_initObject



8
9
10
11
12
13
14
15
16
17
# File 'lib/emtraceroute/handler.rb', line 8

def post_init
  @hops = []
  @out_queue = []
  @waiting = true

  @deferred = EM::DefaultDeferrable.new

  # send first probe packet
  @out_queue << EM::Traceroute::Hop.new(@target, 1)
end

#unbindObject



60
61
# File 'lib/emtraceroute/handler.rb', line 60

def unbind
end