Class: IPAccess::List

Inherits:
NetAddr::Tree
  • Object
show all
Defined in:
lib/ipaccess/ip_access_list.rb

Overview

This class maintains a simple access list containing two lists of rules.

Access lists

IPAccess::List objects contain two lists of rules: a white list and a black list. You can add IP rules (both IPv4 and IPv6) to these lists. Rules are IP addresses with netmasks, internally keept as NetAddr::CIDR objects.

Rules management

The class provides methods for easy administration of lists and makes use of method IPAccess.to_cidrs that “understands” most common IP representations including DNS names, sockets, file descriptors bound to sockets and more.

Checking access

You may check access for provided IP addresses against white and black lists using proper methods. An address will match if it’s in a range of defined rule.

Access is evaluated as denied when tested IP address matches rule from black list and not matches any rule from white list. In other words: white list has precedence over black list. If an IP address doesn’t match any rule from any list then methods evaluating access permit it. The default policy is to accept. To change the default policy you may want to add :all rule to a black list, which would match all addresses, then just whitelist permitted.

IPv4 and IPv6

IPv6 addresses that are IPv4 compatible or IPv4 masked are automatically translated into IPv4 addresses while adding or searching.

Examples

Simple usage

access = IPAccess::List.new           # create new access list
access.blacklist :ipv4_private      # blacklist private IPv4 addresses
access.whitelist '172.16.0.7'       # whitelist 172.16.0.7
access.granted? '172.16.0.7'        # check access
access.granted? '172.16.0.1'        # check access
access.delete :black, '172.16.0.1'  # remove 172.16.0.1 from blacklist 
access.granted? '172.16.0.1'        # check access

Deny-all & allow-selected strategy:

access = IPAccess::List.new       # create new access list
access.deny :all                # blacklist all
access.allow '192.168.1.0/24'   # allow my private network
access.allow :local             # allow localhost

puts access.show                # display internal structure
puts access.blacklist           # display blacklisted IP addresses
puts access.whitelist           # display whitelisted IP addresses

Direct Known Subclasses

Check

Defined Under Namespace

Classes: Check

Instance Method Summary collapse

Constructor Details

#initialize(*addresses) ⇒ List

Creates new IPAccess::List object. You may pass objects (containing IP information) to it. These objects will create black list rules. See IPAccess.to_cidrs description for more info on how to pass arguments.

IPAccess::List object and/or NetAddr::CIDR object(s) may carry black or white list assignments inside. If such object(s) will be used to create initial ruleset then assignment found there would be used instead of default.

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time,. That may cause security flaws.

Examples

IPAccess::List.new '192.168.0.0/16', '127.0.0.1/255.0.0.0'
IPAccess::List.new :private, :local
IPAccess::List.new "randomseed.pl", :nonpublic


117
118
119
120
121
122
# File 'lib/ipaccess/ip_access_list.rb', line 117

def initialize(*addresses)
  addresses = [] if addresses == [nil]
  super()
  add!(*addresses) unless addresses.empty?
  return self
end

Instance Method Details

#+(*addresses) ⇒ Object

Returns new instance containing elements from this object and objects passed as an argument. If objects contain IP information but it’s impossible to obtain whether they relate to black or white list, then blacklisting is assumed.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



903
904
905
906
907
# File 'lib/ipaccess/ip_access_list.rb', line 903

def +(*addresses)
  obj = self.class.new(self)
  obj.add!(*addresses)
  return obj
end

#-(*addresses) ⇒ Object

Returns new list with removed CIDR objects which are exactly the same as objects passed as an argument. The original object is not changed.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



916
917
918
919
920
# File 'lib/ipaccess/ip_access_list.rb', line 916

def -(*addresses)
  self_copy = self.class.new(self)
  self_copy.delete(*addresses)
  return self_copy
end

#<<(*addresses) ⇒ Object

This operator calls add! method.



947
948
949
950
# File 'lib/ipaccess/ip_access_list.rb', line 947

def <<(*addresses)
  add!(*addresses)
  return self
end

#add!(*addresses) ⇒ Object Also known as: add

This method adds new rule(s) to access list. By default elements are added to black list. If first or last argument is :white or :black then element is added to the specified list.

If the given rule is exact (IP and mask) as pre-existent rule in the same access list then it is not added.

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time, which may cause security flaws.

