Module: NetAddr

### Home Classes Methods

### In Files

- lib/cidr_shortcuts.rb
- lib/cidr.rb
- lib/ip_math.rb
- lib/validation_shortcuts.rb
- lib/eui.rb
- lib/netaddr.rb
- lib/methods.rb
- lib/tree.rb

### Namespace

- CLASS NetAddr::CIDR
- CLASS NetAddr::CIDRv4
- CLASS NetAddr::CIDRv6
- CLASS NetAddr::EUI
- CLASS NetAddr::EUI48
- CLASS NetAddr::EUI64
- CLASS NetAddr::Tree

### Methods

- ::binary_mirror
- ::bits_to_mask
- ::cidr_build
- ::cidr_compare
- ::cidr_fill_in
- ::cidr_find_in_list
- ::cidr_gt_lt
- ::cidr_make_subnets_from_base_and_ip_count
- ::cidr_sort
- ::cidr_summarize
- ::cidr_supernets
- ::detect_ip_version
- ::i_to_bits
- ::i_to_ip
- ::ip_count_to_size
- ::ip_int_to_str
- ::ip_str_to_int
- ::ip_to_i
- ::mask_to_bits
- ::merge
- ::minimum_size
- ::netmask_sort
- ::netmask_str_to_int
- ::netmask_to_i
- ::range
- ::shorten
- ::sort
- ::supernets
- ::unshorten
- ::validate_args
- ::validate_eui
- ::validate_ip_addr
- ::validate_ip_int
- ::validate_ip_netmask
- ::validate_ip_str
- ::validate_netmask_int
- ::validate_netmask_str
- ::wildcard

### Files

- Errors
- README
- changelog

### Class/Module Index

Quicksearch

- NetAddr
- NetAddr::CIDR
- NetAddr::CIDRv4
- NetAddr::CIDRv6
- NetAddr::EUI
- NetAddr::EUI48
- NetAddr::EUI64
- NetAddr::Tree

No matching classes.

# NetAddr

Copyleft (c) 2006 Dustin Spinhirne

Licensed under the same terms as Ruby, No Warranty is provided.

Copyleft (c) 2006 Dustin Spinhirne

Licensed under the same terms as Ruby, No Warranty is provided.

Copyleft (c) 2006 Dustin Spinhirne

Licensed under the same terms as Ruby, No Warranty is provided.

Copyleft (c) 2006 Dustin Spinhirne

Licensed under the same terms as Ruby, No Warranty is provided.

### Public Class Methods

binary_mirror(num, bit_count) click to toggle source

given an integer and number of bits to consider, return its binary mirror

    # File lib/ip_math.rb, line 13
    def binary_mirror(num, bit_count)
        mirror = 0
        bit_count.times do # make mirror image of num by capturning lsb and left-shifting it onto mirror
            mirror = mirror << 1
            lsb = num & 1
            num = num >> 1
            mirror = mirror | lsb
        end
        return(mirror)
    end

bits_to_mask(netmask,version) click to toggle source

convert a netmask (in bits) to an integer mask

    # File lib/ip_math.rb, line 31
    def bits_to_mask(netmask,version)
        return(0) if (netmask == 0)
        all_f = 2**32-1
        all_f = 2**128-1 if (version == 6)
        return( all_f ^ (all_f >> netmask) )
    end

cidr_build(version, ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false) click to toggle source

create either a CIDRv4 or CIDRv6 object

    # File lib/cidr_shortcuts.rb, line 12
    def cidr_build(version, ip, netmask=nil, tag={}, wildcard_mask=nil, wildcard_mask_bit_flipped=false)
         return( NetAddr::CIDRv4.new(ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) ) if (version == 4)
         return( NetAddr::CIDRv6.new(ip, netmask, tag, wildcard_mask, wildcard_mask_bit_flipped) )
    end

cidr_compare(cidr1,cidr2) click to toggle source

    compare 2 CIDR objects

return:

- 1 if the cidr1 contains cidr2

- 0 if the cidr1 and cidr2 are equal

- -1 if cidr1 is a subnet of cidr2

- nil if the two are unrelated

    # File lib/cidr_shortcuts.rb, line 30
    def cidr_compare(cidr1,cidr2)
        comparasin = nil
        if ( cidr1.to_i(:network) == cidr2.to_i(:network) )
            # same network, check netmask
            if (cidr1.to_i(:netmask) == cidr2.to_i(:netmask) )
                comparasin = 0
            elsif(cidr1.to_i(:netmask) < cidr2.to_i(:netmask))
                comparasin = 1
            elsif(cidr1.to_i(:netmask) > cidr2.to_i(:netmask))
                comparasin = -1
            end

        elsif( (cidr2.to_i(:network) | cidr1.to_i(:hostmask)) == (cidr1.to_i(:network) | cidr1.to_i(:hostmask)) )
            # cidr1 contains cidr2
            comparasin = 1

        elsif( (cidr2.to_i(:network) | cidr2.to_i(:hostmask)) == (cidr1.to_i(:network) | cidr2.to_i(:hostmask)) )
            # cidr2 contains cidr1
            comparasin = -1
        end

        return(comparasin)
    end

cidr_fill_in(supernet,list) click to toggle source

Given a list of subnets of supernet, return a new list with any holes (missing subnets) filled in.

    # File lib/cidr_shortcuts.rb, line 88
    def cidr_fill_in(supernet,list)
            # sort our cidr's and see what is missing
            complete_list = []
            expected = supernet.to_i(:network)
            all_f = supernet.all_f

            NetAddr.cidr_sort(list).each do |cidr|
                network = cidr.to_i(:network)
                bitstep = (all_f + 1) - cidr.to_i(:netmask)

                if (network > expected) # missing space at beginning of supernet, so fill in the hole
                    num_ips_missing = network - expected
                    sub_list = cidr_make_subnets_from_base_and_ip_count(supernet,expected,num_ips_missing)
                    complete_list.concat(sub_list)
                elsif (network < expected)
                    next
                end

                complete_list.push(cidr)
                expected = network + bitstep
            end

            # if expected is not the next subnet, then we're missing subnets
            # at the end of the cidr
            next_sub = supernet.next_subnet(:Objectify => true).to_i(:network)
            if (expected != next_sub)
                num_ips_missing = next_sub - expected
                sub_list = cidr_make_subnets_from_base_and_ip_count(supernet,expected,num_ips_missing)
                complete_list.concat(sub_list)
            end

            return(complete_list)
    end

cidr_find_in_list(cidr,list) click to toggle source

evaluate cidr against list of cidrs.

return entry from list if entry is supernet of cidr (first matching entry) return index # of entry if entry is a duplicate of cidr return nil if no match found

    # File lib/cidr_shortcuts.rb, line 133
    def cidr_find_in_list(cidr,list)
        return(nil) if (list.length == 0)

        match = nil
        low = 0
        high = list.length - 1
        index = low + ( (high-low)/2 )
        while ( low <= high)
            cmp = cidr_gt_lt(cidr,list[index])
            if ( cmp == -1 )
                high = index - 1

            elsif ( cmp == 1 )
                if (cidr_compare(cidr,list[index]) == -1)
                    match = list[index]
                    break
                end
                low = index + 1

            else
                match = index
                break
            end
            index = low + ( (high-low)/2 )
        end
        return(match)
    end

