Problem with IPAddr

Hello all,

I’m having a problem with IPAddr, and I’m hoping someone can explain it
to
me. I’ve done the following test, and I get the results shown below.

irb(main):001:0> require ‘ipaddr’
=> true
irb(main):002:0> net_1 = IPAddr.new(“192.168.0.0/16”)
=> #<IPAddr: IPv4:192.168.0.0/255.255.0.0>
irb(main):003:0> net_2 = IPAddr.new(“192.168.0.0/24”)
=> #<IPAddr: IPv4:192.168.0.0/255.255.255.0>
irb(main):004:0> net_1.include?(net_2)
=> true
irb(main):005:0> net_2.include?(net_1)
=> true
irb(main):006:0>

I understand how net_1 can include net_2, but why does net_2 include
net_1?! Thanks in advance! – BTR

On Jan 16, 2008, at 12:02 AM, Bryan R. wrote:

irb(main):003:0> net_2 = IPAddr.new(“192.168.0.0/24”)
=> #<IPAddr: IPv4:192.168.0.0/255.255.255.0>
irb(main):004:0> net_1.include?(net_2)
=> true
irb(main):005:0> net_2.include?(net_1)
=> true
irb(main):006:0>

It is because include? is treating its argument as an address not as
a network. The subnet mask of the argument is ignored. So
net_2.include?(net_1) is really asking whether the first address of
net_1 (192.168.0.0) is contained in net_2 and that is true.

Gary W.

Gary,

Thanks for the reply. Here’s what I get when I try something else:

irb(main):001:0> require ‘ipaddr’
=> true
irb(main):002:0> net_1 = IPAddr.new(“192.168.0.0/16”)
=> #<IPAddr: IPv4:192.168.0.0/255.255.0.0>
irb(main):003:0> net_2 = IPAddr.new(“192.168.101.0/24”)
=> #<IPAddr: IPv4:192.168.101.0/255.255.255.0>
irb(main):004:0> net_1.include?(net_2)
=> true
irb(main):005:0> net_2.include?(net_1)
=> false
irb(main):006:0>

Makes sense I guess. Is there any way to tell IPAddr to look at it as a
network instead of as an address? I have a situation where I may come
across an address (ending in .0, so defining a network) where the
netmask
isn’t given, so I assign it as a small network (say /29). Later on I
may
come across it again, this time with the netmask defined (say /16), and
I
want to merge the first one into the second one. Therefore, each time I
add
a new network to my database, I compare it to the existing ones to see
if
any should be merged. Any suggestions? Thanks!! – BTR

On Jan 15, 2008 11:53 PM, Bryan R. [email protected] wrote:

irb(main):004:0> net_1.include?(net_2)
want to merge the first one into the second one. Therefore, each time I add
a new network to my database, I compare it to the existing ones to see if
any should be merged. Any suggestions? Thanks!! – BTR

You could open up IPAddr to get at the mask for comparison.

class IPAddr
def net
@mask_addr
end
end

ip1 = IPAddr.new(“192.168.0.0/16”)
ip2 = IPAddr.new(“192.168.0.0/24”)

ip1.net > ip2.net # => false (which seems contradictory, but the mask
number is larger for smaller networks)
ip2.net > ip1.net #=> true

hth,
Todd

On Wed, 2008-01-16 at 14:53 +0900, Bryan R. wrote:

irb(main):004:0> net_1.include?(net_2)
want to merge the first one into the second one. Therefore, each time I add
a new network to my database, I compare it to the existing ones to see if
any should be merged. Any suggestions? Thanks!! – BTR

First I’d like to add that the last octet being 0 does not mean that the
IP address is a network address: In the network 10.0.0.0/25, 10.0.1.0 is
a host address.

IPAddr doesn’t seem to have this functionality, but you can add it like
this:

$ irb
irb(main):001:0> require ‘ipaddr’
=> true
irb(main):002:0> class IPAddr
irb(main):003:1> def broadcast_addr
irb(main):004:2> _to_string(@addr | (2**32 - 1) - (@mask_addr))
irb(main):005:2> end
irb(main):006:1> def network_in_network?(network)
irb(main):007:2> return false unless self.include?(network)
irb(main):008:2> return false unless
self.include?(IPAddr.new(network.broadcast_addr))
irb(main):009:2> return true
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> a = IPAddr.new(‘192.168.0.128/25’)
=> #<IPAddr: IPv4:192.168.0.128/255.255.255.128>
irb(main):013:0> b = IPAddr.new(‘192.168.0.0/24’)
=> #<IPAddr: IPv4:192.168.0.0/255.255.255.0>
irb(main):014:0> a.network_in_network?(b)
=> false
irb(main):015:0> b.network_in_network?(a)
=> true
irb(main):016:0>

This works by determining the broadcast address of the network (by ORing
the network address with the reverse netmask) and then checking if both
network and broadcast address are included in the range you’re checking
against.

HTH,

Felix

Todd,

I believe Felix’s suggestion is the way to go. With yours, the
addresses
could be different, but as long as the mask was bigger it would still
return
true… not correct. Example:

a = IPAddr.new(“192.168.15.5”)
b = IPAddr.new(“192.168.16.0/24”)

a.network_in_network?(b) #==> true

Thanks! – BTR

On Jan 16, 2008 9:12 PM, Bryan R. [email protected] wrote:

Todd,

I believe Felix’s suggestion is the way to go. With yours, the addresses
could be different, but as long as the mask was bigger it would still return
true… not correct.

Good point!

thanx,
Todd

On Jan 16, 2008 6:52 AM, fw [email protected] wrote:

=> #<IPAddr: IPv4:192.168.101.0/255.255.255.0>
come across it again, this time with the netmask defined (say /16), and I

self.include?(IPAddr.new(network.broadcast_addr))
irb(main):015:0> b.network_in_network?(a)
=> true
irb(main):016:0>

This works by determining the broadcast address of the network (by ORing
the network address with the reverse netmask) and then checking if both
network and broadcast address are included in the range you’re checking
against.

This might work too…

class IPAddr
attr_accessor :mask_addr
def network_in_network? ipaddr
@mask_addr > ipaddr.mask_addr
end
end

Todd