Special case: some CIDR objects may carry information about access list they should belong to. If the last argument of this method does not specify access list and added rule is the kind of special CIDR containing information about assignment to some list then this extra sugar will be used in assignment instead of default :black. These special CIDR object are usualy result of passing IPAccess::List as an argument. To be sure, whichaccess list will be altered always give its name when passing IPAccess::List.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



200
201
202
# File 'lib/ipaccess/ip_access_list.rb', line 200

def add!(*addresses)
  add_core(nil, *addresses)
end

#add_reasonable!(reason, *addresses) ⇒ Object Also known as: add_reasonable

This method works the same way as add! but allows you to add a reason that will be stored with an element.



210
211
212
# File 'lib/ipaccess/ip_access_list.rb', line 210

def add_reasonable!(reason, *addresses)
  add_core(reason, *addresses)
end

#blacklist(*addresses) ⇒ Object Also known as: add_black, deny, block

Adds IP addresses from given object(s) to black list if called with at least one argument. Returns black list if called without arguments (array of CIDR objects).

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time, which may cause security flaws.



372
373
374
# File 'lib/ipaccess/ip_access_list.rb', line 372

def blacklist(*addresses)
  addresses.empty? ? self.to_a(:black) : add!(:black, *addresses)
end

#blacklist_reasonable(reason, *addresses) ⇒ Object

This works the same way as blacklist but allows you to store a reason.



383
384
385
# File 'lib/ipaccess/ip_access_list.rb', line 383

def blacklist_reasonable(reason, *addresses)
  addresses.empty? ? self.to_a(:black) : add_reasonable!(reason, :black, *addresses)
end

#blacklist_rule_exists_cidr?(addr) ⇒ Boolean

This method returns true if the given IP address is on the IP rules black list.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

Returns:

  • (Boolean)


609
610
611
# File 'lib/ipaccess/ip_access_list.rb', line 609

def blacklist_rule_exists_cidr?(addr)
  not rule_exists_cidr(:black, addr).nil?
end

#blacklist_rules_exist?(*addresses) ⇒ Boolean Also known as: blacklist_rule_exists?

This method returns true if ALL of the given IP addresses/masks are present in the black list.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

Returns:

  • (Boolean)


591
592
593
594
595
596
597
598
599
# File 'lib/ipaccess/ip_access_list.rb', line 591

def blacklist_rules_exist?(*addresses)
  addrs = IPAccess.to_cidrs(*addresses)
  return found if addrs.empty?
  addrs.each do |addr|
    rule = rule_exists_cidr(:black, addr)
    return false if rule.nil?
  end
  return true
end

#clear!Object

Remove all elements.



933
934
935
936
# File 'lib/ipaccess/ip_access_list.rb', line 933

def clear!
  remove!('0.0.0.0/0')
  remove!('::/0')
end

#delete!(*addresses) ⇒ Object Also known as: del!, delete

This method removes CIDR rules specified by the given objects containing IP information. It returns an array of removed CIDR rules.

Make sure you will specify correct and exact netmasks in order to delete proper rules. This method will NOT remove rules that imprecisely match given address or rules that logically depends on specified rules, e.g. removing 192.168.0.0/16 will leave 192.168.0.0/24 untouched. To create access exceptions for some ranges and/or addresses whitelist them using permit method. This method removes rules matching exact addresses/masks.

If the first or last argument is a symbol and it’s :white or :black then the specified rule will be removed only from the given (white or black) list. If the list is not specified the rule will be removed from both lists.

Special case: some CIDR objects may carry information about access list they should belong to. If the last argument of this method does not specify access list and added rule is the kind of special CIDR containing information about assignment to some list then this extra sugar will be used while removing. These special CIDR objects are usualy result of passing IPAccess::List as an argument. To be sure, whichaccess list will be altered always give its name when passing IPAccess::List.

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time, which may cause security flaws.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/ipaccess/ip_access_list.rb', line 285

