scriptroute 0.4.14 → 0.4.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d192161acfbf508dfd7d953bc7ec1a219930d15
4
- data.tar.gz: a3c7cbd73442f9aa4cc263830a71b62023f08355
3
+ metadata.gz: e286d4b4fa4a450c8a2aaac1fe6987ae1ac8ed8b
4
+ data.tar.gz: af98fdafbc90ad8b9b528b0104851f3e5465e88e
5
5
  SHA512:
6
- metadata.gz: 3a98db9cec4c8d90da6c8958e68d063d3049c68d88ac612184abfef44a789f8b57120b2325625f3704c770db3a6557aa2ad6336d36655be28067426b0fff69f0
7
- data.tar.gz: 77be1bb191576fa8890c8395c1d93577e060cfe4a846989c74c51ae24797e3dbf1c78f091dbedc33ef72c3aa78c373ba391cfe1ee1eed3dd88c70815dee82425
6
+ metadata.gz: ab994b7c31ffdc3b72622689776bd70cd3545bd8abfe6c046112130cbae57874773b3c28b399206e1fbf59079bd1cefd1573bcaa5eee244f2f88d6826884a5f0
7
+ data.tar.gz: f8f93fc4ef3c998d1a622e476ff1a414bce2fd3ace0720ac7a83f8e2ad44c8bb006d895c7aeced6cad670eeeea07f8c0eca8a534827d5404e5465199845a8ff9
@@ -0,0 +1,37 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'scriptroute'
4
+ require 'scriptroute/packets'
5
+
6
+ if ARGV.empty? then
7
+ puts "usage: #{$0} address_or_hostname"
8
+ exit 1
9
+ end
10
+
11
+ probe = Scriptroute::UDP6.new(12)
12
+
13
+ probe.ip6_dst = ARGV[0]
14
+
15
+ unreach = false
16
+
17
+ puts "Traceroute to #{ARGV[0]} (#{probe.ip6_dst})"
18
+
19
+ catch(:unreachable) do
20
+ ( 1..64 ).each { |ttl|
21
+ ( 1..3 ).each { |rep|
22
+ probe.ip_ttl = ttl
23
+ packets = Scriptroute::send_train([ Struct::DelayedPacket.new(0,probe) ])
24
+ response = (packets[0].response) ? packets[0].response.packet : nil
25
+ if(response) then
26
+ puts '%d %s %5.3f ms' % [ ttl, response.ip6_src, packets[0].rtt * 1000.0 ]
27
+ if(response.is_a?(Scriptroute::ICMP6)) then
28
+ unreach = true if(response.icmp_type == Scriptroute::ICMP6::ICMP6_DST_UNREACH)
29
+ end
30
+ else
31
+ puts ttl.to_s + ' *'
32
+ end
33
+ $stdout.flush
34
+ }
35
+ throw :unreachable if(unreach)
36
+ }
37
+ end
@@ -105,15 +105,15 @@ end
105
105
  # useful value in calculating rtt when NTP's adjustments
106
106
  # via skew cause trouble.
107
107
  attr_accessor :tsc
108
- # @return [IPv4]
108
+ # @return [IP]
109
109
  attr_accessor :packet
110
110
 
111
111
  # @param time [Float,nil] Seconds since the epoch, or nil if we didn't see the packet leave due to pcap (happens)
112
112
  # @param tsc [Fixnum,nil] Value of the cycle counter (rdtsc) or nil if not supported
113
- # @param packet [IPv4] The packet received.
113
+ # @param packet [IP] The packet received.
114
114
  def initialize(time, tsc, packet)
115
115
  raise ArgumentError, "no packet" unless packet
116
- raise ArgumentError, "packet of the wrong class" unless packet.is_a?(IPv4)
116
+ raise ArgumentError, "packet of the wrong class" unless packet.is_a?(IP)
117
117
  @time = time
118
118
  @tsc = tsc
119
119
  @packet = packet
@@ -225,15 +225,20 @@ end
225
225
  def Scriptroute::dns_lookup(name)
226
226
  Resolv.getaddress name
227
227
  end
228
+ private
229
+ @@config = nil
230
+ public
228
231
  # @return [Hash] the configuration of the running daemon,
229
232
  # useful for checking rate limiting parameters or filters
230
233
  # if a specially configured daemon is needed.
231
234
  def Scriptroute::DaemonConfig
232
235
  ret = nil
233
- with_scriptroute_connection do |c|
234
- ret = c.get_config
236
+ unless @@config then
237
+ with_scriptroute_connection do |c|
238
+ @@config = c.get_config
239
+ end
235
240
  end
236
- ret
241
+ @@config
237
242
  end
238
243
  # no op for backward compatibility with the srinterpreter version
239
244
  # that had a dedicated packet instance
@@ -266,7 +271,7 @@ end
266
271
  delay = boxcar[:delay]
267
272
  packet = boxcar[:packet]
268
273
  raise "no packet" unless packet
269
- if packet.is_a?(Scriptroute::IPv4) then
274
+ if packet.is_a?(Scriptroute::IP) then
270
275
  packet = packet.marshal
