nmap-parser 0.3.1 → 0.3.2

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.
data/BUGS CHANGED
@@ -1,2 +1,4 @@
1
- If you find any bugs, please report them to me: katterjohn@gmail.com
1
+ If you find any bugs, please report them to me:
2
+
3
+ Kris Katterjohn <katterjohn[at]gmail.com>
2
4
 
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007, 2008, 2009 Kris Katterjohn
1
+ Copyright (c) 2007-2009 Kris Katterjohn
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README CHANGED
@@ -3,7 +3,7 @@
3
3
  == Kris Katterjohn katterjohn@gmail.com ==
4
4
  ===============================================================================
5
5
 
6
- $Id: README 91 2009-01-01 20:50:08Z kjak $
6
+ $Id: README 126 2009-02-08 15:32:04Z kjak $
7
7
 
8
8
 
9
9
  OVERVIEW
@@ -13,10 +13,11 @@ This library provides a Ruby interface to Nmap's scan data. It can run Nmap
13
13
  and parse its XML output directly from the scan, parse a file containing the
14
14
  XML data from a separate scan, parse a String of XML data from a scan, or parse
15
15
  XML data from an object via its read() method. This information is presented
16
- in an easy-to-use and intuitive fashion for storing and manipulating.
16
+ in an easy-to-use and intuitive fashion for storage and manipulation.
17
17
 
18
- This is not just some Ruby port of Anthony Persaud's Perl Nmap::Parser! There
19
- are more classes, many different methods, and blocks are extensively available.
18
+ Keep in mind that this is not just some Ruby port of Anthony Persaud's Perl
19
+ Nmap::Parser! There are more classes, many different methods, and blocks are
20
+ extensively available.
20
21
 
21
22
 
22
23
  REQUIREMENTS and RECOMMENDATIONS
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # Very simple script to print out the open TCP ports for each host
4
+ #
5
+ # Kris Katterjohn 01/27/2009
6
+
7
+ require 'nmap/parser'
8
+
9
+ p = Nmap::Parser.parsescan("nmap", "192.168.11.0/24")
10
+
11
+ p.hosts("up") do |host|
12
+ puts "#{host.addr}:"
13
+
14
+ host.tcp_ports("open") do |port|
15
+ puts "Got #{port.num}/tcp"
16
+ end
17
+
18
+ puts
19
+ end
20
+
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # A really simplistic script which prints out service information for the
4
+ # open TCP and UDP ports found by scanning a host
5
+ #
6
+ # Kris Katterjohn 01/27/2009
7
+
8
+ require 'nmap/parser'
9
+
10
+ def printport(port, proto)
11
+ srv = port.service
12
+
13
+ puts
14
+ puts "Port ##{port.num}/#{proto} is open (#{port.reason})"
15
+ puts "\tService: #{srv.name}" if srv.name
16
+ puts "\tProduct: #{srv.product}" if srv.product
17
+ puts "\tVersion: #{srv.version}" if srv.version
18
+ puts
19
+ end
20
+
21
+ p = Nmap::Parser.parsescan("sudo nmap", "-sSUV 192.168.11.1")
22
+
23
+ p.hosts("up") do |host|
24
+ puts "#{host.addr}:"
25
+ host.tcp_ports("open") { |port| printport(port, "tcp") }
26
+ host.udp_ports("open") { |port| printport(port, "udp") }
27
+ puts
28
+ end
29
+
@@ -4,7 +4,7 @@
4
4
  #
5
5
  # Author: Kris Katterjohn <katterjohn@gmail.com>
6
6
  #
7
- # Copyright (c) 2007, 2008, 2009 Kris Katterjohn
7
+ # Copyright (c) 2007-2009 Kris Katterjohn
8
8
  #
9
9
  # Permission is hereby granted, free of charge, to any person obtaining a copy
10
10
  # of this software and associated documentation files (the "Software"), to deal
@@ -24,7 +24,7 @@
24
24
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
25
  # THE SOFTWARE.
26
26
 
27
- # $Id: parser.rb 92 2009-01-01 21:14:58Z kjak $
27
+ # $Id: parser.rb 129 2009-02-08 17:14:39Z kjak $
28
28
  # https://rubynmap.svn.sourceforge.net/svnroot/rubynmap