def delete!(*addresses)
  acl_list = nil
  acl_list = addresses.shift if (addresses.first.is_a?(Symbol) && (addresses.first == :white || addresses.first == :black))
  acl_list = addresses.pop if (addresses.last.is_a?(Symbol) && (addresses.last == :white || addresses.last == :black))
  removed = []
  return removed if (addresses.empty? || empty?)
  addrs = IPAccess.to_cidrs(*addresses)
  addrs.each do |addr|
    addr = addr.ipv4 if addr.ipv4_compliant?
    exists = find_me(addr)
    unless exists.nil?
      src_list  = acl_list.nil? ? addr.tag[:ACL] : acl_list
      src_list  = nil if src_list == :grey
      ex_list   = exists.tag[:ACL]
      parent    = exists.tag[:Parent]
      children  = exists.tag[:Subnets]
      if (!src_list.nil? && ex_list == :grey)
        removed.push exists.safe_dup(:Subnets, :Parent)
        if src_list == :black
          exists.tag[:ACL] = :white
          exists.tag.delete(:Reason_black)
        else
          exists.tag[:ACL] = :black
          exists.tag.delete(:Reason_white)
        end
        #exists.tag[:ACL] = (src_list == :black) ? :white : :black
      elsif (src_list.nil? || ex_list == src_list)
        removed.push exists.safe_dup(:Subnets, :Parent)
        exists.tag.delete(:Reason_white) # help garbage collector a bit
        exists.tag.delete(:Reason_black)
        exists.tag.delete(:ACL)
        exists.tag.delete(:Originator)
        parent.tag[:Subnets].delete(exists)
        children.each { |childaddr| add_to_parent(childaddr, parent) }
      end
    end # if found
  end # addresses.each
  return removed
end

#denied(*addresses) ⇒ Object

This method checks if access for IP or IPs is denied. It returns an array of hashes containing tested CIDR objects (named :IP) and rules objects (named :Rule). This pair is present in returned hash if given IP address matches black list rules and noesn’t match white list rules.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

It should be used to check access for many IP addresses and/or address(-es) that are not necessarily represented by CIDR objects.

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time, which may cause security flaws.

To not create copy of objects when reporting rules but to use reference to original entries you may set last argument true. Use this with caution since modifying returned object may affect internal structure of access list.



789
790
791
792
793
794
795
796
797
798
799
# File 'lib/ipaccess/ip_access_list.rb', line 789

def denied(*addresses)
  found = []
  return found if empty?
  nodup = addresses.last.is_a?(TrueClass) ? addresses.pop : false
  addrs = IPAccess.to_cidrs(*addresses)
  addrs.each do |addr|
    pair = denied_cidr(addr, nodup)
    found.push(pair) unless pair.empty?
  end
  return found
end

#denied?(*addresses) ⇒ Boolean Also known as: denied_one?, denied_one_of?

This method returns true if at least one of given CIDR objects matches black list rules and doesn’t match white list rules. Otherwise it returns false.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

Returns:

  • (Boolean)


808
809
810
811
# File 'lib/ipaccess/ip_access_list.rb', line 808

def denied?(*addresses)
  addresses.push true
  not denied(*addresses).empty?
end

#denied_cidr(addr, nodup = false) ⇒ Object

This method should be used to check whether access is denied for the IP given as argument. It is recommended to use it in low-level routines.

This method returns a hash containing pair of CIDR objects. First, indexed as :IP, contains an IP address. Second, indexed as :Rule, contains matching rule. Matching means that IP is blacklisted and is not whitelisted.

If there is no match it returns an empty hash.

To not create copy of object when reporting rule but to use reference to original entry you may set second argument to true. Use this with caution since modifying returned object may affect internal structure of access list.



720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
# File 'lib/ipaccess/ip_access_list.rb', line 720

def denied_cidr(addr, nodup=false)
  addr = addr.ipv4 if addr.ipv4_compliant?
  root = addr.version == 4 ? @v4_root : @v6_root
  list = root
  ret = {}
  return ret if list.tag[:Subnets].length.zero?
  
  until (li = NetAddr.cidr_find_in_list(addr, list.tag[:Subnets])).nil?
    if li.is_a?(Integer)
      li = list.tag[:Subnets][li]
      break
    else
      if li.tag[:ACL] == :black
        list = li
      else
        break
      end
    end
  end
  
  li = list if li.nil?
  if (!li.nil? && li.tag[:ACL] == :black && li.matches?(addr))
    if nodup
      rule = li
      addr = addr
    else
      rule = li.safe_dup(:Subnets, :Parent)
      addr = addr.safe_dup
    end
    ret[:IP] = addr
    ret[:Rule] = rule
  end
  return ret