cidr_gt_lt(cidr1,cidr2) click to toggle source

given a pair of CIDRs, determine if first is greater than or less than the second

return 1 if cidr1 > cidr2 return 0 if cidr1 == cidr2 return -1 if cidr1 < cidr2

    # File lib/cidr_shortcuts.rb, line 65
    def cidr_gt_lt(cidr1,cidr2)
        gt_lt = 1
        if(cidr1.to_i(:network) < cidr2.to_i(:network))
            gt_lt = -1
        elsif (cidr1.to_i(:network) == cidr2.to_i(:network))
            if (cidr1.to_i(:netmask) < cidr2.to_i(:netmask))
                gt_lt = -1
            elsif (cidr1.to_i(:netmask) == cidr2.to_i(:netmask))
                gt_lt = 0
            end
        end

        return(gt_lt)
    end

cidr_make_subnets_from_base_and_ip_count(cidr,base_addr,ip_count) click to toggle source

    Make CIDR addresses from a base addr and an number of ip's to encapsulate.

### Arguments:

    * cidr
    * base ip as integer
    * number of ip's required

### Returns:

    * array of NetAddr::CIDR objects

    # File lib/cidr_shortcuts.rb, line 176
    def cidr_make_subnets_from_base_and_ip_count(cidr,base_addr,ip_count)
        list = []
        until (ip_count == 0)
            mask = cidr.all_f
            multiplier = 0
            bitstep = 0
            last_addr = base_addr
            done = false
            until (done == true)
                if (bitstep < ip_count && (base_addr & mask == last_addr & mask) )
                    multiplier += 1
                elsif (bitstep > ip_count || (base_addr & mask != last_addr & mask) )
                    multiplier -= 1
                    done = true
                else
                    done = true
                end
                bitstep = 2**multiplier
                mask = cidr.all_f << multiplier & cidr.all_f
                last_addr = base_addr + bitstep - 1
            end

            list.push(NetAddr.cidr_build(cidr.version,base_addr,mask))
            ip_count -= bitstep
            base_addr += bitstep
        end

        return(list)
    end

cidr_sort(list, desc=false) click to toggle source

given a list of NetAddr::CIDRs, return them as a sorted list

    # File lib/cidr_shortcuts.rb, line 213
    def cidr_sort(list, desc=false)
        # uses simple quicksort algorithm
        sorted_list = []
        if (list.length < 1)
            sorted_list = list
        else
            less_list = []
            greater_list = []
            equal_list = []
            pivot = list[rand(list.length)]
            if (desc)
                list.each do |x|
                    if ( pivot.to_i(:network) < x.to_i(:network) )
                        less_list.push(x)
                    elsif ( pivot.to_i(:network) > x.to_i(:network) )
                        greater_list.push(x)
                    else
                        if ( pivot.to_i(:netmask) < x.to_i(:netmask) )
                            greater_list.push(x)
                        elsif ( pivot.to_i(:netmask) > x.to_i(:netmask) )
                            less_list.push(x)
                        else
                            equal_list.push(x)
                        end
                    end
                end
            else
                list.each do |x|
                    gt_lt = cidr_gt_lt(pivot,x)
                    if (gt_lt == 1)
                        less_list.push(x)
                    elsif (gt_lt == -1)
                        greater_list.push(x)
                    else
                        equal_list.push(x)
                    end
                end
            end

            sorted_list.concat( cidr_sort(less_list, desc) )
            sorted_list.concat(equal_list)
            sorted_list.concat( cidr_sort(greater_list, desc) )
        end

        return(sorted_list)
    end

cidr_summarize(subnet_list) click to toggle source

given a list of NetAddr::CIDRs (of the same version) summarize them

return a hash, with the key = summary address and val = array of original cidrs

    # File lib/cidr_shortcuts.rb, line 269
    def cidr_summarize(subnet_list)
        all_f = subnet_list[0].all_f
        version = subnet_list[0].version
        subnet_list = cidr_sort(subnet_list)

        # continue summarization attempts until sorted_list stops getting shorter
        sorted_list = subnet_list.dup
        sorted_list_len = sorted_list.length
        while (1)
            summarized_list = []
            until (sorted_list.length == 0)
                cidr = sorted_list.shift
                network, netmask = cidr.to_i(:network), cidr.to_i(:netmask)
                supermask = (netmask << 1) & all_f
                supernet = supermask & network

                if (network == supernet && sorted_list.length > 0)
                    # network is lower half of supernet, so see if we have the upper half
                    bitstep = (all_f + 1) - netmask
                    expected = network + bitstep
                    next_cidr = sorted_list.shift
                    next_network, next_netmask = next_cidr.to_i(:network), next_cidr.to_i(:netmask)

                    if ( (next_network == expected) && (next_netmask == netmask) )
                        # we do indeed have the upper half. store new supernet.
                        summarized_list.push( cidr_build(version,supernet,supermask) )
                    else
                        # we do not have the upper half. put next_cidr back into sorted_list
                        # and store only the original network
                        sorted_list.unshift(next_cidr)
                        summarized_list.push(cidr)
                    end
                else
                    # network is upper half of supernet, so save original network only
                    summarized_list.push(cidr)
                end

            end

            sorted_list = summarized_list.dup
            break if (sorted_list.length == sorted_list_len)
            sorted_list_len = sorted_list.length
        end

        # clean up summarized_list
        unique_list = {}
        summarized_list.reverse.each do |supernet|
            next if ( unique_list.has_key?(supernet.desc) )
            # remove duplicates
            unique_list[supernet.desc] = supernet

            # remove any summary blocks that are children of other summary blocks
            index = 0
            until (index >= summarized_list.length)
                subnet = summarized_list[index]
                if (subnet &&  cidr_compare(supernet,subnet) == 1 )
                    subnet_list[index] = nil
                end
                index += 1
            end
        end
        summarized_list = unique_list.values

        # map original blocks to their summaries
        summarized_list.each do |supernet|
            supernet.tag[:Subnets] = []
            index = 0
            until (index >= subnet_list.length)
                subnet = subnet_list[index]
                if (subnet && cidr_compare(supernet,subnet) == 1 )
                    subnet_list[index] = nil
                    supernet.tag[:Subnets].push(subnet)
                end
                index += 1
            end
        end

        return( NetAddr.cidr_sort(summarized_list) )
    end

cidr_supernets(subnet_list) click to toggle source