29
29
 
30
30
  require 'rexml/document'
@@ -32,7 +32,7 @@ require 'rexml/document'
32
32
  begin
33
33
  require 'open3'
34
34
  rescue LoadError
35
- # We'll resort to IO.popen()
35
+ # We'll just use IO.popen()
36
36
  end
37
37
 
38
38
  # Just holds the big Parser class.
@@ -47,12 +47,13 @@ This library provides a Ruby interface to Nmap's scan data. It can run Nmap
47
47
  and parse its XML output directly from the scan, parse a file containing the
48
48
  XML data from a separate scan, parse a String of XML data from a scan, or parse
49
49
  XML data from an object via its read() method. This information is presented
50
- in an easy-to-use and intuitive fashion for storing and manipulating.
50
+ in an easy-to-use and intuitive fashion for storage and manipulation.
51
51
 
52
- This is not just some Ruby port of Anthony Persaud's Perl Nmap::Parser! There
53
- are more classes, many different methods, and blocks are extensively available.
52
+ Keep in mind that this is not just some Ruby port of Anthony Persaud's Perl
53
+ Nmap::Parser! There are more classes, many different methods, and blocks are
54
+ extensively available.
54
55
 
55
- The Nmap Security Scanner is a great program written and maintained by
56
+ The Nmap Security Scanner is an awesome program written and maintained by
56
57
  Fyodor <fyodor@insecure.org>. Its main function is port scanning, but it also
57
58
  has service and operating system detection, its own scripting engine and a
58
59
  whole lot more. One of its many available output formats is XML, which allows
@@ -88,7 +89,7 @@ is given.
88
89
  |
89
90
  + Script <- NSE Script information (both host and port)
90
91
  |
91
- + Times <- Timimg information (srtt, etc)
92
+ + Times <- Timimg information (round-trip time, etc)
92
93
  |
93
94
  + Traceroute <- General Traceroute information
94
95
  | |
@@ -104,7 +105,8 @@ is given.
104
105
 
105
106
  require 'nmap/parser'
106
107
 
107
- parser = Nmap::Parser.new(xml) # String of XML data
108
+ parser = Nmap::Parser.parsestring(xml) # String of XML
109
+ parser = Nmap::Parser.new(xml) # Same thing
108
110
 
109
111
  == Reading and Parsing from a File
110
112
 
@@ -115,7 +117,7 @@ is given.
115
117
  == Reading and Parsing from an Object
116
118
 
117
119
  This method can read from any object that responds to a read() method that
118
- returns a String: $stdin is just one example.
120
+ returns a String.
119
121
 
120
122
  require 'nmap/parser'
121
123
 
@@ -123,7 +125,7 @@ returns a String: $stdin is just one example.
123
125
 
124
126
  == Scanning and Parsing
125
127
 
126
- This is the only parser method that requires Nmap to be available.
128
+ This is the only Parser method that requires Nmap to be available.
127
129
 
128
130
  require 'nmap/parser'
129
131
 
@@ -132,48 +134,30 @@ This is the only parser method that requires Nmap to be available.
132
134
  == Actually Doing Something
133
135
 
134
136
  After printing a little session information, this example will cycle
135
- through all of the up hosts, printing service information on the
136
- open TCP ports, along with the name and output of any scripts that
137
- ran (on the host and individual ports).
137
+ through all of the up hosts, printing state and service information on
138
+ the open TCP ports. See the examples directory that comes with this
139
+ library for more examples.
138
140
 
139
141
  puts "Nmap args: #{parser.session.scan_args}"
140
142
  puts "Runtime: #{parser.session.scan_time} seconds"
141
143
  puts
142
144
 
143
145
  parser.hosts("up") do |host|
144
- puts "** Host #{host.addr} is up **"
146
+ puts "#{host.addr} is up:"
145
147
  puts
146
148
 
147
149
  host.tcp_ports("open") do |port|
148
150
  srv = port.service
149
151
 
150
- puts "Port ##{port.num} is open (#{port.reason})"
152
+ puts "Port ##{port.num}/tcp is open (#{port.reason})"
151
153
  puts "\tService: #{srv.name}" if srv.name
