iptables-web 0.3.5.pre3 → 0.3.5.pre4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|