given a list of NetAddr::CIDRs (of the same version), return only the 'top level' blocks (i.e. blocks not contained by other blocks

    # File lib/cidr_shortcuts.rb, line 357
    def cidr_supernets(subnet_list)
        summary_list = []
        subnet_list = netmask_sort(subnet_list)
        subnet_list.each do |child|
            is_parent = true
            summary_list.each do |parent|
                if (NetAddr.cidr_compare(parent,child) == 1)
                    is_parent = false
                    parent.tag[:Subnets].push(child)
                end
            end

            if (is_parent)
                child.tag[:Subnets] = []
                summary_list.push(child)
            end
        end

        return(summary_list)
    end

detect_ip_version(ip) click to toggle source

determine the ip version from ip address string.

return 4, 6, or nil

    # File lib/ip_math.rb, line 47
    def detect_ip_version(ip)
        version = nil
        if ( ip =~ /\./ && ip !~ /:/ )
            version = 4
        elsif (ip =~ /:/)
            version = 6
        else
            raise ValidationError, "Could not auto-detect IP version for '#{ip}'."
        end
        return(version)
    end

i_to_bits(netmask_int) click to toggle source

### Synopsis

Convert an Integer representing a binary netmask into an Integer representing the number of bits in that netmask.

    Example:
    NetAddr.i_to_bits(0xfffffffe) => 31
    NetAddr.i_to_bits(0xffffffffffffffff0000000000000000) => 64

### Arguments:

- netmask_int = Integer representing a binary netmask

### Returns:

- Integer

    # File lib/methods.rb, line 27
    def i_to_bits(netmask_int)

        # validate netmask_int
        raise ArgumentError, "Integer expected for argument 'netmask_int', " +
                             "but #{netmask_int.class} provided." if (!netmask_int.kind_of?(Integer))

        return( mask_to_bits(netmask_int) )
    end

i_to_ip(ip_int, options=nil) click to toggle source

### Synopsis

Convert an Integer into an IP address. This method will attempt to auto-detect the IP version if not provided, however, a slight speed increase is realized if version is provided.

    Example:
    NetAddr.i_to_ip(3232235906) => "192.168.1.130"
    NetAddr.i_to_ip(0xffff0000000000000000000000000001, :Version => 6) => "ffff:0000:0000:0000:0000:0000:0000:0001"

### Arguments:

- ip_int = IP address as an Integer

- options = Hash with the following keys:

      :Version -- IP version - Integer (optional)
      :IPv4Mapped -- if true, unpack IPv6 as an IPv4 mapped address (optional)

### Returns:

- String

    # File lib/methods.rb, line 59
    def i_to_ip(ip_int, options=nil)
        known_args = [:Version, :IPv4Mapped]
        ipv4_mapped = false
        version = nil

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
            NetAddr.validate_args(options.keys,known_args)

            if (options.has_key?(:Version))
                version = options[:Version]
                if (version != 4 && version != 6)
                    raise VersionError, ":Version should be 4 or 6, but was '#{version}'."
                end
            end

            if (options.has_key?(:IPv4Mapped) && options[:IPv4Mapped] == true)
                ipv4_mapped = true
            end
        end

        # validate & unpack
        raise ArgumentError, "Integer expected for argument 'ip_int', " +
                             "but #{ip_int.class} provided." if (!ip_int.kind_of?(Integer))
        version = validate_ip_int(ip_int, version)
        ip = ip_int_to_str(ip_int, version, ipv4_mapped)

        return(ip)
    end

ip_count_to_size(ipcount,version,extended=false) click to toggle source

given an ip count, determine the most appropriate mask (in bits)

    # File lib/ip_math.rb, line 66
    def ip_count_to_size(ipcount,version,extended=false)
        address_len = 32
        address_len = 128 if (version == 6 )

        if (ipcount > 2**address_len)
            raise BoundaryError, "Required IP count exceeds number of IP addresses available " +
                                 "for IPv#{version}."
        end

        bits_needed = 0
        until (2**bits_needed >= ipcount)
            bits_needed += 1
        end
        subnet_bits = address_len - bits_needed

        return( ip_int_to_str(bits_to_mask(subnet_bits, 4), 4) ) if (extended && version == 4)
        return(subnet_bits)
    end

ip_int_to_str(ip_int, version, ipv4_mapped=nil) click to toggle source

unpack an int into an ip address string

    # File lib/ip_math.rb, line 92
    def ip_int_to_str(ip_int, version, ipv4_mapped=nil)
        ip = nil
        version = 4 if (!version && ip_int < 2**32)
        if (version == 4)
            octets = []
            4.times do
                octet = ip_int & 0xFF
                octets.unshift(octet.to_s)
                ip_int = ip_int >> 8
            end
            ip = octets.join('.')
        else
            fields = []
            if (!ipv4_mapped)
                loop_count = 8
            else
                loop_count = 6
                ipv4_int = ip_int & 0xffffffff
                ipv4_addr = ip_int_to_str(ipv4_int, 4)
                fields.unshift(ipv4_addr)
                ip_int = ip_int >> 32
            end

            loop_count.times do
                octet = ip_int & 0xFFFF
                octet = octet.to_s(16)
                ip_int = ip_int >> 16

                # if octet < 4 characters, then pad with 0's
                (4 - octet.length).times do
                    octet = '0' << octet
                end
                fields.unshift(octet)
            end
            ip = fields.join(':')
        end
        return(ip)
    end

ip_str_to_int(ip,version) click to toggle source

convert an ip string into an int

    # File lib/ip_math.rb, line 138
    def ip_str_to_int(ip,version)
        ip_int = 0
        if ( version == 4)
            octets = ip.split('.')
            (0..3).each do |x|
                octet = octets.pop.to_i
                octet = octet << 8*x
                ip_int = ip_int | octet
            end

        else
            # if ipv4-mapped ipv6 addr
            if (ip =~ /\./)
                dotted_dec = true
            end

            # split up by ':'
            fields = []
            if (ip =~ /::/)
               shrthnd = ip.split( /::/ )
                if (shrthnd.length == 0)
                    return(0)
                else
                    first_half = shrthnd[0].split( /:/ ) if (shrthnd[0])
                    sec_half = shrthnd[1].split( /:/ ) if (shrthnd[1])
                    first_half = [] if (!first_half)
                    sec_half = [] if (!sec_half)
                end
                missing_fields = 8 - first_half.length - sec_half.length
                missing_fields -= 1 if dotted_dec
                fields = fields.concat(first_half)
                missing_fields.times {fields.push('0')}
                fields = fields.concat(sec_half)

            else
               fields = ip.split(':')
            end

            if (dotted_dec)
                ipv4_addr = fields.pop
                ipv4_int = NetAddr.ip_to_i(ipv4_addr, :Version => 4)
                octets = []
                2.times do
                    octet = ipv4_int & 0xFFFF
                    octets.unshift(octet.to_s(16))
                    ipv4_int = ipv4_int >> 16
                end
                fields.concat(octets)
            end

            # pack
            (0..7).each do |x|
                field = fields.pop.to_i(16)
                field = field << 16*x
                ip_int = ip_int | field
            end

       end
        return(ip_int)
    end

ip_to_i(ip, options=nil) click to toggle source

### Synopsis

Convert IP addresses into an Integer. This method will attempt to auto-detect the IP version if not provided, however a slight speed increase is realized if version is provided.

    Example:
    NetAddr.ip_to_i('192.168.1.1') => 3232235777
    NetAddr.ip_to_i('ffff::1', :Version => 6) => 340277174624079928635746076935438991361
    NetAddr.ip_to_i('::192.168.1.1') => 3232235777

### Arguments:

- ip = IP address as a String

- options = Hash with the following keys:

      :Version -- IP version - Integer

### Returns:

- Integer

    # File lib/methods.rb, line 112
    def ip_to_i(ip, options=nil)
        known_args = [:Version]
        to_validate = {}
        version = nil

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
            validate_args(options.keys,known_args)

            if (options.has_key?(:Version))
                version = options[:Version]
                to_validate[:Version] = version
                if (version != 4 && version != 6)
                    raise  VersionError, ":Version should be 4 or 6, but was '#{version}'."
                end
            end
        end

        if ( ip.kind_of?(String) )
            version = detect_ip_version(ip) if (!version)
            validate_ip_str(ip,version)
            ip_int = ip_str_to_int(ip,version)

        else
            raise ArgumentError, "String expected for argument 'ip' but #{ip.class} provided."
        end

        return(ip_int)
    end

mask_to_bits(netmask_int) click to toggle source

convert integer into a cidr formatted netmask (bits)

    # File lib/ip_math.rb, line 206
    def mask_to_bits(netmask_int)
        return(netmask_int) if (netmask_int == 0)

        mask = nil
        if (netmask_int < 2**32)
            mask = 32
            validate_netmask_int(netmask_int, 4, true)
        else
            mask = 128
            validate_netmask_int(netmask_int, 6, true)
        end

        mask.times do
            if ( (netmask_int & 1) == 1)
                break
            end
            netmask_int = netmask_int >> 1
            mask = mask - 1
        end
        return(mask)
    end

merge(list,options=nil) click to toggle source

### Synopsis

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

I have designed this with enough flexibility so that you can pass in CIDR addresses that arent even related (ex. 192.168.1.0/26, 192.168.1.64/27, 192.168.1.96/27 10.1.0.0/26, 10.1.0.64/26) and they will be merged properly (ie 192.168.1.0/25, and 10.1.0.0/25 would be returned).

If the :Objectify option is enabled, then any summary addresses returned will contain the original CIDRs used to create them within the tag value :Subnets (ie. cidr_x.tag would be an Array of the CIDRs used to create cidr_x)

    Example:
    cidr1 = NetAddr::CIDR.create('192.168.1.0/27')
    cidr2 = NetAddr::CIDR.create('192.168.1.32/27')
    NetAddr.merge([cidr1,cidr2])
    ip_net_range = NetAddr.range('192.168.35.0','192.168.39.255',:Inclusive => true, :Objectify => true)
    NetAddr.merge(ip_net_range, :Objectify => true)

### Arguments:

- list = Array of CIDR addresses as Strings, or an Array of NetAddr::CIDR objects

- options = Hash with the following keys:

      :Objectify -- if true, return NetAddr::CIDR objects
      :Short -- if true, return IPv6 addresses in short-hand notation

### Returns:

- Array of CIDR addresses or NetAddr::CIDR objects

    # File lib/methods.rb, line 181
    def merge(list,options=nil)
        known_args = [:Objectify, :Short]
        short = false
        objectify = false
        verbose = false

        # validate list
        raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) )

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) )
            NetAddr.validate_args(options.keys,known_args)

            if (options.has_key?(:Objectify) && options[:Objectify] == true)
                objectify = true
            end

            if (options.has_key?(:Short) && options[:Short] == true)
                short = true
            end
        end

        # make sure all are valid types of the same IP version
        v4_list = []
        v6_list = []
        list.each do |obj|
            if (!obj.kind_of?(NetAddr::CIDR))
                begin
                    obj = NetAddr::CIDR.create(obj)
                rescue Exception => error
                    raise ArgumentError, "One of the provided CIDR addresses raised the following " +
                                         "errors: #{error}"
                end
            end

            if (obj.version == 4)
                v4_list.push(obj)
            else
                v6_list.push(obj)
            end
        end

        # summarize
        v4_summary = []
        v6_summary = []
        if (v4_list.length != 0)
            v4_summary = NetAddr.cidr_summarize(v4_list)
        end

        if (v6_list.length != 0)
            v6_summary = NetAddr.cidr_summarize(v6_list)
        end

        # decide what to return
        summarized_list = []
        if (!objectify)
            summarized_list = []
            if (v4_summary.length != 0)
                v4_summary.each {|x| summarized_list.push(x.desc())}
            end

            if (v6_summary.length != 0)
                v6_summary.each {|x| summarized_list.push(x.desc(:Short => short))}
            end

        else
            summarized_list.concat(v4_summary) if (v4_summary.length != 0)
            summarized_list.concat(v6_summary) if (v6_summary.length != 0)
        end

        return(summarized_list)
    end