152
154
  puts "\tProduct: #{srv.product}" if srv.product
153
155
  puts "\tVersion: #{srv.version}" if srv.version
154
156
  puts
155
-
156
- port.scripts do |script|
157
- puts "\tScript Name: #{script.id}"
158
- puts "\tScript Output: #{script.output}"
159
- puts
160
- end
161
- end
162
-
163
- if host.scripts.any?
164
- puts "Host Scripts Run:"
165
- puts
166
-
167
- host.scripts do |script|
168
- puts "\tScript Name: #{script.id}"
169
- puts "\tScript Output: #{script.output}"
170
- puts
171
- end
172
157
  end
173
158
 
174
159
  puts
175
160
  end
176
-
177
161
  =end
178
162
  class Nmap::Parser
179
163
  # Holds the raw XML output from Nmap
@@ -189,36 +173,38 @@ class Nmap::Parser
189
173
  # one is given
190
174
  def self.parseread(obj) # :yields: parser
191
175
  if not obj.respond_to?("read")
192
- raise "Object must respond to read()"
176
+ raise "Passed object must respond to read()"
193
177
  end
194
178
 
195
179
  r = obj.read
196
180
 
197
- if not r.is_a?String
198
- raise "read() returned #{r.class} instead of a String"
181
+ if not r.is_a?(String)
182
+ raise "Passed object's read() must return a String (got #{r.class})"
199
183
  end
200
184
 
201
- p = new(r)
202
-
203
- yield p if block_given?
204
-
205
- p
185
+ new(r) { |p| yield p if block_given? }
206
186
  end
207
187
 
208
- # Read and parse contents of the Nmap XML file +filename+
188
+ # Read and parse the contents of the Nmap XML file +filename+
209
189
  #
210
190
  # Returns a new Nmap::Parser object, and passes it to a block if
211
191
  # one is given
212
192
  def self.parsefile(filename) # :yields: parser
213
193
  begin
214
- p = parseread(File.open(filename))
194
+ File.open(filename) { |f|
195
+ parseread(f) { |p| yield p if block_given? }
196
+ }
215
197
  rescue
216
198
  raise "Error parsing \"#{filename}\": #{$!}"
217
199
  end
200
+ end
218
201
 
219
- yield p if block_given?
220
-
221
- p
202
+ # Read and parse the String of XML. Currently an alias for new().
203
+ #
204
+ # Returns a new Nmap::Parser object, and passes it to a block if
205
+ # one is given
206
+ def self.parsestring(str) # :yields: parser
207
+ new(str) { |p| yield p if block_given? }
222
208
  end
223
209
 
224
210
  # Runs "+nmap+ -d +args+ +targets+"; returns a new Nmap::Parser object,
@@ -316,14 +302,9 @@ class Nmap::Parser
316
302
  #
317
303
  # If an argument is given, only hosts matching +status+ are given
318
304
  def get_ips(status = "") # :yields: host.addr
319
- ips = []
305
+ ips = hosts(status).map { |h| h.addr }
320
306
 
321
- @hosts.each do |host|
322
- if status.empty? or host.status == status
323
- ips << host.addr
324
- yield host.addr if block_given?
325
- end
326
- end
307
+ ips.each { |ip| yield host.addr } if block_given?
327
308
 
328
309
  ips
329
310
  end
@@ -336,8 +317,8 @@ class Nmap::Parser
336
317
  private
337
318
 
338
319
  def initialize(xml) # :yields: parser
339
- if not xml.is_a?String
340
- raise "Invalid input: new() should be passed a String"
320
+ if not xml.is_a?(String)
321
+ raise "Must be passed a String (got #{xml.class})"
341
322
  end
342
323
 
343
324
  parse(xml)
@@ -377,7 +358,7 @@ class Nmap::Parser::Session
377
358
  attr_reader :start_str, :start_time
378
359
  # Ending time
379
360
  attr_reader :stop_str, :stop_time
380
- # How long the scan took (in seconds). Same as stop_time - start_time
361
+ # Total scan time in seconds (can differ from stop_time - start_time)
381
362
  attr_reader :scan_time
382
363
  # Amount of verbosity (-v) used while scanning
383
364
  attr_reader :verbose
