ipaccess 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +64 -0
- data/docs/COPYING +61 -0
- data/docs/DOWNLOAD +17 -0
- data/docs/LEGAL +11 -0
- data/docs/LGPL-LICENSE +169 -0
- data/docs/README +95 -0
- data/docs/TODO +18 -0
- data/docs/WELCOME +8 -0
- data/examples/tcp_socket.rb +9 -0
- data/lib/ipaccess.rb +35 -0
- data/lib/ipaccess/arm_sockets.rb +33 -0
- data/lib/ipaccess/ghost_doc.rb +206 -0
- data/lib/ipaccess/ghost_doc_acl.rb +31 -0
- data/lib/ipaccess/ip_access.rb +455 -0
- data/lib/ipaccess/ip_access_errors.rb +131 -0
- data/lib/ipaccess/ip_access_list.rb +1209 -0
- data/lib/ipaccess/ip_access_patches.rb +435 -0
- data/lib/ipaccess/netaddr_patch.rb +127 -0
- data/lib/ipaccess/sockets.rb +53 -0
- data/spec/core_spec.rb +5 -0
- data/spec/ip_access_list_spec.rb +302 -0
- data/spec/rcov.opts +7 -0
- data/spec/spec.opts +2 -0
- metadata +84 -0
data/lib/ipaccess.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
4
|
+
# Copyright:: Copyright (c) 2009 Paweł Wilk
|
5
|
+
# License:: This program is licensed under the terms of {GNU Lesser General Public License}[link:docs/LGPL-LICENSE.html] or {Ruby License}[link:docs/COPYING.html].
|
6
|
+
#
|
7
|
+
# Classes contained in this library allow you to create
|
8
|
+
# and manage IP access lists in an easy way. You may use
|
9
|
+
# IPAccess class to maintain inpu/output traffic control.
|
10
|
+
# You also may use IPAccessList class directly to build
|
11
|
+
# your own access sets based on black lists and white lists.
|
12
|
+
#
|
13
|
+
#--
|
14
|
+
#
|
15
|
+
# Copyright (C) 2009 by Paweł Wilk. All Rights Reserved.
|
16
|
+
#
|
17
|
+
# This program is free software; you can redistribute it and/or modify
|
18
|
+
# it under the terms of either: 1) the GNU Lesser General Public License
|
19
|
+
# as published by the Free Software Foundation; either version 3 of the
|
20
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
21
|
+
#
|
22
|
+
# See the file COPYING for complete licensing information.
|
23
|
+
#
|
24
|
+
#++
|
25
|
+
|
26
|
+
require 'rubygems'
|
27
|
+
require 'socket'
|
28
|
+
require 'resolv'
|
29
|
+
require 'netaddr'
|
30
|
+
|
31
|
+
require 'ipaccess/netaddr_patch'
|
32
|
+
require 'ipaccess/ip_access_list'
|
33
|
+
require 'ipaccess/ip_access'
|
34
|
+
require 'ipaccess/sockets'
|
35
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
4
|
+
# Copyright:: Copyright (c) 2009 Paweł Wilk
|
5
|
+
# License:: This program is licensed under the terms of {GNU Lesser General Public License}[link:docs/LGPL-LICENSE.html] or {Ruby License}[link:docs/COPYING.html].
|
6
|
+
#
|
7
|
+
# By requiring this file you are able to
|
8
|
+
# enable IP access control for all
|
9
|
+
# standard Ruby sockets.
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
#
|
13
|
+
# Copyright (C) 2009 by Paweł Wilk. All Rights Reserved.
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU Lesser General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 3 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#++
|
23
|
+
|
24
|
+
require 'socket'
|
25
|
+
require 'ipaccess/ip_access'
|
26
|
+
require 'ipaccess/ip_access_patches'
|
27
|
+
|
28
|
+
IPAccess.arm Socket
|
29
|
+
IPAccess.arm UDPSocket
|
30
|
+
IPAccess.arm TCPSocket
|
31
|
+
IPAccess.arm TCPServer
|
32
|
+
IPAccess.arm SOCKSSocket if Object.const_defined?(:SOCKSSocket)
|
33
|
+
|
@@ -0,0 +1,206 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
4
|
+
# Copyright:: Copyright (c) 2009 Paweł Wilk
|
5
|
+
# License:: This program is licensed under the terms of {GNU Lesser General Public License}[link:LGPL-LICENSE.html] or Ruby License.
|
6
|
+
#
|
7
|
+
# Classes contained are just for documentary purposes.
|
8
|
+
# It is a scaffold for keeping virtual methods that
|
9
|
+
# cannot be detected by RDoc.
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
#
|
13
|
+
# Copyright (C) 2009 by Paweł Wilk. All Rights Reserved.
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU Lesser General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 3 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#++
|
23
|
+
|
24
|
+
|
25
|
+
######################################################
|
26
|
+
# Socket class with IP access control.
|
27
|
+
# It uses input and output access lists.
|
28
|
+
#
|
29
|
+
# This acts the same way as Socket class but
|
30
|
+
# provides special member called +acl+ for
|
31
|
+
# controlling IP access.
|
32
|
+
#
|
33
|
+
# ==== Example
|
34
|
+
# require 'ipaddr/sockets'
|
35
|
+
# include Socket::Constants
|
36
|
+
#
|
37
|
+
# IPAccess::Global.input.blacklist :localhost # add localhost to global access set
|
38
|
+
# # as a black rule of input list
|
39
|
+
# socket = IPAccess::Socket.new(AF_INET, SOCK_STREAM, 0) # create TCP socket
|
40
|
+
# sockaddr = Socket.sockaddr_in(31337, '127.0.0.1') # create sockadr_in structure
|
41
|
+
# socket.bind(sockaddr) # bind to port 31331 and IP 127.0.0.1
|
42
|
+
# socket.listen(5) # listen on socket
|
43
|
+
# begin
|
44
|
+
# c_socket, c_sockaddr = socket.accept_nonblock # call non-blocking accept for connections
|
45
|
+
# rescue Errno::EAGAIN, Errno::ECONNABORTED,
|
46
|
+
# Errno::EPROTO, Errno::EINTR
|
47
|
+
# IO.select([socket]) # retry on retriable errors
|
48
|
+
# retry
|
49
|
+
# rescue IPAccessDenied # when access is denied
|
50
|
+
# c_socket.close # close client socket
|
51
|
+
# socket.close # close listener
|
52
|
+
# raise # raise exception
|
53
|
+
# end
|
54
|
+
# c_socket.puts "Hello world!" # otherwise continue
|
55
|
+
# c_socket.close
|
56
|
+
# socket.close
|
57
|
+
#
|
58
|
+
class IPAccess::Socket
|
59
|
+
#:include:ghost_doc_acl.rb
|
60
|
+
#
|
61
|
+
# ==== Example
|
62
|
+
#
|
63
|
+
# socket = IPAccess::Socket.new(AF_INET, SOCK_STREAM, 0)
|
64
|
+
# socket.acl = :global # use global access set
|
65
|
+
# socket.acl = :private # create and use individual access set
|
66
|
+
# socket.acl = IPAccess.new # use external (shared) access set
|
67
|
+
def acl=(set); end
|
68
|
+
|
69
|
+
# This member allows you to manipulate local and shared access sets
|
70
|
+
# associated with this socket. To control global access set use
|
71
|
+
# IPAccess::Global
|
72
|
+
attr_reader :acl
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
######################################################
|
77
|
+
# UDPSocket class with IP access control.
|
78
|
+
# It uses input access lists.
|
79
|
+
#
|
80
|
+
# This acts the same way as UDPSocket class but
|
81
|
+
# provides special member called +acl+ for
|
82
|
+
# controlling IP access.
|
83
|
+
|
84
|
+
class IPAccess::UDPSocket
|
85
|
+
#:include:ghost_doc_acl.rb
|
86
|
+
#
|
87
|
+
# ==== Example
|
88
|
+
#
|
89
|
+
# socket = IPAccess::UDPSocket.new
|
90
|
+
# socket.acl = :global # use global access set
|
91
|
+
# socket.acl = :private # create and use individual access set
|
92
|
+
# socket.acl = IPAccess.new # use external (shared) access set
|
93
|
+
def acl=(set); end
|
94
|
+
|
95
|
+
# This member allows you to manipulate local and shared access sets
|
96
|
+
# associated with this socket. To control global access set use
|
97
|
+
# IPAccess::Global
|
98
|
+
attr_reader :acl
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
######################################################
|
103
|
+
# SOCKSSocket class with IP access control.
|
104
|
+
# It uses input access lists.
|
105
|
+
#
|
106
|
+
# This acts the same way as SOCKSSocket class but
|
107
|
+
# provides special member called +acl+ for
|
108
|
+
# controlling IP access.
|
109
|
+
|
110
|
+
class IPAccess::SOCKSSocket
|
111
|
+
#:include:ghost_doc_acl.rb
|
112
|
+
#
|
113
|
+
# ==== Example
|
114
|
+
#
|
115
|
+
# acl_set = IPAccess.new # create shared access set
|
116
|
+
# acl_set.output.block 'randomseed.pl' # block connections to this host
|
117
|
+
#
|
118
|
+
# socket = IPAccess::SOCKSSocket.new('randomseed.pl', 80) # use global access set
|
119
|
+
# socket = IPAccess::SOCKSSocket.new('randomseed.pl', 80, :private) # use private access set (!?!)
|
120
|
+
# socket = IPAccess::SOCKSSocket.new('randomseed.pl', 80, acl_set) # use shared access set
|
121
|
+
#
|
122
|
+
# Because SOCKSSocket objects tend to open connection when
|
123
|
+
# are created you have to assign access set in the very moment
|
124
|
+
# of initialization. Note that using private access set is
|
125
|
+
# possible but useles in this case.
|
126
|
+
def acl=(set); end
|
127
|
+
|
128
|
+
# This member allows you to manipulate local and shared access sets
|
129
|
+
# associated with this socket. To control global access set use
|
130
|
+
# IPAccess::Global
|
131
|
+
attr_reader :acl
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
######################################################
|
136
|
+
# TCPSocket class with IP access control.
|
137
|
+
# It uses output access lists.
|
138
|
+
#
|
139
|
+
# This acts the same way as TCPSocket class but
|
140
|
+
# provides special member called +acl+ for
|
141
|
+
# controlling IP access.
|
142
|
+
|
143
|
+
class IPAccess::TCPSocket
|
144
|
+
#:include:ghost_doc_acl.rb
|
145
|
+
#
|
146
|
+
# ==== Example
|
147
|
+
#
|
148
|
+
# acl_set = IPAccess.new # create shared access set
|
149
|
+
# acl_set.output.block 'randomseed.pl' # block connections to this host
|
150
|
+
#
|
151
|
+
# socket = IPAccess::TCPSocket.new('randomseed.pl', 80) # use global access set
|
152
|
+
# socket = IPAccess::TCPSocket.new('randomseed.pl', 80, :private) # use private access set (!?!)
|
153
|
+
# socket = IPAccess::TCPSocket.new('randomseed.pl', 80, acl_set) # use shared access set
|
154
|
+
#
|
155
|
+
# Because SOCKSSocket objects tend to open connection when
|
156
|
+
# are created you have to assign access set in the very moment
|
157
|
+
# of initialization. Note that using private access set is
|
158
|
+
# possible but useles in this case.
|
159
|
+
def acl=(set); end
|
160
|
+
|
161
|
+
# This member allows you to manipulate local and shared access sets
|
162
|
+
# associated with this socket. To control global access set use
|
163
|
+
# IPAccess::Global
|
164
|
+
attr_reader :acl
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
######################################################
|
169
|
+
# TCPServer class with IP access control.
|
170
|
+
# It uses input access lists.
|
171
|
+
#
|
172
|
+
# This acts the same way as TCPServer class but
|
173
|
+
# provides special member called +acl+ for
|
174
|
+
# controlling IP access.
|
175
|
+
#
|
176
|
+
# ==== Example
|
177
|
+
# require 'ipaddr/sockets'
|
178
|
+
#
|
179
|
+
# serv = IPAccess::TCPServer.new(31337) # create listening TCP socket
|
180
|
+
# serv.acl = :private # create and use private access set
|
181
|
+
# serv.acl.input.block :local, :private # block local and private addresses
|
182
|
+
# serv.acl.input.permit '127.0.0.5' # make an exception
|
183
|
+
#
|
184
|
+
# puts serv.acl.input.blacklist # show blacklisted IP addresses
|
185
|
+
# puts serv.acl.input.whitelist # show whitelisted IP addresses
|
186
|
+
#
|
187
|
+
# sock = serv.sysaccept # accept connection
|
188
|
+
|
189
|
+
class IPAccess::TCPServer
|
190
|
+
#:include:ghost_doc_acl.rb
|
191
|
+
#
|
192
|
+
# ==== Example
|
193
|
+
#
|
194
|
+
# socket = IPAccess::TCPServer.new(31337) # create TCP server
|
195
|
+
# socket.acl = :global # use global access set
|
196
|
+
# socket.acl = :private # create and use individual access set
|
197
|
+
# socket.acl = IPAccess.new # use external (shared) access set
|
198
|
+
def acl=(set); end
|
199
|
+
|
200
|
+
# This member allows you to manipulate local and shared access sets
|
201
|
+
# associated with this socket. To control global access set use
|
202
|
+
# IPAccess::Global
|
203
|
+
attr_reader :acl
|
204
|
+
|
205
|
+
end
|
206
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# This method selects IPAccess object that will be used to
|
2
|
+
# control IP access for a socket. You may assign global access set,
|
3
|
+
# create local access set or use shared set.
|
4
|
+
#
|
5
|
+
# - If argument is +:global+ it uses global access set.
|
6
|
+
# - If argument is +:private+ it creates an empty, private access set.
|
7
|
+
# - If argument is an IPAccess object then it is used as external, shared set.
|
8
|
+
#
|
9
|
+
# ==== Global access set
|
10
|
+
#
|
11
|
+
# Global access set is an IPAccess object referenced by contant IPAccess::Global
|
12
|
+
# It cannot be modified by calling +acl+ attribute. To add or remove rules
|
13
|
+
# use mentioned constant. By default all sockets with enabled IP access control
|
14
|
+
# are using this set.
|
15
|
+
#
|
16
|
+
# ==== Private access set
|
17
|
+
#
|
18
|
+
# Private access set is an IPAccess object created for socket object.
|
19
|
+
# You may modify it by referencing to +acl+ member of the socket object.
|
20
|
+
#
|
21
|
+
# Under some circumstances it is possible to share private access set
|
22
|
+
# – you just have to pass the +acl+ member of a socket to initializer
|
23
|
+
# of new socket object as shared access set.
|
24
|
+
#
|
25
|
+
# ==== Shared access set
|
26
|
+
#
|
27
|
+
# Shared access set is an IPAccess object that more than one socket
|
28
|
+
# may use to control IP access. It differs from private access set
|
29
|
+
# only by operation used to create. The private access set is created
|
30
|
+
# automatically and shared access set exists before socket object is
|
31
|
+
# formed.
|
@@ -0,0 +1,455 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
4
|
+
# Copyright:: Copyright (c) 2009 Paweł Wilk
|
5
|
+
# License:: This program is licensed under the terms of {GNU Lesser General Public License}[link:docs/LGPL-LICENSE.html] or {Ruby License}[link:docs/COPYING.html].
|
6
|
+
#
|
7
|
+
# This file contains IPAccess class, which uses
|
8
|
+
# IPAccessList objects to implement IP input/output
|
9
|
+
# access control.
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
#
|
13
|
+
# Copyright (C) 2009 by Paweł Wilk. All Rights Reserved.
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU Lesser General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 3 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#++
|
23
|
+
|
24
|
+
require 'socket'
|
25
|
+
require 'ipaccess/ip_access_list'
|
26
|
+
require 'ipaccess/ip_access_errors'
|
27
|
+
|
28
|
+
# This class maintains access set used in
|
29
|
+
# IP access control. It has methods that do
|
30
|
+
# access checks for given IP addresses.
|
31
|
+
# To test if access for certain IP should be
|
32
|
+
# denied or granted is uses two access lists:
|
33
|
+
# +input+ for incoming traffic and +output+ for
|
34
|
+
# outgoing traffic. Each of those list is a kind of
|
35
|
+
# IPAccessList object containing access rules
|
36
|
+
# (white and black). Use IPAccessList instance
|
37
|
+
# methods to add or remove rules from this lists.
|
38
|
+
# Both IPv4 and IPv6 addresses are supported.
|
39
|
+
#
|
40
|
+
# This class has no methods
|
41
|
+
# that actualy do network operations, it just
|
42
|
+
# allows you to check IP access for already
|
43
|
+
# given objects.
|
44
|
+
#
|
45
|
+
# When access for tested IP is denied test
|
46
|
+
# methods of this class throw exceptions that
|
47
|
+
# are subclasses of IPAccessDenied:
|
48
|
+
# IPAccessDenied::Input for input rules and
|
49
|
+
# IPAccessDenied::Output in case of output rules.
|
50
|
+
#
|
51
|
+
# ==== Usage examples
|
52
|
+
#
|
53
|
+
# access = IPAccess.new 'mylist' # create access set
|
54
|
+
# access.input.block :private # input list: block private subnets
|
55
|
+
# access.input.permit '192.168.1.1' # input list: but permit 192.168.1.1
|
56
|
+
# access.check_in '192.168.1.1' # should pass
|
57
|
+
# access.check_in '192.168.1.2' # should raise an exception
|
58
|
+
#
|
59
|
+
# In the example above checking access is covered
|
60
|
+
# by the check_in method. It is generic, easy to use
|
61
|
+
# routine, but if you are fan of performance
|
62
|
+
# you may want to use dedicated methods designed
|
63
|
+
# to handle single IP stored in socket, file descriptor,
|
64
|
+
# NetAddr::CIDR object, sockaddr structure or IP string.
|
65
|
+
#
|
66
|
+
# require 'uri'
|
67
|
+
# require 'net/http'
|
68
|
+
#
|
69
|
+
# access = IPAccess.new 'outgoing http' # create access set
|
70
|
+
# access.output.block :all # output list: block all
|
71
|
+
#
|
72
|
+
# url = URI('http://randomseed.pl/') # parse URL
|
73
|
+
# res = Net::HTTP.new(url.host, url.port) # create HTTP resource
|
74
|
+
# req = Net::HTTP::Get.new(url.path) # create HTTP request
|
75
|
+
#
|
76
|
+
# res.start do # start HTTP session
|
77
|
+
# access.check_out(res) # check access for socket extracted from HTTP object
|
78
|
+
# response = res.request(req) # read response
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# In the example above, which is probably more real
|
82
|
+
# than previous, we're using check_out method for testing
|
83
|
+
# Net::HTTP response object. The method is clever enough to
|
84
|
+
# extract IP socket from such object.
|
85
|
+
#
|
86
|
+
# Although the problem still exists because
|
87
|
+
# access for incoming connection is validated
|
88
|
+
# after the HTTP session has already started. We cannot
|
89
|
+
# be 100% sure whether any data has been sent or not.
|
90
|
+
# The cause of that problem is lack of controlled
|
91
|
+
# low-level connect operation that we can issue in
|
92
|
+
# that particular case.
|
93
|
+
#
|
94
|
+
# To fix issues like that you may want to
|
95
|
+
# globally enable IP access control for original
|
96
|
+
# Ruby's socket classes or use special versions
|
97
|
+
# of them shipped with this library. To patch original
|
98
|
+
# sockets use IPAccess.arm class method. To
|
99
|
+
# use extended classes use classes like IPAccess::TCPSocket.
|
100
|
+
|
101
|
+
class IPAccess
|
102
|
+
|
103
|
+
# Access list for incoming IP traffic. See IPAccessList class
|
104
|
+
# for more information on how to manage it.
|
105
|
+
|
106
|
+
attr_reader :input
|
107
|
+
|
108
|
+
alias_method :in, :input
|
109
|
+
alias_method :incoming, :input
|
110
|
+
|
111
|
+
# Access list for outgoing IP traffic. See IPAccessList class
|
112
|
+
# for more information on how to manage it.
|
113
|
+
|
114
|
+
attr_reader :output
|
115
|
+
|
116
|
+
alias_method :out, :output
|
117
|
+
alias_method :outgoing, :output
|
118
|
+
|
119
|
+
# Descriptive name of this object. Used in error reporting.
|
120
|
+
|
121
|
+
attr_accessor :name
|
122
|
+
|
123
|
+
# This method creates new IPAccess object. It optionally takes
|
124
|
+
# two IPAccessList objects (initial data for access lists)
|
125
|
+
# and a name of an access set used in error reporting.
|
126
|
+
#
|
127
|
+
# If there is only one argument it is assumed that it also
|
128
|
+
# contains this set's descriptive name.
|
129
|
+
|
130
|
+
def initialize(input=nil, output=nil, name=nil)
|
131
|
+
@name = nil
|
132
|
+
@name, input = input, nil if (output.nil? && name.nil?)
|
133
|
+
@input = IPAccessList.new(input)
|
134
|
+
@output = IPAccessList.new(output)
|
135
|
+
return self
|
136
|
+
end
|
137
|
+
|
138
|
+
# Raises default exception including remote address and address-rule hash.
|
139
|
+
# First argument should be a hash containing CIDR objects: a testet address
|
140
|
+
# (+:IP+) and a matching rule (+:Rule+). Second argument should be exception class.
|
141
|
+
|
142
|
+
def scream!(pair, use_exception=IPAccessDenied::Input)
|
143
|
+
raise use_exception.new(pair[:IP], pair[:Rule], self)
|
144
|
+
end
|
145
|
+
|
146
|
+
# This method returns +true+ if all access lists are empty.
|
147
|
+
# Otherwise returns +false+.
|
148
|
+
|
149
|
+
def empty?
|
150
|
+
@input.empty? && @output.empty?
|
151
|
+
end
|
152
|
+
|
153
|
+
# This method removes all rules from both input and
|
154
|
+
# output access list.
|
155
|
+
|
156
|
+
def clear!
|
157
|
+
@input.clear!
|
158
|
+
@output.clear!
|
159
|
+
end
|
160
|
+
|
161
|
+
# This method returns true if access set works
|
162
|
+
# in bidirectional mode.
|
163
|
+
|
164
|
+
def bidirectional?
|
165
|
+
return (@output.object_id == @input.object_id)
|
166
|
+
end
|
167
|
+
|
168
|
+
# This method switches set to bidirectional
|
169
|
+
# mode if the given argument is not +false+
|
170
|
+
# and is not +nil+. When access set
|
171
|
+
# operates in this mode there is no difference
|
172
|
+
# between incoming and outgoing acceess list.
|
173
|
+
# In bidirectional mode each access check
|
174
|
+
# is performed against one list which contains
|
175
|
+
# both input and output rules. Still the only
|
176
|
+
# way to add or delete rules is to straight
|
177
|
+
# call +input+ or +output+. The difference is
|
178
|
+
# that these lists are linked together
|
179
|
+
# in bidirectional mode.
|
180
|
+
#
|
181
|
+
# Be aware that switching mode will alter
|
182
|
+
# your access lists. When switching to
|
183
|
+
# bidirectional it will combine input and
|
184
|
+
# output rules and put it into one list.
|
185
|
+
# When switching back from bidirectional
|
186
|
+
# to normal mode input and output lists
|
187
|
+
# will have the same rules inside.
|
188
|
+
#
|
189
|
+
# It may be good idea to prune access lists before
|
190
|
+
# switching mode or to switch mode before adding
|
191
|
+
# any rules to avoid unexpected results. You may
|
192
|
+
# of course change mode anyway if you really know
|
193
|
+
# what you are doing.
|
194
|
+
|
195
|
+
def bidirectional=(enable)
|
196
|
+
enable = enable ? true : false
|
197
|
+
if enable != bidirectional?
|
198
|
+
if enable
|
199
|
+
@input.add @output
|
200
|
+
@output.clear!
|
201
|
+
@output = @input
|
202
|
+
else
|
203
|
+
@output = IPAccessList.new @input
|
204
|
+
end
|
205
|
+
end
|
206
|
+
return nil
|
207
|
+
end
|
208
|
+
|
209
|
+
# This method checks IP access of traffic for
|
210
|
+
# CIDR objects. If access is denied it raises an exception
|
211
|
+
# reporting first rejected IP. If access is granted it
|
212
|
+
# returns an array containing the given argument(s).
|
213
|
+
#
|
214
|
+
# See IPAccessList.obj_to_cidr description for more info
|
215
|
+
# about arguments you may pass to it.
|
216
|
+
|
217
|
+
def check(list, exc, *args)
|
218
|
+
return args if list.empty?
|
219
|
+
pairs = list.denied(*args)
|
220
|
+
unless pairs.empty?
|
221
|
+
yield(pairs.first, args) if block_given?
|
222
|
+
scream!(pairs.first, exc)
|
223
|
+
end
|
224
|
+
return args
|
225
|
+
end
|
226
|
+
private :check
|
227
|
+
|
228
|
+
# This method checks access for a socket.
|
229
|
+
|
230
|
+
def check_socket(list, exc, socket)
|
231
|
+
if (list.empty? || !socket.respond_to?(:getpeername))
|
232
|
+
return socket
|
233
|
+
end
|
234
|
+
begin
|
235
|
+
peeraddr = Socket.unpack_sockaddr_in(socket.getpeername).last
|
236
|
+
rescue Errno::ENOTCONN, Errno::ENOTSOCK, ArgumentError # socket is not INET, not a socket nor connected
|
237
|
+
return socket
|
238
|
+
end
|
239
|
+
peer_ip = NetAddr::CIDR.create(peeraddr.split('%').first)
|
240
|
+
pair = list.denied_cidr(peer_ip, true)
|
241
|
+
unless pair.empty?
|
242
|
+
yield(pair, socket) if block_given?
|
243
|
+
scream!(pair, exc)
|
244
|
+
end
|
245
|
+
return socket
|
246
|
+
end
|
247
|
+
private :check_socket
|
248
|
+
|
249
|
+
# This method checks access for a sockaddr.
|
250
|
+
|
251
|
+
def check_sockaddr(list, exc, sockaddr)
|
252
|
+
return sockaddr if list.empty?
|
253
|
+
begin
|
254
|
+
peeraddr = Socket.unpack_sockaddr_in(sockaddr).last
|
255
|
+
rescue ArgumentError # sockaddr is not INET
|
256
|
+
return sockaddr
|
257
|
+
end
|
258
|
+
peer_ip = NetAddr::CIDR.create(peeraddr.split('%').first)
|
259
|
+
pair = list.denied_cidr(peer_ip, true)
|
260
|
+
unless pair.empty?
|
261
|
+
yield(pair, sockaddr) if block_given?
|
262
|
+
scream!(pair, exc)
|
263
|
+
end
|
264
|
+
return sockaddr
|
265
|
+
end
|
266
|
+
private :check_sockaddr
|
267
|
+
|
268
|
+
# This method checks access for a CIDR object.
|
269
|
+
|
270
|
+
def check_cidr(list, exc, cidr)
|
271
|
+
pair = list.denied_cidr(cidr, true)
|
272
|
+
unless pair.empty?
|
273
|
+
yield(pair, cidr) if block_given?
|
274
|
+
scream!(pair, exc)
|
275
|
+
end
|
276
|
+
return cidr
|
277
|
+
end
|
278
|
+
private :check_cidr
|
279
|
+
|
280
|
+
# This method checks access for a string containing
|
281
|
+
# IP address.
|
282
|
+
|
283
|
+
def check_ipstring(list, exc, ipstring)
|
284
|
+
return ipstring if list.empty?
|
285
|
+
addr = NetAddr::CIDR.create(ipstring.split('%').first)
|
286
|
+
pair = list.denied_cidr(addr, true)
|
287
|
+
unless pair.empty?
|
288
|
+
yield(pair, ipstring) if block_given?
|
289
|
+
scream!(pair, exc)
|
290
|
+
end
|
291
|
+
return ipstring
|
292
|
+
end
|
293
|
+
private :check_ipstring
|
294
|
+
|
295
|
+
# This method checks IP access but bases on file descriptor.
|
296
|
+
|
297
|
+
def check_fd(list, exc, fd)
|
298
|
+
check_socket(list, exc, Socket.for_fd(fd))
|
299
|
+
end
|
300
|
+
private :check_fd
|
301
|
+
|
302
|
+
# This method checks access for the given objects
|
303
|
+
# containing IP information against input access list.
|
304
|
+
# If access is denied it raises an exception reporting
|
305
|
+
# first rejected IP and a matching rule. If access is
|
306
|
+
# granted it returns an array containing the given arguments.
|
307
|
+
#
|
308
|
+
# See IPAccessList.obj_to_cidr description for more info
|
309
|
+
# about arguments you may pass to it.
|
310
|
+
#
|
311
|
+
# You may also want to use more efficient access checking
|
312
|
+
# methods if your object contains information about
|
313
|
+
# single IP and has a known type.
|
314
|
+
|
315
|
+
def check_in(*args)
|
316
|
+
check(@input, IPAccessDenied::Input, *args)
|
317
|
+
end
|
318
|
+
|
319
|
+
# This method checks access for the given objects
|
320
|
+
# containing IP information against output access list.
|
321
|
+
# If access is denied it raises an exception reporting
|
322
|
+
# first rejected IP and a matching rule. If access is
|
323
|
+
# granted it returns an array containing the given arguments.
|
324
|
+
#
|
325
|
+
# See IPAccessList.obj_to_cidr description for more info
|
326
|
+
# about arguments you may pass to it.
|
327
|
+
#
|
328
|
+
# You may also want to use more efficient access checking
|
329
|
+
# methods if your object contains information about
|
330
|
+
# single IP and has a known type.
|
331
|
+
|
332
|
+
def check_out(*args)
|
333
|
+
check(@output, IPAccessDenied::Output, *args)
|
334
|
+
end
|
335
|
+
|
336
|
+
# This method checks access for the given CIDR object
|
337
|
+
# containing IP information against input access list.
|
338
|
+
# If access is denied it raises an exception reporting
|
339
|
+
# rejected IP and a matching rule. If access is granted
|
340
|
+
# it returns the given argument.
|
341
|
+
#
|
342
|
+
# Expected argument should be kind of NetAddr::CIDR.
|
343
|
+
|
344
|
+
def check_in_cidr(cidr)
|
345
|
+
check_cidr(@input, IPAccessDenied::Input, cidr)
|
346
|
+
end
|
347
|
+
|
348
|
+
# This method checks access for the given CIDR object
|
349
|
+
# containing IP information against output access list.
|
350
|
+
# If access is denied it raises an exception reporting
|
351
|
+
# rejected IP and a matching rule. If access is granted
|
352
|
+
# it returns the given argument.
|
353
|
+
#
|
354
|
+
# Expected argument should be kind of NetAddr::CIDR.
|
355
|
+
|
356
|
+
def check_out_cidr(cidr)
|
357
|
+
check_cidr(@output, IPAccessDenied::Output, cidr)
|
358
|
+
end
|
359
|
+
|
360
|
+
# This method checks access for the given string
|
361
|
+
# containing IP information against input access list.
|
362
|
+
# If access is denied it raises an exception reporting
|
363
|
+
# rejected IP and a matching rule. If access is granted
|
364
|
+
# it returns the given argument.
|
365
|
+
|
366
|
+
def check_in_ipstring(ipstring)
|
367
|
+
check_ipstring(@input, IPAccessDenied::Input, ipstring)
|
368
|
+
end
|
369
|
+
|
370
|
+
# This method checks access for the given string
|
371
|
+
# containing IP information against output access list.
|
372
|
+
# If access is denied it raises an exception reporting
|
373
|
+
# rejected IP and a matching rule. If access is granted
|
374
|
+
# it returns the given argument.
|
375
|
+
|
376
|
+
def check_out_ipstring(ipstring)
|
377
|
+
check_ipstring(@output, IPAccessDenied::Output, ipstring)
|
378
|
+
end
|
379
|
+
|
380
|
+
# This method checks access for the given socket object
|
381
|
+
# containing IP information against input access list.
|
382
|
+
# If access is denied it raises an exception reporting
|
383
|
+
# rejected IP and a matching rule. If access is granted
|
384
|
+
# it returns the given argument.
|
385
|
+
#
|
386
|
+
# Expected argument should be kind of IPSocket.
|
387
|
+
|
388
|
+
def check_in_socket(socket)
|
389
|
+
check_socket(@input, IPAccessDenied::Input, socket)
|
390
|
+
end
|
391
|
+
|
392
|
+
# This method checks access for the given socket object
|
393
|
+
# containing IP information against output access list.
|
394
|
+
# If access is denied it raises an exception reporting
|
395
|
+
# rejected IP and a matching rule. If access is granted
|
396
|
+
# it returns the given argument.
|
397
|
+
#
|
398
|
+
# Expected argument should be kind of IPSocket.
|
399
|
+
|
400
|
+
def check_out_socket(socket)
|
401
|
+
check_socket(@output, IPAccessDenied::Output, socket)
|
402
|
+
end
|
403
|
+
|
404
|
+
# This method checks access for the given sockaddr structure
|
405
|
+
# containing IP information against input access list.
|
406
|
+
# If access is denied it raises an exception reporting
|
407
|
+
# rejected IP and a matching rule. If access is granted
|
408
|
+
# it returns the given argument.
|
409
|
+
|
410
|
+
def check_in_sockaddr(sockaddr)
|
411
|
+
check_sockaddr(@input, IPAccessDenied::Input, sockaddr)
|
412
|
+
end
|
413
|
+
|
414
|
+
# This method checks access for the given sockaddr structure
|
415
|
+
# containing IP information against output access list.
|
416
|
+
# If access is denied it raises an exception reporting
|
417
|
+
# rejected IP and a matching rule. If access is granted
|
418
|
+
# it returns the given argument.
|
419
|
+
|
420
|
+
def check_out_sockaddr(sockaddr)
|
421
|
+
check_sockaddr(@output, IPAccessDenied::Output, sockaddr)
|
422
|
+
end
|
423
|
+
|
424
|
+
# This method checks access for the given file descriptor
|
425
|
+
# containing IP information against input access list.
|
426
|
+
# If access is denied it raises an exception reporting
|
427
|
+
# rejected IP and a matching rule. If access is granted
|
428
|
+
# it returns the given argument.
|
429
|
+
#
|
430
|
+
# Expected argument should be a number representing a valid
|
431
|
+
# file descriptor bound to an IP socket.
|
432
|
+
|
433
|
+
def check_in_fd(fd)
|
434
|
+
check_fd(@input, IPAccessDenied::Input, fd)
|
435
|
+
end
|
436
|
+
|
437
|
+
# This method checks access for the given file descriptor
|
438
|
+
# containing IP information against output access list.
|
439
|
+
# If access is denied it raises an exception reporting
|
440
|
+
# rejected IP and a matching rule. If access is granted
|
441
|
+
# it returns the given argument.
|
442
|
+
#
|
443
|
+
# Expected argument should be a number representing a valid
|
444
|
+
# file descriptor bound to an IP socket.
|
445
|
+
|
446
|
+
def check_out_fd(fd)
|
447
|
+
check_fd(@output, IPAccessDenied::Output, fd)
|
448
|
+
end
|
449
|
+
|
450
|
+
end
|
451
|
+
|
452
|
+
require 'ipaccess/ip_access_patches'
|
453
|
+
|
454
|
+
|
455
|
+
|