minimum_size(ipcount, options=nil) click to toggle source

### Synopsis

Given the number of IP addresses required in a subnet, return the minimum netmask (bits by default) required for that subnet. IP version is assumed to be 4 unless specified otherwise.

    Example:
    NetAddr.minimum_size(14) => 28
    NetAddr.minimum_size(65536, :Version => 6) => 112

### Arguments:

- ipcount = IP count as an Integer

- options = Hash with the following keys:

      :Extended -- If true, then return the netmask, as a String, in extended format (IPv4 only y.y.y.y)
      :Version -- IP version - Integer

### Returns:

- Integer or String

    # File lib/methods.rb, line 277
    def minimum_size(ipcount, options=nil)
        version = 4
        extended = false
        known_args = [:Version, :Extended]

        # validate ipcount
        raise ArgumentError, "Integer expected for argument 'ipcount' but #{ipcount.class} provided." if (!ipcount.kind_of?(Integer))

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))

            NetAddr.validate_args(options.keys,known_args)

            if (options.has_key?(:Version))
                version = options[:Version]
            end

            if (options.has_key?(:Extended) && options[:Extended] == true)
                extended = true
            end
        end

        return( ip_count_to_size(ipcount,version,extended) )
    end

netmask_sort(list, desc=false) click to toggle source

given a list of NetAddr::CIDRs, return them as a sorted (by netmask) list

    # File lib/cidr_shortcuts.rb, line 385
    def netmask_sort(list, desc=false)
        # uses simple quicksort algorithm
        sorted_list = []
        if (list.length < 1)
            sorted_list = list
        else
            less_list = []
            greater_list = []
            equal_list = []
            pivot = list[rand(list.length)]
            if (desc)
                list.each do |x|
                    if ( pivot.to_i(:netmask) < x.to_i(:netmask) )
                        less_list.push(x)
                    elsif ( pivot.to_i(:netmask) > x.to_i(:netmask) )
                        greater_list.push(x)
                    else
                        if ( pivot.to_i(:network) < x.to_i(:network) )
                            greater_list.push(x)
                        elsif ( pivot.to_i(:network) > x.to_i(:network) )
                            less_list.push(x)
                        else
                            equal_list.push(x)
                        end
                    end
                end
            else
                list.each do |x|
                    if ( pivot.to_i(:netmask) < x.to_i(:netmask) )
                        greater_list.push(x)
                    elsif ( pivot.to_i(:netmask) > x.to_i(:netmask) )
                        less_list.push(x)
                    else
                        if ( pivot.to_i(:network) < x.to_i(:network) )
                            greater_list.push(x)
                        elsif ( pivot.to_i(:network) > x.to_i(:network) )
                            less_list.push(x)
                        else
                            equal_list.push(x)
                        end
                    end
                end
            end

            sorted_list.concat( netmask_sort(less_list, desc) )
            sorted_list.concat(equal_list)
            sorted_list.concat( netmask_sort(greater_list, desc) )
        end

        return(sorted_list)
    end