@@ -456,7 +437,7 @@ class Nmap::Parser::Session
456
437
  @stop_str = root.elements['runstats/finished'].attributes['timestr']
457
438
  @stop_time = root.elements['runstats/finished'].attributes['time'].to_i
458
439
 
459
- @scan_time = @stop_time - @start_time
440
+ @scan_time = root.elements['runstats/finished'].attributes['elapsed'].to_f
460
441
 
461
442
  @verbose = root.elements['verbose'].attributes['level'].to_i
462
443
  @debug = root.elements['debugging'].attributes['level'].to_i
@@ -536,11 +517,7 @@ class Nmap::Parser::Host
536
517
  # Returns an array containing all of the hostnames for this host,
537
518
  # and passes them each to a block if one is given
538
519
  def all_hostnames
539
- if block_given?
540
- @hostnames.each do |hostname|
541
- yield hostname
542
- end
543
- end
520
+ @hostnames.each { |hostname| yield hostname } if block_given?
544
521
 
545
522
  @hostnames
546
523
  end
@@ -554,12 +531,8 @@ class Nmap::Parser::Host
554
531
 
555
532
  # Returns an array of ExtraPorts objects, and passes them each to a
556
533
  # block if one if given
557
- def extraports
558
- if block_given?
559
- @extraports.each do |extraports|
560
- yield extraports
561
- end
562
- end
534
+ def extraports # :yields: extraports
535
+ @extraports.each { |e| yield e } if block_given?
563
536
 
564
537
  @extraports
565
538
  end
@@ -567,26 +540,25 @@ class Nmap::Parser::Host
567
540
  # Returns the Port object for the TCP port +portnum+, and passes it to
568
541
  # a block if one is given
569
542
  def tcp_port(portnum) # :yields: port
570
- yield @tcpPorts[portnum.to_s] if block_given?
571
-
572
- @tcpPorts[portnum.to_s]
543
+ port = @tcpPorts[portnum.to_i]
544
+ yield port if block_given?
545
+ port
573
546
  end
574
547
 
575
548
  # Returns an array of Port objects for each TCP port, and passes them
576
549
  # each to a block if one is given
577
550
  #
578
- # If an argument is given, only ports matching +state+ are given.
579
- # Note: "open" will also match "open|filtered", but not vice versa.
551
+ # If an argument is given, only ports matching +state+ are given. Note
552
+ # that combinations like "open|filtered" will get matched by "open" and
553
+ # "filtered"
580
554
  def tcp_ports(state = "")