end

#denied_cidr?(addr) ⇒ Boolean

This method returns true if the given CIDR contains blacklisted and not whitelisted address. Otherwise it returns false.

It should be used to check access for one IP. It is recommended to use it in low-level routines.

Returns:

  • (Boolean)


762
763
764
# File 'lib/ipaccess/ip_access_list.rb', line 762

def denied_cidr?(addr)
  not denied_cidr(addr, true).empty?
end

#empty?Boolean

This method returns true if the list is empty.

Returns:

  • (Boolean)


940
941
942
943
# File 'lib/ipaccess/ip_access_list.rb', line 940

def empty?
  @v4_root.tag[:Subnets].empty? &&
  @v6_root.tag[:Subnets].empty?
end

#find(addr) ⇒ Object

This method returns CIDR rule that is the same as given IP and mask. It returns copy of a rule that query matches (CIDR object) or nil if no match was found.

Examples:

access = IPAccess::List.new '127.0.0.1/8'   # blacklisted local IP
access.find '127.0.0.1'                   # returns nil
access.find '127.0.0.1/24'                # returns nil
access.find '127.0.0.1'/8                 # returns CIDR: 127.0.0.0/8
access.find '127.0.1.2'/8                 # returns CIDR: 127.0.0.0/8

If you want simpler or more fancy search in rules (e.g. without need to specify mask or with ability to check many rules at one time) use methods like find_blacklist_rules or find_whitelist_rules.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about argument you may pass to it. Be aware that in case of name or special symbol given as an address only first result will be used and it will probably do not match because lack of proper netmask.



692
693
694
695
696
697
698
699
700
# File 'lib/ipaccess/ip_access_list.rb', line 692

def find(addr)
  return nil if empty?
  addr = IPAccess.to_cidr(addr)
  return nil if addr.nil?
  addr = addr.ipv4 if addr.ipv4_compliant?
  root = addr.version == 4 ? @v4_root : @v6_root
  return nil if root.tag[:Subnets].empty?
  return super(addr)
end

#find_blacklist_rule_cidr(addr) ⇒ Object

This method returns CDIR object that equals given IP rule in the black list. Otherwise it returns nil.

It is designed to browse rules, NOT to check access. To do access check use granted_cidr and denied_cidr methods.



578
579
580
# File 'lib/ipaccess/ip_access_list.rb', line 578

def find_blacklist_rule_cidr(addr)
  rule_exists_cidr(:black, addr)
end

#find_blacklist_rules(*addresses) ⇒ Object Also known as: find_blacklist_rule

This method returns an array containing CDIR objects that are result of finding given IP rules in the black list.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



565
566
567
# File 'lib/ipaccess/ip_access_list.rb', line 565

def find_blacklist_rules(*addresses)
  rule_exists(:black, *addresses)
end

#find_whitelist_rule_cidr(addr) ⇒ Object

This method returns CDIR object that equals given IP rule in the white list.

It is designed to check rules, NOT access. To do access check use allowed_cidr and denied_cidr methods.



634
635
636
# File 'lib/ipaccess/ip_access_list.rb', line 634

def find_whitelist_rule_cidr(addr)
  rule_exists_cidr(:white, addr)
end

#find_whitelist_rules(*addresses) ⇒ Object

This method returns an array containing CDIR objects that is result of finding given IP rules in the white list.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



622
623
624
# File 'lib/ipaccess/ip_access_list.rb', line 622

def find_whitelist_rules(*addresses)
  rule_exists(:white, *addresses)
end

#granted(*addresses) ⇒ Object

This method returns an array of the given CIDR objects that don’t match black list rules or match white list rules.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

It should be used to check access for many IP addresses and/or address(-es) that are not necessarily represented by CIDR objects.

If the symbol :include_origin is present as one of the given arguments then underlying, resolving method will attach each original, passed in object to corresponding NetAddr::CIDR used while checking. These objects may be accessed using tag[:Originator] called on each resulting object.

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time, which may cause security flaws.



858
859
860
861
862
863
864
865
866
867
# File 'lib/ipaccess/ip_access_list.rb', line 858