netmask_str_to_int(netmask,version) click to toggle source

convert string into integer mask

    # File lib/ip_math.rb, line 235
    def netmask_str_to_int(netmask,version)
        netmask_int = nil
        all_f = 2**32-1
        all_f = 2**128-1 if (version == 6)
        if(netmask =~ /\./)
            netmask_int = NetAddr.ip_to_i(netmask)
        else
            # remove '/' if present
            if (netmask =~ /^\// )
                netmask[0] = " "
                netmask.lstrip!
            end
            netmask = netmask.to_i
            netmask_int = all_f ^ (all_f >> netmask)
        end
        return(netmask_int)
    end

netmask_to_i(netmask, options=nil) click to toggle source

### Synopsis

Convert IP netmask into an Integer. Netmask may be in either CIDR (/yy) or extended (y.y.y.y) format. CIDR formatted netmasks may either be a String or an Integer. IP version defaults to 4. It may be necessary to specify the version if an IPv6 netmask of /32 or smaller is provided.

    Example:
    NetAddr.netmask_to_i('255.255.255.0') => 4294967040
    NetAddr.netmask_to_i('24') => 4294967040
    NetAddr.netmask_to_i(24) => 4294967040
    NetAddr.netmask_to_i('/24') => 4294967040
    NetAddr.netmask_to_i('32', :Version => 6) => 340282366841710300949110269838224261120

### Arguments

- netmask = Netmask as a String or Integer

- options = Hash with the following keys:

      :Version -- IP version - Integer

### Returns:

- Integer

    # File lib/methods.rb, line 329
    def netmask_to_i(netmask, options=nil)
        known_args = [:Version]
        version = 4
        netmask_int = nil

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
            NetAddr.validate_args(options.keys,known_args)

            if (options.has_key?(:Version))
                version = options[:Version]
                if (version != 4 && version != 6)
                    raise VersionError, ":Version should be 4 or 6, but was '#{version}'."
                end
            end
        end

        if (netmask.kind_of?(String))
            validate_netmask_str(netmask, version)
            netmask_int = netmask_str_to_int(netmask,version)

        elsif (netmask.kind_of?(Integer))
            validate_netmask_int(netmask, version, true)
            netmask_int = bits_to_mask(netmask,version)

        else
            raise ArgumentError, "String or Integer expected for argument 'netmask', " +
                                 "but #{netmask.class} provided." if (!netmask.kind_of?(Integer) && !netmask.kind_of?(String))
        end

        return(netmask_int)
    end

range(lower, upper, options=nil) click to toggle source

### Synopsis

Given two CIDR addresses or NetAddr::CIDR objects of the same version, return all IP addresses between them. NetAddr.range will use the original IP address passed during the initialization of the NetAddr::CIDR objects, or the IP address portion of any CIDR addresses passed. The default behavior is to be non-inclusive (don't include boundaries as part of returned data).

    Example:
    lower = NetAddr::CIDR.create('192.168.35.0')
    upper = NetAddr::CIDR.create('192.168.39.255')
    NetAddr.range(lower,upper, :Limit => 10, :Bitstep => 32)
    NetAddr.range('192.168.35.0','192.168.39.255', :Inclusive => true)
    NetAddr.range('192.168.35.0','192.168.39.255', :Inclusive => true, :Size => true)

### Arguments:

- lower = Lower boundary CIDR as a String or NetAddr::CIDR object

- upper = Upper boundary CIDR as a String or NetAddr::CIDR object

- options = Hash with the following keys:

      :Bitstep -- enumerate in X sized steps - Integer
      :Inclusive -- if true, include boundaries in returned data
      :Limit -- limit returned list to X number of items - Integer
      :Objectify -- if true, return CIDR objects
      :Short -- if true, return IPv6 addresses in short-hand notation
      :Size -- if true, return the number of addresses in this range, but not the addresses themselves

### Returns:

- Array of Strings or NetAddr::CIDR objects, or an Integer

### Note:

If you do not need all of the fancy options in this method, then please consider using the standard Ruby Range class as shown below.

    Example:
    start = NetAddr::CIDR.create('192.168.1.0')
    fin = NetAddr::CIDR.create('192.168.2.3')
    (start..fin).each {|addr| puts addr.desc}

    # File lib/methods.rb, line 405
    def range(lower, upper, options=nil)
        known_args = [:Bitstep, :Inclusive, :Limit, :Objectify, :Short, :Size]
        list = []
        bitstep = 1
        objectify = false
        short = false
        size_only = false
        inclusive = false
        limit = nil

        # if lower/upper are not CIDR objects, then attempt to create
        # cidr objects from them
        if ( !lower.kind_of?(NetAddr::CIDR) )
            begin
                lower = NetAddr::CIDR.create(lower)
            rescue Exception => error
                raise ArgumentError, "Argument 'lower' raised the following " +
                                     "errors: #{error}"
            end
        end

        if ( !upper.kind_of?(NetAddr::CIDR))
            begin
                upper = NetAddr::CIDR.create(upper)
            rescue Exception => error
                raise ArgumentError, "Argument 'upper' raised the following " +
                                     "errors: #{error}"
            end
        end

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
            NetAddr.validate_args(options.keys,known_args)

            if( options.has_key?(:Bitstep) )
                bitstep = options[:Bitstep]
            end

            if( options.has_key?(:Objectify) && options[:Objectify] == true )
                objectify = true
            end

            if( options.has_key?(:Short) && options[:Short] == true )
                short = true
            end

            if( options.has_key?(:Size) && options[:Size] == true )
                size_only = true
            end

            if( options.has_key?(:Inclusive) && options[:Inclusive] == true )
                inclusive = true
            end

            if( options.has_key?(:Limit) )
                limit = options[:Limit]
            end
        end

        # check version, store & sort
        if (lower.version == upper.version)
            version = lower.version
            boundaries = [lower.to_i(:ip), upper.to_i(:ip)]
            boundaries.sort
        else
            raise VersionError, "Provided NetAddr::CIDR objects are of different IP versions."
        end

        # dump our range
        if (!inclusive)
            my_ip = boundaries[0] + 1
            end_ip = boundaries[1]
        else
            my_ip = boundaries[0]
            end_ip = boundaries[1] + 1
        end

        if (!size_only)
            until (my_ip >= end_ip)
                if (!objectify)
                    my_ip_s = ip_int_to_str(my_ip, version)
                    my_ips = shorten(my_ips) if (short && version == 6)
                    list.push(my_ip_s)
                else
                    list.push( cidr_build(version,my_ip) )
                end

                my_ip = my_ip + bitstep
                if (limit)
                    limit = limit -1
                    break if (limit == 0)
                end
            end
        else
            list = end_ip - my_ip
        end

        return(list)
    end

shorten(addr) click to toggle source

### Synopsis

Take a standard IPv6 address and format it in short-hand notation. The address should not contain a netmask.

    Example:
    NetAddr.shorten('fec0:0000:0000:0000:0000:0000:0000:0001') => "fec0::1"

### Arguments:

- addr = String

### Returns:

- String

    # File lib/methods.rb, line 524
    def shorten(addr)

        # is this a string?
        if (!addr.kind_of? String)
            raise ArgumentError, "Expected String, but #{addr.class} provided."
        end

        validate_ip_str(addr, 6)

        # make sure this isnt already shorthand
        if (addr =~ /::/)
            return(addr)
        end

        # split into fields
        fields = addr.split(":")

        # check last field for ipv4-mapped addr
        if (fields.last() =~ /\./ )
            ipv4_mapped = fields.pop()
        end

        # look for most consecutive '0' fields
        start_field,end_field = nil,nil
        start_end = []
        consecutive,longest = 0,0

        (0..(fields.length-1)).each do |x|
            fields[x] = fields[x].to_i(16)

            if (fields[x] == 0)
                if (!start_field)
                    start_field = x
                    end_field = x
                else
                    end_field = x
                end
                consecutive += 1
            else
                if (start_field)
                    if (consecutive > longest)
                        longest = consecutive
                        start_end = [start_field,end_field]
                        start_field,end_field = nil,nil
                    end
                    consecutive = 0
                end
            end

            fields[x] = fields[x].to_s(16)
        end

        # if our longest set of 0's is at the end, then start & end fields
        # are already set. if not, then make start & end fields the ones we've
        # stored away in start_end
        if (consecutive > longest)
            longest = consecutive
        else
            start_field = start_end[0]
            end_field = start_end[1]
        end

        if (longest > 1)
            fields[start_field] = ''
            start_field += 1
            fields.slice!(start_field..end_field)
        end
        fields.push(ipv4_mapped) if (ipv4_mapped)
        short = fields.join(':')
        short << ':' if (short =~ /:$/)

        return(short)
    end

sort(list, options=nil) click to toggle source

### Synopsis

Sort a list of CIDR addresses or NetAddr::CIDR objects,

    Example:
    cidr1 = NetAddr::CIDR.create('192.168.1.32/27')
    cidr2 = NetAddr::CIDR.create('192.168.1.0/27')
    NetAddr.sort([cidr1,cidr2])
    NetAddr.sort(['192.168.1.32/27','192.168.1.0/27','192.168.2.0/24'], :Desc => true)

### Arguments:

- list = Array of CIDR addresses as Strings, or Array of NetAddr::CIDR objects

- options = Hash with the following keys:

      :ByMask -- if true, sorts based on the netmask length
      :Desc -- if true, return results in descending order

### Returns:

- Array of Strings, or Array of NetAddr::CIDR objects

    # File lib/methods.rb, line 621
    def sort(list, options=nil)
        # make sure list is an array
        if ( !list.kind_of?(Array) )
            raise ArgumentError, "Array of NetAddr::CIDR or NetStruct " +
                                 "objects expected, but #{list.class} provided."
        end

        desc = false
        by_mask = false
        # validate options
        if (options)
            known_args = [:Desc, :ByMask]
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
            NetAddr.validate_args(options.keys,known_args)

            if( options.has_key?(:Desc) && options[:Desc] == true )
                desc = true
            end

            if( options.has_key?(:ByMask) && options[:ByMask] == true )
                by_mask = true
            end

        end

        # make sure all are valid types of the same IP version
        version = nil
        cidr_hash = {}
        list.each do |cidr|
            if (!cidr.kind_of?(NetAddr::CIDR))
                begin
                    new_cidr = NetAddr::CIDR.create(cidr)
                rescue Exception => error
                    raise ArgumentError, "An element of the provided Array " +
                                         "raised the following errors: #{error}"
                end
            else
                new_cidr = cidr
            end
            cidr_hash[new_cidr] = cidr

            version = new_cidr.version if (!version)
            unless (new_cidr.version == version)
                raise VersionError, "Provided CIDR addresses must all be of the same IP version."
            end
        end

        # perform sort
        if (by_mask)
            sorted_list = netmask_sort(cidr_hash.keys, desc)
        else
            sorted_list = cidr_sort(cidr_hash.keys, desc)
        end

        # return original values passed
        ret_list = []
        sorted_list.each {|x| ret_list.push(cidr_hash[x])}

        return(ret_list)
    end

supernets(list,options=nil) click to toggle source

### Synopsis

Given a list of CIDR addresses or NetAddr::CIDR objects, return only the top-level supernet CIDR addresses.

If the :Objectify option is enabled, then returned CIDR objects will store the more specific CIDRs (i.e. subnets of those CIDRs) within the tag value :Subnets For example, cidr_x.tag would be an Array of CIDR subnets of cidr_x.

    Example:
    NetAddr.supernets(['192.168.0.0', '192.168.0.1', '192.168.0.0/31'])

### Arguments:

- list = Array of CIDR addresses as Strings, or an Array of NetAddr::CIDR objects

- options = Hash with the following keys:

      :Objectify -- if true, return NetAddr::CIDR objects
      :Short -- if true, return IPv6 addresses in short-hand notation

### Returns:

- Array of CIDR addresses or NetAddr::CIDR objects

    # File lib/methods.rb, line 708
    def supernets(list,options=nil)
        known_args = [:Objectify, :Short]
        short = false
        objectify = false
        verbose = false

        # validate list
        raise ArgumentError, "Array expected for argument 'list' but #{list.class} provided." if (!list.kind_of?(Array) )

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash) )
            NetAddr.validate_args(options.keys,known_args)

            if (options.has_key?(:Objectify) && options[:Objectify] == true)
                objectify = true
            end

            if (options.has_key?(:Short) && options[:Short] == true)
                short = true
            end
        end

        # make sure all are valid types of the same IP version
        v4_list = []
        v6_list = []
        list.each do |obj|
            if (!obj.kind_of?(NetAddr::CIDR))
                begin
                    obj = NetAddr::CIDR.create(obj)
                rescue Exception => error
                    raise ArgumentError, "One of the provided CIDR addresses raised the following " +
                                         "errors: #{error}"
                end
            end

            if (obj.version == 4)
                v4_list.push(obj)
            else
                v6_list.push(obj)
            end
        end

        # do summary calcs
        v4_summary = []
        v6_summary = []
        if (v4_list.length != 0)
            v4_summary = NetAddr.cidr_supernets(v4_list)
        end

        if (v6_list.length != 0)
            v6_summary = NetAddr.cidr_supernets(v6_list)
        end

        # decide what to return
        summarized_list = []
        if (!objectify)
            summarized_list = []
            if (v4_summary.length != 0)
                v4_summary.each {|x| summarized_list.push(x.desc())}
            end

            if (v6_summary.length != 0)
                v6_summary.each {|x| summarized_list.push(x.desc(:Short => short))}
            end

        else
            summarized_list.concat(v4_summary) if (v4_summary.length != 0)
            summarized_list.concat(v6_summary) if (v6_summary.length != 0)
        end

        return(summarized_list)
    end