271
276
  end
272
277
  raise "packet is #{packet.class}, not a string" unless packet.is_a?(String)
@@ -300,7 +305,7 @@ end
300
305
  io = ($4 == '>') ? 0 : 1
301
306
  st = $5
302
307
  packet_string = Base64.strict_decode64(st)
303
- p = IPv4.creator(packet_string)
308
+ p = IP.creator(packet_string)
304
309
  tv_s = nil if tv_s < 0 # didn't see it leave.
305
310
  tp = TimedPacket.new(tv_s, rdtsc, p)
306
311
  if io == 0 then
@@ -111,7 +111,7 @@ class Ally
111
111
  # a helper function to handle comparing ipid's, as they are
112
112
  # unsigned short counters that can wrap.
113
113
  # @return [Boolean]
114
- def before
114
+ def before(seq1,seq2)
115
115
  Ally.before(seq1,seq2)
116
116
  end
117
117
 
@@ -0,0 +1,58 @@
1
+ require 'ipaddr'
2
+ # require 'my-ipaddr'
3
+
4
+ class IPAddr4 < IPAddr
5
+ # subclass that trusts its initializer and assumes IPv4
6
+ def in_addr(addr)
7
+ if addr =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/
8
+ (($1.to_i << 24) + ($2.to_i << 16) + ($3.to_i << 8) + ($4.to_i))
9
+ else
10
+ nil
11
+ end
12
+ end
13
+ def initialize(addr)
14
+ @family = Socket::AF_INET
15
+ if( addr.kind_of?(String) ) then
16
+ prefix, len = addr.split('/')
17
+ @addr = in_addr(prefix)
18
+ if(len) then
19
+ mask_len!(len.to_i)
20
+ else
21
+ @mask_addr = IN4MASK
22
+ end
23
+ else
24
+ @addr = addr
25
+ @mask_addr = IN4MASK
26
+ end
27
+ end
28
+ # faster include method that only works for ipv4.
29
+ def include?(other)
30
+ if other.kind_of?(IPAddr)
31
+ other_addr = other.to_i
32
+ else # Not IPAddr - assume integer in same family as us
33
+ other_addr = other.to_i
34
+ end
35
+ return ((@addr & @mask_addr) == (other_addr & @mask_addr))
36
+ end
37
+ def eql?(other)
38
+ if other.kind_of?(IPAddr4) && @family != other.family
39
+ return false
40
+ end
41
+ return (@addr == other.to_i)
42
+ end
43
+ def hash
44
+ @addr.to_i
45
+ end
46
+ def to_s
47
+ # about twice as fast as the map/join based to_s.
48
+ # appears slightly faster than mask then shift.
49
+ "%d.%d.%d.%d" % [ (@addr >> 24) & 0xff, (@addr >> 16) & 0xff, (@addr >> 8) & 0xff, (0xff&@addr) ]
50
+ end
51
+ def ==(other)
52
+ if other.kind_of?(IPAddr4)
53
+ @addr == other.addr
54
+ else
55
+ @addr == other.to_i # dunno why.
56
+ end
57
+ end
58
+ end
@@ -2,10 +2,140 @@ module Scriptroute
2
2
  # a small library of routines for constructing packets
3
3
  # as strings to hand off to the interpreter.
4
4
 
5
- class IPv4
6
- IPPROTO_ICMP = 1
7
- IPPROTO_TCP = 6
5
+ class IP
6
+ IPPROTO_TCP = 6 # apply to both 4 and 6.
8
7
  IPPROTO_UDP = 17