def granted(*addresses)
  found = []
  return found if empty?
  addresses = IPAccess.to_cidrs(*addresses)
  addresses.each do |addr|
    rule = denied_cidr(addr, true)
    found.push(addr) if rule.empty?
  end
  return found
end

#granted?(*addresses) ⇒ Boolean Also known as: granted_one?, granted_one_of?

This method returns true if all of given CIDR objects are not blacklisted or are whitelisted. Otherwise it returns false.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

If the symbol :include_origin is present as one of the given arguments then underlying, resolving method will attach each original, passed in object to corresponding NetAddr::CIDR used while checking. These objects may be accessed using tag[:Originator] called on each resulting object.

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time, which may cause security flaws.

Returns:

  • (Boolean)


887
888
889
890
# File 'lib/ipaccess/ip_access_list.rb', line 887

def granted?(*addresses)
  addresses.push true
  denied(*addresses).empty?
end

#granted_cidr(addr) ⇒ Object

This method returns given CIDR object if the given CIDR is not blacklisted or is whitelisted. Otherwise it returns nil.

It should be used to check access for one IP. It is recommended to use it in low-level routines.



823
824
825
# File 'lib/ipaccess/ip_access_list.rb', line 823

def granted_cidr(addr)
  denied_cidr(addr, true).empty? ? addr : nil
end

#granted_cidr?(addr) ⇒ Boolean

This method returns true if the given CIDR is not blacklisted or is whitelisted. Otherwise it returns false.

It should be used to check access for one IP. It is recommended to use it in low-level routines.

Returns:

  • (Boolean)


833
834
835
# File 'lib/ipaccess/ip_access_list.rb', line 833

def granted_cidr?(addr)
  denied_cidr(addr, true).empty?
end

#grep(*addresses) ⇒ Object Also known as: search

This method finds all matching addresses in the list and returns an array containing these addresses. If the optional block is supplied, each matching element is passed to it, and the block‘s result is stored in the output array.

Ba aware that it may call the block for same object twice if you’ll pass two matching addresses.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



136
137
138
139
140
141
142
143
144
145
# File 'lib/ipaccess/ip_access_list.rb', line 136

def grep(*addresses)
  return [] if empty?
  out_ary = []
  addrs = IPAccess.to_cidrs(*addresses)
  addrs.each do |addr|
    m = included_cidr(addr)
    out_ary.push( block_given? ? yield(m) : m) unless m.nil?
  end
  return out_ary
end

#grep_exact(*addresses) ⇒ Object

This method finds all addresses in the list that are equal to given addresses/netmasks and returns an array containing these addresses. It is intended to be used to operate on lists rather than to match IPs to them.

If the optional block is supplied, each matching element is passed to it, and the block‘s result is stored in the output array.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/ipaccess/ip_access_list.rb', line 161

def grep_exact(*addresses)
  return [] if empty?
  out_ary = []
  addrs = IPAccess.to_cidrs(*addresses)
  addrs.each do |addr|
    m = included_cidr(addr)
    if (m == addr)
      out_ary.push( block_given? ? yield(m) : m)
    end
  end
  return out_ary
end

#include?(*addresses) ⇒ Boolean Also known as: include_all?

This method returns true if ALL of the given objects containing IP information match some rules. Otherwise it returns false.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

Returns:

  • (Boolean)


438
439
440
441
442
443
444
445
446
447
# File 'lib/ipaccess/ip_access_list.rb', line 438

def include?(*addresses)
  return false if empty?
  addrs = IPAccess.to_cidrs(*addresses)
  return false if addrs.empty?
  addrs.each do |addr|
    rule = included_cidr(addr)
    return false if rule.nil?
  end
  return true
end

#include_cidr?(addr) ⇒ Boolean

This method returns true if the given IP address (expressed as CIDR object) matches some rule. Otherwise it returns false.

It is designed to browse rules, NOT to check access. To do access check use granted_cidr and denied_cidr methods.

Returns:

  • (Boolean)


507
508
509
# File 'lib/ipaccess/ip_access_list.rb', line 507

def include_cidr?(addr)
  not included_cidr(addr).nil?
end

#include_one?(*addresses) ⇒ Boolean

This method returns true if at least one of the given objects containing IP information matches rule from the list. Otherwise it returns false.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

Returns:

  • (Boolean)