unshorten(ip) click to toggle source

### Synopsis

Take an IPv6 address in short-hand format, and expand it into standard notation. The address should not contain a netmask.

    Example:
    NetAddr.unshorten('fec0::1') => "fec0:0000:0000:0000:0000:0000:0000:0001"

### Arguments:

- ip = CIDR address as a String

### Returns:

- String

    # File lib/methods.rb, line 800
    def unshorten(ip)

        # is this a string?
        if (!ip.kind_of? String)
            raise ArgumentError, "Expected String, but #{ip.class} provided."
        end

        validate_ip_str(ip, 6)
        ipv4_mapped = true if (ip =~ /\./)

        ip_int = ip_to_i(ip, :Version => 6)
        if (!ipv4_mapped)
            long = ip_int_to_str(ip_int, 6)
        else
            long = ip_int_to_str(ip_int, 6, true)
        end

        return(long)
    end

validate_args(to_validate,known_args) click to toggle source

validate options hash

    # File lib/validation_shortcuts.rb, line 10
    def validate_args(to_validate,known_args)
        to_validate.each do |x|
            raise ArgumentError, "Unrecognized argument #{x}. Valid arguments are " +
                                 "#{known_args.join(',')}" if (!known_args.include?(x))
        end
    end

validate_eui(eui) click to toggle source

