iptablez 1.0.0.pre
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +141 -0
- data/Rakefile +6 -0
- data/Vagrantfile +100 -0
- data/bin/console +14 -0
- data/bin/iptblz.rb +21 -0
- data/bin/setup +8 -0
- data/giant_squid.txt +12 -0
- data/iptablez.gemspec +27 -0
- data/lib/iptablez.rb +33 -0
- data/lib/iptablez/chains/README.md +139 -0
- data/lib/iptablez/chains/chains.rb +227 -0
- data/lib/iptablez/commands/append_chain.rb +62 -0
- data/lib/iptablez/commands/delete_chain.rb +106 -0
- data/lib/iptablez/commands/flush_chain.rb +72 -0
- data/lib/iptablez/commands/helpers/argument_helpers.rb +163 -0
- data/lib/iptablez/commands/helpers/errors.rb +11 -0
- data/lib/iptablez/commands/helpers/move_on.rb +14 -0
- data/lib/iptablez/commands/interface.rb +80 -0
- data/lib/iptablez/commands/list.rb +210 -0
- data/lib/iptablez/commands/new_chain.rb +71 -0
- data/lib/iptablez/commands/policy.rb +65 -0
- data/lib/iptablez/commands/rename_chain.rb +65 -0
- data/lib/iptablez/commands/version.rb +18 -0
- data/lib/iptablez/commands/zero.rb +18 -0
- data/lib/iptablez/helpers/helpers.rb +46 -0
- data/lib/iptablez/helpers/version.rb +3 -0
- metadata +121 -0
@@ -0,0 +1,210 @@
|
|
1
|
+
module Iptablez
|
2
|
+
module Commands
|
3
|
+
module List
|
4
|
+
# Move on Module
|
5
|
+
include MoveOn
|
6
|
+
|
7
|
+
UNKOWN_OPTION = 'unknown option'.freeze
|
8
|
+
NO_CHAIN_MATCH_ERROR = 'iptables: No chain/target/match by that name.'.freeze
|
9
|
+
PERMISSION_DENIED = 'Permission denied (you must be root)'.freeze
|
10
|
+
INVALID_RULE_NUMBER = 'Invalid rule number'.freeze
|
11
|
+
|
12
|
+
KNOWN_ERRORS = [NO_CHAIN_MATCH_ERROR, PERMISSION_DENIED, INVALID_RULE_NUMBER, UNKOWN_OPTION].freeze
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
# Determine a given error. Optionally a chain can be used to provide better context.
|
16
|
+
private_class_method def self.determine_error(error:, chain: false, number: false)
|
17
|
+
if error == NO_CHAIN_MATCH_ERROR
|
18
|
+
raise ChainExistenceError, "#{chain} doesn't exist!"
|
19
|
+
elsif error == INVALID_RULE_NUMBER
|
20
|
+
raise InvalidRuleIndexError, "#{chain} invalid number #{number}!"
|
21
|
+
else
|
22
|
+
raise error
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# List all of the `iptables` rules. Note: this will not include policies.
|
27
|
+
# @todo Document params.
|
28
|
+
# @example Basic Usage
|
29
|
+
# Iptablez::Commands::List.all
|
30
|
+
# # => []
|
31
|
+
# Iptablez::Commands::List.all.empty? # if no rules
|
32
|
+
# # => true
|
33
|
+
# @example Basic Usage with a Block
|
34
|
+
# Iptablez::Commands::List.all do |rule|
|
35
|
+
# puts rule
|
36
|
+
# end
|
37
|
+
# @yield Each result if a block is given.
|
38
|
+
# @return [Hash] key value pairing of each chain and the result of the check.
|
39
|
+
def self.all(error: false, continue: !error)
|
40
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-L')
|
41
|
+
if e["you must be root"]
|
42
|
+
e = PERMISSION_DENIED
|
43
|
+
else
|
44
|
+
e.strip!
|
45
|
+
end
|
46
|
+
results = []
|
47
|
+
if s.success?
|
48
|
+
o.split("\n").map(&:strip).each do |line|
|
49
|
+
next if line.split[0] == "Chain" || line.split[0] == "target" || line.empty?
|
50
|
+
yield line if block_given?
|
51
|
+
results << line
|
52
|
+
end
|
53
|
+
results
|
54
|
+
elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
|
55
|
+
return results
|
56
|
+
else
|
57
|
+
determine_error(chain: name, error: e)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# List the `iptables` rules for a chain of a given `name`.
|
62
|
+
# @todo Document params.
|
63
|
+
# @example Basic Usage
|
64
|
+
# Iptablez::Commands::List.defaults
|
65
|
+
# # => {"INPUT"=>"ACCEPT", "FORWARD"=>"ACCEPT", "OUTPUT"=>"ACCEPT"}
|
66
|
+
# @example Basic Usage with a Block
|
67
|
+
# Iptablez::Commands::List.defaults do |name, target|
|
68
|
+
# puts "#{name}: #{target}"
|
69
|
+
# end
|
70
|
+
def self.defaults(names: Iptablez::Chains.defaults, error: false, continue: !error)
|
71
|
+
results = {}
|
72
|
+
names.each do |name|
|
73
|
+
result = chain(name: name, policy: true, continue: true)
|
74
|
+
result = result.map(&:split).map(&:last)[0] if result
|
75
|
+
yield [name, result] if block_given?
|
76
|
+
results[name] = result
|
77
|
+
end
|
78
|
+
results
|
79
|
+
end
|
80
|
+
|
81
|
+
# List the full `iptables` output (no filtering from STDOUT) for a `chain` of a given name, or
|
82
|
+
# all chains if no chain `name` is given.
|
83
|
+
# @todo Document params.
|
84
|
+
# @example Basic Usage
|
85
|
+
# Iptablez::Commands::List.full
|
86
|
+
# Iptablez::Commands::List.full(chain: "INPUT")
|
87
|
+
# @example Basic Usage with a Block
|
88
|
+
# Iptablez::Commands::List.full { |l| puts l }
|
89
|
+
# Iptablez::Commands::List.full(chain: "FORWARD") do |line|
|
90
|
+
# puts line
|
91
|
+
# end
|
92
|
+
# @yield Each result if a block is given.
|
93
|
+
# @return [Array] Each line as the result.
|
94
|
+
def self.full(chain: false, error: false, continue: !error)
|
95
|
+
if chain
|
96
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-L', chain)
|
97
|
+
else
|
98
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-L')
|
99
|
+
end
|
100
|
+
e.strip!
|
101
|
+
if s.success?
|
102
|
+
return o.split("\n").map(&:strip).each do |line|
|
103
|
+
yield line if block_given?
|
104
|
+
end
|
105
|
+
elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
|
106
|
+
return false
|
107
|
+
else
|
108
|
+
determine_error(chain: name, error: e)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# List a rule for a `chain` of a given name and `number`.
|
113
|
+
# @example Basic Usage
|
114
|
+
# Iptablez::Commands::List.number(chain: "INPUT", number: 1)
|
115
|
+
# # => false
|
116
|
+
# Iptablez::Commands::List.number(chain: "FORWARD", number: 1)
|
117
|
+
# # => String containing rule number 1 from the FOWARD chain.
|
118
|
+
# @example Basic Usage with a Block
|
119
|
+
# Iptablez::Commands::List.number(chain: "INPUT", number: 1) do |chain, num, result|
|
120
|
+
# puts "Rule #{num} in #{chain} is #{result}" if result
|
121
|
+
# end
|
122
|
+
def self.number(chain:, number:, error: false, continue: !error)
|
123
|
+
if number.is_a? Integer
|
124
|
+
if number <= 0 && error
|
125
|
+
raise ArgumentError, "Invalid rule number #{number}!"
|
126
|
+
else
|
127
|
+
number = number.to_s
|
128
|
+
end
|
129
|
+
end
|
130
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-L', chain, number.to_s)
|
131
|
+
e.strip!
|
132
|
+
o.strip!
|
133
|
+
o = false if o.empty?
|
134
|
+
e = INVALID_RULE_NUMBER if e["Invalid rule number"]
|
135
|
+
e = UNKOWN_OPTION if e[": unknown option "]
|
136
|
+
if s.success?
|
137
|
+
yield [chain, number, o] if block_given?
|
138
|
+
return o
|
139
|
+
elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
|
140
|
+
return false
|
141
|
+
else
|
142
|
+
determine_error(chain: name, error: e, number: number)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Determine if there is a rule for a given `chain` name with a given `number`.
|
147
|
+
# @example Basic Usage
|
148
|
+
# Iptablez::Commands::List.number?(chain: "INPUT", number: 1)
|
149
|
+
# # => false
|
150
|
+
# Iptablez::Commands::List.number?(chain: "FORWARD", number: 1)
|
151
|
+
# # => true
|
152
|
+
def self.number?(chain:, number:, error: false, continue: !error)
|
153
|
+
if number(chain: chain, number: number, continue: continue)
|
154
|
+
true
|
155
|
+
else
|
156
|
+
false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Determine if a given `number` could even be a possible number. Note: this will not
|
161
|
+
# check `iptables` for validation.
|
162
|
+
# @example Basic Usage
|
163
|
+
# Iptablez::Commands::List.possible_valid_number?(number: 2)
|
164
|
+
# # => true
|
165
|
+
# Iptablez::Commands::List.possible_valid_number?(number: 0)
|
166
|
+
# # => false
|
167
|
+
def self.possible_valid_number?(number:)
|
168
|
+
number = number.to_i if number.is_a? String
|
169
|
+
if number >= 1
|
170
|
+
true
|
171
|
+
else
|
172
|
+
false
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# List the `iptables` rules for a chain of a given `name`. Optionally, you
|
177
|
+
# may specify to include `policy` information which can be helpful.
|
178
|
+
# @example Basic Usage
|
179
|
+
# Iptablez::Commands::List.chain(name: "INPUT")
|
180
|
+
# # => []
|
181
|
+
# Iptablez::Commands::List.chain(name: "INPUT", policy: true)
|
182
|
+
# # => ["-P INPUT ACCEPT"]
|
183
|
+
# @example Basic Usage with a Block
|
184
|
+
# Iptablez::Commands::List.chain(name: "INPUT", policy: true) do |rule|
|
185
|
+
# puts rule
|
186
|
+
# end
|
187
|
+
def self.chain(name:, policy: false, error: false, continue: !error)
|
188
|
+
if policy
|
189
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-S', name)
|
190
|
+
else
|
191
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-L', name)
|
192
|
+
end
|
193
|
+
e.strip!
|
194
|
+
if s.success?
|
195
|
+
results = o.split("\n").map(&:strip).delete_if do |line|
|
196
|
+
line if line.split[0] == "Chain" || line.split[0] == "target"
|
197
|
+
end
|
198
|
+
results.each do |line|
|
199
|
+
yield line if block_given?
|
200
|
+
end
|
201
|
+
results
|
202
|
+
elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
|
203
|
+
return false
|
204
|
+
else
|
205
|
+
determine_error(chain: name, error: e)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Iptablez
|
2
|
+
module Commands
|
3
|
+
module NewChain
|
4
|
+
# Move on Module
|
5
|
+
include MoveOn
|
6
|
+
|
7
|
+
CHAIN_ALREADY_EXITS_ERROR = 'iptables: Chain already exists.'
|
8
|
+
KNOWN_ERRORS = [CHAIN_ALREADY_EXITS_ERROR]
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
# Determine a given error. Optionally a chain can be used to provide better context.
|
12
|
+
private_class_method def self.determine_error(error:, chain: false)
|
13
|
+
error.strip!
|
14
|
+
if error == CHAIN_ALREADY_EXITS_ERROR
|
15
|
+
raise ChainAlreadyExistsError, "#{chain} already exist!"
|
16
|
+
else
|
17
|
+
raise error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Create a new chain of a given +name+, unless is already exists. This is the heart of the module.
|
22
|
+
# @param name [String] Single chain +name+.
|
23
|
+
# @param error [Boolean] Determine if operations should raise/halt other possible operations with errors.
|
24
|
+
# @param continue [Boolean] Determine if operations should continue despite errors.
|
25
|
+
#
|
26
|
+
# @example Basic Usage
|
27
|
+
# Iptablez::Commands::NewChain.chain(name: "dogs")
|
28
|
+
# # => true
|
29
|
+
# Iptablez::Commands::NewChain.chain(name: "dogs")
|
30
|
+
# # => false
|
31
|
+
# @yield [String, Boolean] The +name+ of the chain and +result+ of the operation if a block if given.
|
32
|
+
# @return [String, Boolean] Key value pairing of the given chain +name+ and the +result+ of the operation.
|
33
|
+
def self.chain(name:, error: false, continue: !error)
|
34
|
+
name = name.to_s unless name.is_a? String
|
35
|
+
_, e, s = Open3.capture3(Iptablez.bin_path, '-N', name.shellescape)
|
36
|
+
e.strip! # remove new line
|
37
|
+
if s.success?
|
38
|
+
yield [name, true] if block_given?
|
39
|
+
return true
|
40
|
+
elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
|
41
|
+
yield [name, false] if block_given?
|
42
|
+
return false
|
43
|
+
else
|
44
|
+
determine_error(chain: name, error: e)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Create each +name+ from a given array of +names+ unless the chain already exists.
|
49
|
+
# @param names [Array<String>] An array of chains to delete.
|
50
|
+
# @param error [Boolean] Determine if operations should raise/halt other possible operations with errors.
|
51
|
+
# @param continue [Boolean] Determine if operations should continue despite errors.
|
52
|
+
#
|
53
|
+
# @example Basic Usage
|
54
|
+
# Iptablez::Commands::DeleteChain.chain(names: ["dogs", "whales"])
|
55
|
+
# # => {"dogs"=>false, "whales"=>true}
|
56
|
+
#
|
57
|
+
# @yield [String, Boolean] The +name+ of the chain and +result+ of the operation if a block if given.
|
58
|
+
# @return [Hash] Key value pairing of each given chain +name+ and the +result+ of the operation.
|
59
|
+
def self.chains(names:, error: false, continue: !error)
|
60
|
+
results = {}
|
61
|
+
names.each do |name|
|
62
|
+
chain(name: name, continue: continue) do |name, result|
|
63
|
+
yield [name, result] if block_given?
|
64
|
+
results[name] = result
|
65
|
+
end
|
66
|
+
end
|
67
|
+
results
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Iptablez
|
2
|
+
module Commands
|
3
|
+
module Policy
|
4
|
+
# Move on Module
|
5
|
+
include MoveOn
|
6
|
+
|
7
|
+
NO_CHAIN_MATCH_ERROR = 'iptables: No chain/target/match by that name.'.freeze
|
8
|
+
KNOWN_ERRORS = [NO_CHAIN_MATCH_ERROR].freeze
|
9
|
+
|
10
|
+
# @api private
|
11
|
+
# Determine a given error. Optionally a chain can be used to provide better context.
|
12
|
+
private_class_method def self.determine_error(error:, chain: false)
|
13
|
+
if error == NO_CHAIN_MATCH_ERROR
|
14
|
+
raise ChainExistenceError, "#{chain} doesn't exist!"
|
15
|
+
else
|
16
|
+
raise error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.all(target:, error: false, continue: !error)
|
21
|
+
if target
|
22
|
+
chains(names: Iptablez::Chains.defaults, target: target, continue: continue) do |result|
|
23
|
+
yield result if block_given?
|
24
|
+
end
|
25
|
+
else
|
26
|
+
Iptables::Chains.policies do |result|
|
27
|
+
yield result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.defaults(target:, error: false, continue: !error)
|
33
|
+
chains(names: Iptablez::Chains.defaults, target: target, continue: continue) do |result|
|
34
|
+
yield result if block_given?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.chain(name:, target:, error: false, continue: !error)
|
39
|
+
_, e, s = Open3.capture3(Iptablez.bin_path, '-P', name, target)
|
40
|
+
e.strip!
|
41
|
+
if s.success?
|
42
|
+
yield [name, target, true] if block_given?
|
43
|
+
return true
|
44
|
+
elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
|
45
|
+
yield [name, target, false] if block_given?
|
46
|
+
return false
|
47
|
+
else
|
48
|
+
determine_error(chain: name, error: e)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.chains(names:, target:, error: false, continue: !error)
|
53
|
+
results = {}
|
54
|
+
names.each do |name|
|
55
|
+
results[name] = {}
|
56
|
+
results[name][target] = chain(name: name, target: target, continue: continue) do |result|
|
57
|
+
yield result if block_given?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
results
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Iptablez
|
2
|
+
module Commands
|
3
|
+
module RenameChain
|
4
|
+
# Move on Module
|
5
|
+
include MoveOn
|
6
|
+
|
7
|
+
|
8
|
+
NO_CHAIN_MATCH_ERROR = 'iptables: No chain/target/match by that name.'.freeze
|
9
|
+
CHAIN_ALREADY_EXISTS = 'iptables: File exists.'.freeze
|
10
|
+
KNOWN_ERRORS = [NO_CHAIN_MATCH_ERROR, CHAIN_ALREADY_EXISTS].freeze
|
11
|
+
|
12
|
+
# @api private
|
13
|
+
# Determine a given error. Optionally a chain can be used to provide better context.
|
14
|
+
private_class_method def self.determine_error(error:, chain: false)
|
15
|
+
if error == NO_CHAIN_MATCH_ERROR
|
16
|
+
raise ChainExistenceError, "#{chain} doesn't exist!"
|
17
|
+
elsif error == CHAIN_ALREADY_EXISTS
|
18
|
+
raise ChainExistenceError, "#{chain} already exists!"
|
19
|
+
else
|
20
|
+
raise error
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Rename a chain +from+ a given name +to+ a new name. This is the heart of this module.
|
25
|
+
# @param from [String] Single chain name to change +from+.
|
26
|
+
# @param to [String] Single chain name to change +to+.
|
27
|
+
#
|
28
|
+
# @example Basic Usage
|
29
|
+
# Iptablez::Commands::RenameChain.chain(from: "dogs", to: "cats")
|
30
|
+
# # => true
|
31
|
+
# Iptablez::Commands::RenameChain.chain(from: "dogs", to: "birds")
|
32
|
+
# # => false
|
33
|
+
#
|
34
|
+
# @yield [String, String]
|
35
|
+
# @return [Boolean]
|
36
|
+
def self.chain(from:, to:, error: false, continue: !error)
|
37
|
+
to = to.to_s unless to.is_a? String
|
38
|
+
from = from.to_s unless from.is_a? String
|
39
|
+
_, e, s = Open3.capture3(Iptablez.bin_path, '-E', from.shellescape, to.shellescape)
|
40
|
+
e.strip!
|
41
|
+
if s.success?
|
42
|
+
yield [from, to, true] if block_given?
|
43
|
+
return true
|
44
|
+
elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
|
45
|
+
yield [from, to, false] if block_given?
|
46
|
+
return false
|
47
|
+
else
|
48
|
+
determine_error(chain: name, error: e)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.chains(pairs:, error: false, continue: !error)
|
53
|
+
results = {}
|
54
|
+
pairs.each do |from, to|
|
55
|
+
results[from] = {}
|
56
|
+
results[from][to] = chain(from: from, to: to, continue: continue) do |from, to, result|
|
57
|
+
yield [from, to, result] if block_given?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
results
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Iptablez
|
2
|
+
module Commands
|
3
|
+
# @todo
|
4
|
+
module Version
|
5
|
+
def self.number
|
6
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '--version')
|
7
|
+
return o.strip.split[1].gsub('v','') if s.success?
|
8
|
+
raise e
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.full
|
12
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '--version')
|
13
|
+
return o.strip if s.success?
|
14
|
+
raise e
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Iptablez
|
2
|
+
module Commands
|
3
|
+
# @todo
|
4
|
+
module Zero
|
5
|
+
def self.all
|
6
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-Z')
|
7
|
+
return true if s.success?
|
8
|
+
raise e
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.chain(name:)
|
12
|
+
o, e, s = Open3.capture3(Iptablez.bin_path, '-Z', name)
|
13
|
+
return true if s.success?
|
14
|
+
raise e
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|