482
483
484
# File 'lib/ipaccess/ip_access_list.rb', line 482

def include_one?(*addresses)
  not included_first.nil?
end

#included(*addresses) ⇒ Object

This method returns an array of matching CIDR objects for the given objects containing IP information.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

Examples:

access = IPAccess::List.new '127.0.0.1/8' # blacklisted local IP
access.included '127.0.0.1'               # returns [127.0.0.0/8]
access.included '127.0.0.1/24'            # returns [127.0.0.0/8]
access.included '127.0.0.1'/8             # returns [127.0.0.0/8]
access.included '127.0.1.2'/8             # returns [127.0.0.0/8]


416
417
418
419
420
421
422
423
424
425
426
# File 'lib/ipaccess/ip_access_list.rb', line 416

def included(*addresses)
  found = []
  return found if empty?
  addrs = IPAccess.to_cidrs(*addresses)
  return found if addrs.empty?
  addrs.each do |addr|
    rule = included_cidr(addr)
    found.push(rule) unless rule.nil?
  end
  return found
end

#included_cidr(addr) ⇒ Object

This method returns matching CIDR rule if the given IP address (expressed as CIDR object) is on the list. Otherwise it returns nil.



489
490
491
492
493
494
495
496
497
498
# File 'lib/ipaccess/ip_access_list.rb', line 489

def included_cidr(addr)
  addr = addr.ipv4 if addr.ipv4_compliant?
  root = addr.version == 4 ? @v4_root : @v6_root
  return nil if root.tag[:Subnets].empty?
  found = nil
  found = find_me(addr)
  found = find_parent(addr) if found.nil?
  return nil if (found.nil? || found.hash == root.hash || !found.matches?(addr))
  return found.safe_dup(:Subnets, :Parent)
end

#included_first(*addresses) ⇒ Object

This method returns first matching CIDR rule from the given objects containing IP information. Otherwise it returns nil.

It is designed to browse rules, NOT to check access. To do access check use IPAccess::List#granted and IPAccess::List#denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.



461
462
463
464
465
466
467
468
469
470
# File 'lib/ipaccess/ip_access_list.rb', line 461

def included_first(*addresses)
  return nil if empty?
  addrs = IPAccess.to_cidrs(*addresses)
  return nil if addrs.empty?
  addrs.each do |addr|
    rule = included_cidr(addr)
    return rule unless rule.nil?
  end
  return nil
end

#join(sep = ' ') ⇒ Object

Returns list of addresses and masks as a string with elements joined using space or given string.



925
926
927
928
929
# File 'lib/ipaccess/ip_access_list.rb', line 925

def join(sep=' ')
  dump.map do |obj|
    obj[:CIDR].to_s
  end.join(sep)
end

#show(reasons = false) ⇒ Object

This method shows internal tree of CIDR objects marked with access list they belong to.

While interpreting it you should be aware that access for tested IP will not be denied if black list rule has at least one whitelisted, preceding rule in the path that leads to it. You may also notice doubled entries sometimes. That happens in case when the same rule is belongs to both: black list and white list.

When the argument is set to true it will also print a reasons of adding to lists.



996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
# File 'lib/ipaccess/ip_access_list.rb', line 996