8
+ def to_bytes
9
+ marshal
10
+ end
11
+ def IP.creator(str)
12
+ ip_vhl = str.unpack("c")[0]
13
+ ip_v = ((ip_vhl & 0xf0) >> 4)
14
+ if(ip_v == 4) then
15
+ IPv4.creator(str)
16
+ elsif(ip_v == 6) then
17
+ IPv6.creator(str)
18
+ else
19
+ raise "unknown IP version #%d in %s" % [ ip_v, str.unpack("C*").map { |c| "%x" % c }.join(' ') ]
20
+ end
21
+ end
22
+ end
23
+
24
+ class IPv4 < IP
25
+ IPPROTO_ICMP = 1
26
+ end
27
+
28
+ class IPv6 < IP
29
+ IPPROTO_ICMP6 = 58
30
+ attr_accessor :ip6_src, :ip6_hlim, :ip6_flow
31
+ attr_reader :ip6_dst
32
+ @@creators = Hash.new
33
+ def IPv6.creator(str)
34
+ flow, plen, nxt, hlim, saddr, daddr = str.unpack("Nncca16a16")
35
+ if(@@creators[nxt]) then
36
+ pkt = (@@creators[nxt]).call(str[40..40+plen])
37
+ pkt.ipv6_unmarshal(str)
38
+ pkt
39
+ else
40
+ raise "unknown IPv6 next header #%d in %s" % [ nxt, str.unpack("H*") ]
41
+ end
42
+ end
43
+ def ipv6_unmarshal(str)
44
+ @ip6_flow, @ip6_plen, @ip6_nxt, @ip6_hlim, ip6_saddr, ip6_daddr = str.unpack("Nncca16a16")
45
+ @ip6_src, @ip6_dst = [ip6_saddr, ip6_daddr].map { |addr| IPAddr.new_ntoh(addr) }
46
+ end
47
+ def initialize(p)
48
+ if(p.is_a?(Fixnum)) then
49
+ @ip6_src = @ip6_dst = @ip6flow = nil
50
+ @ip6_hlim = 64
51
+ @ip6_nxt = p
52
+ # actually, unlikely 7 or 13 are at the moment
53
+ # either, but let's start here.
54
+ $stderr.puts "unlikely v6 protocol header type #{p} is supported" unless [ 7, 13, 58 ].include?(p)
55
+ else
56
+ raise "need a next header type for constructing a v6 packet"
57
+ end
58
+ end
59
+ # for simplicity.
60
+ def ip_ttl=(ttl)
61
+ @ip6_hlim = ttl
62
+ end
63
+ def ip6_dst=(name_or_address)
64
+ if name_or_address.is_a?(IPAddr) then
65
+ if name_or_address.ipv4? then
66
+ @ip6_dst = name_or_address.ipv4_mapped # try to use it.
67
+ else
68
+ @ip6_dst = name_or_address
69
+ end
70
+ elsif Resolv::IPv6::Regex =~ name_or_address then
71
+ @ip6_dst = IPAddr.new(name_or_address, Socket::AF_INET6)
72
+ else
73
+ r = Resolv::DNS.new.getresource(name_or_address, Resolv::DNS::Resource::IN::AAAA)
74
+ if r then
75
+ @ip6_dst = IPAddr.new(r.address.to_s, Socket::AF_INET6)
76
+ else
77
+ raise "failed to lookup #{name_or_address} into a v6 address"
78
+ end
79
+ end
80
+ end
81
+ def marshal
82
+ # probably should force src/dst internal
83
+ # representation to be IPAddr via accessor methods
84
+ # rather than reconvert here.
85
+ puts "unlikely you wanted zero hlim" unless @ip6_hlim and @ip6_hlim > 0
86
+ puts "unlikely you wanted no next protocol" unless @ip6_nxt and @ip6_nxt > 0
87
+ puts "unlikely you wanted nil payload len" unless ip_payload_len
88
+ v6packet = [ 6 << 4, 0, 0, ip_payload_len, @ip6_nxt, @ip6_hlim,
89
+ IPAddr.new(@ip6_src, Socket::AF_INET6).hton,
90
+ IPAddr.new(@ip6_dst, Socket::AF_INET6).hton ].pack("ccnncca16a16")
91
+ end
92
+ def to_s
93
+ "%s -> %s hlim=%d" % [ (@ip6_src or "::0"), (@ip6_dst or "::0"), @ip6_hlim ]
94
+ end
95
+ end
96
+ class ICMP6 < IPv6
97
+ attr_reader :icmp_type, :icmp_code, :icmp_cksum
98
+ attr_reader :ip_payload_len
99
+ # type
100
+ ICMP6_ECHO = 128
101
+ ICMP6_ECHOREPLY = 129
102
+ ICMP6_DST_UNREACH = 1
103
+ ICMP6_PACKET_TOO_BIG = 2
104
+ ICMP6_TIME_EXCEEDED = 3
105
+ ICMP6_PARAM_PROB = 4
106
+
107
+ @@icmp6_creators = Hash.new
108
+ @@creators[IPPROTO_ICMP6] = lambda { |hdr|
109
+ icmp_type, icmp_code, icmp_cksum = hdr.unpack("CCn")
110
+ if(@@icmp6_creators[icmp_type]) then
111
+ pkt = @@icmp6_creators[icmp_type].call(hdr)
112
+ else
113
+ raise "unknown icmp6 type #%d" % icmp_type
114
+ end
115
+ }
116
+ def initialize(type_or_str)
117
+ if(type_or_str.is_a?(Fixnum)) then
118
+ @icmp_type = type_or_str
119
+ @icmp_code = 0
120
+ @icmp_cksum = 0
121
+ super(IPPROTO_ICMP6)
122
+ else
123
+ @icmp_type, @icmp_code, @icmp_cksum = type_or_str.unpack("CCn")
124
+ end
125
+ end
126
+ # @return [String] The packet in string form
127
+ def marshal
128
+ @icmp_type or raise "type is nil"
129
+ @icmp_code or raise "code is nil"
130
+ @icmp_cksum = 0
131
+ super + [ @icmp_type, @icmp_code, @icmp_cksum ].pack("CCn")
132
+ end
133
+ # @return [String]
134
+ def to_s
135
+ super + ": ICMP6: type %d code %d cksum %d" %[ @icmp_type, @icmp_code, @icmp_cksum ]
136
+ end
137
+ #instantiate echo instead.
138
+ private :marshal
9
139
  end
10
140
 
11
141
  class ICMP < IPv4
