summaryrefslogtreecommitdiff
path: root/lib/drb/acl.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/drb/acl.rb')
-rw-r--r--lib/drb/acl.rb250
1 files changed, 250 insertions, 0 deletions
diff --git a/lib/drb/acl.rb b/lib/drb/acl.rb
new file mode 100644
index 0000000..29a3781
--- /dev/null
+++ b/lib/drb/acl.rb
@@ -0,0 +1,250 @@
+# Copyright (c) 2000,2002,2003 Masatoshi SEKI
+#
+# acl.rb is copyrighted free software by Masatoshi SEKI.
+# You can redistribute it and/or modify it under the same terms as Ruby.
+
+require 'ipaddr'
+
+##
+# Simple Access Control Lists.
+#
+# Access control lists are composed of "allow" and "deny" halves to control
+# access. Use "all" or "*" to match any address. To match a specific address
+# use any address or address mask that IPAddr can understand.
+#
+# Example:
+#
+# list = %w[
+# deny all
+# allow 192.168.1.1
+# allow ::ffff:192.168.1.2
+# allow 192.168.1.3
+# ]
+#
+# # From Socket#peeraddr, see also ACL#allow_socket?
+# addr = ["AF_INET", 10, "lc630", "192.168.1.3"]
+#
+# acl = ACL.new
+# p acl.allow_addr?(addr) # => true
+#
+# acl = ACL.new(list, ACL::DENY_ALLOW)
+# p acl.allow_addr?(addr) # => true
+
+class ACL
+
+ ##
+ # The current version of ACL
+
+ VERSION=["2.0.0"]
+
+ ##
+ # An entry in an ACL
+
+ class ACLEntry
+
+ ##
+ # Creates a new entry using +str+.
+ #
+ # +str+ may be "*" or "all" to match any address, an IP address string
+ # to match a specific address, an IP address mask per IPAddr, or one
+ # containing "*" to match part of an IPv4 address.
+
+ def initialize(str)
+ if str == '*' or str == 'all'
+ @pat = [:all]
+ elsif str.include?('*')
+ @pat = [:name, dot_pat(str)]
+ else
+ begin
+ @pat = [:ip, IPAddr.new(str)]
+ rescue ArgumentError
+ @pat = [:name, dot_pat(str)]
+ end
+ end
+ end
+
+ private
+
+ ##
+ # Creates a regular expression to match IPv4 addresses
+
+ def dot_pat_str(str)
+ list = str.split('.').collect { |s|
+ (s == '*') ? '.+' : s
+ }
+ list.join("\\.")
+ end
+
+ private
+
+ ##
+ # Creates a Regexp to match an address.
+
+ def dot_pat(str)
+ exp = "^" + dot_pat_str(str) + "$"
+ Regexp.new(exp)
+ end
+
+ public
+
+ ##
+ # Matches +addr+ against this entry.
+
+ def match(addr)
+ case @pat[0]
+ when :all
+ true
+ when :ip
+ begin
+ ipaddr = IPAddr.new(addr[3])
+ ipaddr = ipaddr.ipv4_mapped if @pat[1].ipv6? && ipaddr.ipv4?
+ rescue ArgumentError
+ return false
+ end
+ (@pat[1].include?(ipaddr)) ? true : false
+ when :name
+ (@pat[1] =~ addr[2]) ? true : false
+ else
+ false
+ end
+ end
+ end
+
+ ##
+ # A list of ACLEntry objects. Used to implement the allow and deny halves
+ # of an ACL
+
+ class ACLList
+
+ ##
+ # Creates an empty ACLList
+
+ def initialize
+ @list = []
+ end
+
+ public
+
+ ##
+ # Matches +addr+ against each ACLEntry in this list.
+
+ def match(addr)
+ @list.each do |e|
+ return true if e.match(addr)
+ end
+ false
+ end
+
+ public
+
+ ##
+ # Adds +str+ as an ACLEntry in this list
+
+ def add(str)
+ @list.push(ACLEntry.new(str))
+ end
+
+ end
+
+ ##
+ # Default to deny
+
+ DENY_ALLOW = 0
+
+ ##
+ # Default to allow
+
+ ALLOW_DENY = 1
+
+ ##
+ # Creates a new ACL from +list+ with an evaluation +order+ of DENY_ALLOW or
+ # ALLOW_DENY.
+ #
+ # An ACL +list+ is an Array of "allow" or "deny" and an address or address
+ # mask or "all" or "*" to match any address:
+ #
+ # %w[
+ # deny all
+ # allow 192.0.2.2
+ # allow 192.0.2.128/26
+ # ]
+
+ def initialize(list=nil, order = DENY_ALLOW)
+ @order = order
+ @deny = ACLList.new
+ @allow = ACLList.new
+ install_list(list) if list
+ end
+
+ public
+
+ ##
+ # Allow connections from Socket +soc+?
+
+ def allow_socket?(soc)
+ allow_addr?(soc.peeraddr)
+ end
+
+ public
+
+ ##
+ # Allow connections from addrinfo +addr+? It must be formatted like
+ # Socket#peeraddr:
+ #
+ # ["AF_INET", 10, "lc630", "192.0.2.1"]
+
+ def allow_addr?(addr)
+ case @order
+ when DENY_ALLOW
+ return true if @allow.match(addr)
+ return false if @deny.match(addr)
+ return true
+ when ALLOW_DENY
+ return false if @deny.match(addr)
+ return true if @allow.match(addr)
+ return false
+ else
+ false
+ end
+ end
+
+ public
+
+ ##
+ # Adds +list+ of ACL entries to this ACL.
+
+ def install_list(list)
+ i = 0
+ while i < list.size
+ permission, domain = list.slice(i,2)
+ case permission.downcase
+ when 'allow'
+ @allow.add(domain)
+ when 'deny'
+ @deny.add(domain)
+ else
+ raise "Invalid ACL entry #{list.to_s}"
+ end
+ i += 2
+ end
+ end
+
+end
+
+if __FILE__ == $0
+ # example
+ list = %w(deny all
+ allow 192.168.1.1
+ allow ::ffff:192.168.1.2
+ allow 192.168.1.3
+ )
+
+ addr = ["AF_INET", 10, "lc630", "192.168.1.3"]
+
+ acl = ACL.new
+ p acl.allow_addr?(addr)
+
+ acl = ACL.new(list, ACL::DENY_ALLOW)
+ p acl.allow_addr?(addr)
+end
+