### Synopsis

Validate an EUI-48 or EUI-64 address. Raises NetAddr::ValidationError on validation failure.

    Example:
    NetAddr.validate_eui('01-00-5e-12-34-56') => true

    - Arguments

- eui = EUI address as a String

### Returns:

- True

    # File lib/methods.rb, line 837
    def validate_eui(eui)
        if (eui.kind_of?(String))
            # check for invalid characters
            if (eui =~ /[^0-9a-fA-F\.\-\:]/)
                raise ValidationError, "#{eui} is invalid (contains invalid characters)."
            end

            # split on formatting characters & check lengths
            if (eui =~ /\-/)
                fields = eui.split('-')
                if (fields.length != 6 && fields.length != 8)
                    raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
                end
                fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 2)}
            elsif (eui =~ /\:/)
                fields = eui.split(':')
                if (fields.length != 6 && fields.length != 8)
                    raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
                end
                fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 2)}
            elsif (eui =~ /\./)
                fields = eui.split('.')
                if (fields.length != 3 && fields.length != 4)
                    raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
                end
                fields.each {|x| raise ValidationError, "#{eui} is invalid (missing characters)." if (x.length != 4)}
            else
                raise ValidationError, "#{eui} is invalid (unrecognized formatting)."
            end

        else
            raise ArgumentError, "EUI address should be a String, but was a#{eui.class}."
        end
        return(true)
    end

validate_ip_addr(ip, options=nil) click to toggle source

### Synopsis

Validate an IP address. The address should not contain a netmask. This method will attempt to auto-detect the IP version if not provided, however a slight speed increase is realized if version is provided. Raises NetAddr::ValidationError on validation failure.

    Example:
    NetAddr.validate_ip_addr('192.168.1.1') => true
    NetAddr.validate_ip_addr('ffff::1', :Version => 6) => true
    NetAddr.validate_ip_addr('::192.168.1.1') => true
    NetAddr.validate_ip_addr(0xFFFFFF) => true
    NetAddr.validate_ip_addr(2**128-1) => true
    NetAddr.validate_ip_addr(2**32-1, :Version => 4) => true

### Arguments

- ip = IP address as a String or Integer

- options = Hash with the following keys:

      :Version -- IP version - Integer (optional)

### Returns:

- True

    # File lib/methods.rb, line 900
    def validate_ip_addr(ip, options=nil)
        known_args = [:Version]
        version = nil

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
            NetAddr.validate_args(options.keys,known_args)

            if (options.has_key?(:Version))
                version = options[:Version]
                if (version != 4 && version != 6)
                    raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
                end
            end
        end

        if ( ip.kind_of?(String) )
            version = NetAddr.detect_ip_version(ip) if (!version)
            NetAddr.validate_ip_str(ip,version)

        elsif ( ip.kind_of?(Integer) )
            NetAddr.validate_ip_int(ip,version)

        else
            raise ArgumentError, "Integer or String expected for argument 'ip' but " +
                                 "#{ip.class} provided." if (!ip.kind_of?(String) && !ip.kind_of?(Integer))
        end

        return(true)
    end

validate_ip_int(ip,version) click to toggle source
#

    validate_ip_int()

#

    # File lib/validation_shortcuts.rb, line 22
    def validate_ip_int(ip,version)
        version = 4 if (!version && ip < 2**32)
        if (version == 4)
            raise ValidationError, "#{ip} is invalid for IPv4 (Integer is out of bounds)." if ( (ip < 0) || (ip > 2**32-1) )
        else
            raise ValidationError, "#{ip} is invalid for both IPv4 and IPv6 (Integer is out of bounds)." if ( (ip < 0) || (ip > 2**128-1) )
            version = 6
        end
        return(version)
    end

validate_ip_netmask(netmask, options=nil) click to toggle source

### Synopsis

Validate IP Netmask. Version defaults to 4 if not specified. Raises NetAddr::ValidationError on validation failure.

    Examples:
    NetAddr.validate_ip_netmask('/32') => true
    NetAddr.validate_ip_netmask(32) => true
    NetAddr.validate_ip_netmask(0xffffffff, :Integer => true) => true

### Arguments:

- netmask = Netmask as a String or Integer

- options = Hash with the following keys:

      :Integer -- if true, the provided Netmask is an Integer mask
      :Version -- IP version - Integer (optional)

### Returns:

- True

    # File lib/methods.rb, line 955
    def validate_ip_netmask(netmask, options=nil)
        known_args = [:Integer, :Version]
        is_integer = false
        version = 4

        # validate options
        if (options)
            raise ArgumentError, "Hash expected for argument 'options' but #{options.class} provided." if (!options.kind_of?(Hash))
            NetAddr.validate_args(options.keys,known_args)

            if (options.has_key?(:Integer) && options[:Integer] == true)
                is_integer = true
            end

            if (options.has_key?(:Version))
                version = options[:Version]
                if (version != 4 && version != 6)
                    raise ArgumentError, ":Version should be 4 or 6, but was '#{version}'."
                end
            end
        end

        # validate netmask
        if (netmask.kind_of?(String))
            validate_netmask_str(netmask,version)
        elsif (netmask.kind_of?(Integer) )
            validate_netmask_int(netmask,version,is_integer)
        else
            raise ArgumentError, "Integer or String expected for argument 'netmask' but " +
                                 "#{netmask.class} provided." if (!netmask.kind_of?(String) && !netmask.kind_of?(Integer))
        end

        return(true)
    end

validate_ip_str(ip,version) click to toggle source
#

    validate_ip_str()