581
- list = @tcpPorts.invert.keys.find_all { |port|
582
- state.empty? or port.state >= state
555
+ list = @tcpPorts.values.find_all { |port|
556
+ state.empty? or
557
+ port.state == state or
558
+ port.state.split(/\|/).include?(state)
583
559
  }.sort
584
560
 
585
- if block_given?
586
- list.each do |port|
587
- yield port
588
- end
589
- end
561
+ list.each { |port| yield port } if block_given?
590
562
 
591
563
  list
592
564
  end
@@ -595,94 +567,79 @@ class Nmap::Parser::Host
595
567
  # if one given
596
568
  #
597
569
  # If an argument is given, only ports matching +state+ are given.
598
- # Note: "open" will also match "open|filtered", but not vice versa.
599
570
  def tcp_port_list(state = "")
600
- list = @tcpPorts.invert.keys.map { |port|
601
- port.num if state.empty? or port.state >= state
602
- }.compact.sort
603
-
604
- if block_given?
605
- list.each do |port|
606
- yield port
607
- end
608
- end
609
-
571
+ list = tcp_ports(state).map { |p| p.num }
572
+ list.each { |port| yield port } if block_given?
610
573
  list
611
574
  end
612
575
 
613
576
  # Returns the state reason of TCP port +portnum+
614
577
  def tcp_reason(portnum)
615
- return nil if @tcpPorts[portnum.to_s].nil?
616
-
617
- @tcpPorts[portnum.to_s].reason
578
+ port = tcp_port(portnum)
579
+ return nil if port.nil?
580
+ port.reason
618
581
  end
619
582
 
620
583
  # Returns the Script object for the script +name+ run against the
621
584
  # TCP port +portnum+
622
585
  def tcp_script(portnum, name)
623
- return nil if @tcpPorts[portnum.to_s].nil?
624
-
625
- @tcpPorts[portnum.to_s].script(name)
586
+ port = tcp_port(portnum)
587
+ return nil if port.nil?
588
+ port.script(name)
626
589
  end
627
590
 
628
591
  # Returns an array of Script objects for each script run on the
629
592
  # TCP port +portnum+, and passes them each to a block if given
630
- def tcp_scripts(portnum)
631
- return nil if @tcpPorts[portnum.to_s].nil?
632
-
633
- if block_given?
634
- @tcpPorts[portnum.to_s].scripts do |script|
635
- yield script
636
- end
637
- end
638
-
639
- @tcpPorts[portnum.to_s].scripts
593
+ def tcp_scripts(portnum) # :yields: script
594
+ port = tcp_port(portnum)
595
+ return nil if port.nil?
596
+ port.scripts { |s| yield s } if block_given?
597
+ port.scripts
640
598
  end
641
599
 
642
600
  # Returns the output of the script +name+ on the TCP port +portnum+
643
601
  def tcp_script_output(portnum, name)
644
- return nil if @tcpPorts[portnum.to_s].nil?
645
-
646
- @tcpPorts[portnum.to_s].script_output(name)
602
+ port = tcp_port(portnum)
603
+ return nil if port.nil?
604
+ port.script_output(name)
647
605
  end
648
606
 
649
607
  # Returns a Port::Service object for TCP port +portnum+
650
608
  def tcp_service(portnum)
651
- return nil if @tcpPorts[portnum.to_s].nil?
652
-
653
- @tcpPorts[portnum.to_s].service
609
+ port = tcp_port(portnum)
610
+ return nil if port.nil?
611
+ port.service
654
612
  end
655
613
 
656
614
  # Returns the state of TCP port +portnum+
657
615
  def tcp_state(portnum)
658
- return nil if @tcpPorts[portnum.to_s].nil?
659
-
660
- @tcpPorts[portnum.to_s].state
616
+ port = tcp_port(portnum)
617
+ return nil if port.nil?
618
+ port.state
661
619
  end
662
620
 
663
621
  # Returns the Port object for the UDP port +portnum+, and passes it to
664
622
  # a block if one is given
665
623
  def udp_port(portnum) # :yields: port
666
- yield @udpPorts[portnum.to_s] if block_given?
667
-
668
- @udpPorts[portnum.to_s]
624
+ port = @udpPorts[portnum.to_i]
625
+ yield port if block_given?
626
+ port
669
627
  end
670
628
 
671
629
  # Returns an array of Port objects for each UDP port, and passes them
672
630
  # each to a block if one is given
673
631
  #
674
- # If an argument is given, only ports matching +state+ are given.
675
- # Note: "open" will also match "open|filtered", but not vice versa.
632
+ # If an argument is given, only ports matching +state+ are given. Note
633
+ # that combinations like "open|filtered" will get matched by "open" and
634
+ # "filtered"
676
635
  def udp_ports(state = "")
677
- list = @udpPorts.invert.keys.find_all { |port|
678
- state.empty? or port.state >= state
636
+ list = @udpPorts.values.find_all { |port|
637
+ state.empty? or
638
+ port.state == state or
639
+ port.state.split(/\|/).include?(state)
679
640
  }.sort
680
641
 
681
- if block_given?
682
- list.each do |port|
683
- yield port
684
- end
685
- end
642
+ list.each { |port| yield port } if block_given?
686
643
 
687
644
  list
688
645
  end
@@ -691,94 +648,79 @@ class Nmap::Parser::Host
691
648
  # if one is given
692
649
  #
693
650
  # If an argument is given, only ports matching +state+ are given.
694
- # Note: "open" will also match "open|filtered", but not vice versa.
695
651
  def udp_port_list(state = "")
696
- list = @udpPorts.invert.keys.map { |port|
697
- port.num if state.empty? or port.state >= state
698
- }.compact.sort
699
-
700
- if block_given?
701
- list.each do |port|
702
- yield port
703
- end
704
- end
705
-
652
+ list = udp_ports(state).map { |p| p.num }
653
+ list.each { |port| yield port } if block_given?
706
654
  list
707
655
  end
708
656
 
709
657
  # Returns the state reason of UDP port +portnum+
710
658
  def udp_reason(portnum)
711
- return nil if @udpPorts[portnum.to_s].nil?
712
-
713
- @udpPorts[portnum.to_s].reason
659
+ port = udp_port(portnum)
660
+ return nil if port.nil?
661
+ port.reason
714
662
  end
715
663
 
716
664
  # Returns the Script object for the script +name+ run against the
717
665
  # UDP port +portnum+
718
666
  def udp_script(portnum, name)
719
- return nil if @udpPorts[portnum.to_s].nil?
720
-
721
- @udpPorts[portnum.to_s].script(name)
667
+ port = udp_port(portnum)
668
+ return nil if port.nil?
669
+ port.script(name)
722
670
  end
723
671
 
724
672
  # Returns an array of Script objects for each script run on the
725
673
  # UDP port +portnum+, and passes them each to a block if given
726
- def udp_scripts(portnum)
727
- return nil if @udpPorts[portnum.to_s].nil?
728
-
729
- if block_given?
730
- @udpPorts[portnum.to_s].scripts do |script|
731
- yield script
732
- end
733
- end
734
-
735
- @udpPorts[portnum.to_s].scripts
674
+ def udp_scripts(portnum) # :yields: script
675
+ port = udp_port(portnum)
676
+ return nil if port.nil?
677
+ port.scripts { |s| yield s } if block_given?
678
+ port.scripts
736
679
  end
737
680
 
738
681
  # Returns the output of the script +name+ on the UDP port +portnum+
739
682
  def udp_script_output(portnum, name)
740
- return nil if @udpPorts[portnum.to_s].nil?
741
-
742
- @udpPorts[portnum.to_s].script_output(name)
683
+ port = udp_port(portnum)
684
+ return nil if port.nil?
685
+ port.script_output(name)
743
686
  end
744
687
 
745
688
  # Returns a Port::Service object for UDP port +portnum+
746
689
  def udp_service(portnum)
747
- return nil if @udpPorts[portnum.to_s].nil?
748
-
749
- @udpPorts[portnum.to_s].service
690
+ port = udp_port(portnum)
691
+ return nil if port.nil?
692
+ port.service
750
693
  end
751
694
 
752
695
  # Returns the state of UDP port +portnum+
753
696
  def udp_state(portnum)
754
- return nil if @udpPorts[portnum.to_s].nil?
755
-
756
- @udpPorts[portnum.to_s].state
697
+ port = udp_port(portnum)
698
+ return nil if port.nil?
699
+ port.state
757
700
  end
758
701
 
759
702
  # Returns the Port object for the IP protocol +protonum+, and passes it
760
703
  # to a block if one is given
761
704
  def ip_proto(protonum) # :yields: proto
762
- yield @ipProtos[protonum.to_s] if block_given?
763
-
764
- @ipProtos[protonum.to_s]
705
+ proto = @ipProtos[protonum.to_i]
706
+ yield proto if block_given?
707
+ proto
765
708
  end
766
709
 
767
710
  # Returns an array of Port objects for each IP protocol, and passes
768
711
  # them each to a block if one is given
769
712
  #
770
713
  # If an argument is given, only protocols matching +state+ are given.
771
- # Note: "open" will also match "open|filtered", but not vice versa.
714
+ # Note that combinations like "open|filtered" will get matched by
715
+ # "open" and "filtered"
772
716
  def ip_protos(state = "")
773
- list = @ipProtos.invert.keys.find_all { |proto|
774
- state.empty? or proto.state >= state
717
+ list = @ipProtos.values.find_all { |proto|
718
+ state.empty? or
719
+ proto.state == state or
720
+ proto.state.split(/\|/).include?(state)
775
721
  }.sort
776
722
 
777
- if block_given?
778
- list.each do |proto|
779
- yield proto
780
- end
781
- end
723
+ list.each { |proto| yield proto } if block_given?
782
724
 
783
725
  list
784
726
  end
@@ -787,57 +729,42 @@ class Nmap::Parser::Host
787
729
  # block if one given
788
730
  #
789
731
  # If an argument is given, only protocols matching +state+ are given.
790
- # Note: "open" will also match "open|filtered", but not vice versa.
791
732
  def ip_proto_list(state = "")
792
- list = @ipProtos.invert.keys.map { |proto|
793
- proto.num if state.empty? or proto.state >= state
794
- }.compact.sort
795
-
796
- if block_given?
797
- list.each do |proto|
798
- yield proto
799
- end
800
- end
801
-
733
+ list = ip_protos(state).map { |p| p.num }
734
+ list.each { |proto| yield proto } if block_given?
802
735
  list
803
736
  end
804
737
 
805
738
  # Returns the state reason of IP protocol +protonum+
806
739
  def ip_reason(protonum)
807
- return nil if @ipProtos[protonum.to_s].nil?
808
-
809
- @ipProtos[protonum.to_s].reason
740
+ proto = ip_proto(protonum)
741
+ return nil if proto.nil?
742
+ proto.reason
810
743
  end
811
744
 
812
745
  # Returns a Port::Service object for IP protocol +protonum+
813
746
  def ip_service(protonum)
814
- return nil if @ipProtos[protonum.to_s].nil?
815
-
816
- @ipProtos[protonum.to_s].service
747
+ proto = ip_proto(protonum)
748
+ return nil if proto.nil?
749
+ proto.service
817
750
  end
818
751
 
819
752
  # Returns the state of IP protocol +protonum+
820
753
  def ip_state(protonum)
821
- return nil if @ipProtos[protonum.to_s].nil?
822
-
823
- @ipProtos[protonum.to_s].state
754
+ proto = ip_proto(protonum)
755
+ return nil if proto.nil?
756
+ proto.state
824
757
  end
825
758
 
826
759
  # Returns the Script object for the specified host script +name+
827
760
  def script(name)
828
- @scripts.find do |script|
829
- script.id == name
830
- end
761
+ @scripts.find { |script| script.id == name }
831
762
  end
832
763
 
833
764
  # Returns an array of Script objects for each host script run, and
834
765
  # passes them each to a block if given
835
766
  def scripts
836
- if block_given?
837
- @scripts.each do |script|
838
- yield script
839
- end
840
- end
767
+ @scripts.each { |script| yield script } if block_given?
841
768
 
842
769
  @scripts
843
770
  end
@@ -857,28 +784,6 @@ class Nmap::Parser::Host
857
784
  parse(hostinfo)
858
785
  end
859
786
 
860
- # Convert a string like "22-25,80,110-900" into
861
- # an array with all the uncondensed elements, e.g.
862
- # [ 22, 23, 24, 25, 80, 110, 111 ... ]
863
- def parsePortlist(ports)
864
- list = []
865
-
866
- # Build array from port specification
867
- ports.split(/,/).each do |item|
868
- start, stop = item.split(/-/).map { |p| p.to_i }
869
-
870
- start ||= 0
871
- stop ||= item.match(/-/) ? 65535 : start
872
-
873
- start, stop = stop, start if stop < start
874
-
875
- start.upto(stop) { |p| list << p }
876
- end
877
-
878
- # Sort, and remove dups and invalid ports
879
- list.sort.uniq.delete_if { |p| p < 0 or p > 65535 }
880
- end
881
-
882
787
  def parseAddr(elem)
883
788
  case elem.attributes['addrtype']
884
789
  when "mac"
@@ -909,7 +814,7 @@ class Nmap::Parser::Host
909
814
  return nil if ports.nil?
910
815
 
911
816
  ports.each_element('port') do |port|
912
- num = port.attributes['portid']
817
+ num = port.attributes['portid'].to_i
913
818
  proto = port.attributes['protocol']
914
819
 
915
820
  if proto == "tcp"
@@ -931,9 +836,7 @@ class Nmap::Parser::Host
931
836
  ExtraPorts.new(e)
932
837
  end
933
838
 
934
- @extraports.sort! do |x, y|
935
- x.count <=> y.count
936
- end
839
+ @extraports.sort!
937
840
  end
938
841
 
939
842
  def parseScripts(scriptlist)
@@ -1091,19 +994,13 @@ class Nmap::Parser::Host::Port
1091
994
 
1092
995
  # Returns the Script object with the specified +name+
1093
996
  def script(name)
1094
- @scripts.find do |script|
1095
- script.id == name
1096
- end
997
+ @scripts.find { |script| script.id == name }
1097
998
  end
1098
999
 
1099
1000
  # Returns an array of Script objects associated with this port, and
1100
1001
  # passes them each to a block if one is given
1101
1002
  def scripts
1102
- if block_given?
1103
- @scripts.each do |script|
1104
- yield script
1105
- end
1106
- end
1003
+ @scripts.each { |script| yield script } if block_given?
1107
1004
 
1108
1005
  @scripts
1109
1006
  end
@@ -1160,15 +1057,16 @@ class Nmap::Parser::Host::ExtraPorts
1160
1057
  # for each set of reasons, and passes them each to a block if one is
1161
1058
  # given
1162
1059
  def reasons
1163
- if block_given?
1164
- @reasons.each do |reason|
1165
- yield reason
1166
- end
1167
- end
1060
+ @reasons.each { |reason| yield reason } if block_given?
1168
1061
 
1169
1062
  @reasons
1170
1063
  end
1171
1064
 
1065
+ # Compares the port counts
1066
+ def <=>(extraports)
1067
+ @count <=> extraports.count
1068
+ end
1069
+
1172
1070
  private
1173
1071
 
1174
1072
  def initialize(extraports)
@@ -1199,19 +1097,13 @@ class Nmap::Parser::Host::Traceroute
1199
1097
 
1200
1098
  # Returns the Hop object for the given TTL
1201
1099
  def hop(ttl)
1202
- @hops.find do |h|
1203
- h.ttl == ttl.to_i
1204
- end
1100
+ @hops.find { |hop| hop.ttl == ttl.to_i }
1205
1101
  end
1206
1102
 
1207
1103
  # Returns an array of Hop objects, which are each a responsive hop,
1208
1104
  # and passes them each to a block if one if given.
1209
- def hops() # :yields: hop
1210
- if block_given?
1211
- @hops.each do |h|
1212
- yield h
1213
- end
1214
- end
1105
+ def hops
1106
+ @hops.each { |hop| yield hop } if block_given?
1215
1107
 
1216
1108
  @hops
1217
1109
  end
@@ -1246,6 +1138,11 @@ class Nmap::Parser::Host::Traceroute::Hop
1246
1138
  alias host hostname
1247
1139
  alias ipaddr addr
1248
1140
 
1141
+ # Compares the TTLs
1142
+ def <=>(hop)
1143
+ @ttl <=> hop.ttl
1144
+ end
1145
+
1249
1146
  private
1250
1147
 
1251
1148
  def initialize(hop)
@@ -1337,11 +1234,7 @@ class Nmap::Parser::Host::OS
1337
1234
  # Returns an array of OSClass objects, and passes them each to a
1338
1235
  # block if one is given
1339
1236
  def osclasses
1340
- if block_given?
1341
- @osclasses.each do |osclass|
1342
- yield osclass
1343
- end
1344
- end
1237
+ @osclasses.each { |osclass| yield osclass } if block_given?
1345
1238
 
1346
1239
  @osclasses
1347
1240
  end
@@ -1349,11 +1242,7 @@ class Nmap::Parser::Host::OS
1349
1242
  # Returns an array of OSMatch objects, and passes them each to a
1350
1243
  # block if one is given
1351
1244
  def osmatches
1352
- if block_given?
1353
- @osmatches.each do |osmatch|
1354
- yield osmatch
1355
- end
1356
- end
1245
+ @osmatches.each { |osmatch| yield osmatch } if block_given?
1357
1246
 
1358
1247
  @osmatches
1359
1248
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nmap-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kris Katterjohn
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-01 00:00:00 -06:00
12
+ date: 2009-02-08 00:00:00 -06:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -26,6 +26,8 @@ files:
26
26
  - LICENSE
27
27
  - README
28
28
  - lib/nmap/parser.rb
29
+ - examples/listopentcp.rb
30
+ - examples/services.rb
29
31
  has_rdoc: true
30
32
  homepage: http://rubynmap.sourceforge.net
31
33
  post_install_message: