Ruby: How to Convert Ip Range to Array of Ip'S

Ruby: How to convert IP range to array of IP's

Use the Ruby standard library IPAddr

# I would suggest naming your function using underscore rather than camelcase
# because of Ruby naming conventions
#
require 'ipaddr'

def convert_ip_range(start_ip, end_ip)
start_ip = IPAddr.new(start_ip)
end_ip = IPAddr.new(end_ip)

# map to_s if you like, you can also call to_a,
# IPAddrs have some neat functions regarding IPs,
# be sure to check them out
#
(start_ip..end_ip).map(&:to_s)
end

How to convert IP range to a single CIDR using Ruby

Found it!

require 'netaddr'

startip = '250.154.64.0'
endip = '250.154.64.255'

ip_net_range = NetAddr.range(startip, endip, :Inclusive => true, :Objectify => true)
cidrs = NetAddr.merge(ip_net_range, :Objectify => true)

puts cidrs

output: 250.154.64.0/24

How to generate a list of IP addresses between two addresses with Ruby

Use IPAddr from the Ruby Stdlib.

IPAddr provides a set of methods to manipulate an IP address. Both
IPv4 and IPv6 are supported.

require 'ipaddr'

# I used a smaller number to limit the output
ip_range = IPAddr.new("192.168.1.3")..IPAddr.new("192.168.1.13")
ip_range.to_a

The output is an array of IPAddr instances.

=> [#<IPAddr: IPv4:192.168.1.3/255.255.255.255>, #<IPAddr: IPv4:192.168.1.4/255.255.255.255>, #<IPAddr: IPv4:192.168.1.5/255.255.255.255>, #<IPAddr: IPv4:192.168.1.6/255.255.255.255>, #<IPAddr: IPv4:192.168.1.7/255.255.255.255>, #<IPAddr: IPv4:192.168.1.8/255.255.255.255>, #<IPAddr: IPv4:192.168.1.9/255.255.255.255>, #<IPAddr: IPv4:192.168.1.10/255.255.255.255>, #<IPAddr: IPv4:192.168.1.11/255.255.255.255>, #<IPAddr: IPv4:192.168.1.12/255.255.255.255>, #<IPAddr: IPv4:192.168.1.13/255.255.255.255>]

A word of warning though. If you are taking user input make sure to catch the potential IPAddr::InvalidAddressError that can occur.

begin 
IPAddr.new(params[:from])..IPAddr.new(params[:to])
rescue IPAddr::InvalidAddressError
# @todo handle error
logger.info("Oh Noes!")
end

Convert a list of arrays into ip ranges

Convert the IP address to 32 bit integer (Assume you're dealing with IPv4 address according to your post), remove the duplicates, sort them, and do the merge. After that, convert the integers back to IP string:

require 'ipaddr'

def to_ranges(ips)
ips = ips.map{|ip| IPAddr.new(ip).to_i }.uniq.sort

prev = ips[0]
ips
.slice_before {|e|
prev2, prev = prev, e
prev2 + 1 != e
}
.map {|addrs| if addrs.length > 1 then [addrs[0], addrs[-1]] else addrs end }
.map {|addrs| addrs.map{|ip| IPAddr.new(ip, Socket::AF_INET)}.join("-") }
end

# some ip samples
ips = (0..255).map{|i| ["192.168.0.#{i}", "192.168.1.#{i}", "192.168.2.#{i}"] }.reduce(:+)
ips += ["192.168.3.0", "192.168.3.1"]
ips += ["192.168.3.5", "192.168.3.6"]
ips += ["192.168.5.1"]
ips += ["192.168.6.255", "192.168.7.0", "192.168.7.1"]

p to_ranges(ips)
# => ["192.168.0.0-192.168.3.1", "192.168.3.5-192.168.3.6", "192.168.5.1", "192.168.6.255-192.168.7.1"]

Reading IP addresses from file and storing them in an array should be relatively easy. 2 million IP addresses is a small set. You don't need to worry to much about the memory usage. (If it really matters, you may need to implement a algorithm to incrementally convert and merge the addresses)

BTW, I found the handy method Enumerable#slice_before when solving your problem.

How to manually convert an integer into an IP address in Ruby

An IP is just a 32-bit integer representing a 4-byte array:

[631271850].pack('N').unpack('CCCC').join('.')
=> "37.160.113.170"

Just for fun, another way to convert IP to int:

"37.160.113.170".split(".").map(&:to_i).pack('CCCC').unpack('N')[0]
=> 631271850

How to populate an array with IP address pattern

You're looking for map

Ranges are enumerables so you can call map on them. And it's also simpler and easier to understand:

(203..210).map { |i| "10.13.#{i}.3" }

Would give you:

#=> ["10.13.203.3", "10.13.204.3", "10.13.205.3", "10.13.206.3", "10.13.207.3", "10.13.208.3", "10.13.209.3", "10.13.210.3"]

Separate IP Range to Separate IPs

I have figured this out using Ruby code, and applied it after saving the Excel file as a tab-delimited TXT file.

 def expand_lines(line)
id, inst, ip = line.split("\t")

ip_compontents = ip.split('.')
if ip_compontents[2] =~ /(\d+)-(\d+)/
$1.to_i.upto($2.to_i).map do |i|
new_ip = [*ip_compontents[0..1], i, ip_compontents[3]].join('.')
[id, inst, new_ip]
end
else
[[id, inst, ip]]
end
end

if $0 == __FILE__
ext = File.extname(ARGV[0])
base = File.basename(ARGV[0], ext)
dir = File.dirname(ARGV[0])

outfile = File.join(dir, "#{base}_expanded#{ext}")

expanded = IO.read(ARGV[0]).split("\n").map {|l| expand_lines(l.chomp)}.flatten(1)
File.open(outfile, 'w') do |f|
f.puts expanded.map {|l| l.join("\t")}
end
end

Creating IP address range in Ruby

require 'ipaddr'
puts IPAddr.new("123.123.0.0/16").to_range.to_a

If you absolutely have to use the ambiguous "IP defines range" data in the question,

require 'ipaddr'
STDIN.read.each_line do |line|
num_zeroes = line[/(\.0)*$/].length / 2
ip_range_string = "#{line.chomp}/#{32 - num_zeroes * 8}"
puts IPAddr.new(ip_range_string).to_range.to_a
end

Count IP addresses

If you need to convert an IP to a range, you'll need a function that converts an IPv4 value to an integer, then do math on those:

require 'ipaddr'

def ip(string)
IPAddr.new(string).to_i
end

def parse_ip(string)
string.split(/\s+\-\s+/).collect { |v| ip(v) }
end

def ip_range(string)
ips = parse_ip(string)

ips.last - ips.first + 1
end

ip_range("10.2.3.10 - 10.2.3.15")
# => 6

That should do it.



Related Topics



Leave a reply



Submit