@@ -227,14 +357,22 @@ module Scriptroute
227
357
  ip_id, ip_off,
228
358
  ip_ttl, ip_p, ip_sum,
229
359
  ip_src, ip_dst = str.unpack("ccn" + "nn" + "ccn" + "N" + "N");
230
- ip_hl = ip_vhl & 0xf;
231
- if(@@creators[ip_p]) then
232
- pkt = (@@creators[ip_p]).call(str[(ip_hl * 4) .. ip_len])
233
-
234
- pkt.ipv4_unmarshal(str)
235
- pkt
360
+ ip_v = ((ip_vhl & 0xf0) >> 4)
361
+ if(ip_v == 4) then
362
+ ip_hl = ip_vhl & 0xf;
363
+ if(@@creators[ip_p]) then
364
+ pkt = (@@creators[ip_p]).call(str[(ip_hl * 4) .. ip_len])
365
+ pkt.ipv4_unmarshal(str)
366
+ pkt
367
+ else
368
+ raise "unknown IPv4 protocol #%d in %s" % [ ip_p, str.unpack("C*").map { |c| "%x" % c }.join(' ') ]
369
+ end
370
+ elsif(ip_v == 6) then
371
+ # probably should do this someplace above IPv4 creator.
372
+ puts "received v6 packet %s" % [ str.unpack("H*") ]
373
+ str
236
374
  else
237
- raise "unknown protocol #%d in %s" % [ ip_p, str.unpack("C*").map { |c| "%x" % c }.join(' ') ]
375
+ raise "unknown IP version #%d in %s" % [ ip_v, str.unpack("C*").map { |c| "%x" % c }.join(' ') ]
238
376
  end
239
377
  end
240
378
 
@@ -398,24 +536,14 @@ module Scriptroute
398
536
  end
399
537
  end
400
538
 
401
- class UDP < IPv4
539
+ module UDPgeneric
402
540
  # @return [Fixnum]
403
541
  attr_reader :uh_sport, :uh_dport, :uh_ulen, :uh_sum
404
542
  attr_writer :uh_dport, :uh_sum
405
543
 
406
- @@creators[IPPROTO_UDP] = lambda { |hdr|
407
- uh_sport, uh_dport, uh_ulen, uh_sum = hdr.unpack("nnnn")
408
- if uh_sport==123 || uh_dport==123 then
409
- p = NTP.new(hdr[8..hdr.length])
410
- p.udp_unmarshal(hdr)
411
- else
412
- p = UDP.new(hdr)
413
- end
414
- p
415
- }
416
-
417
544
  # @return [Fixnum] the udp data plus header length, uh_ulen
418
545
  def ip_payload_len
546
+ raise "ip_payload_len was nil when asked" unless @uh_ulen
419
547
  @uh_ulen
420
548
  end
421
549
 
@@ -431,7 +559,7 @@ module Scriptroute
431
559
  @uh_sport = 32945
432
560
  @uh_dport = 33434
433
561
  @uh_sum = 0
434
- super( IPPROTO_UDP )
562
+ super( Scriptroute::IP::IPPROTO_UDP )
435
563
  else
436
564
  @uh_sport, @uh_dport, @uh_ulen, @uh_sum = paylen_or_str.unpack("nnnn")
437
565
  end
@@ -445,12 +573,11 @@ module Scriptroute
445
573
  array_of_elements = [ @uh_sport, @uh_dport, @uh_ulen, @uh_sum ]
446
574
  raise "a UDP header field was unset" if array_of_elements.include?(nil)
447
575
  super + [ @uh_sport, @uh_dport, @uh_ulen, @uh_sum ].pack("nnnn") +
448
- if ( self.class == UDP ) then
576
+ if ( self.class == UDP or self.class == UDP6 ) then
449
577
  "\0" * ( @uh_ulen - 8 )
450
578
  else
451
579
  "" # the subclass will take care of it
452
580
  end
453
-
454
581
  end
455
582
 
456
583
  # Used for subclasses to set the UDP header fields.
@@ -468,6 +595,29 @@ module Scriptroute
468
595
 
469
596
  end
470
597
 
598
+ class UDP < IPv4
599
+ include UDPgeneric
600
+
601
+ @@creators[IPPROTO_UDP] = lambda { |hdr|
602
+ uh_sport, uh_dport, uh_ulen, uh_sum = hdr.unpack("nnnn")
603
+ if uh_sport==123 || uh_dport==123 then
604
+ p = NTP.new(hdr[8..hdr.length])
605
+ p.udp_unmarshal(hdr)
606
+ else
607
+ p = UDP.new(hdr)
608
+ end
609
+ p
610
+ }
611
+ end
612
+
613
+ class UDP6 < IPv6
614
+ include UDPgeneric
615
+
616
+ @@creators[IPPROTO_UDP] = lambda { |hdr|
617
+ UDP6.new(hdr)
618
+ }
619
+ end
620
+
471
621
  class TCP < IPv4
472
622
  attr_reader :th_sport, :th_dport, :th_sum, :th_seq, :th_ack,
