scriptroute 0.4.14 → 0.4.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: