iptablez 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|