473
623
  :th_win, :th_flags, :th_win, :th_sum, :th_urp
@@ -584,6 +734,38 @@ module Scriptroute
584
734
  super + ": ECHO: id %d seq %d len %d" % [ @icmp_id, @icmp_seq, @ip_payload_len ]
585
735
  end
586
736
  end
737
+ # Class for ping packets (echo and echo reply) much duplicated with ICMPecho
738
+ class ICMP6echo < ICMP6
739
+ # @return [Fixnum]
740
+ attr_reader :icmp_id, :icmp_seq
741
+ attr_writer :icmp_seq
742
+ @@icmp6_creators[ICMP6_ECHO] =
743
+ @@icmp6_creators[ICMP6_ECHOREPLY] = lambda { |hdr|
744
+ ICMP6echo.new(hdr)
745
+ }
746
+ def initialize(paylen_or_str = 0)
747
+ if(paylen_or_str.is_a?(Fixnum)) then
748
+ if( paylen_or_str < 0) then raise "payload length must be >= 0" end
749
+ @ip_payload_len = paylen_or_str + 4 + 4
750
+ @icmp_id = 666
751
+ @icmp_seq = 1
752
+ super(ICMP6_ECHO)
753
+ else
754
+ # x is skip forward a character.
755
+ @ip_payload_len = paylen_or_str.length - 8
756
+ @icmp_id, @icmp_seq = paylen_or_str.unpack("xxxxnn")
757
+ super(paylen_or_str)
758
+ end
759
+ end
760
+ # @return [String] The packet in string form
761
+ def marshal
762
+ super + [ @icmp_id, @icmp_seq ].pack("nn") + "\0" * ( @ip_payload_len - 4 - 4 )
763
+ end
764
+ # @return [String]
765
+ def to_s
766
+ super + ": ECHO6: id %d seq %d len %d" % [ @icmp_id, @icmp_seq, @ip_payload_len ]
767
+ end
768
+ end
587
769
 
588
770
  class ICMPtstamp < ICMP
589
771
  # @return [Fixnum]
@@ -666,6 +848,33 @@ module Scriptroute
666
848
  end
667
849
  end
668
850
 
851
+ class ICMP6unreach< ICMP6
852
+ # @return [IPv4] The packet header embedded within the ICMP unreachable error message.
853
+ attr_reader :contents
854
+ @@icmp6_creators[ICMP6_DST_UNREACH] = @@icmp6_creators[ICMP6_TIME_EXCEEDED] =
855
+ lambda { |hdr|
856
+ ICMP6unreach.new(hdr)
857
+ }
858
+ # Can create an unreachable only from string contents, never from filling in fields given a size.
859
+ # param string [String] the contents of the received packet.
860
+ def initialize(string)
861
+ # first four are code, type, checksum.
862
+ # second four are undefined
863
+ @contents = IPv6.creator(string[8..-1])
864
+ super(string)
865
+ end
866
+ # Cannot marshal an unreachable packet for transmission; raises an exception.
867
+ # @return [void]
868
+ def marshal
869
+ raise "not supported"
870
+ end
871
+ # @return [String] formats the packet and the embedded packet as a string.
872
+ def to_s
873
+ super + " ( " + @contents.to_s + " )"
874
+ end
875
+ end
876
+
877
+
669
878
  class NTP < UDP
670
879
  # @return [Fixnum]
671
880
  attr_accessor :leap_indicator, :version_number, :mode, :stratum
@@ -790,7 +999,15 @@ module Scriptroute
790
999
  # this method implemented in pure ruby regardless of interpreter state.
791
1000
  # @return [String]
792
1001
  def to_s
793
- "%s @%5.6f -> %s +%5.6f" % [@probe, @probe.time, (@response or "<none>"), (rtt or "-1")]
1002
+ if @probe then
1003
+ if(@probe.time) then
1004
+ "%s @%5.6f -> %s +%5.6f" % [@probe.packet, @probe.time, (@response ? @response.packet : "<none>"), (rtt or "-1")]
1005
+ else
1006
+ "%s (not seen leaving) -> %s" % [@probe.packet, (@response or "<none>")]
1007
+ end
1008
+ else
1009
+ "bizarre nothingness. no probe."
1010
+ end
794
1011
  end
795
1012
  end
796
1013
  end
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/ruby -w
2
+
3
+ require 'test/unit'
4
+ require 'scriptroute/commando'
5
+
6
+ $SAFE = 2
7
+
8
+
9
+ class ScriptrouteCommandoTest < Test::Unit::TestCase
10
+
11
+ def test_one
12
+
13
+ c = Commando.new([ "--start-speed", 3 ],
14
+ [ CommandoVar.new( "--start-speed", "Kbps rate to start" , "$StartSpeedKbps", 20),
15
+ CommandoVar.new( "--train-length", "Filler packets in train" , "$TrainLength", 20),
16
+ CommandoVar.new( "--hop", "Specific hop to study (ttl=hop and hop-1), 0 for e2e", "$Hop", 0 ),
17
+ CommandoVar.new( [ "--verbose", "-v" ], "print gobs of messages" , "$VERBOSE", false) ],
18
+ "destination-host")
19
+
20
+ raise "failed to set dollar startspeedkbps" unless($StartSpeedKbps == 3)
21
+ raise "failed to default dollar TrainLength" unless($TrainLength == 20)
22
+ raise "failed to construct Commando c" unless c
23
+
24
+ end
25
+ end
26
+
@@ -2,10 +2,11 @@
2
2
  require 'test/unit'
