PageRenderTime 57ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/nmap/host.rb

http://github.com/sophsec/ruby-nmap
Ruby | 587 lines | 210 code | 65 blank | 312 comment | 27 complexity | 49c0d91d0325ce46d7144199940e68ac MD5 | raw file
  1. require 'nmap/status'
  2. require 'nmap/address'
  3. require 'nmap/hostname'
  4. require 'nmap/os'
  5. require 'nmap/port'
  6. require 'nmap/ip_id_sequence'
  7. require 'nmap/tcp_sequence'
  8. require 'nmap/tcp_ts_sequence'
  9. require 'nmap/uptime'
  10. require 'nmap/traceroute'
  11. require 'nmap/host_script'
  12. require 'nokogiri'
  13. require 'time'
  14. module Nmap
  15. #
  16. # Wraps a `host` XML element.
  17. #
  18. class Host
  19. include Enumerable
  20. #
  21. # Creates a new Host object.
  22. #
  23. # @param [Nokogiri::XML::Node] node
  24. # The XML node that contains the host information.
  25. #
  26. def initialize(node)
  27. @node = node
  28. end
  29. #
  30. # The time the host was first scanned.
  31. #
  32. # @return [Time]
  33. # The time the host was first scanned.
  34. #
  35. # @since 0.1.2
  36. #
  37. def start_time
  38. @start_time ||= Time.at(@node['starttime'].to_i)
  39. end
  40. #
  41. # The time the host was last scanned.
  42. #
  43. # @return [Time]
  44. # The time the host was last scanned.
  45. #
  46. # @since 0.1.2
  47. #
  48. def end_time
  49. @end_time ||= Time.at(@node['endtime'].to_i)
  50. end
  51. #
  52. # Parses the status of the host.
  53. #
  54. # @return [Status]
  55. # The status of the host.
  56. #
  57. def status
  58. unless @status
  59. status = @node.at_xpath('status')
  60. @status = Status.new(
  61. status['state'].to_sym,
  62. status['reason'],
  63. status['reason_ttl'].to_i
  64. )
  65. end
  66. return @status
  67. end
  68. #
  69. # Parses each address of the host.
  70. #
  71. # @yield [addr]
  72. # Each parsed address will be pass to a given block.
  73. #
  74. # @yieldparam [Address] addr
  75. # A address of the host.
  76. #
  77. # @return [Host, Enumerator]
  78. # The host.
  79. # If no block was given, an enumerator will be returned.
  80. #
  81. def each_address
  82. return enum_for(__method__) unless block_given?
  83. @node.xpath("address[@addr]").each do |addr|
  84. address = Address.new(
  85. addr['addrtype'].to_sym,
  86. addr['addr'],
  87. addr['vendor']
  88. )
  89. yield address
  90. end
  91. return self
  92. end
  93. #
  94. # Parses the addresses of the host.
  95. #
  96. # @return [Array<Host>]
  97. # The addresses of the host.
  98. #
  99. def addresses
  100. each_address.to_a
  101. end
  102. #
  103. # Parses the MAC address of the host.
  104. #
  105. # @return [String]
  106. # The MAC address of the host.
  107. #
  108. def mac
  109. @mac ||= if (addr = @node.at_xpath("address[@addrtype='mac']"))
  110. addr['addr']
  111. end
  112. end
  113. #
  114. # Parses the MAC vendor of the host.
  115. #
  116. # @return [String]
  117. # The Mac Vendor of the host.
  118. #
  119. # @since 0.8.0
  120. #
  121. def vendor
  122. @vendor ||= if (vendor = @node.at_xpath("address/@vendor"))
  123. vendor.inner_text
  124. end
  125. end
  126. #
  127. # Parses the IPv4 address of the host.
  128. #
  129. # @return [String]
  130. # The IPv4 address of the host.
  131. #
  132. def ipv4
  133. @ipv4 ||= if (addr = @node.at_xpath("address[@addrtype='ipv4']"))
  134. addr['addr']
  135. end
  136. end
  137. #
  138. # Parses the IPv6 address of the host.
  139. #
  140. # @return [String]
  141. # The IPv6 address of the host.
  142. #
  143. def ipv6
  144. @ipv6 ||= if (addr = @node.at_xpath("address[@addrtype='ipv6']"))
  145. addr['addr']
  146. end
  147. end
  148. #
  149. # The IP address of the host.
  150. #
  151. # @return [String]
  152. # The IPv4 or IPv6 address of the host.
  153. #
  154. def ip
  155. ipv6 || ipv4
  156. end
  157. #
  158. # The address of the host.
  159. #
  160. # @return [String]
  161. # The IP or MAC address of the host.
  162. #
  163. def address
  164. ip || mac
  165. end
  166. #
  167. # Parses the hostnames of the host.
  168. #
  169. # @yield [host]
  170. # Each parsed hostname will be passed to the given block.
  171. #
  172. # @yieldparam [Hostname] host
  173. # A hostname of the host.
  174. #
  175. # @return [Host, Enumerator]
  176. # The host.
  177. # If no block was given, an enumerator will be returned.
  178. #
  179. def each_hostname
  180. return enum_for(__method__) unless block_given?
  181. @node.xpath("hostnames/hostname[@name]").each do |host|
  182. yield Hostname.new(host['type'],host['name'])
  183. end
  184. return self
  185. end
  186. #
  187. # Parses the hostnames of the host.
  188. #
  189. # @return [Array<Hostname>]
  190. # The hostnames of the host.
  191. #
  192. def hostnames
  193. each_hostname.to_a
  194. end
  195. #
  196. # The primary hostname of the host.
  197. #
  198. # @return [Hostname, nil]
  199. #
  200. # @since 0.8.0
  201. #
  202. def hostname
  203. each_hostname.first
  204. end
  205. #
  206. # Parses the OS guessing information of the host.
  207. #
  208. # @yield [os]
  209. # If a block is given, it will be passed the OS guessing information.
  210. #
  211. # @yieldparam [OS] os
  212. # The OS guessing information.
  213. #
  214. # @return [OS]
  215. # The OS guessing information.
  216. #
  217. def os
  218. @os ||= if (os = @node.at_xpath('os'))
  219. OS.new(os)
  220. end
  221. yield @os if (@os && block_given?)
  222. return @os
  223. end
  224. #
  225. # Parses the Uptime analysis of the host.
  226. #
  227. # @yield [uptime]
  228. # If a block is given, it will be passed the resulting object
  229. #
  230. # @yieldparam [Uptime]
  231. # Uptime value.
  232. #
  233. # @return [Uptime]
  234. # The parsed object.
  235. #
  236. # @since 0.7.0
  237. #
  238. def uptime
  239. @uptime ||= if (uptime = @node.at_xpath('uptime'))
  240. Uptime.new(
  241. uptime['seconds'].to_i,
  242. Time.parse(uptime['lastboot'])
  243. )
  244. end
  245. yield @uptime if (@uptime && block_given?)
  246. return @uptime
  247. end
  248. #
  249. # Parses the TCP Sequence number analysis of the host.
  250. #
  251. # @yield [sequence]
  252. # If a block is given, it will be passed the resulting object
  253. #
  254. # @yieldparam [TcpSequence] sequence
  255. # TCP Sequence number analysis.
  256. #
  257. # @return [TcpSequence]
  258. # The parsed object.
  259. #
  260. def tcp_sequence
  261. @tcp_sequence ||= if (seq = @node.at_xpath('tcpsequence'))
  262. TcpSequence.new(seq)
  263. end
  264. yield @tcp_sequence if (@tcp_sequence && block_given?)
  265. return @tcp_sequence
  266. end
  267. #
  268. # @deprecated Use {#tcp_sequence} instead.
  269. #
  270. def tcpsequence(&block)
  271. warn "DEPRECATION: use #{self.class}#tcp_sequence instead"
  272. tcp_sequence(&block)
  273. end
  274. #
  275. # Parses the IPID sequence number analysis of the host.
  276. #
  277. # @yield [ipidsequence]
  278. # If a block is given, it will be passed the resulting object
  279. #
  280. # @yieldparam [IpIdSequence] ipidsequence
  281. # IPID Sequence number analysis.
  282. #
  283. # @return [IpIdSequence]
  284. # The parsed object.
  285. #
  286. def ip_id_sequence
  287. @ip_id_sequence ||= if (seq = @node.at_xpath('ipidsequence'))
  288. IpIdSequence.new(seq)
  289. end
  290. yield @ip_id_sequence if (@ip_id_sequence && block_given?)
  291. return @ip_id_sequence
  292. end
  293. #
  294. # @deprecated Use {#ip_id_sequence} instead.
  295. #
  296. def ipidsequence(&block)
  297. warn "DEPRECATION: use #{self.class}#ip_id_sequence instead"
  298. ip_id_sequence(&block)
  299. end
  300. #
  301. # Parses the TCP Timestamp sequence number analysis of the host.
  302. #
  303. # @yield [tcptssequence]
  304. # If a block is given, it will be passed the resulting object
  305. #
  306. # @yieldparam [TcpTsSequence] tcptssequence
  307. # TCP Timestamp Sequence number analysis.
  308. #
  309. # @return [TcpTsSequence]
  310. # The parsed object.
  311. #
  312. def tcp_ts_sequence
  313. @tcp_ts_sequence ||= if (seq = @node.at_xpath('tcptssequence'))
  314. TcpTsSequence.new(seq)
  315. end
  316. yield @tcp_ts_sequence if (@tcp_ts_sequence && block_given?)
  317. return @tcp_ts_sequence
  318. end
  319. #
  320. # @deprecated Use {#tcp_ts_sequence} instead.
  321. #
  322. def tcptssequence(&block)
  323. warn "DEPRECATION: use #{self.class}#tcp_ts_sequence instead"
  324. tcp_ts_sequence(&block)
  325. end
  326. #
  327. # Parses the scanned ports of the host.
  328. #
  329. # @yield [port]
  330. # Each scanned port of the host.
  331. #
  332. # @yieldparam [Port] port
  333. # A scanned port of the host.
  334. #
  335. # @return [Host, Enumerator]
  336. # The host.
  337. # If no block was given, an enumerator will be returned.
  338. #
  339. def each_port
  340. return enum_for(__method__) unless block_given?
  341. @node.xpath("ports/port").each do |port|
  342. yield Port.new(port)
  343. end
  344. return self
  345. end
  346. #
  347. # Parses the scanned ports of the host.
  348. #
  349. # @return [Array<Port>]
  350. # The scanned ports of the host.
  351. #
  352. def ports
  353. each_port.to_a
  354. end
  355. #
  356. # Parses the open ports of the host.
  357. #
  358. # @yield [port]
  359. # Each open port of the host.
  360. #
  361. # @yieldparam [Port] port
  362. # An open scanned port of the host.
  363. #
  364. # @return [Host, Enumerator]
  365. # The host.
  366. # If no block was given, an enumerator will be returned.
  367. #
  368. def each_open_port
  369. return enum_for(__method__) unless block_given?
  370. @node.xpath("ports/port[state/@state='open']").each do |port|
  371. yield Port.new(port)
  372. end
  373. return self
  374. end
  375. #
  376. # Parses the open ports of the host.
  377. #
  378. # @return [Array<Port>]
  379. # The open ports of the host.
  380. #
  381. def open_ports
  382. each_open_port.to_a
  383. end
  384. #
  385. # Parses the TCP ports of the host.
  386. #
  387. # @yield [port]
  388. # Each TCP port of the host.
  389. #
  390. # @yieldparam [Port] port
  391. # An TCP scanned port of the host.
  392. #
  393. # @return [Host, Enumerator]
  394. # The host.
  395. # If no block was given, an enumerator will be returned.
  396. #
  397. def each_tcp_port
  398. return enum_for(__method__) unless block_given?
  399. @node.xpath("ports/port[@protocol='tcp']").each do |port|
  400. yield Port.new(port)
  401. end
  402. return self
  403. end
  404. #
  405. # Parses the TCP ports of the host.
  406. #
  407. # @return [Array<Port>]
  408. # The TCP ports of the host.
  409. #
  410. def tcp_ports
  411. each_tcp_port.to_a
  412. end
  413. #
  414. # Parses the UDP ports of the host.
  415. #
  416. # @yield [port]
  417. # Each UDP port of the host.
  418. #
  419. # @yieldparam [Port] port
  420. # An UDP scanned port of the host.
  421. #
  422. # @return [Host, Enumerator]
  423. # The host.
  424. # If no block was given, an enumerator will be returned.
  425. #
  426. def each_udp_port
  427. return enum_for(__method__) unless block_given?
  428. @node.xpath("ports/port[@protocol='udp']").each do |port|
  429. yield Port.new(port)
  430. end
  431. return self
  432. end
  433. #
  434. # Parses the UDP ports of the host.
  435. #
  436. # @return [Array<Port>]
  437. # The UDP ports of the host.
  438. #
  439. def udp_ports
  440. each_udp_port.to_a
  441. end
  442. #
  443. # Parses the open ports of the host.
  444. #
  445. # @see each_open_port
  446. #
  447. def each(&block)
  448. each_open_port(&block)
  449. end
  450. #
  451. # The output from the NSE scripts ran against the host.
  452. #
  453. # @return [Hash{String => String}]
  454. # The NSE script names and output.
  455. #
  456. # @since 0.3.0
  457. #
  458. # @deprecated Use {#host_script} instead.
  459. #
  460. def scripts
  461. if host_script
  462. host_script.scripts
  463. else
  464. {}
  465. end
  466. end
  467. #
  468. # The NSE scripts ran against the host.
  469. #
  470. # @return [HostScript, nil]
  471. # Contains the host script output and data.
  472. #
  473. # @since 0.9.0
  474. #
  475. def host_script
  476. @host_script ||= if (hostscript = @node.at_xpath('hostscript'))
  477. HostScript.new(hostscript)
  478. end
  479. end
  480. #
  481. # Parses the traceroute information, if present.
  482. #
  483. # @yield [traceroute]
  484. # If a block is given, it will be passed the traceroute information.
  485. #
  486. # @yieldparam [Traceroute] traceroute
  487. # The traceroute information.
  488. #
  489. # @return [Traceroute]
  490. # The traceroute information.
  491. #
  492. # @since 0.7.0
  493. #
  494. def traceroute
  495. @traceroute ||= if (trace = @node.at_xpath('trace'))
  496. Traceroute.new(trace)
  497. end
  498. yield @traceroute if (@traceroute && block_given?)
  499. return @traceroute
  500. end
  501. #
  502. # Converts the host to a String.
  503. #
  504. # @return [String]
  505. # The hostname or address of the host.
  506. #
  507. # @see address
  508. #
  509. def to_s
  510. (hostname || address).to_s
  511. end
  512. #
  513. # Inspects the host.
  514. #
  515. # @return [String]
  516. # The inspected host.
  517. #
  518. def inspect
  519. "#<#{self.class}: #{self}>"
  520. end
  521. end
  522. end