Netmask to CIDR in ruby
Here is the quick and dirty way
require 'ipaddr'
puts IPAddr.new("255.255.255.0").to_i.to_s(2).count("1")
There should be proper function for that, I couldn't find that, so I just count "1"
If you're going to be using the function in a number of places and don't mind monkeypatching, this could help:
IPAddr.class_eval
def to_cidr
"/" + self.to_i.to_s(2).count("1")
end
end
Then you get
IPAddr.new('255.255.255.0').to_cidr
# => "/24"
IP Range to CIDR in Ruby/Rails?
Well, to get the CIDR notation of a range, you need an IP and the number of network bits (calculated from the netmask).
To enumerate the addresses of a given range, you can use the NetAddr
(< 2.x) gem.
p NetAddr::CIDR.create('192.168.1.0/24').enumerate
=> ['192.168.1.0', '192.168.1.1', '192.168.1.2'... '192.168.1.255']
You can also calculate the bits from the netmask on the fly:
mask_int = NetAddr.netmask_to_i('255.255.255.0')
p NetAddr.mask_to_bits(mask_int)
=> 24
And to create a range based on two IPs:
lower = NetAddr::CIDR.create('192.168.1.1')
upper = NetAddr::CIDR.create('192.168.1.10')
p NetAddr.range(lower, upper)
=> ['192.168.1.2', '192.168.1.3'... '192.168.1.9']
So now that you can create a CIDR range, you can check to see if an IP is a part of it:
cidr = NetAddr::CIDR.create('192.168.1.0/24')
p cidr.contains?('192.168.1.10')
=> true
Ruby IPAddr: find address mask
Some parts of the Ruby core library are sometimes just sketched in, and IPAddr appears to be one of those that is, unfortunately, a little bit incomplete.
Not to worry. You can fix this with a simple monkey-patch:
class IPAddr
def cidr_mask
case (@family)
when Socket::AF_INET
32 - Math.log2((1<<32) - @mask_addr).to_i
when Socket::AF_INET6
128 - Math.log2((1<<128) - @mask_addr).to_i
else
raise AddressFamilyError, "unsupported address family"
end
end
end
That should handle IPv4 and IPv6 addresses:
IPAddr.new('151.101.65.69').cidr_mask
# => 32
IPAddr.new('151.101.65.69/26').cidr_mask
# => 26
IPAddr.new('151.101.65.69/255.255.255.0').cidr_mask
# => 24
IPAddr.new('2607:f8b0:4006:800::200e').cidr_mask
# => 128
IPAddr.new('2607:f8b0:4006:800::200e/100').cidr_mask
# => 100
It's not necessarily the best solution here, but it works.
Rails how to validate subnet mask before ip range calculation
ruby ipaddr
require 'ipaddr'
net1 = IPAddr.new("192.168.2.0/24")
net2 = IPAddr.new("192.168.2.100")
net3 = IPAddr.new("192.168.3.0")
p net1.include?(net2) #=> true
p net1.include?(net3) #=> false
NetAddr::Tree take list of CIDR and merge them?
Have you taken a look at NetAddr::merge?
From the docs:
Given a list of CIDR addresses or NetAddr::CIDR objects, merge (summarize) them in the most efficient way possible. Summarization will only occur when the newly created supernets will not result in the ‘creation’ of new IP space. For example the following blocks (192.168.0.0/24, 192.168.1.0/24, and 192.168.2.0/24) would be summarized into 192.168.0.0/23 and 192.168.2.0/24 rather than into 192.168.0.0/22
require 'netaddr'
require 'pp'
pp NetAddr.merge(
%w[
12.26.8.0/21
12.26.16.0/21
12.26.24.0/21
12.26.32.0/21
12.26.40.0/21
12.27.152.0/21
].map{ |ip| NetAddr::CIDR.create(ip) }
)
=> ["12.26.8.0/21", "12.26.16.0/20", "12.26.32.0/20", "12.27.152.0/21"]
Find out if an IP is within a range of IPs
>> require "ipaddr"
=> true
>> low = IPAddr.new("62.0.0.0").to_i
=> 1040187392
>> high = IPAddr.new("62.255.255.255").to_i
=> 1056964607
>> ip = IPAddr.new("62.156.244.13").to_i
=> 1050473485
>> (low..high)===ip
=> true
If you are given the network instead of the start and end addresses, it is even simpler
>> net = IPAddr.new("62.0.0.0/8")
=> #<IPAddr: IPv4:62.0.0.0/255.0.0.0>
>> net===IPAddr.new("62.156.244.13")
=> true
IPAddr
will also work with IPv6 addresses
>> low = IPAddr.new('1::')
=> #<IPAddr: IPv6:0001:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
>> high = IPAddr.new('2::')
=> #<IPAddr: IPv6:0002:0000:0000:0000:0000:0000:0000:0000/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>
>> (low..high)===IPAddr.new('1::1')
=> true
convert ipv4 netmask to cidr format
The complicated way would be to convert the netmask to binary and count the number of leading 1 bits. But since there are only 33 possible values, a simpler way is just an associative array:
$netmask_to_cidr = array(
'255.255.255.255' => 32,
'255.255.255.254' => 31,
'255.255.255.252' => 30,
...
'128.0.0.0' => 1,
'0.0.0.0' => 0);
Related Topics
Adding Username to Devise Rails 4
Dealing with Large CSV Files (20G) in Ruby
Trouble Downgrading Ruby on Os X Mavericks
How to Pass an Argument When Calling a View File
Describe VS Context in Rspec. Differences
Rails Way to Detect Mobile Device
Why Doesn't "Case" with "When > 2" Work
How to Remove a Non-Breaking Space in Ruby
Ruby Select and Reject in One Method
Testing Hash Contents Using Rspec
Limiting Characters/Words in View - Ruby on Rails
List Dynamic Attributes in a Mongoid Model
Devise Authentication Gem: How to Save the Logged in User Id
Advice on Using Modules with Ruby on Rails
What's the Cleanest Way to Override Activerecord's Find for Both Models and Collections