iptables-web 0.3.5.pre3 → 0.3.5.pre4
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/README.md +4 -15
- data/lib/iptables_web/cli/command/install.rb +12 -29
- data/lib/iptables_web/cli/command/update.rb +15 -16
- data/lib/iptables_web/cli/import.rb +1 -1
- data/lib/iptables_web/cli/logged_output.rb +20 -11
- data/lib/iptables_web/cli/multi_io.rb +22 -0
- data/lib/iptables_web/cli/pid_file.rb +3 -3
- data/lib/iptables_web/cli.rb +11 -2
- data/lib/iptables_web/configuration.rb +38 -50
- data/lib/iptables_web/iptables.rb +81 -37
- data/lib/iptables_web/mixin/config_parser.rb +22 -0
- data/lib/iptables_web/model/access_rule.rb +8 -16
- data/lib/iptables_web/model/node.rb +2 -3
- data/lib/iptables_web/version.rb +1 -1
- data/lib/iptables_web.rb +4 -1
- metadata +52 -34
- checksums.yaml +0 -7
data/README.md
CHANGED
@@ -4,22 +4,11 @@ TODO: Write a gem description
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
gem 'iptables-web'
|
10
|
-
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
14
|
-
|
15
|
-
Or install it yourself as:
|
16
|
-
|
17
|
-
$ gem install iptables-web
|
18
|
-
|
19
|
-
## Usage
|
20
|
-
|
21
|
-
TODO: Write usage instructions here
|
7
|
+
Recommended installation on the server (system wide):
|
22
8
|
|
9
|
+
sudo /usr/local/ruby/1.9.3/bin/gem install iptables-web
|
10
|
+
sudo ln -sf /usr/local/ruby/1.9.3/bin/iptables-web /usr/local/bin/iptables-web
|
11
|
+
|
23
12
|
## Contributing
|
24
13
|
|
25
14
|
1. Fork it ( https://github.com/[my-github-username]/iptables-web/fork )
|
@@ -3,28 +3,33 @@ module IptablesWeb
|
|
3
3
|
module Command
|
4
4
|
module Install
|
5
5
|
def install_command
|
6
|
+
command :crontab do |c|
|
7
|
+
|
8
|
+
end
|
9
|
+
|
6
10
|
command :install do |c|
|
7
11
|
c.syntax = 'iptables-web install'
|
8
12
|
c.description = 'Displays foo'
|
9
13
|
c.option '--force', 'Force config '
|
10
14
|
c.action do |args, options|
|
15
|
+
# TODO: Should be refactored
|
11
16
|
config = IptablesWeb::Configuration.new
|
12
17
|
api_url = ask('Api base url: ') { |q| q.default = config['api_base_url'] }
|
13
18
|
token = ask('Access token: ') { |q| q.default = config['access_token'] }
|
14
19
|
update_period = ask('Update every [min]', Integer) { |q| q.default = 1; q.in = 0..59 }
|
15
|
-
|
20
|
+
config_path = IptablesWeb.config_path
|
21
|
+
config_dir = File.dirname(IptablesWeb.config_path)
|
16
22
|
unless File.exist?(config_dir)
|
17
23
|
say "Create config directory: #{config_dir}"
|
18
|
-
Dir.mkdir(config_dir)
|
24
|
+
Dir.mkdir(File.dirname(config_dir))
|
19
25
|
end
|
20
|
-
|
21
|
-
|
22
|
-
File.write config_file, <<CONFIG
|
26
|
+
say "Write config to #{config_path}"
|
27
|
+
File.write config_path, <<CONFIG
|
23
28
|
api_base_url: #{api_url}
|
24
29
|
access_token: #{token}
|
25
30
|
CONFIG
|
26
31
|
if system("LANG=C bash -l -c \"type rvm | cat | head -1 | grep -q '^rvm is a function$'\"")
|
27
|
-
wrapper =
|
32
|
+
wrapper = 'rvm system do iptables-web'
|
28
33
|
else
|
29
34
|
wrapper = 'iptables-web'
|
30
35
|
end
|
@@ -33,7 +38,7 @@ CONFIG
|
|
33
38
|
say "Write file #{cron_file}"
|
34
39
|
File.write cron_file, <<CONFIG
|
35
40
|
#/bin/env ruby
|
36
|
-
#{wrapper}
|
41
|
+
#{wrapper}
|
37
42
|
CONFIG
|
38
43
|
File.chmod(0700, cron_file)
|
39
44
|
say "Add cronjob #{cron_file}"
|
@@ -42,28 +47,6 @@ CONFIG
|
|
42
47
|
jobs.reject! { |job| job.include?('.iptables-web') }
|
43
48
|
jobs << "*/#{update_period} * * * * #{File.join(ENV['HOME'], '.iptables-web', 'cron.sh')}"
|
44
49
|
crontab.save(jobs)
|
45
|
-
|
46
|
-
static_rules = File.join(config_dir, 'static_rules')
|
47
|
-
|
48
|
-
say "Create file for static rules #{static_rules}"
|
49
|
-
say "* * * * * * * * * * * * * * * * * * * * * * * *\n"
|
50
|
-
say "* You can write predefined rules to this file.\n"
|
51
|
-
say "* This file will be concat with rules \n"
|
52
|
-
say "* See 'iptables-save' format.\n"
|
53
|
-
say "* * * * * * * * * * * * * * * * * * * * * * * * \n"
|
54
|
-
|
55
|
-
if File.exist?(static_rules) && !options.force
|
56
|
-
say 'File already exist!'
|
57
|
-
else
|
58
|
-
File.write static_rules, <<STATIC_RULES
|
59
|
-
*filter
|
60
|
-
-A INPUT -i lo -j ACCEPT
|
61
|
-
-A FORWARD -i lo -j ACCEPT
|
62
|
-
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
63
|
-
-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
|
64
|
-
COMMIT
|
65
|
-
STATIC_RULES
|
66
|
-
end
|
67
50
|
end
|
68
51
|
end
|
69
52
|
end
|
@@ -8,34 +8,33 @@ module IptablesWeb
|
|
8
8
|
c.syntax = 'iptables-web update'
|
9
9
|
c.description = 'Display bar with optional prefix and suffix'
|
10
10
|
c.option '--config STRING', String, 'Path to config file'
|
11
|
-
c.option '--print', '
|
11
|
+
c.option '--print', 'Just print rules'
|
12
12
|
c.option '--force', 'Set rules omit checksum check'
|
13
|
-
c.option '--dry-run', 'Skip handshake'
|
13
|
+
c.option '--dry-run', 'Skip handshake and update'
|
14
14
|
c.action do |_, options|
|
15
15
|
begin
|
16
16
|
IptablesWeb.configuration.load(options.config) if options.config
|
17
|
-
|
17
|
+
logger_log "Use iptables server #{IptablesWeb.api_base_url}"
|
18
18
|
IptablesWeb.pid_file do
|
19
19
|
IptablesWeb::Model::Node.handshake(options.dry_run || options.print) do
|
20
20
|
rules = IptablesWeb::Model::AccessRule.all
|
21
21
|
iptables = IptablesWeb::Iptables.new
|
22
22
|
request_etag = rules.response.headers[:etag].first
|
23
23
|
if options.print
|
24
|
-
logged_say 'Run client in print mode'
|
25
|
-
logged_say 'Nothing changed.' if IptablesWeb.checksum?(request_etag)
|
26
|
-
logged_say "Previous checksum #{IptablesWeb.checksum}"
|
27
|
-
logged_say "Current checksum #{IptablesWeb.make_checksum(request_etag)}"
|
28
24
|
say iptables.render(rules)
|
29
25
|
else
|
30
|
-
|
31
|
-
|
26
|
+
logger_log 'Run client in DRY-RUN mode' if options.dry_run
|
27
|
+
logger_log("Etag value: #{request_etag.inspect}", ::Logger::DEBUG)
|
32
28
|
if IptablesWeb.checksum?(request_etag) && !options.force
|
33
|
-
|
29
|
+
logger_log '**** Nothing changed ****'
|
34
30
|
else
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
iptables.
|
31
|
+
logger_log '*** Iptables updated! ***'
|
32
|
+
if options.dry_run
|
33
|
+
logger_log('New rules:', ::Logger::INFO)
|
34
|
+
logger_log(iptables.render(rules), ::Logger::INFO)
|
35
|
+
else
|
36
|
+
iptables.update(rules)
|
37
|
+
logger_log(iptables.diff, ::Logger::DEBUG)
|
39
38
|
IptablesWeb.checksum = request_etag
|
40
39
|
end
|
41
40
|
end
|
@@ -43,8 +42,8 @@ module IptablesWeb
|
|
43
42
|
end
|
44
43
|
end
|
45
44
|
rescue Exception => e
|
46
|
-
|
47
|
-
|
45
|
+
logger_log(e.message)
|
46
|
+
logger_log(e.backtrace.join("\n"))
|
48
47
|
end
|
49
48
|
end
|
50
49
|
end
|
@@ -4,5 +4,5 @@ require 'forwardable'
|
|
4
4
|
$terminal = IptablesWeb::Cli::LoggedOutput.new
|
5
5
|
module Kernel
|
6
6
|
extend Forwardable
|
7
|
-
def_delegators :$terminal, :agree, :ask, :choose, :say, :
|
7
|
+
def_delegators :$terminal, :agree, :ask, :choose, :say, :logger_log, :logger_log
|
8
8
|
end
|
@@ -14,29 +14,38 @@ module IptablesWeb
|
|
14
14
|
def logger
|
15
15
|
@logger ||= begin
|
16
16
|
logfile = IptablesWeb::log_path
|
17
|
-
|
18
|
-
|
19
|
-
log_level = log_level.to_i
|
20
|
-
say("Open log file #{logfile}")
|
21
|
-
logger =::Logger.new(logfile)
|
22
|
-
logger.level = log_level.to_i
|
17
|
+
@log_io = MultiIO.new(File.open(logfile, 'a'))
|
18
|
+
logger =::Logger.new(@log_io)
|
23
19
|
logger.formatter = ::Logger::Formatter.new
|
24
20
|
logger
|
25
21
|
end
|
26
22
|
end
|
27
23
|
|
24
|
+
def log_stdout
|
25
|
+
@log_io.add(STDOUT)
|
26
|
+
end
|
27
|
+
|
28
|
+
def log_level=(log_level)
|
29
|
+
log_level = LOG_LEVEL_MAP[log_level] if LOG_LEVEL_MAP[log_level]
|
30
|
+
logger.level = log_level.to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
def log_level
|
34
|
+
logger.level
|
35
|
+
end
|
36
|
+
|
28
37
|
def reset
|
29
38
|
@logger = nil
|
30
39
|
end
|
31
40
|
|
32
41
|
def logger_log(message, log_level = Logger::INFO)
|
33
|
-
logger.log(log_level, message) if logger
|
42
|
+
logger.log(log_level, message.to_s.strip) if logger
|
34
43
|
end
|
35
44
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
end
|
45
|
+
# def logger_log(message, log_level = Logger::INFO)
|
46
|
+
# logger_log(message, log_level)
|
47
|
+
# say(message)
|
48
|
+
# end
|
40
49
|
end
|
41
50
|
end
|
42
51
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module IptablesWeb
|
2
|
+
class Cli
|
3
|
+
class MultiIO
|
4
|
+
def initialize(*targets)
|
5
|
+
@targets = targets
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(target)
|
9
|
+
@targets << target
|
10
|
+
end
|
11
|
+
|
12
|
+
def write(*args)
|
13
|
+
@targets.each { |t| t.write(*args) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def close
|
17
|
+
@targets.each(&:close)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -8,8 +8,8 @@ module IptablesWeb
|
|
8
8
|
|
9
9
|
def create
|
10
10
|
raise AnotherLaunched.new("Another process with #{pid} already launched!") if another_exist?
|
11
|
-
|
12
|
-
|
11
|
+
logger_log("Create pidfile #{self} for pid #{Process.pid}")
|
12
|
+
logger_log("Grab pidfile #{self} for pid #{Process.pid} due process #{pid} is down.") if other?
|
13
13
|
File.open(@pidfile, 'w') do |file|
|
14
14
|
file.write(Process.pid)
|
15
15
|
end
|
@@ -18,7 +18,7 @@ module IptablesWeb
|
|
18
18
|
|
19
19
|
def delete
|
20
20
|
raise AnotherLaunched.new("Delete error. Another process with #{pid} already launched!") if another_exist?
|
21
|
-
|
21
|
+
logger_log("Delete pidfile #{self} for pid #{pid}")
|
22
22
|
File.unlink(@pidfile) if exist?
|
23
23
|
end
|
24
24
|
|
data/lib/iptables_web/cli.rb
CHANGED
@@ -18,14 +18,23 @@ module IptablesWeb
|
|
18
18
|
IptablesWeb.reload
|
19
19
|
end
|
20
20
|
|
21
|
-
global_option('--
|
21
|
+
global_option('--verbose', 'Combination of --log-level debug and --log-stdout') do |_|
|
22
|
+
IptablesWeb.log_level = ::Logger::INFO
|
23
|
+
IptablesWeb.log_stdout
|
24
|
+
end
|
25
|
+
|
26
|
+
global_option('--log-file FILE', 'Log file path') do |log_path|
|
22
27
|
IptablesWeb.log_path = log_path
|
23
28
|
end
|
24
29
|
|
25
|
-
global_option('--
|
30
|
+
global_option('--log-level LEVEL', 'Log level') do |log_level|
|
26
31
|
IptablesWeb.log_level = log_level
|
27
32
|
end
|
28
33
|
|
34
|
+
global_option('--log-stdout', 'Write log to stdout too') do |log_level|
|
35
|
+
IptablesWeb.log_stdout = log_level
|
36
|
+
end
|
37
|
+
|
29
38
|
global_option('--host URL', 'Server base url') do |server_base_url|
|
30
39
|
IptablesWeb.api_base_url = server_base_url
|
31
40
|
end
|
@@ -1,30 +1,33 @@
|
|
1
1
|
require 'yaml'
|
2
|
+
require 'fileutils'
|
2
3
|
module IptablesWeb
|
3
4
|
module Configuration
|
5
|
+
include IptablesWeb::Mixin::ConfigParser
|
6
|
+
|
4
7
|
def reload
|
5
8
|
if File.exists?(config_path)
|
6
|
-
|
9
|
+
logger_log("Load config file #{config_path}")
|
7
10
|
YAML.load_file(config_path).each do |method, value|
|
8
11
|
send("#{method}=".to_sym, value)
|
9
12
|
end
|
10
13
|
else
|
11
|
-
|
14
|
+
logger_log("Config file #{config_path} does not exist")
|
12
15
|
end
|
13
16
|
end
|
14
17
|
|
15
18
|
def static_rules
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
else
|
26
|
-
{ 'filter' => rules.split("\n") }
|
19
|
+
unless static_rules?
|
20
|
+
return {
|
21
|
+
'filter' => [
|
22
|
+
'-A INPUT -i lo -j ACCEPT',
|
23
|
+
'-A FORWARD -i lo -j ACCEPT',
|
24
|
+
'-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT',
|
25
|
+
'-A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT'
|
26
|
+
]
|
27
|
+
}
|
27
28
|
end
|
29
|
+
rules = File.read(static_rules_path)
|
30
|
+
parse_rules(rules)
|
28
31
|
end
|
29
32
|
|
30
33
|
def static_rules?
|
@@ -39,35 +42,28 @@ module IptablesWeb
|
|
39
42
|
@home = home
|
40
43
|
end
|
41
44
|
|
42
|
-
def
|
43
|
-
@
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
File.expand_path(File.join(home, '.iptables-web'))
|
48
|
-
end
|
45
|
+
def work_dir
|
46
|
+
@work_dir ||= begin
|
47
|
+
work_dir = '/tmp/iptables-web'
|
48
|
+
FileUtils.mkdir_p(work_dir) unless File.exist?(work_dir)
|
49
|
+
work_dir
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
|
-
def
|
53
|
-
@
|
53
|
+
def work_dir=(d)
|
54
|
+
@work_dir = d
|
54
55
|
end
|
55
56
|
|
56
|
-
def
|
57
|
-
File.expand_path(path,
|
57
|
+
def work_path(path)
|
58
|
+
File.expand_path(path, work_dir)
|
58
59
|
end
|
59
60
|
|
60
61
|
def root?
|
61
62
|
Process::UID.eid == 0
|
62
63
|
end
|
63
64
|
|
64
|
-
#
|
65
65
|
def config_path
|
66
|
-
|
67
|
-
'/etc/iptables_web/config.yml'
|
68
|
-
else
|
69
|
-
path(@config_path || 'config.yml')
|
70
|
-
end
|
66
|
+
@config_path || '/etc/iptables-web/config.yml'
|
71
67
|
end
|
72
68
|
|
73
69
|
def config_path=(config_path)
|
@@ -76,7 +72,7 @@ module IptablesWeb
|
|
76
72
|
|
77
73
|
#
|
78
74
|
def pid_path
|
79
|
-
|
75
|
+
work_path(@pid_path || 'run.pid')
|
80
76
|
end
|
81
77
|
|
82
78
|
def pid_path=(pid_path)
|
@@ -85,29 +81,28 @@ module IptablesWeb
|
|
85
81
|
|
86
82
|
#
|
87
83
|
def log_path
|
88
|
-
|
89
|
-
'/var/log/iptables-web.log'
|
90
|
-
else
|
91
|
-
path(@log_path || 'run.log')
|
92
|
-
end
|
84
|
+
@log_path || '/var/log/iptables-web/run.log'
|
93
85
|
end
|
94
86
|
|
95
87
|
def log_path=(pid_path)
|
96
88
|
@log_path = pid_path
|
97
|
-
$terminal.reset if $terminal.present?
|
89
|
+
$terminal.reset if $terminal.present?
|
98
90
|
end
|
99
91
|
|
100
92
|
def log_level=(level)
|
101
|
-
|
102
|
-
|
93
|
+
$terminal.log_level = level if $terminal.present?
|
94
|
+
end
|
95
|
+
|
96
|
+
def log_stdout
|
97
|
+
$terminal.log_stdout if $terminal.present?
|
103
98
|
end
|
104
99
|
|
105
100
|
def log_level
|
106
|
-
|
101
|
+
$terminal.present? ? $terminal.log_level : ::Logger::INFO
|
107
102
|
end
|
108
103
|
|
109
104
|
def checksum_path
|
110
|
-
|
105
|
+
work_path(@checksum_path || 'checksum')
|
111
106
|
end
|
112
107
|
|
113
108
|
def checksum
|
@@ -133,20 +128,14 @@ module IptablesWeb
|
|
133
128
|
Digest::MD5.hexdigest(check_sum)
|
134
129
|
end
|
135
130
|
|
136
|
-
#
|
137
131
|
def static_rules_path
|
138
|
-
|
139
|
-
'/etc/iptables_web/static_rules'
|
140
|
-
else
|
141
|
-
path(@static_rules_path || 'static_rules')
|
142
|
-
end
|
132
|
+
@static_rules_path || File.expand_path('static_rules', File.dirname(config_path))
|
143
133
|
end
|
144
134
|
|
145
135
|
def static_rules_path=(static_rules_path)
|
146
136
|
@static_rules_path = static_rules_path
|
147
137
|
end
|
148
138
|
|
149
|
-
#
|
150
139
|
def api_base_url
|
151
140
|
# raise 'api_base_url is required' unless @api_base_url
|
152
141
|
@api_base_url
|
@@ -174,9 +163,8 @@ module IptablesWeb
|
|
174
163
|
block.call(pid_file)
|
175
164
|
pid_file.delete
|
176
165
|
rescue Cli::PidFile::AnotherLaunched => e
|
177
|
-
|
178
166
|
pid_file.delete
|
179
|
-
|
167
|
+
logger_log(e.message)
|
180
168
|
return
|
181
169
|
rescue Exception => e
|
182
170
|
pid_file.delete
|
@@ -1,63 +1,107 @@
|
|
1
1
|
require 'tempfile'
|
2
2
|
module IptablesWeb
|
3
3
|
class Iptables
|
4
|
+
LABEL = '[iptables-web]'
|
5
|
+
|
6
|
+
IPTABLES_COMMAND = 'iptables'
|
7
|
+
IPTABLES_SAVE_COMMAND = 'iptables-save'
|
8
|
+
IPTABLES_RESTORE_COMMAND = 'iptables-restore'
|
9
|
+
|
4
10
|
include IptablesWeb::Mixin::Sudo
|
11
|
+
include IptablesWeb::Mixin::ConfigParser
|
5
12
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
return
|
11
|
-
end
|
13
|
+
def update(access_rules)
|
14
|
+
bash_file = Tempfile.new('rules')
|
15
|
+
bash_file.write "#!/bin/bash\n"
|
16
|
+
bash_file.write "set -e\n"
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
+
lines = combine_new_rules(access_rules)
|
19
|
+
current_rules = parse_rules(execute('iptables-save'))
|
20
|
+
# set default policy to ACCEPT
|
21
|
+
bash_file.write "#{IPTABLES_COMMAND} -P INPUT ACCEPT\n"
|
22
|
+
current_rules.each do |table, rules|
|
23
|
+
rules.each do |rule|
|
24
|
+
next unless rule.include?(LABEL)
|
25
|
+
bash_file.write("#{IPTABLES_COMMAND} -t #{table} #{rule.gsub('-A', '-D')}")
|
26
|
+
bash_file.write("\n")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
bash_file.write "# Create rules\n"
|
30
|
+
bash_file.write lines.join("\n")
|
31
|
+
bash_file.write "\n"
|
32
|
+
# Close only if rules exist
|
33
|
+
if lines.size > 0
|
34
|
+
bash_file.write "#{IPTABLES_COMMAND} -P INPUT DROP\n"
|
35
|
+
end
|
36
|
+
bash_file.rewind
|
37
|
+
backup
|
38
|
+
res = execute("bash #{bash_file.path}")
|
39
|
+
unless $? == 0
|
40
|
+
logger_log('Failed to import settings. Restore previous configuration. See log for more details.', ::Logger::ERROR)
|
41
|
+
logger_log(res, ::Logger::ERROR)
|
42
|
+
restore
|
43
|
+
end
|
18
44
|
ensure
|
19
|
-
if
|
20
|
-
|
21
|
-
|
45
|
+
if bash_file
|
46
|
+
bash_file.close
|
47
|
+
bash_file.unlink
|
22
48
|
end
|
23
49
|
end
|
24
50
|
|
25
51
|
def save
|
26
|
-
execute(
|
52
|
+
execute(IPTABLES_SAVE_COMMAND).split("\n")
|
27
53
|
end
|
28
54
|
|
29
55
|
def static_rules
|
30
56
|
IptablesWeb.static_rules
|
31
57
|
end
|
32
58
|
|
33
|
-
def
|
34
|
-
|
35
|
-
static_filter =
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
if filter_rules.size > 0
|
43
|
-
lines << '*filter'
|
44
|
-
lines << ':INPUT DROP [0:0]'
|
45
|
-
lines << ':FORWARD ACCEPT [0:0]'
|
46
|
-
lines << ':OUTPUT ACCEPT [0:0]'
|
47
|
-
lines = lines | filter_rules
|
48
|
-
lines << "COMMIT\n"
|
59
|
+
def combine_new_rules(rules)
|
60
|
+
all_rules = self.static_rules
|
61
|
+
static_filter = all_rules.delete('filter')
|
62
|
+
all_rules['filter'] = Array(static_filter) | Array(rules).map(&:make).flatten
|
63
|
+
all_rules.each_with_object([]) do |(table, sub_rules), arr|
|
64
|
+
sub_rules.reject! { |s| s.strip.empty? }
|
65
|
+
sub_rules.each do |rule|
|
66
|
+
arr << "#{IPTABLES_COMMAND} -t #{table} #{add_label(rule)}"
|
67
|
+
end
|
49
68
|
end
|
69
|
+
end
|
50
70
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
71
|
+
def add_label(rule)
|
72
|
+
m = rule.match("^(.*?--comment)(\s+)\"(.*?)\"(.*?)$")
|
73
|
+
if m
|
74
|
+
return rule if m[3].include?(LABEL)
|
75
|
+
comment = "#{LABEL} #{m[3]}"
|
76
|
+
"#{m[1]} \"#{comment.strip}\"#{m[4]}"
|
77
|
+
else
|
78
|
+
"#{rule} -m comment --comment \"#{LABEL}\""
|
55
79
|
end
|
56
|
-
lines
|
57
80
|
end
|
58
81
|
|
59
82
|
def render(rules)
|
60
|
-
|
83
|
+
combine_new_rules(rules).join("\n")
|
84
|
+
end
|
85
|
+
|
86
|
+
def diff
|
87
|
+
if @backup
|
88
|
+
@after = Tempfile.new('iptables-after')
|
89
|
+
execute("iptables-save > #{@after.path}")
|
90
|
+
execute("diff -c #{@backup.path} #{@after.path}")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def backup
|
95
|
+
@backup ||= Tempfile.new('iptables-before')
|
96
|
+
logger_log("Create backup #{@backup.path}\n", ::Logger::DEBUG)
|
97
|
+
execute("iptables-save > #{@backup.path}")
|
98
|
+
@backup.rewind
|
99
|
+
end
|
100
|
+
|
101
|
+
def restore
|
102
|
+
if @backup && File.exist?(@backup.path)
|
103
|
+
execute("/sbin/iptables-restore -c #{@backup.path}")
|
104
|
+
end
|
61
105
|
end
|
62
106
|
end
|
63
107
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module IptablesWeb
|
2
|
+
module Mixin
|
3
|
+
module ConfigParser
|
4
|
+
def parse_rules(rules)
|
5
|
+
chains = rules.scan(/\*(filter|nat|mangle)(.*?)COMMIT/m)
|
6
|
+
if chains && chains.size > 0
|
7
|
+
chains.each_with_object({}) do |r, obj|
|
8
|
+
chain = r[0]
|
9
|
+
obj[chain] ||= []
|
10
|
+
obj[chain] = obj[chain] + reject_comments(r[1].split("\n"))
|
11
|
+
end
|
12
|
+
else
|
13
|
+
{ 'filter' => reject_comments(rules.split("\n")) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def reject_comments(rules)
|
18
|
+
rules.reject { |l| l[0]=='#' }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,19 +3,18 @@ module IptablesWeb
|
|
3
3
|
module Model
|
4
4
|
class AccessRule < Base
|
5
5
|
self.element_name = 'access_rule'
|
6
|
-
|
7
6
|
SUPPORTED_PROTOCOLS = %w(tcp udp)
|
8
7
|
|
9
|
-
def
|
10
|
-
protocols = protocol.to_s.downcase
|
8
|
+
def make
|
9
|
+
protocols = protocol.to_s.downcase == 'all' ? SUPPORTED_PROTOCOLS : [protocol]
|
11
10
|
protocols.map do |protocol|
|
12
11
|
self.resolved_ips.map do |ip|
|
13
12
|
command = %w(-A INPUT)
|
14
13
|
self.attributes.each do |name, value|
|
15
14
|
case name.to_sym
|
16
15
|
when :port
|
17
|
-
next if
|
18
|
-
if value.
|
16
|
+
next if value.to_s.empty? || !value
|
17
|
+
if value.match(/(:|,)/)
|
19
18
|
command << '-m'
|
20
19
|
command << 'multiport'
|
21
20
|
command << '--dports'
|
@@ -24,20 +23,18 @@ module IptablesWeb
|
|
24
23
|
command << '--dport'
|
25
24
|
command << value
|
26
25
|
end
|
27
|
-
# when :ip
|
28
|
-
# command << '-s'
|
29
|
-
# command << value
|
30
26
|
when :protocol
|
31
27
|
next unless protocol
|
32
28
|
command << '-p'
|
33
29
|
command << protocol
|
34
30
|
when :description
|
35
|
-
if value
|
31
|
+
if value && !value.empty?
|
36
32
|
command << '-m'
|
37
33
|
command << 'comment'
|
38
34
|
command << '--comment'
|
39
|
-
command <<
|
35
|
+
command << "\"#{description.strip.gsub('"', '\"')}\""
|
40
36
|
end
|
37
|
+
|
41
38
|
else
|
42
39
|
#skip
|
43
40
|
end
|
@@ -48,12 +45,7 @@ module IptablesWeb
|
|
48
45
|
command << 'ACCEPT'
|
49
46
|
command.join(' ')
|
50
47
|
end
|
51
|
-
end
|
52
|
-
# -A INPUT -s 88.150.233.48/29 -p tcp -m tcp --dport 9200 -j ACCEPT
|
53
|
-
end
|
54
|
-
|
55
|
-
def mapping(parameter)
|
56
|
-
|
48
|
+
end
|
57
49
|
end
|
58
50
|
end
|
59
51
|
end
|
@@ -17,7 +17,6 @@ module IptablesWeb
|
|
17
17
|
raise e
|
18
18
|
ensure
|
19
19
|
return if dry_run
|
20
|
-
puts ''
|
21
20
|
# save node after updating
|
22
21
|
node.ips = []
|
23
22
|
::System.get_ifaddrs.each do |interface, config|
|
@@ -28,10 +27,10 @@ module IptablesWeb
|
|
28
27
|
netmask: config[:netmask]
|
29
28
|
})
|
30
29
|
end
|
31
|
-
|
30
|
+
logger_log('*** Found interfaces!!! ***', ::Logger::DEBUG)
|
32
31
|
logger_log(node.ips.inspect, ::Logger::DEBUG)
|
33
32
|
node.ips.uniq! { |ip| ip[:ip] }
|
34
|
-
|
33
|
+
logger_log('*** Unique interfaces!!! ***', ::Logger::DEBUG)
|
35
34
|
logger_log(node.ips.inspect, ::Logger::DEBUG)
|
36
35
|
node.hostname = `hostname -f`
|
37
36
|
node.save
|
data/lib/iptables_web/version.rb
CHANGED
data/lib/iptables_web.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
|
2
2
|
require 'iptables_web/version'
|
3
|
+
require 'iptables_web/mixin/sudo'
|
4
|
+
require 'iptables_web/mixin/config_parser'
|
3
5
|
require 'iptables_web/configuration'
|
4
6
|
require 'system/getifaddrs'
|
5
|
-
require 'iptables_web/mixin/sudo'
|
6
7
|
require 'iptables_web/model/base'
|
7
8
|
require 'iptables_web/model/access_rule'
|
8
9
|
require 'iptables_web/model/node'
|
@@ -12,12 +13,14 @@ require 'iptables_web/iptables'
|
|
12
13
|
require 'commander'
|
13
14
|
require 'iptables_web/cli/command/install'
|
14
15
|
require 'iptables_web/cli/command/update'
|
16
|
+
require 'iptables_web/cli/multi_io'
|
15
17
|
require 'iptables_web/cli/logged_output'
|
16
18
|
require 'iptables_web/cli/import'
|
17
19
|
require 'iptables_web/cli'
|
18
20
|
|
19
21
|
|
20
22
|
module IptablesWeb
|
23
|
+
|
21
24
|
extend Configuration
|
22
25
|
end
|
23
26
|
|
metadata
CHANGED
@@ -1,135 +1,150 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iptables-web
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.5.
|
4
|
+
version: 0.3.5.pre4
|
5
|
+
prerelease: 6
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- NikolayMurga
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2016-
|
12
|
+
date: 2016-03-20 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: system-getifaddrs
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- -
|
19
|
+
- - ~>
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: 0.2.0
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- -
|
27
|
+
- - ~>
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 0.2.0
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: activeresource
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
|
-
- -
|
35
|
+
- - ~>
|
32
36
|
- !ruby/object:Gem::Version
|
33
37
|
version: '4.0'
|
34
|
-
- -
|
38
|
+
- - ! '>='
|
35
39
|
- !ruby/object:Gem::Version
|
36
40
|
version: 4.0.0
|
37
41
|
type: :runtime
|
38
42
|
prerelease: false
|
39
43
|
version_requirements: !ruby/object:Gem::Requirement
|
44
|
+
none: false
|
40
45
|
requirements:
|
41
|
-
- -
|
46
|
+
- - ~>
|
42
47
|
- !ruby/object:Gem::Version
|
43
48
|
version: '4.0'
|
44
|
-
- -
|
49
|
+
- - ! '>='
|
45
50
|
- !ruby/object:Gem::Version
|
46
51
|
version: 4.0.0
|
47
52
|
- !ruby/object:Gem::Dependency
|
48
53
|
name: commander
|
49
54
|
requirement: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
50
56
|
requirements:
|
51
|
-
- -
|
57
|
+
- - ~>
|
52
58
|
- !ruby/object:Gem::Version
|
53
59
|
version: '4.3'
|
54
|
-
- -
|
60
|
+
- - ! '>='
|
55
61
|
- !ruby/object:Gem::Version
|
56
62
|
version: 4.3.5
|
57
63
|
type: :runtime
|
58
64
|
prerelease: false
|
59
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
60
67
|
requirements:
|
61
|
-
- -
|
68
|
+
- - ~>
|
62
69
|
- !ruby/object:Gem::Version
|
63
70
|
version: '4.3'
|
64
|
-
- -
|
71
|
+
- - ! '>='
|
65
72
|
- !ruby/object:Gem::Version
|
66
73
|
version: 4.3.5
|
67
74
|
- !ruby/object:Gem::Dependency
|
68
75
|
name: activeresource-response
|
69
76
|
requirement: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
70
78
|
requirements:
|
71
|
-
- -
|
79
|
+
- - ~>
|
72
80
|
- !ruby/object:Gem::Version
|
73
81
|
version: '1.0'
|
74
|
-
- -
|
82
|
+
- - ! '>='
|
75
83
|
- !ruby/object:Gem::Version
|
76
84
|
version: 1.1.1
|
77
85
|
type: :runtime
|
78
86
|
prerelease: false
|
79
87
|
version_requirements: !ruby/object:Gem::Requirement
|
88
|
+
none: false
|
80
89
|
requirements:
|
81
|
-
- -
|
90
|
+
- - ~>
|
82
91
|
- !ruby/object:Gem::Version
|
83
92
|
version: '1.0'
|
84
|
-
- -
|
93
|
+
- - ! '>='
|
85
94
|
- !ruby/object:Gem::Version
|
86
95
|
version: 1.1.1
|
87
96
|
- !ruby/object:Gem::Dependency
|
88
97
|
name: lockfile
|
89
98
|
requirement: !ruby/object:Gem::Requirement
|
99
|
+
none: false
|
90
100
|
requirements:
|
91
|
-
- -
|
101
|
+
- - ~>
|
92
102
|
- !ruby/object:Gem::Version
|
93
103
|
version: '2'
|
94
|
-
- -
|
104
|
+
- - ! '>='
|
95
105
|
- !ruby/object:Gem::Version
|
96
106
|
version: 2.1.3
|
97
107
|
type: :runtime
|
98
108
|
prerelease: false
|
99
109
|
version_requirements: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
100
111
|
requirements:
|
101
|
-
- -
|
112
|
+
- - ~>
|
102
113
|
- !ruby/object:Gem::Version
|
103
114
|
version: '2'
|
104
|
-
- -
|
115
|
+
- - ! '>='
|
105
116
|
- !ruby/object:Gem::Version
|
106
117
|
version: 2.1.3
|
107
118
|
- !ruby/object:Gem::Dependency
|
108
119
|
name: bundler
|
109
120
|
requirement: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
110
122
|
requirements:
|
111
|
-
- -
|
123
|
+
- - ~>
|
112
124
|
- !ruby/object:Gem::Version
|
113
125
|
version: '1.6'
|
114
126
|
type: :development
|
115
127
|
prerelease: false
|
116
128
|
version_requirements: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
117
130
|
requirements:
|
118
|
-
- -
|
131
|
+
- - ~>
|
119
132
|
- !ruby/object:Gem::Version
|
120
133
|
version: '1.6'
|
121
134
|
- !ruby/object:Gem::Dependency
|
122
135
|
name: rake
|
123
136
|
requirement: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
124
138
|
requirements:
|
125
|
-
- -
|
139
|
+
- - ~>
|
126
140
|
- !ruby/object:Gem::Version
|
127
141
|
version: '0'
|
128
142
|
type: :development
|
129
143
|
prerelease: false
|
130
144
|
version_requirements: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
131
146
|
requirements:
|
132
|
-
- -
|
147
|
+
- - ~>
|
133
148
|
- !ruby/object:Gem::Version
|
134
149
|
version: '0'
|
135
150
|
description: Write a longer description. Optional.
|
@@ -140,46 +155,49 @@ executables:
|
|
140
155
|
extensions: []
|
141
156
|
extra_rdoc_files: []
|
142
157
|
files:
|
143
|
-
- LICENSE.txt
|
144
|
-
- README.md
|
145
|
-
- bin/iptables-web
|
146
|
-
- lib/iptables_web.rb
|
147
|
-
- lib/iptables_web/cli.rb
|
148
158
|
- lib/iptables_web/cli/command/install.rb
|
149
159
|
- lib/iptables_web/cli/command/update.rb
|
150
160
|
- lib/iptables_web/cli/import.rb
|
151
161
|
- lib/iptables_web/cli/logged_output.rb
|
162
|
+
- lib/iptables_web/cli/multi_io.rb
|
152
163
|
- lib/iptables_web/cli/pid_file.rb
|
164
|
+
- lib/iptables_web/cli.rb
|
153
165
|
- lib/iptables_web/configuration.rb
|
154
166
|
- lib/iptables_web/crontab.rb
|
155
167
|
- lib/iptables_web/iptables.rb
|
168
|
+
- lib/iptables_web/mixin/config_parser.rb
|
156
169
|
- lib/iptables_web/mixin/sudo.rb
|
157
170
|
- lib/iptables_web/model/access_rule.rb
|
158
171
|
- lib/iptables_web/model/base.rb
|
159
172
|
- lib/iptables_web/model/node.rb
|
160
173
|
- lib/iptables_web/version.rb
|
174
|
+
- lib/iptables_web.rb
|
175
|
+
- bin/iptables-web
|
176
|
+
- LICENSE.txt
|
177
|
+
- README.md
|
161
178
|
homepage: https://github.com/MurgaNikolay/iptables-web-client
|
162
179
|
licenses:
|
163
180
|
- MIT
|
164
|
-
metadata: {}
|
165
181
|
post_install_message:
|
166
182
|
rdoc_options: []
|
167
183
|
require_paths:
|
168
184
|
- lib
|
169
185
|
required_ruby_version: !ruby/object:Gem::Requirement
|
186
|
+
none: false
|
170
187
|
requirements:
|
171
|
-
- -
|
188
|
+
- - ! '>='
|
172
189
|
- !ruby/object:Gem::Version
|
173
190
|
version: '0'
|
174
191
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
|
+
none: false
|
175
193
|
requirements:
|
176
|
-
- -
|
194
|
+
- - ! '>'
|
177
195
|
- !ruby/object:Gem::Version
|
178
196
|
version: 1.3.1
|
179
197
|
requirements: []
|
180
198
|
rubyforge_project:
|
181
|
-
rubygems_version:
|
199
|
+
rubygems_version: 1.8.23
|
182
200
|
signing_key:
|
183
|
-
specification_version:
|
201
|
+
specification_version: 3
|
184
202
|
summary: Write a short summary. Required.
|
185
203
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: d82c50d21d327346d81fe8256ddd1b5c76cb90de
|
4
|
-
data.tar.gz: 64a251f60a292bfbaa6f2106a27f0900bd04b603
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: fefdc6e3a7f46fb33db8662b7878f162613f196c7a6c68523b562adb90f93ab0ca50917abace21b3b11b62a5253f2f257bf1d4e4d7c70964f73b80a19346f939
|
7
|
-
data.tar.gz: 0ce33638f0d7404ba4f450eb407c90c93a1fb53282af092d649188d5d635b658d1af012751af0c837248175e3613af98d3e8ae92f7a889c6de8c2f3f6a7a03d5
|