PageRenderTime 41ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ipaddress/ipv4.rb

https://gitlab.com/intruxxer/ipaddress
Ruby | 1004 lines | 235 code | 59 blank | 710 comment | 28 complexity | 7f72154d4d6e5ebc91525be76f2cddb1 MD5 | raw file
  1. require 'ipaddress/prefix'
  2. module IPAddress;
  3. #
  4. # =Name
  5. #
  6. # IPAddress::IPv4 - IP version 4 address manipulation library
  7. #
  8. # =Synopsis
  9. #
  10. # require 'ipaddress'
  11. #
  12. # =Description
  13. #
  14. # Class IPAddress::IPv4 is used to handle IPv4 type addresses.
  15. #
  16. class IPv4
  17. include IPAddress
  18. include Enumerable
  19. include Comparable
  20. #
  21. # This Hash contains the prefix values for Classful networks
  22. #
  23. # Note that classes C, D and E will all have a default
  24. # prefix of /24 or 255.255.255.0
  25. #
  26. CLASSFUL = {
  27. /^0../ => 8, # Class A, from 0.0.0.0 to 127.255.255.255
  28. /^10./ => 16, # Class B, from 128.0.0.0 to 191.255.255.255
  29. /^110/ => 24 # Class C, D and E, from 192.0.0.0 to 255.255.255.254
  30. }
  31. #
  32. # Regular expression to match an IPv4 address
  33. #
  34. REGEXP = Regexp.new(/((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)/)
  35. #
  36. # Creates a new IPv4 address object.
  37. #
  38. # An IPv4 address can be expressed in any of the following forms:
  39. #
  40. # * "10.1.1.1/24": ip +address+ and +prefix+. This is the common and
  41. # suggested way to create an object .
  42. # * "10.1.1.1/255.255.255.0": ip +address+ and +netmask+. Although
  43. # convenient sometimes, this format is less clear than the previous
  44. # one.
  45. # * "10.1.1.1": if the address alone is specified, the prefix will be
  46. # set as default 32, also known as the host prefix
  47. #
  48. # Examples:
  49. #
  50. # # These two are the same
  51. # ip = IPAddress::IPv4.new("10.0.0.1/24")
  52. # ip = IPAddress("10.0.0.1/24")
  53. #
  54. # # These two are the same
  55. # IPAddress::IPv4.new "10.0.0.1/8"
  56. # IPAddress::IPv4.new "10.0.0.1/255.0.0.0"
  57. #
  58. def initialize(str)
  59. ip, netmask = str.split("/")
  60. # Check the ip and remove white space
  61. if IPAddress.valid_ipv4?(ip)
  62. @address = ip.strip
  63. else
  64. raise ArgumentError, "Invalid IP #{ip.inspect}"
  65. end
  66. # Check the netmask
  67. if netmask # netmask is defined
  68. netmask.strip!
  69. if netmask =~ /^\d{1,2}$/ # netmask in cidr format
  70. @prefix = Prefix32.new(netmask.to_i)
  71. elsif IPAddress.valid_ipv4_netmask?(netmask) # netmask in IP format
  72. @prefix = Prefix32.parse_netmask(netmask)
  73. else # invalid netmask
  74. raise ArgumentError, "Invalid netmask #{netmask}"
  75. end
  76. else # netmask is nil, reverting to defaul classful mask
  77. @prefix = Prefix32.new(32)
  78. end
  79. # Array formed with the IP octets
  80. @octets = @address.split(".").map{|i| i.to_i}
  81. # 32 bits interger containing the address
  82. @u32 = (@octets[0]<< 24) + (@octets[1]<< 16) + (@octets[2]<< 8) + (@octets[3])
  83. end # def initialize
  84. #
  85. # Returns the address portion of the IPv4 object
  86. # as a string.
  87. #
  88. # ip = IPAddress("172.16.100.4/22")
  89. #
  90. # ip.address
  91. # #=> "172.16.100.4"
  92. #
  93. def address
  94. @address
  95. end
  96. #
  97. # Returns the prefix portion of the IPv4 object
  98. # as a IPAddress::Prefix32 object
  99. #
  100. # ip = IPAddress("172.16.100.4/22")
  101. #
  102. # ip.prefix
  103. # #=> 22
  104. #
  105. # ip.prefix.class
  106. # #=> IPAddress::Prefix32
  107. #
  108. def prefix
  109. @prefix
  110. end
  111. #
  112. # Set a new prefix number for the object
  113. #
  114. # This is useful if you want to change the prefix
  115. # to an object created with IPv4::parse_u32 or
  116. # if the object was created using the classful
  117. # mask.
  118. #
  119. # ip = IPAddress("172.16.100.4")
  120. #
  121. # puts ip
  122. # #=> 172.16.100.4/16
  123. #
  124. # ip.prefix = 22
  125. #
  126. # puts ip
  127. # #=> 172.16.100.4/22
  128. #
  129. def prefix=(num)
  130. @prefix = Prefix32.new(num)
  131. end
  132. #
  133. # Returns the address as an array of decimal values
  134. #
  135. # ip = IPAddress("172.16.100.4")
  136. #
  137. # ip.octets
  138. # #=> [172, 16, 100, 4]
  139. #
  140. def octets
  141. @octets
  142. end
  143. #
  144. # Returns a string with the address portion of
  145. # the IPv4 object
  146. #
  147. # ip = IPAddress("172.16.100.4/22")
  148. #
  149. # ip.to_s
  150. # #=> "172.16.100.4"
  151. #
  152. def to_s
  153. @address
  154. end
  155. #
  156. # Returns a string with the IP address in canonical
  157. # form.
  158. #
  159. # ip = IPAddress("172.16.100.4/22")
  160. #
  161. # ip.to_string
  162. # #=> "172.16.100.4/22"
  163. #
  164. def to_string
  165. "#@address/#@prefix"
  166. end
  167. #
  168. # Returns the prefix as a string in IP format
  169. #
  170. # ip = IPAddress("172.16.100.4/22")
  171. #
  172. # ip.netmask
  173. # #=> "255.255.252.0"
  174. #
  175. def netmask
  176. @prefix.to_ip
  177. end
  178. #
  179. # Like IPv4#prefix=, this method allow you to
  180. # change the prefix / netmask of an IP address
  181. # object.
  182. #
  183. # ip = IPAddress("172.16.100.4")
  184. #
  185. # puts ip
  186. # #=> 172.16.100.4/16
  187. #
  188. # ip.netmask = "255.255.252.0"
  189. #
  190. # puts ip
  191. # #=> 172.16.100.4/22
  192. #
  193. def netmask=(addr)
  194. @prefix = Prefix32.parse_netmask(addr)
  195. end
  196. #
  197. # Returns the address portion in unsigned
  198. # 32 bits integer format.
  199. #
  200. # This method is identical to the C function
  201. # inet_pton to create a 32 bits address family
  202. # structure.
  203. #
  204. # ip = IPAddress("10.0.0.0/8")
  205. #
  206. # ip.to_i
  207. # #=> 167772160
  208. #
  209. def u32
  210. @u32
  211. end
  212. alias_method :to_i, :u32
  213. alias_method :to_u32, :u32
  214. #
  215. # Returns the address portion of an IPv4 object
  216. # in a network byte order format.
  217. #
  218. # ip = IPAddress("172.16.10.1/24")
  219. #
  220. # ip.data
  221. # #=> "\254\020\n\001"
  222. #
  223. # It is usually used to include an IP address
  224. # in a data packet to be sent over a socket
  225. #
  226. # a = Socket.open(params) # socket details here
  227. # ip = IPAddress("10.1.1.0/24")
  228. # binary_data = ["Address: "].pack("a*") + ip.data
  229. #
  230. # # Send binary data
  231. # a.puts binary_data
  232. #
  233. def data
  234. [@u32].pack("N")
  235. end
  236. #
  237. # Returns the octet specified by index
  238. #
  239. # ip = IPAddress("172.16.100.50/24")
  240. #
  241. # ip[0]
  242. # #=> 172
  243. # ip[1]
  244. # #=> 16
  245. # ip[2]
  246. # #=> 100
  247. # ip[3]
  248. # #=> 50
  249. #
  250. def [](index)
  251. @octets[index]
  252. end
  253. alias_method :octet, :[]
  254. #
  255. # Returns the address portion of an IP in binary format,
  256. # as a string containing a sequence of 0 and 1
  257. #
  258. # ip = IPAddress("127.0.0.1")
  259. #
  260. # ip.bits
  261. # #=> "01111111000000000000000000000001"
  262. #
  263. def bits
  264. data.unpack("B*").first
  265. end
  266. #
  267. # Returns the broadcast address for the given IP.
  268. #
  269. # ip = IPAddress("172.16.10.64/24")
  270. #
  271. # ip.broadcast.to_s
  272. # #=> "172.16.10.255"
  273. #
  274. def broadcast
  275. self.class.parse_u32(broadcast_u32, @prefix)
  276. end
  277. #
  278. # Checks if the IP address is actually a network
  279. #
  280. # ip = IPAddress("172.16.10.64/24")
  281. #
  282. # ip.network?
  283. # #=> false
  284. #
  285. # ip = IPAddress("172.16.10.64/26")
  286. #
  287. # ip.network?
  288. # #=> true
  289. #
  290. def network?
  291. @u32 | @prefix.to_u32 == @prefix.to_u32
  292. end
  293. #
  294. # Returns a new IPv4 object with the network number
  295. # for the given IP.
  296. #
  297. # ip = IPAddress("172.16.10.64/24")
  298. #
  299. # ip.network.to_s
  300. # #=> "172.16.10.0"
  301. #
  302. def network
  303. self.class.parse_u32(network_u32, @prefix)
  304. end
  305. #
  306. # Returns a new IPv4 object with the
  307. # first host IP address in the range.
  308. #
  309. # Example: given the 192.168.100.0/24 network, the first
  310. # host IP address is 192.168.100.1.
  311. #
  312. # ip = IPAddress("192.168.100.0/24")
  313. #
  314. # ip.first.to_s
  315. # #=> "192.168.100.1"
  316. #
  317. # The object IP doesn't need to be a network: the method
  318. # automatically gets the network number from it
  319. #
  320. # ip = IPAddress("192.168.100.50/24")
  321. #
  322. # ip.first.to_s
  323. # #=> "192.168.100.1"
  324. #
  325. def first
  326. self.class.parse_u32(network_u32+1, @prefix)
  327. end
  328. #
  329. # Like its sibling method IPv4#first, this method
  330. # returns a new IPv4 object with the
  331. # last host IP address in the range.
  332. #
  333. # Example: given the 192.168.100.0/24 network, the last
  334. # host IP address is 192.168.100.254
  335. #
  336. # ip = IPAddress("192.168.100.0/24")
  337. #
  338. # ip.last.to_s
  339. # #=> "192.168.100.254"
  340. #
  341. # The object IP doesn't need to be a network: the method
  342. # automatically gets the network number from it
  343. #
  344. # ip = IPAddress("192.168.100.50/24")
  345. #
  346. # ip.last.to_s
  347. # #=> "192.168.100.254"
  348. #
  349. def last
  350. self.class.parse_u32(broadcast_u32-1, @prefix)
  351. end
  352. #
  353. # Iterates over all the hosts IP addresses for the given
  354. # network (or IP address).
  355. #
  356. # ip = IPAddress("10.0.0.1/29")
  357. #
  358. # ip.each_host do |i|
  359. # p i.to_s
  360. # end
  361. # #=> "10.0.0.1"
  362. # #=> "10.0.0.2"
  363. # #=> "10.0.0.3"
  364. # #=> "10.0.0.4"
  365. # #=> "10.0.0.5"
  366. # #=> "10.0.0.6"
  367. #
  368. def each_host
  369. (network_u32+1..broadcast_u32-1).each do |i|
  370. yield self.class.parse_u32(i, @prefix)
  371. end
  372. end
  373. #
  374. # Iterates over all the IP addresses for the given
  375. # network (or IP address).
  376. #
  377. # The object yielded is a new IPv4 object created
  378. # from the iteration.
  379. #
  380. # ip = IPAddress("10.0.0.1/29")
  381. #
  382. # ip.each do |i|
  383. # p i.address
  384. # end
  385. # #=> "10.0.0.0"
  386. # #=> "10.0.0.1"
  387. # #=> "10.0.0.2"
  388. # #=> "10.0.0.3"
  389. # #=> "10.0.0.4"
  390. # #=> "10.0.0.5"
  391. # #=> "10.0.0.6"
  392. # #=> "10.0.0.7"
  393. #
  394. def each
  395. (network_u32..broadcast_u32).each do |i|
  396. yield self.class.parse_u32(i, @prefix)
  397. end
  398. end
  399. #
  400. # Spaceship operator to compare IPv4 objects
  401. #
  402. # Comparing IPv4 addresses is useful to ordinate
  403. # them into lists that match our intuitive
  404. # perception of ordered IP addresses.
  405. #
  406. # The first comparison criteria is the u32 value.
  407. # For example, 10.100.100.1 will be considered
  408. # to be less than 172.16.0.1, because, in a ordered list,
  409. # we expect 10.100.100.1 to come before 172.16.0.1.
  410. #
  411. # The second criteria, in case two IPv4 objects
  412. # have identical addresses, is the prefix. An higher
  413. # prefix will be considered greater than a lower
  414. # prefix. This is because we expect to see
  415. # 10.100.100.0/24 come before 10.100.100.0/25.
  416. #
  417. # Example:
  418. #
  419. # ip1 = IPAddress "10.100.100.1/8"
  420. # ip2 = IPAddress "172.16.0.1/16"
  421. # ip3 = IPAddress "10.100.100.1/16"
  422. #
  423. # ip1 < ip2
  424. # #=> true
  425. # ip1 > ip3
  426. # #=> false
  427. #
  428. # [ip1,ip2,ip3].sort.map{|i| i.to_string}
  429. # #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"]
  430. #
  431. def <=>(oth)
  432. return prefix <=> oth.prefix if to_u32 == oth.to_u32
  433. to_u32 <=> oth.to_u32
  434. end
  435. #
  436. # Returns the number of IP addresses included
  437. # in the network. It also counts the network
  438. # address and the broadcast address.
  439. #
  440. # ip = IPAddress("10.0.0.1/29")
  441. #
  442. # ip.size
  443. # #=> 8
  444. #
  445. def size
  446. 2 ** @prefix.host_prefix
  447. end
  448. #
  449. # Returns an array with the IP addresses of
  450. # all the hosts in the network.
  451. #
  452. # ip = IPAddress("10.0.0.1/29")
  453. #
  454. # ip.hosts.map {|i| i.address}
  455. # #=> ["10.0.0.1",
  456. # #=> "10.0.0.2",
  457. # #=> "10.0.0.3",
  458. # #=> "10.0.0.4",
  459. # #=> "10.0.0.5",
  460. # #=> "10.0.0.6"]
  461. #
  462. def hosts
  463. to_a[1..-2]
  464. end
  465. #
  466. # Returns the network number in Unsigned 32bits format
  467. #
  468. # ip = IPAddress("10.0.0.1/29")
  469. #
  470. # ip.network_u32
  471. # #=> 167772160
  472. #
  473. def network_u32
  474. @u32 & @prefix.to_u32
  475. end
  476. #
  477. # Returns the broadcast address in Unsigned 32bits format
  478. #
  479. # ip = IPaddress("10.0.0.1/29")
  480. #
  481. # ip.broadcast_u32
  482. # #=> 167772167
  483. #
  484. def broadcast_u32
  485. network_u32 + size - 1
  486. end
  487. #
  488. # Checks whether a subnet includes the given IP address.
  489. #
  490. # Accepts an IPAddress::IPv4 object.
  491. #
  492. # ip = IPAddress("192.168.10.100/24")
  493. #
  494. # addr = IPAddress("192.168.10.102/24")
  495. #
  496. # ip.include? addr
  497. # #=> true
  498. #
  499. # ip.include? IPAddress("172.16.0.48/16")
  500. # #=> false
  501. #
  502. def include?(oth)
  503. @prefix <= oth.prefix and network_u32 == (oth.to_u32 & @prefix.to_u32)
  504. end
  505. #
  506. # Checks whether a subnet includes all the
  507. # given IPv4 objects.
  508. #
  509. # ip = IPAddress("192.168.10.100/24")
  510. #
  511. # addr1 = IPAddress("192.168.10.102/24")
  512. # addr2 = IPAddress("192.168.10.103/24")
  513. #
  514. # ip.include_all?(addr1,addr2)
  515. # #=> true
  516. #
  517. def include_all?(*others)
  518. others.all? {|oth| include?(oth)}
  519. end
  520. #
  521. # Checks if an IPv4 address objects belongs
  522. # to a private network RFC1918
  523. #
  524. # Example:
  525. #
  526. # ip = IPAddress "10.1.1.1/24"
  527. # ip.private?
  528. # #=> true
  529. #
  530. def private?
  531. [self.class.new("10.0.0.0/8"),
  532. self.class.new("172.16.0.0/12"),
  533. self.class.new("192.168.0.0/16")].any? {|i| i.include? self}
  534. end
  535. #
  536. # Returns the IP address in in-addr.arpa format
  537. # for DNS lookups
  538. #
  539. # ip = IPAddress("172.16.100.50/24")
  540. #
  541. # ip.reverse
  542. # #=> "50.100.16.172.in-addr.arpa"
  543. #
  544. def reverse
  545. @octets.reverse.join(".") + ".in-addr.arpa"
  546. end
  547. alias_method :arpa, :reverse
  548. #
  549. # Splits a network into different subnets
  550. #
  551. # If the IP Address is a network, it can be divided into
  552. # multiple networks. If +self+ is not a network, this
  553. # method will calculate the network from the IP and then
  554. # subnet it.
  555. #
  556. # If +subnets+ is an power of two number, the resulting
  557. # networks will be divided evenly from the supernet.
  558. #
  559. # network = IPAddress("172.16.10.0/24")
  560. #
  561. # network / 4 # implies map{|i| i.to_string}
  562. # #=> ["172.16.10.0/26",
  563. # "172.16.10.64/26",
  564. # "172.16.10.128/26",
  565. # "172.16.10.192/26"]
  566. #
  567. # If +num+ is any other number, the supernet will be
  568. # divided into some networks with a even number of hosts and
  569. # other networks with the remaining addresses.
  570. #
  571. # network = IPAddress("172.16.10.0/24")
  572. #
  573. # network / 3 # implies map{|i| i.to_string}
  574. # #=> ["172.16.10.0/26",
  575. # "172.16.10.64/26",
  576. # "172.16.10.128/25"]
  577. #
  578. # Returns an array of IPv4 objects
  579. #
  580. def split(subnets=2)
  581. unless (1..(2**@prefix.host_prefix)).include? subnets
  582. raise ArgumentError, "Value #{subnets} out of range"
  583. end
  584. networks = subnet(newprefix(subnets))
  585. until networks.size == subnets
  586. networks = sum_first_found(networks)
  587. end
  588. return networks
  589. end
  590. alias_method :/, :split
  591. #
  592. # Returns a new IPv4 object from the supernetting
  593. # of the instance network.
  594. #
  595. # Supernetting is similar to subnetting, except
  596. # that you getting as a result a network with a
  597. # smaller prefix (bigger host space). For example,
  598. # given the network
  599. #
  600. # ip = IPAddress("172.16.10.0/24")
  601. #
  602. # you can supernet it with a new /23 prefix
  603. #
  604. # ip.supernet(23).to_string
  605. # #=> "172.16.10.0/23"
  606. #
  607. # However if you supernet it with a /22 prefix, the
  608. # network address will change:
  609. #
  610. # ip.supernet(22).to_string
  611. # #=> "172.16.8.0/22"
  612. #
  613. # If +new_prefix+ is less than 1, returns 0.0.0.0/0
  614. #
  615. def supernet(new_prefix)
  616. raise ArgumentError, "New prefix must be smaller than existing prefix" if new_prefix >= @prefix.to_i
  617. return self.class.new("0.0.0.0/0") if new_prefix < 1
  618. return self.class.new(@address+"/#{new_prefix}").network
  619. end
  620. #
  621. # This method implements the subnetting function
  622. # similar to the one described in RFC3531.
  623. #
  624. # By specifying a new prefix, the method calculates
  625. # the network number for the given IPv4 object
  626. # and calculates the subnets associated to the new
  627. # prefix.
  628. #
  629. # For example, given the following network:
  630. #
  631. # ip = IPAddress "172.16.10.0/24"
  632. #
  633. # we can calculate the subnets with a /26 prefix
  634. #
  635. # ip.subnets(26).map{&:to_string)
  636. # #=> ["172.16.10.0/26", "172.16.10.64/26",
  637. # "172.16.10.128/26", "172.16.10.192/26"]
  638. #
  639. # The resulting number of subnets will of course always be
  640. # a power of two.
  641. #
  642. def subnet(subprefix)
  643. unless ((@prefix.to_i)..32).include? subprefix
  644. raise ArgumentError, "New prefix must be between #@prefix and 32"
  645. end
  646. Array.new(2**(subprefix-@prefix.to_i)) do |i|
  647. self.class.parse_u32(network_u32+(i*(2**(32-subprefix))), subprefix)
  648. end
  649. end
  650. #
  651. # Returns the difference between two IP addresses
  652. # in unsigned int 32 bits format
  653. #
  654. # Example:
  655. #
  656. # ip1 = IPAddress("172.16.10.0/24")
  657. # ip2 = IPAddress("172.16.11.0/24")
  658. #
  659. # puts ip1 - ip2
  660. # #=> 256
  661. #
  662. def -(oth)
  663. return (to_u32 - oth.to_u32).abs
  664. end
  665. #
  666. # Returns a new IPv4 object which is the result
  667. # of the summarization, if possible, of the two
  668. # objects
  669. #
  670. # Example:
  671. #
  672. # ip1 = IPAddress("172.16.10.1/24")
  673. # ip2 = IPAddress("172.16.11.2/24")
  674. #
  675. # p (ip1 + ip2).map {|i| i.to_string}
  676. # #=> ["172.16.10.0/23"]
  677. #
  678. # If the networks are not contiguous, returns
  679. # the two network numbers from the objects
  680. #
  681. # ip1 = IPAddress("10.0.0.1/24")
  682. # ip2 = IPAddress("10.0.2.1/24")
  683. #
  684. # p (ip1 + ip2).map {|i| i.to_string}
  685. # #=> ["10.0.0.0/24","10.0.2.0/24"]
  686. #
  687. def +(oth)
  688. aggregate(*[self,oth].sort.map{|i| i.network})
  689. end
  690. #
  691. # Checks whether the ip address belongs to a
  692. # RFC 791 CLASS A network, no matter
  693. # what the subnet mask is.
  694. #
  695. # Example:
  696. #
  697. # ip = IPAddress("10.0.0.1/24")
  698. #
  699. # ip.a?
  700. # #=> true
  701. #
  702. def a?
  703. CLASSFUL.key(8) === bits
  704. end
  705. #
  706. # Checks whether the ip address belongs to a
  707. # RFC 791 CLASS B network, no matter
  708. # what the subnet mask is.
  709. #
  710. # Example:
  711. #
  712. # ip = IPAddress("172.16.10.1/24")
  713. #
  714. # ip.b?
  715. # #=> true
  716. #
  717. def b?
  718. CLASSFUL.key(16) === bits
  719. end
  720. #
  721. # Checks whether the ip address belongs to a
  722. # RFC 791 CLASS C network, no matter
  723. # what the subnet mask is.
  724. #
  725. # Example:
  726. #
  727. # ip = IPAddress("192.168.1.1/30")
  728. #
  729. # ip.c?
  730. # #=> true
  731. #
  732. def c?
  733. CLASSFUL.key(24) === bits
  734. end
  735. #
  736. # Return the ip address in a format compatible
  737. # with the IPv6 Mapped IPv4 addresses
  738. #
  739. # Example:
  740. #
  741. # ip = IPAddress("172.16.10.1/24")
  742. #
  743. # ip.to_ipv6
  744. # #=> "ac10:0a01"
  745. #
  746. def to_ipv6
  747. "%.4x:%.4x" % [to_u32].pack("N").unpack("nn")
  748. end
  749. #
  750. # Creates a new IPv4 object from an
  751. # unsigned 32bits integer.
  752. #
  753. # ip = IPAddress::IPv4::parse_u32(167772160)
  754. #
  755. # ip.prefix = 8
  756. # ip.to_string
  757. # #=> "10.0.0.0/8"
  758. #
  759. # The +prefix+ parameter is optional:
  760. #
  761. # ip = IPAddress::IPv4::parse_u32(167772160, 8)
  762. #
  763. # ip.to_string
  764. # #=> "10.0.0.0/8"
  765. #
  766. def self.parse_u32(u32, prefix=32)
  767. self.new([u32].pack("N").unpack("C4").join(".")+"/#{prefix}")
  768. end
  769. #
  770. # Creates a new IPv4 object from binary data,
  771. # like the one you get from a network stream.
  772. #
  773. # For example, on a network stream the IP 172.16.0.1
  774. # is represented with the binary "\254\020\n\001".
  775. #
  776. # ip = IPAddress::IPv4::parse_data "\254\020\n\001"
  777. # ip.prefix = 24
  778. #
  779. # ip.to_string
  780. # #=> "172.16.10.1/24"
  781. #
  782. def self.parse_data(str, prefix=32)
  783. self.new(str.unpack("C4").join(".")+"/#{prefix}")
  784. end
  785. #
  786. # Extract an IPv4 address from a string and
  787. # returns a new object
  788. #
  789. # Example:
  790. #
  791. # str = "foobar172.16.10.1barbaz"
  792. # ip = IPAddress::IPv4::extract str
  793. #
  794. # ip.to_s
  795. # #=> "172.16.10.1"
  796. #
  797. def self.extract(str)
  798. self.new REGEXP.match(str).to_s
  799. end
  800. #
  801. # Summarization (or aggregation) is the process when two or more
  802. # networks are taken together to check if a supernet, including all
  803. # and only these networks, exists. If it exists then this supernet
  804. # is called the summarized (or aggregated) network.
  805. #
  806. # It is very important to understand that summarization can only
  807. # occur if there are no holes in the aggregated network, or, in other
  808. # words, if the given networks fill completely the address space
  809. # of the supernet. So the two rules are:
  810. #
  811. # 1) The aggregate network must contain +all+ the IP addresses of the
  812. # original networks;
  813. # 2) The aggregate network must contain +only+ the IP addresses of the
  814. # original networks;
  815. #
  816. # A few examples will help clarify the above. Let's consider for
  817. # instance the following two networks:
  818. #
  819. # ip1 = IPAddress("172.16.10.0/24")
  820. # ip2 = IPAddress("172.16.11.0/24")
  821. #
  822. # These two networks can be expressed using only one IP address
  823. # network if we change the prefix. Let Ruby do the work:
  824. #
  825. # IPAddress::IPv4::summarize(ip1,ip2).to_s
  826. # #=> "172.16.10.0/23"
  827. #
  828. # We note how the network "172.16.10.0/23" includes all the addresses
  829. # specified in the above networks, and (more important) includes
  830. # ONLY those addresses.
  831. #
  832. # If we summarized +ip1+ and +ip2+ with the following network:
  833. #
  834. # "172.16.0.0/16"
  835. #
  836. # we would have satisfied rule #1 above, but not rule #2. So "172.16.0.0/16"
  837. # is not an aggregate network for +ip1+ and +ip2+.
  838. #
  839. # If it's not possible to compute a single aggregated network for all the
  840. # original networks, the method returns an array with all the aggregate
  841. # networks found. For example, the following four networks can be
  842. # aggregated in a single /22:
  843. #
  844. # ip1 = IPAddress("10.0.0.1/24")
  845. # ip2 = IPAddress("10.0.1.1/24")
  846. # ip3 = IPAddress("10.0.2.1/24")
  847. # ip4 = IPAddress("10.0.3.1/24")
  848. #
  849. # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_string
  850. # #=> "10.0.0.0/22",
  851. #
  852. # But the following networks can't be summarized in a single network:
  853. #
  854. # ip1 = IPAddress("10.0.1.1/24")
  855. # ip2 = IPAddress("10.0.2.1/24")
  856. # ip3 = IPAddress("10.0.3.1/24")
  857. # ip4 = IPAddress("10.0.4.1/24")
  858. #
  859. # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
  860. # #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
  861. #
  862. def self.summarize(*args)
  863. # one network? no need to summarize
  864. return [args.first.network] if args.size == 1
  865. i = 0
  866. result = args.dup.sort.map{|ip| ip.network}
  867. while i < result.size-1
  868. sum = result[i] + result[i+1]
  869. result[i..i+1] = sum.first if sum.size == 1
  870. i += 1
  871. end
  872. result.flatten!
  873. if result.size == args.size
  874. # nothing more to summarize
  875. return result
  876. else
  877. # keep on summarizing
  878. return self.summarize(*result)
  879. end
  880. end
  881. #
  882. # Creates a new IPv4 address object by parsing the
  883. # address in a classful way.
  884. #
  885. # Classful addresses have a fixed netmask based on the
  886. # class they belong to:
  887. #
  888. # * Class A, from 0.0.0.0 to 127.255.255.255
  889. # * Class B, from 128.0.0.0 to 191.255.255.255
  890. # * Class C, D and E, from 192.0.0.0 to 255.255.255.254
  891. #
  892. # Example:
  893. #
  894. # ip = IPAddress::IPv4.parse_classful "10.0.0.1"
  895. #
  896. # ip.netmask
  897. # #=> "255.0.0.0"
  898. # ip.a?
  899. # #=> true
  900. #
  901. # Note that classes C, D and E will all have a default
  902. # prefix of /24 or 255.255.255.0
  903. #
  904. def self.parse_classful(ip)
  905. if IPAddress.valid_ipv4?(ip)
  906. address = ip.strip
  907. else
  908. raise ArgumentError, "Invalid IP #{ip.inspect}"
  909. end
  910. prefix = CLASSFUL.find{|h,k| h === ("%.8b" % address.to_i)}.last
  911. self.new "#{address}/#{prefix}"
  912. end
  913. #
  914. # private methods
  915. #
  916. private
  917. def newprefix(num)
  918. num.upto(32) do |i|
  919. if (a = Math::log2(i).to_i) == Math::log2(i)
  920. return @prefix + a
  921. end
  922. end
  923. end
  924. def sum_first_found(arr)
  925. dup = arr.dup.reverse
  926. dup.each_with_index do |obj,i|
  927. a = [self.class.summarize(obj,dup[i+1])].flatten
  928. if a.size == 1
  929. dup[i..i+1] = a
  930. return dup.reverse
  931. end
  932. end
  933. return dup.reverse
  934. end
  935. def aggregate(ip1,ip2)
  936. return [ip1] if ip1.include? ip2
  937. snet = ip1.supernet(ip1.prefix-1)
  938. if snet.include_all?(ip1, ip2) && ((ip1.size + ip2.size) == snet.size)
  939. return [snet]
  940. else
  941. return [ip1, ip2]
  942. end
  943. end
  944. end # class IPv4
  945. end # module IPAddress