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.
data/iptablez.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'iptablez/helpers/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "iptablez"
8
+ spec.version = Iptablez::VERSION
9
+ spec.authors = ["Kent 'picat' Gruber"]
10
+ spec.email = ["kgruber1@emich.edu"]
11
+
12
+ spec.summary = %q{A friendly Ruby API to iptables.}
13
+ #spec.description = %q{TODO: Write a longer description or delete this line.}
14
+ spec.homepage = "https://github.com/picatz/iptablez"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "bin"
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.14"
25
+ spec.add_development_dependency "rake", "~> 10.0"
26
+ spec.add_development_dependency "rspec", "~> 3.0"
27
+ end
data/lib/iptablez.rb ADDED
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "shellwords"
4
+ require "open3"
5
+
6
+ require "iptablez/helpers/version"
7
+ require "iptablez/helpers/helpers"
8
+ require "iptablez/commands/helpers/move_on"
9
+ require "iptablez/commands/helpers/errors"
10
+ require "iptablez/commands/helpers/argument_helpers"
11
+ require "iptablez/commands/flush_chain"
12
+ require "iptablez/commands/interface"
13
+ require "iptablez/commands/policy"
14
+ require "iptablez/commands/new_chain"
15
+ require "iptablez/commands/append_chain"
16
+ require "iptablez/commands/rename_chain"
17
+ require "iptablez/commands/delete_chain"
18
+ require "iptablez/commands/version"
19
+ require "iptablez/commands/list"
20
+ require "iptablez/chains/chains"
21
+
22
+ module Iptablez
23
+
24
+ def self.squid
25
+ # easter egg / mascot
26
+ puts "<コ:彡"
27
+ end
28
+
29
+ def self.giant_squid
30
+ puts File.read('giant_squid.txt')
31
+ end
32
+
33
+ end
@@ -0,0 +1,139 @@
1
+ # Chains Interface
2
+
3
+ The `Chains` Inteface is a collection of helpful methods to act as a clear, friendly interface to the possible collection of `Commands` which Iptablez implements. You're free to use the commands, just as the `Chains` interface would under the hood.
4
+
5
+ ## Method Overview
6
+ ```ruby
7
+ require 'iptablez'
8
+
9
+ Iptablez::Chains.all
10
+ Iptablez::Chains.defaults
11
+ Iptablez::Chains.create
12
+ Iptablez::Chains.rename
13
+ Iptablez::Chains.flush
14
+ Iptablez::Chains.delete
15
+ Iptablez::Chains.exists?
16
+ Iptablez::Chains.policies
17
+ Iptablez::Chains.policy?
18
+ Iptablez::Chains.user_defined
19
+ Iptablez::Chains.user_defined?
20
+ ```
21
+
22
+ ## All
23
+
24
+ Return a list of all the possible chains including defaults and user defined.
25
+
26
+ ```ruby
27
+ Iptablez::Chains.all
28
+ # => ["INPUT", "FORWARD", "OUTPUT", "cats", "dogs"]
29
+
30
+ Iptablez::Chains.all do |chain|
31
+ puts chain
32
+ end
33
+
34
+ Iptablez::Chains.all { |chain| puts chain }
35
+
36
+ Iptablez::Chains.all.each do |chain|
37
+ puts chain
38
+ end
39
+ ```
40
+
41
+ ## Defaults
42
+
43
+ Return a list of all the default chains.
44
+
45
+ ```ruby
46
+ Iptablez::Chains.defaults
47
+ # => ["INPUT", "FORWARD", "OUTPUT"]
48
+
49
+ Iptablez::Chains.defualts do |chain|
50
+ puts chain
51
+ end
52
+
53
+ Iptablez::Chains.defaults { |chain| puts chain }
54
+
55
+ Iptablez::Chains.defaults.each do |chain|
56
+ puts chain
57
+ end
58
+ ```
59
+
60
+ ## Delete
61
+
62
+ Delete a list of a given single `name` or an array of `names`. If the chain is not empty, the operation will fail. Consider flushing the chain(s) if you want to delete them.
63
+
64
+ ```ruby
65
+ Iptablez::Chains.delete(name: "frogs") # frogs is not a real chain
66
+ # => false
67
+
68
+ Iptablez::Chains.delete(name: "frogs") do |name, result|
69
+ if result # this will be false
70
+ puts "#{name} was deleted!"
71
+ else
72
+ puts "#{name} couldn't be deleted!"
73
+ end
74
+ end
75
+
76
+ Iptablez::Chains.delete(names: ["dogs", "cats"])
77
+ # => {"dogs"=>true, "cats"=>true}
78
+
79
+ Iptablez::Chains.delete(names: ["dogs", "cats"]) do |name, result|
80
+ puts name if result # won't happen, already deleted! :)
81
+ end
82
+ # => {"dogs"=>false, "cats"=>false}
83
+ ```
84
+
85
+ ## Exists?
86
+
87
+ Check if a list of a given single `name` or an array of `names` actually exists.
88
+
89
+ ```ruby
90
+ Iptablez::Chains.exists?(name: "frogs") # frogs is not a real chain
91
+ # => false
92
+
93
+ Iptablez::Chains.exists?(name: "frogs") do |name, result|
94
+ if result # this will be false
95
+ puts "#{name} exists!"
96
+ else
97
+ puts "#{name} doesn't exist!"
98
+ end
99
+ end
100
+
101
+ Iptablez::Chains.exists?(names: ["dogs", "cats"])
102
+ # => {"dogs"=>true, "cats"=>true}
103
+
104
+ Iptablez::Chains.exists?(names: ["dogs", "cats"]) do |name, result|
105
+ puts name if result # won't happen, already deleted! :)
106
+ end
107
+ # => {"dogs"=>false, "cats"=>false}
108
+ ```
109
+
110
+ ## Policies
111
+
112
+ Get a a list of a given single `name` or an array of `names` default policy response/target.
113
+
114
+ ```ruby
115
+ Iptablez::Chains.policies(name: "frogs") # frogs is not a real chain
116
+ # => false
117
+
118
+ Iptablez::Chains.exists?(name: "frogs") do |name, result|
119
+ if result # this will be false
120
+ puts "#{name} exists!"
121
+ else
122
+ puts "#{name} doesn't exist!"
123
+ end
124
+ end
125
+
126
+ Iptablez::Chains.exists?(names: ["dogs", "cats"])
127
+ # => {"dogs"=>true, "cats"=>true}
128
+
129
+ Iptablez::Chains.exists?(names: ["dogs", "cats"]) do |name, result|
130
+ puts name if result # won't happen, already deleted! :)
131
+ end
132
+ # => {"dogs"=>false, "cats"=>false}
133
+ ```
134
+
135
+
136
+
137
+
138
+
139
+
@@ -0,0 +1,227 @@
1
+ module Iptablez
2
+
3
+ module Chains
4
+
5
+ DEFAULT = ["INPUT", "FORWARD", "OUTPUT"]
6
+
7
+ # List all of the current chains found in +iptables+.
8
+ #
9
+ # @example Basic Usage
10
+ # Iptablez::Chains.all
11
+ # # => ["INPUT", "FORWARD", "OUTPUT"]
12
+ #
13
+ # @example Block Usage
14
+ # Iptablez::Chains.all do |chain|
15
+ # puts chain
16
+ # end
17
+ #
18
+ # @yield Each chain if a block is given.
19
+ # @return [Array<String>] An array of chain names.
20
+ def self.all
21
+ chains = Commands::List.full.find_all do |line|
22
+ line if line.split[0] == "Chain"
23
+ end.map(&:split).collect { |array| array[1] }
24
+ chains.each { |c| yield c } if block_given?
25
+ return chains
26
+ end
27
+
28
+ # List the default policies for default chains.
29
+ #
30
+ # @example Basic Usage
31
+ # Iptablez::Chains.policies
32
+ # # => {"INPUT"=>"ACCEPT", "FORWARD"=>"ACCEPT", "OUTPUT"=>"ACCEPT"}
33
+ #
34
+ # @example Block Usage
35
+ # Iptablez::Chains.policies do |name, policy|
36
+ # puts "#{name}: #{policy}"
37
+ # end
38
+ #
39
+ # @yield Each chain name and policy if a block is given.
40
+ # @return [Hash] Key value pairing of each chain and its default policy.
41
+ def self.policies(names: Iptablez::Chains.defaults, error: false, continue: !error)
42
+ Commands::List.defaults(names: names, continue: continue) do |result|
43
+ yield result if block_given?
44
+ end
45
+ end
46
+
47
+ # Check if there are any user defined chains, optionally
48
+ # giving a single name to check or an array of names.
49
+ #
50
+ # @example Basic Usage
51
+ # Iptablez::Chains.user_defined?
52
+ # # => false
53
+ # @example Basic Block Usage
54
+ # Iptablez::Chains.user_defined? do |result|
55
+ # if result
56
+ # puts "Found user defined chains."
57
+ # else
58
+ # puts "Did not find user defined chains."
59
+ # end
60
+ # end
61
+ # @example Check Single Name
62
+ # Iptablez::Chains.user_defined?(name: "dogs")
63
+ # # => false
64
+ # @example Check Single Name with a Block
65
+ # Iptablez::Chains.user_defined?(name: "dogs") do |result|
66
+ # result ? "User defined!" : "No user defined!"
67
+ # end
68
+ # @example Check Multiple Names
69
+ # Iptablez::Chains.user_defined?(names: ["dogs", "frogs"])
70
+ # # => {"dogs"=>false, "frogs"=>false}
71
+ # @example Check Multiple Names with a Block
72
+ # Iptablez::Chains.user_defined?(names: ["dogs", "frogs"]) do |name, result|
73
+ # phrase = if result
74
+ # "is"
75
+ # else
76
+ # "is not"
77
+ # end
78
+ # puts "#{name} #{phrase} user defined."
79
+ # end
80
+ # @param name [String] Single name.
81
+ # @param names [Array<String>] Multiple names.
82
+ #
83
+ # @yield results if a block is given.
84
+ # @return [Hash] key value pairing of each chain and the result of the check.
85
+ def self.user_defined?(name: false, names: [])
86
+ if name && names.empty?
87
+ r = user_defined.include?(name)
88
+ return r unless block_given?
89
+ yield r
90
+ elsif names[0] && ! name
91
+ r = {}
92
+ names.each do |n|
93
+ r.clear if block_given?
94
+ r[n] = user_defined.include?(n)
95
+ yield r.flatten if block_given?
96
+ end
97
+ return r unless block_given?
98
+ elsif names[0] && name
99
+ raise "Cannot use both a single name and multiple names together."
100
+ else
101
+ all.count > 3 ? true : false
102
+ end
103
+ end
104
+
105
+ # List all of the user_defined chains.
106
+ #
107
+ # @yield Each name of the user defined chains if a block if given.
108
+ # @return [Array<String>] Easy user defined chain as an array.
109
+ def self.user_defined
110
+ user_defined_chains = all.find_all { |c| c unless DEFAULT.include?(c) }
111
+ return user_defined_chains unless block_given?
112
+ user_defined_chains.each { |c| yield c }
113
+ end
114
+
115
+ # Check if a chain exists by a given name.
116
+ # @todo Fix documentation.
117
+ # @param name [String] Single name.
118
+ # @param names [Array<String>] Multiple names.
119
+ # @return [Boolean] Easy user defined chain as an array.
120
+ def self.exists?(name: false, names: [])
121
+ if name
122
+ all do |chain|
123
+ if chain == name
124
+ yield [name, true] if block_given?
125
+ return true
126
+ end
127
+ end
128
+ elsif !names.empty?
129
+ results = {}
130
+ names.each do |name|
131
+ results[name] = false
132
+ all { |chain| results[name] = true if chain == name }
133
+ yield [name, results[name]] if block_given?
134
+ end
135
+ results
136
+ end
137
+ end
138
+
139
+ def self.defaults
140
+ return DEFAULT unless block_given?
141
+ DEFAULT.each { |c| yield c }
142
+ end
143
+
144
+ def self.policy?(name:, policy:, names: [])
145
+ if name && names.empty?
146
+ r = if policies[name] == policy
147
+ true
148
+ else
149
+ false
150
+ end
151
+ return r unless block_given?
152
+ yield r
153
+ elsif names[0] && ! name && policy
154
+ r = {}
155
+ names.each do |n|
156
+ begin
157
+ r[n] = if policies[name] == policy
158
+ true
159
+ else
160
+ false
161
+ end
162
+ yield r[n] if block_given?
163
+ rescue => e
164
+ raise e
165
+ end
166
+ end
167
+ return r unless block_given?
168
+ elsif name && names[0]
169
+ raise "Cannot use both a single name and multiple names together."
170
+ end
171
+ end
172
+
173
+ def self.create(name: false, names: [], error: false, continue: !error)
174
+ if name
175
+ Commands::NewChain.chain(name: name, continue: continue) do |result|
176
+ yield result if block_given?
177
+ end
178
+ elsif !names.empty?
179
+ Commands::NewChain.chains(names: names, continue: continue) do |result|
180
+ yield result if block_given?
181
+ end
182
+ end
183
+ end
184
+
185
+ def self.delete(name: false, names: [], error: false, continue: !error)
186
+ if name
187
+ Commands::DeleteChain.chain(name: name, continue: continue) do |result|
188
+ yield result if block_given?
189
+ end
190
+ elsif !names.empty?
191
+ Commands::DeleteChain.chains(names: names, continue: continue) do |result|
192
+ yield result if block_given?
193
+ end
194
+ end
195
+ end
196
+
197
+ def self.flush(name: false, names: [], error: false, continue: !error)
198
+ if name
199
+ Commands::FlushChain.chain(name: name, continue: continue) do |result|
200
+ yield result if block_given?
201
+ end
202
+ elsif !names.empty?
203
+ Commands::FlushChain.chains(names: names, continue: continue) do |result|
204
+ yield result if block_given?
205
+ end
206
+ end
207
+ end
208
+
209
+ def self.rename(from: false, to: false, pairs: {}, error: false, continue: !error)
210
+ if from && to
211
+ Commands::RenameChain.chain(from: from, to: to, continue: continue) do |result|
212
+ yield result if block_given?
213
+ end
214
+ elsif (!from && to) or (from && !to)
215
+ return false if continue
216
+ raise ArgumentError, "Cannot use from: without to:"
217
+ elsif !pairs.empty?
218
+ Commands::RenameChain.chains(pairs: pairs, continue: continue) do |result|
219
+ yield result if block_given?
220
+ end
221
+ end
222
+ end
223
+
224
+
225
+ end
226
+
227
+ end
@@ -0,0 +1,62 @@
1
+ module Iptablez
2
+ module Commands
3
+ # The namespace to describe the `iptables` `-X` argument to delete a chain.
4
+ # @author Kent 'picat' Gruber
5
+ module AppendChain
6
+ # Move on Module
7
+ include MoveOn
8
+ include ArgumentHelpers
9
+
10
+ NO_CHAIN_MATCH_ERROR = 'iptables: No chain/target/match by that name.'.freeze
11
+ KNOWN_ERRORS = [NO_CHAIN_MATCH_ERROR].freeze
12
+
13
+ # @api private
14
+ # Determine a given error. Optionally a chain can be used to provide better context.
15
+ private_class_method def self.determine_error(error:, chain: false)
16
+ if error == NO_CHAIN_MATCH_ERROR
17
+ raise ChainExistenceError, "#{chain} doesn't exist!"
18
+ elsif
19
+ raise ChainNotEmpty, "#{chain} is not empty! Will probably need to flush (-F) it to delete it!"
20
+ else
21
+ raise error
22
+ end
23
+ end
24
+
25
+ # Delete a chain of a given +name+. This is the heart of this module.
26
+ # @param name [String] Single chain +name+.
27
+ # @param error [Boolean] Determine if operations should raise/halt other possible operations with errors.
28
+ # @param continue [Boolean] Determine if operations should continue despite errors.
29
+ #
30
+ # @example Basic Usage
31
+ # Iptablez::Commands::AppendChain.chain(name: "dogs")
32
+ # # => true
33
+ # Iptablez::Commands::List.chain(name: "kittens")
34
+ # # => ["all -- anywhere anywhere"]
35
+ #
36
+ # @yield [String, Boolean] The +name+ of the chain and +result+ of the operation if a block if given.
37
+ # @return [Boolean] The result of the operation.
38
+ #
39
+ # @raise An error will be raised if the +error+ or +continue+ keywords are +true+ and the operation fails.
40
+ def self.chain(name:, error: false, continue: !error, **args)
41
+ name = name.to_s unless name.is_a? String
42
+ name = name.shellescape
43
+ first_arguments = [Iptablez.bin_path, '-A', name]
44
+ args = ArgumentHelpers.normalize_arguments(args).values.map(&:split).flatten # fucking crazy shit here
45
+ cmd = first_arguments + args
46
+ _, e, s = Open3.capture3(cmd.join(" "))
47
+ #_, e, s = Open3.capture3(Iptablez.bin_path, '-A', name, args.values.map(&:split).flatten)
48
+ e.strip! # remove new line
49
+ if s.success?
50
+ yield [name, true] if block_given?
51
+ return true
52
+ elsif MoveOn.continue?(continue: continue, message: e, known_errors: KNOWN_ERRORS)
53
+ yield [name, false] if block_given?
54
+ return false
55
+ else
56
+ determine_error(chain: name, error: e)
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end