3
3
  require 'scriptroute'
4
4
  require 'scriptroute/nameify'
5
+ require 'ipaddr'
5
6
 
6
7
  class ScriptrouteTest < Test::Unit::TestCase
7
8
  def test_abba # be first
8
- unless Scriptroute::is_daemon_running?
9
+ unless Scriptroute.is_daemon_running?
9
10
  exit
10
11
  end
11
12
 
@@ -21,8 +22,8 @@ class ScriptrouteTest < Test::Unit::TestCase
21
22
  end
22
23
  def test_abc_get_config
23
24
  raise "no config returned" unless Scriptroute::DaemonConfig()
24
- raise "config not a hash" unless Scriptroute::DaemonConfig.is_a?(Hash)
25
- raise "config lacks an expected key" unless Scriptroute::DaemonConfig['Filter.listenfilter']
25
+ raise "config not a hash" unless Scriptroute::DaemonConfig().is_a?(Hash)
26
+ raise "config lacks an expected key" unless Scriptroute::DaemonConfig().has_key?('Filter.listen_filter')
26
27
  end
27
28
  def test_ally
28
29
  verdict = Scriptroute::Ally.new('128.8.126.92', '128.8.126.104')
@@ -34,6 +35,7 @@ class ScriptrouteTest < Test::Unit::TestCase
34
35
  end
35
36
 
36
37
  def test_forbidden
38
+ $stderr.puts "the next line should be 'ERROR: packet administratively filtered'..."
37
39
  i = Scriptroute::ICMPecho.new(0)
38
40
  # an address ending with .255 seems more likely to be broadcast.
39
41
  i.ip_dst = 0x805f02ff
@@ -87,31 +89,35 @@ class ScriptrouteTest < Test::Unit::TestCase
87
89
  puts m.length.to_s + " " + m.gsub(/./) { |b| "%x " % b[0].to_i }
88
90
  puts m.length.to_s + " " + m.bytes.map { |b| "%x " % b }.join if has_bytes ## 1.9
89
91
  # puts "decode: " + Scriptroute::stringpacket(m)
90
- puts "encode: " + Scriptroute::pkt_from_string(m).to_s
92
+ q = Scriptroute::pkt_from_string(m)
91
93
 
92
94
  m = Scriptroute::ICMPtstamp.new.marshal
93
95
  puts m.length.to_s + " " + m.gsub(/./) { |b| "%x " % b[0].to_i }
94
96
  puts m.length.to_s + " " + m.bytes.map { |b| "%x " % b }.join if has_bytes ## 1.9
95
97
  # puts "decode: " + Scriptroute::stringpacket(m)
96
- puts "encode: " + Scriptroute::pkt_from_string(m).to_s
98
+ q = Scriptroute::pkt_from_string(m)
99
+ # garbage. puts "encode: " + Scriptroute::pkt_from_string(m).to_s
97
100
 
98
101
  m = Scriptroute::TCP.new.marshal
99
102
  puts m.length.to_s + " " + m.gsub(/./) { |b| "%x " % b[0].to_i }
100
103
  puts m.length.to_s + " " + m.bytes.map { |b| "%x " % b }.join if has_bytes ## 1.9
101
104
  # puts "decode: " + Scriptroute::stringpacket(m)
102
- puts "encode: " + Scriptroute::pkt_from_string(m).to_s
105
+ # garbage. puts "encode: " + Scriptroute::pkt_from_string(m).to_s
106
+ q = Scriptroute::pkt_from_string(m)
103
107
 
104
108
  m = Scriptroute::UDP.new.marshal
105
109
  puts m.length.to_s + " " + m.gsub(/./) { |b| "%x " % b[0].to_i }
106
110
  puts m.length.to_s + " " + m.bytes.map { |b| "%x " % b }.join if has_bytes ## 1.9
107
111
  # puts "decode: " + Scriptroute::stringpacket(m)
108
- puts "encode: " + Scriptroute::pkt_from_string(m).to_s
112
+ # garbage. puts "encode: " + Scriptroute::pkt_from_string(m).to_s
113
+ q = Scriptroute::pkt_from_string(m)
109
114
 
110
115
  m = Scriptroute::UDP.new(8).marshal
111
116
  puts m.length.to_s + " " + m.gsub(/./) { |b| "%x " % b[0].to_i }
112
117
  puts m.length.to_s + " " + m.bytes.map { |b| "%x " % b }.join if has_bytes ## 1.9