def show(reasons=false)
  list4 = dump_children(@v4_root)
  list6 = dump_children(@v6_root)
  
  printed = "IPv4 Tree\n---------\n" if list4.length.nonzero?
  list4.each do |entry|
    cidr    = entry[:CIDR]
    depth   = entry[:Depth]
    alist   = cidr.tag[:ACL]
    indent  = depth.zero? ? "" : " " * (depth*3)
    space   = " " * (44 - (cidr.desc.length+(depth*3)))
    space   = " " if space.empty?
    if alist == :grey
      printed << "[black] #{indent}#{cidr.desc}#{space}#{cidr.tag[:Reason_black]}\n"
      printed << "[white] #{indent}#{cidr.desc}#{space}#{cidr.tag[:Reason_white]}\n"
    else
      alist   = cidr.tag[:ACL].nil? ? "undef" : cidr.tag[:ACL]
      reason  = cidr.tag[("Reason_" + alist.to_s).to_sym]
      printed << "[#{alist}] #{indent}#{cidr.desc}#{space}#{reason}\n"
    end
  end
  
  printed << "\nIPv6 Tree\n---------\n" if list6.length.nonzero?
  list6.each do |entry|
    cidr    = entry[:CIDR]
    depth   = entry[:Depth]
    alist   = cidr.tag[:ACL]
    desc    = cidr.desc(:Short=>true)
    desc    = "::#{desc}" if desc =~ /^\//
    desc    = ":#{desc}" if desc =~ /^:[^:]/
    indent  = depth.zero? ? "" : " " * (depth*3)
    space   = " " * (44 - (desc.length+(depth*3)))
    space   = " " if space.empty?
    if alist == :grey
      printed << "[black] #{indent}#{desc}#{space}#{cidr.tag[:Reason_black]}\n"
      printed << "[white] #{indent}#{desc}#{space}#{cidr.tag[:Reason_white]}\n"
    else
      alist   = cidr.tag[:ACL].nil? ? "undef" : cidr.tag[:ACL]
      reason  = cidr.tag[("Reason_" + alist.to_s).to_sym]
      printed << "[#{alist}] #{indent}#{desc}#{space}#{reason}\n"
    end
  end
  return printed
end

#to_a(type = nil) ⇒ Object

This method produces array of CIDR objects that belong to an access list specified by type (:white or :black). If no type is given it returns all entries. It preserves access list assignment information in CIDR copies.



977
978
979
980
# File 'lib/ipaccess/ip_access_list.rb', line 977

def to_a(type=nil)
  dump_flat_list(@v4_root, type) +
  dump_flat_list(@v6_root, type)
end

#unblacklist(*addresses) ⇒ Object Also known as: unblack, undeny, unblock, del_black

This method removes IP address(-es) from blacklist by calling delete! on it. It returns the result of delete!



391
392
393
# File 'lib/ipaccess/ip_access_list.rb', line 391

def unblacklist(*addresses)
  self.delete!(:black, *addresses)
end

#unwhitelist(*addresses) ⇒ Object Also known as: unwhite, del_white, unallow, unpermit

This method removes IP address(-es) from whitelist by calling delete! on it. It returns the result of delete!



355
356
357
# File 'lib/ipaccess/ip_access_list.rb', line 355

def unwhitelist(*addresses)
  self.delete!(:white, *addresses)
end

#whitelist(*addresses) ⇒ Object Also known as: add_white, allow, permit

Adds IP addresses in given object(s) to white list if called with at least one argument. Returns white list if called without arguments (array of CIDR objects).

You should avoid passing hostnames as arguments since DNS is not reliable and responses may change with time, which may cause security flaws.



336
337
338
# File 'lib/ipaccess/ip_access_list.rb', line 336

def whitelist(*addresses)
  addresses.empty? ? self.to_a(:white) : add!(:white, *addresses)
end

#whitelist_reasonable(reason, *addresses) ⇒ Object

This works the same way as whitelist but allows you to store a reason.



347
348
349
# File 'lib/ipaccess/ip_access_list.rb', line 347

def whitelist_reasonable(reason, *addresses)
  addresses.empty? ? self.to_a(:white) : add_reasonable!(reason, :white, *addresses)
end

#whitelist_rule_exists_cidr?(addr) ⇒ Boolean

This method returns true if the given IP address is on the IP rules white list.

It is designed to check rules, NOT access. To do access check use allowed and denied methods.

Returns:

  • (Boolean)


663
664
665
# File 'lib/ipaccess/ip_access_list.rb', line 663

def whitelist_rule_exists_cidr?(addr)
  not rule_exists_cidr(:white, addr).nil?
end

#whitelist_rules_exist?(*addresses) ⇒ Boolean

This method returns true if ALL of the given IP addresses are on the white list.

It is designed to check rules, NOT access. To do access check use allowed and denied methods.

See IPAccess.to_cidrs description for more info about arguments you may pass to it.

Returns:

  • (Boolean)


647
648
649
650
651
652
653
654
655
# File 'lib/ipaccess/ip_access_list.rb', line 647

def whitelist_rules_exist?(*addresses)
  addrs = IPAccess.to_cidrs(*addresses)
  return found if addrs.empty?
  addrs.each do |addr|
    rule = rule_exists_cidr(:white, addr)
    return false if rule.nil?
  end
  return true
end