#

    # File lib/validation_shortcuts.rb, line 38
    def validate_ip_str(ip,version)
        # check validity of charaters
        if (ip =~ /[^0-9a-fA-F\.:]/)
            raise ValidationError, "#{ip} is invalid (contains invalid characters)."
        end

        if (version == 4)
            octets = ip.split('.')
            raise ValidationError, "#{ip} is invalid (IPv4 requires (4) octets)." if (octets.length != 4)

            # are octets in range 0..255?
            octets.each do |octet|
                raise ValidationError, "#{ip} is invalid (IPv4 dotted-decimal format " +
                                       "should not contain non-numeric characters)." if (octet =~ /[\D]/ || octet == '')
                octet = octet.to_i()
                if ( (octet < 0) || (octet >= 256) )
                    raise ValidationError, "#{ip} is invalid (IPv4 octets should be between 0 and 255)."
                end
            end

        else
                # make sure we only have at most (2) colons in a row, and then only
                # (1) instance of that
                if ( (ip =~ /:{3,}/) || (ip.split("::").length > 2) )
                    raise ValidationError, "#{ip} is invalid (IPv6 field separators (:) are bad)."
                end

                # set flags
                shorthand = false
                if (ip =~ /\./)
                    dotted_dec = true
                else
                    dotted_dec = false
                end

                # split up by ':'
                fields = []
                if (ip =~ /::/)
                    shorthand = true
                    ip.split('::').each do |x|
                        fields.concat( x.split(':') )
                    end
                else
                   fields.concat( ip.split(':') )
                end

                # make sure we have the correct number of fields
                if (shorthand)
                    if ( (dotted_dec && fields.length > 6) || (!dotted_dec && fields.length > 7) )
                        raise ValidationError, "#{ip} is invalid (IPv6 shorthand notation has " +
                                               "incorrect number of fields)."
                    end
                else
                    if ( (dotted_dec && fields.length != 7 ) || (!dotted_dec && fields.length != 8) )
                        raise ValidationError, "#{ip} is invalid (IPv6 address has " +
                                               "incorrect number of fields)."
                    end
                end

                # if dotted_dec then validate the last field
                if (dotted_dec)
                    dotted = fields.pop()
                    octets = dotted.split('.')
                    raise ValidationError, "#{ip} is invalid (Legacy IPv4 portion of IPv6 " +
                                           "address should contain (4) octets)." if (octets.length != 4)
                    octets.each do |x|
                        raise ValidationError, "#{ip} is invalid (egacy IPv4 portion of IPv6 " +
                                               "address should not contain non-numeric characters)." if (x =~ /[^0-9]/ )
                        x = x.to_i
                        if ( (x < 0) || (x >= 256) )
                            raise ValidationError, "#{ip} is invalid (Octets of a legacy IPv4 portion of IPv6 " +
                                                   "address should be between 0 and 255)."
                        end
                    end
                end

                # validate hex fields
                fields.each do |x|
                    if (x =~ /[^0-9a-fA-F]/)
                        raise ValidationError, "#{ip} is invalid (IPv6 address contains invalid hex characters)."
                    else
                        x = x.to_i(16)
                        if ( (x < 0) || (x >= 2**16) )
                            raise ValidationError, "#{ip} is invalid (Fields of an IPv6 address " +
                                                   "should be between 0x0 and 0xFFFF)."
                        end
                    end
                end

        end
        return(true)
    end

validate_netmask_int(netmask,version,is_int=false) click to toggle source
#

    validate_netmask_int()

#

    # File lib/validation_shortcuts.rb, line 135
    def validate_netmask_int(netmask,version,is_int=false)
        address_len = 32
        address_len = 128 if (version == 6)

        if (!is_int)
            if (netmask > address_len || netmask < 0 )
                raise ValidationError, "Netmask, #{netmask}, is out of bounds for IPv#{version}."
            end
        else
            if (netmask >= 2**address_len || netmask < 0 )
                raise ValidationError, "netmask (#{netmask}) is out of bounds for IPv#{version}."
            end
        end
        return(true)
    end

validate_netmask_str(netmask,version) click to toggle source
#

    validate_netmask_str()

#

    # File lib/validation_shortcuts.rb, line 155
    def validate_netmask_str(netmask,version)
        address_len = 32
        address_len = 128 if (version == 6)

        if(netmask =~ /\./) # extended netmask
            all_f = 2**32-1
            netmask_int = 0

            # validate & pack extended mask
            begin
                netmask_int = NetAddr.ip_to_i(netmask, :Version => 4)
            rescue Exception => error
              raise ValidationError, "#{netmask} is improperly formed: #{error}"
            end

            # cycle through the bits of hostmask and compare
            # with netmask_int. when we hit the firt '1' within
            # netmask_int (our netmask boundary), xor hostmask and
            # netmask_int. the result should be all 1's. this whole
            # process is in place to make sure that we dont have
            # and crazy masks such as 255.254.255.0
            hostmask = 1
             32.times do
                check = netmask_int & hostmask
                if ( check != 0)
                    hostmask = hostmask >> 1
                    unless ( (netmask_int ^ hostmask) == all_f)
                        raise ValidationError, "#{netmask} contains '1' bits within the host portion of the netmask."
                    end
                    break
                else
                    hostmask = hostmask << 1
                    hostmask = hostmask | 1
                end
            end

        else # cidr format
            # remove '/' if present
            if (netmask =~ /^\// )
                netmask[0] = " "
                netmask.lstrip!
            end

            # check if we have any non numeric characters
            if (netmask =~ /\D/)
                raise ValidationError, "#{netmask} contains invalid characters."
            end

            netmask = netmask.to_i
            if (netmask > address_len || netmask < 0 )
                raise ValidationError, "Netmask, #{netmask}, is out of bounds for IPv#{version}."
            end

        end
        return(true)
    end

wildcard(ip) click to toggle source

### Synopsis

Convert a wildcard IP into a valid CIDR address. Wildcards must always be at the end of the address. Any data located after the first wildcard will be lost. Shorthand notation is prohibited for IPv6 addresses. IPv6 encoded IPv4 addresses are not currently supported.

    Examples:
    NetAddr.wildcard('192.168.*')
    NetAddr.wildcard('192.168.1.*')
    NetAddr.wildcard('fec0:*')
    NetAddr.wildcard('fec0:1:*')

### Arguments:

- ip = Wildcard IP address as a String

### Returns:

- CIDR object

    # File lib/methods.rb, line 1013
    def wildcard(ip)
        version = 4

        # do operations per version of address
        if (ip =~ /\./ && ip !~ /:/)
            octets = []
            mask = 0

            ip.split('.').each do |x|
                if (x =~ /\*/)
                    break
                end
                octets.push(x)
            end

            octets.length.times do
                mask = mask << 8
                mask = mask | 0xff
            end

            until (octets.length == 4)
                octets.push('0')
                mask = mask << 8
            end
            ip = octets.join('.')

        elsif (ip =~ /:/)
            version = 6
            fields = []
            mask = 0

            raise ArgumentError, "IPv6 encoded IPv4 addresses are unsupported." if (ip =~ /\./)
            raise ArgumentError, "Shorthand IPv6 addresses are unsupported." if (ip =~ /::/)

            ip.split(':').each do |x|
                if (x =~ /\*/)
                    break
                end
                fields.push(x)
            end

            fields.length.times do
                mask = mask << 16
                mask = mask | 0xffff
            end

            until (fields.length == 8)
                fields.push('0')
                mask = mask << 16
            end
            ip = fields.join(':')
        end

        # make & return cidr
        cidr = cidr_build( version, ip_str_to_int(ip,version), mask )

        return(cidr)
    end

[Validate]

Generated with the Darkfish Rdoc Generator 2.