113
- puts "decode: " + Scriptroute::IPv4.creator(m).to_s
114
- puts "encode: " + Scriptroute::pkt_from_string(m).to_s
118
+ # garbage. puts "decode: " + Scriptroute::IPv4.creator(m).to_s
119
+ q = Scriptroute::pkt_from_string(m)
120
+ # garbage. puts "encode: " + Scriptroute::pkt_from_string(m).to_s
115
121
 
116
122
  t = Scriptroute::TCP.new
117
123
  opt = Scriptroute::Timestamp_option.new(1)
@@ -125,7 +131,8 @@ class ScriptrouteTest < Test::Unit::TestCase
125
131
  puts m.length.to_s + " " + m.gsub(/./) { |b| "%x " % b[0].to_i }
126
132
  puts m.length.to_s + " " + m.bytes.map { |b| "%x " % b }.join if has_bytes ## 1.9
127
133
  # puts "decode: " + Scriptroute::stringpacket(m)
128
- puts "encode: " + Scriptroute::pkt_from_string(m).to_s
134
+ # garbage. puts "encode: " + Scriptroute::pkt_from_string(m).to_s
135
+ q = Scriptroute::pkt_from_string(m)
129
136
 
130
137
  #1.times { |i|
131
138
  # m=t.marshal
@@ -148,8 +155,157 @@ class ScriptrouteTest < Test::Unit::TestCase
148
155
  def test_nameify
149
156
  puts Scriptroute.nameify("12.123.203.170")
150
157
  end
158
+
159
+ # pretty much checks whether the packet gets filled in.
160
+ # manually constructed with pack, rather than via
161
+ # scriptroute/packets
162
+ def test_v6
163
+ daddr = IPAddr.new "ff02::fb" # "fd00::230:67ff:febb:7d18"
164
+ # daddr = IPAddr.new "fe80::60c:ceff:fee4:a62" # wlp
165
+ daddr = IPAddr.new "fd00::60c:ceff:fee4:a62" # wlp
166
+ saddr = IPAddr.new "::0"
167
+ # saddr = IPAddr.new "fd00::230:67ff:febb:7d18" # zar
168
+ # saddr = IPAddr.new "fe80::230:67ff:febb:7d18" # fd00::230:67ff:febb:7d18"
169
+ payload_len = 40 #
170
+
171
+ # hard coded the cksum.
172
+ icmp = [ Scriptroute::ICMP6::ICMP6_ECHO, 0, 0xc12b, 0, 1 ].pack("ccnnn") + ( "\0" * 56 )
173
+ v6packet = [ 6 << 4, 0, 0, icmp.length, Scriptroute::IPv6::IPPROTO_ICMP6,
174
+ 64, saddr.hton, daddr.hton ].pack("ccnncca16a16") + icmp
175
+
176
+ raise "too short (#{v6packet.length})" unless v6packet.length >= 40
177
+ puts v6packet.length
178
+ puts v6packet.unpack("H*")
179
+
180
+ p = Scriptroute::send_train([ Struct::DelayedPacket.new(0, v6packet) ])
181
+ puts p
182
+
183
+ p[0].probe or raise "couldn't manage sending a v6 probe"
184
+ p[0].probe.packet or raise "couldn't manage sending a v6 probe packet"
185
+ p[0].probe.packet.ip6_src or raise "v6 probe packet lacks a source"
186
+ p[0].probe.packet.ip6_src != IPAddr.new("::0") or raise "v6 probe packet source seems to be unset."
187
+ p[0].probe.packet.icmp_cksum != 0 or raise "v6 probe packet 99.99% likely unset checksum."
188
+ end
189
+
190
+ # tries to build an medium level of easiness ipv6 ping.
191
+ def test_v6_lookup
192
+ daddr = nil
193
+ Resolv::DNS.open do |dns|
194
+ ress = dns.getresources "www.google.com", Resolv::DNS::Resource::IN::AAAA
195
+ ress.each { |r| daddr = r.address.to_s }
196
+ end
197
+ raise "no address" unless daddr
198
+ p = Scriptroute::ICMP6echo.new(20)
199
+ p.ip6_dst = daddr
200
+ begin
201
+ r = Scriptroute::send_train([ Struct::DelayedPacket.new(0, p) ])
202
+ puts r
203
+ rescue Scriptroute::ScriptrouteError => e
204
+ if e.to_s =~ /unreachable/ then
205
+ puts "Expected ERROR when host supports v6 but lacks routes to the outside world."
206
+ else
207
+ puts "rescued unexpected error: " + e.to_s
208
+ end
209
+ end
210
+ end
211
+ def test_v6_localhost
212
+ p = Scriptroute::ICMP6echo.new(20)
213
+ p.ip6_dst = IPAddr.new("::1")
214
+ p.ip6_dst = "::1"
215
+ r = Scriptroute::send_train([ Struct::DelayedPacket.new(0, p) ])
216
+ rescue Scriptroute::ScriptrouteError => e
217
+ puts "Expected ERROR because localhost is filtered."
218
+ end
219
+ def test_v6_implicit_lookup
220
+ p = Scriptroute::UDP6.new(20)
221
+ p.ip6_dst = "www.google.com"
222
+ puts p.ip6_dst
223
+ end
224
+
225
+ # I don't know whether I want to be able to send to all-routesr
226
+ def test_v6_mcast
227
+ failure = false
228
+ begin
229
+ p = Scriptroute::ICMP6echo.new(20)
230
+ p.ip6_dst = IPAddr.new("ff02::1") # all nodes.
231
+ r = Scriptroute::send_train([ Struct::DelayedPacket.new(0, p) ])
232
+ failure = true if r[0].probe
233
+ rescue Scriptroute::ScriptrouteError => e
234
+ puts "Expected ERROR because multicast is filtered or source cannot be set."
235
+ end
236
+ begin
237
+ p = Scriptroute::ICMP6echo.new(20)
238
+ p.ip6_dst = IPAddr.new("ff02::2") # all routers.
239
+ r = Scriptroute::send_train([ Struct::DelayedPacket.new(0, p) ])
240
+ failure = true if r[0].probe
241
+ rescue Scriptroute::ScriptrouteError => e
242
+ puts "Expected ERROR because multicast is filtered or source cannot be set."
243
+ end
244
+ failure
245
+ end
246
+
247
+ def test_v6_onehop
248
+ daddr = nil
249
+ Resolv::DNS.open do |dns|
250
+ ress = dns.getresources "www.google.com", Resolv::DNS::Resource::IN::AAAA
251
+ ress.each { |r| daddr = r.address.to_s }
252
+ end
253
+ raise "no address" unless daddr
254
+ p = Scriptroute::ICMP6echo.new(20)
255
+ p.ip6_dst = daddr
256
+ p.ip6_hlim = 1
257
+ begin
258
+ r = Scriptroute::send_train([ Struct::DelayedPacket.new(0, p) ])
259
+ if r[0].response then
260
+ puts "success from first hop: %s:" % r[0].response.packet.ip6_src
261
+ puts r[0].response.packet
262
+ true
263
+ else
264
+ puts "failed: expected to see a response to the one-hop ttl limited probe"
265
+ false
266
+ end
267
+ rescue Scriptroute::ScriptrouteError => e
268
+ if e.to_s =~ /unreachable/ then
269
+ puts "Expected ERROR when host supports v6 but lacks routes to the outside world."
270
+ else
271
+ puts "rescued unexpected error: " + e.to_s
272
+ end
273
+ end
274
+ end
275
+
276
+ def test_v6_udp_tr
277
+ daddr = nil
278
+ Resolv::DNS.open do |dns|
279
+ ress = dns.getresources "www.google.com", Resolv::DNS::Resource::IN::AAAA
280
+ ress.each { |r| daddr = r.address.to_s }
281
+ end
282
+ raise "no address" unless daddr
283
+ p = Scriptroute::UDP6.new(20)
284
+ p.ip6_dst = daddr
285
+ puts p.to_s
286
+ begin
287
+ [4,5,6,20].each { |ttl|
288
+ p.ip6_hlim = ttl
289
+ r = Scriptroute::send_train([ Struct::DelayedPacket.new(0, p) ])
290
+ if r[0].response then
291
+ puts "success from hop %d: %s:" % [ ttl, r[0].response.packet.ip6_src ]
292
+ puts r[0].response.packet
293
+ true
294
+ else
295
+ puts "failed: expected to see a response to the one-hop ttl limited probe"
296
+ false
297
+ end
298
+ }
299
+ rescue Scriptroute::ScriptrouteError => e
300
+ if e.to_s =~ /unreachable/ then
301
+ puts "Expected ERROR when host supports v6 but lacks routes to the outside world."
302
+ else
303
+ puts "rescued unexpected error: " + e.to_s
304
+ end
305
+ end
306
+ end
151
307
  end
152
308
 
153
309
  # Local Variables:
154
- # compile-command: "rake test"
310
+ # compile-command: "ruby -I ../lib ./test_scriptroute.rb"
155
311
  # End:
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scriptroute
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.14
4
+ version: 0.4.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Neil Spring
@@ -27,11 +27,13 @@ files:
27
27
  - bin/sr-ping-T
28
28
  - bin/sr-rockettrace
29
29
  - bin/sr-traceroute
30
+ - bin/sr-traceroute6
30
31
  - bin/tulip
31
32
  - lib/scriptroute.rb
32
33
  - lib/scriptroute/ally.rb
33
34
  - lib/scriptroute/commando.rb
34
35
  - lib/scriptroute/fixclock
36
+ - lib/scriptroute/ipaddr4.rb
35
37
  - lib/scriptroute/liveness.rb
36
38
  - lib/scriptroute/nameify.rb
37
39
  - lib/scriptroute/packets.rb
@@ -41,6 +43,7 @@ files:
41
43
  - lib/scriptroute/tulip/queuing.rb
42
44
  - lib/scriptroute/tulip/reordering.rb
43
45
  - test/test_bins.rb
46
+ - test/test_commando.rb
44
47
  - test/test_scriptroute.rb
45
48
  homepage: http://www.scriptroute.org/
46
49
  licenses: