catflap 0.0.2 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+ require 'catflap/plugins/firewall/plugin'
2
+ require 'netfilter/writer'
3
+ include NetfilterWriter
4
+
5
+ ##
6
+ # A firewall plugin driver to implement rules on the NetFilter filter table.
7
+ #
8
+ # This driver passes rules to the filter table via the iptables user-space
9
+ # client.Two new chains are installed in the filter table, named by default:
10
+ # CATFLAP-DENY and CATFLAP-ALLOW. These are installed in the INPUT chain. You
11
+ # can configure the driver to install a LOG to log rejected packets, and also
12
+ # whether to REJECT or DROP denied packets.
13
+ #
14
+ # If you want to redirect to the Catflap server login port instead, then you
15
+ # should use the 'netfilter' driver instead, which is the default.
16
+ #
17
+ # @example firewall: plugin: 'iptables'
18
+ #
19
+ # @author Nyk Cowham <nykcowham@gmail.com>
20
+ class IptablesDriver < FirewallPlugin
21
+ # Initialize the driver class.
22
+ # @param [Hash<String, Hash>] config built by Catflap::initialize_config()
23
+ # @param [Boolean] noop set true to not send commands to firewall client.
24
+ # @param [Boolean] verbose set true to print command output to stdout stream.
25
+ # @return void
26
+ def initialize(config, noop, verbose)
27
+ super
28
+ @chain = config['firewall']['options']['chain'] || 'CATFLAP'
29
+ @log_rejected = config['firewall']['options']['log_rejected'] || false
30
+ @accept_local = config['firewall']['options']['accept_local'] || false
31
+ @policy = config['firewall']['options']['reject_policy'].to_sym || :drop
32
+ @allow = @chain + '-ALLOW'
33
+ @deny = @chain + '-DENY'
34
+ @r = Rules.new(:filter, @dports)
35
+ @r.match('multiport')
36
+ @r.noop = noop
37
+ @r.verbose = verbose
38
+ end
39
+
40
+ # Method to install the driver rules into iptables.
41
+ # @return void
42
+ # @raise StandardError when iptables reports an error.
43
+ def install_rules
44
+ target = (@policy == :reject) ? 'REJECT' : 'DROP'
45
+ log = @log_rejected
46
+ local = @accept_local
47
+ @r.chain(:new, @allow)
48
+ .chain(:new, @deny)
49
+ .rule(:add, chain: 'INPUT', jump: @allow)
50
+ .rule(:add, chain: 'INPUT', jump: @deny)
51
+ .rule(:add, chain: @deny, jump: 'LOG') { log }
52
+ .rule(:add, chain: @deny, jump: target)
53
+ .rule(:add, chain: @allow, jump: 'ACCEPT',
54
+ src: 'localhost') { local }
55
+ .do
56
+ end
57
+
58
+ # Method to uninstall the driver rules from iptables.
59
+ # @return void
60
+ # @raise StandardError when iptables reports an error.
61
+ def uninstall_rules
62
+ @r.rule(:delete, chain: 'INPUT', jump: @allow)
63
+ .rule(:delete, chain: 'INPUT', jump: @deny)
64
+ .chain(:flush, @allow)
65
+ .chain(:delete, @allow)
66
+ .chain(:flush, @deny)
67
+ .chain(:delete, @deny)
68
+ .do
69
+ end
70
+
71
+ # Method to purge all rules from CATFLAP-ALLOW chain.
72
+ # @return void
73
+ # @raise StandardError when iptables reports an error.
74
+ def purge_rules
75
+ @r.chain(:flush, @allow).do
76
+ end
77
+
78
+ # Method to list rules in CATFLAP-ALLOW chain.
79
+ # @return void
80
+ # @raise StandardError when iptables reports an error.
81
+ def list_rules
82
+ @r.chain(:list, @allow).do
83
+ end
84
+
85
+ # Method to check the CATFLAP-ALLOW chain for an allowed IP.
86
+ # @return [Boolean] true indicates that IP address already has access.
87
+ def check_address(ip)
88
+ @r.rule(:check, src: ip, chain: @allow, jump: 'ACCEPT').do?
89
+ end
90
+
91
+ # Method to add/grant an IP access in the CATFLAP-ALLOW chain.
92
+ # @return void
93
+ # @raise StandardError when iptables reports an error.
94
+ def add_address(ip)
95
+ @r.rule(:insert, src: ip, chain: @allow, jump: 'ACCEPT').do
96
+ end
97
+
98
+ # Method to delete/revoke access for an IP in the CATFLAP-ALLOW chain.
99
+ # @return void
100
+ # @raise StandardError when iptables reports an error.
101
+ def delete_address(ip)
102
+ @r.rule(:delete, src: ip, chain: @allow, jump: 'ACCEPT').do
103
+ end
104
+ end
@@ -0,0 +1,114 @@
1
+ require 'catflap/plugins/firewall/plugin'
2
+ require 'netfilter/writer'
3
+ include NetfilterWriter
4
+
5
+ ##
6
+ # A firewall plugin driver to implement rules on the NetFilter NAT table.
7
+ #
8
+ # This driver passes rules to the NAT table via the iptables user-space client.
9
+ # Two new chains are installed in the NAT table, named by default:
10
+ # CATFLAP-DENY and CATFLAP-ALLOW. These are installed in the PREROUTING chain.
11
+ # You can configure the driver to install a LOG to log denied packets.
12
+ #
13
+ # This is the default and recommended driver for Linux systems running iptables.
14
+ #
15
+ # @example firewall: plugin: 'netfilter'
16
+ #
17
+ # @author Nyk Cowham <nykcowham@gmail.com>
18
+ class NetfilterDriver < FirewallPlugin
19
+ # Initialize the driver class.
20
+ # @param [Hash<String, Hash>] config hash: Catflap::initialize_config()
21
+ # @param [Boolean] noop send the commands to the firewall client.
22
+ # @param [Boolean] verbose print the command output to stdout stream.
23
+ # @return void
24
+ def initialize(config, noop = false, verbose = false)
25
+ super
26
+ @chain = config['firewall']['options']['chain'] || 'CATFLAP'
27
+ @forward = config['firewall']['options']['forward']
28
+ @log_rejected = config['firewall']['options']['log_rejected'] || false
29
+ @accept_local = config['firewall']['options']['accept_local'] || false
30
+ @allow = @chain + '-ALLOW'
31
+ @deny = @chain + '-DENY'
32
+ @r = Rules.new(:nat, @dports)
33
+ @r.match('multiport')
34
+ @r.noop = noop
35
+ @r.verbose = verbose
36
+ end
37
+
38
+ # Method to install the driver rules into iptables.
39
+ # @return void
40
+ # @raise StandardError when iptables reports an error.
41
+ def install_rules
42
+ # We must make these local variables, so they are exposed to the blocks.
43
+ log = @log_rejected
44
+ deny_local = !@accept_local
45
+
46
+ # Create a new chain on the NAT table for our catflap netfilter allow rules.
47
+ @r.chain(:new, @allow)
48
+ .chain(:new, @deny)
49
+ .rule(:add, chain: 'PREROUTING', jump: @allow)
50
+ .rule(:add, chain: 'PREROUTING', jump: @deny)
51
+ .rule(:add, chain: @deny, jump: 'LOG') { log }
52
+ .rule(:add, chain: 'OUTPUT', out: 'lo', jump: @allow) { deny_local }
53
+ .rule(:add, chain: 'OUTPUT', out: 'lo', jump: @deny) { deny_local }
54
+
55
+ @forward.each do |src, dest|
56
+ src = src.to_s
57
+ @r.rule(:add, chain: @deny, jump: 'REDIRECT', dports: src, to_port: dest)
58
+ end
59
+ @r.do
60
+ end
61
+
62
+ # Method to uninstall the driver rules from iptables.
63
+ # @return void
64
+ # @raise StandardError when iptables reports an error.
65
+ def uninstall_rules
66
+ deny_local = !@accept_local
67
+
68
+ @r.rule(:delete, chain: 'PREROUTING', jump: @allow)
69
+ .rule(:delete, chain: 'PREROUTING', jump: @deny)
70
+ .rule(:delete, chain: 'OUTPUT', out: 'lo',
71
+ jump: @allow) { deny_local }
72
+ .rule(:delete, chain: 'OUTPUT', out: 'lo',
73
+ jump: @deny) { deny_local }
74
+ .chain(:flush, @allow)
75
+ .chain(:flush, @deny)
76
+ .chain(:delete, @allow)
77
+ .chain(:delete, @deny)
78
+ .do
79
+ end
80
+
81
+ # Method to purge all rules from CATFLAP-ALLOW chain.
82
+ # @return void
83
+ # @raise StandardError when iptables reports an error.
84
+ def purge_rules
85
+ @r.chain(:flush, @allow).do
86
+ end
87
+
88
+ # Method to list rules in CATFLAP-ALLOW chain.
89
+ # @return void
90
+ # @raise StandardError when iptables reports an error.
91
+ def list_rules
92
+ @r.chain(:list, @allow).do
93
+ end
94
+
95
+ # Method to check the CATFLAP-ALLOW chain for an allowed IP.
96
+ # @return [Boolean] true indicates that IP address already has access.
97
+ def check_address(ip)
98
+ @r.rule(:check, src: ip, chain: @allow, jump: 'ACCEPT').do?
99
+ end
100
+
101
+ # Method to add/grant an IP access in the CATFLAP-ALLOW chain.
102
+ # @return void
103
+ # @raise StandardError when iptables reports an error.
104
+ def add_address(ip)
105
+ @r.rule(:insert, src: ip, chain: @allow, jump: 'ACCEPT').do
106
+ end
107
+
108
+ # Method to delete/revoke access for an IP in the CATFLAP-ALLOW chain.
109
+ # @return void
110
+ # @raise StandardError when iptables reports an error.
111
+ def delete_address(ip)
112
+ @r.rule(:delete, src: ip, chain: @allow, jump: 'ACCEPT').do
113
+ end
114
+ end
@@ -0,0 +1,67 @@
1
+ # Abstract class plugin driver to implement rules on the NetFilter filter table.
2
+ #
3
+ # Firewall drivers should inherit from this abstract class and implement each
4
+ # method. This serves as a contract for firewalls to follow to ensure that the
5
+ # driver can respond to firewall calls.
6
+ #
7
+ # @example firewall: plugin: 'iptables'
8
+ #
9
+ # @author Nyk Cowham <nykcowham@gmail.com>
10
+ class FirewallPlugin
11
+ attr_reader :dports, :catflap_port
12
+
13
+ def initialize(config, noop = false, verbose = false)
14
+ @noop = noop
15
+ @verbose = verbose
16
+ @catflap_port = config['server']['port']
17
+ @dports = config['firewall']['dports']
18
+ end
19
+
20
+ # Implement method to install the driver rules into iptables.
21
+ # @return void
22
+ # @raise StandardError when iptables reports an error.
23
+ def install_rules
24
+ raise NotImplementedError
25
+ end
26
+
27
+ # Implement method to uninstall the driver rules from iptables.
28
+ # @return void
29
+ # @raise StandardError when iptables reports an error.
30
+ def uninstall_rules
31
+ raise NotImplementedError
32
+ end
33
+
34
+ # Implement method to purge all rules from CATFLAP-ALLOW chain.
35
+ # @return void
36
+ # @raise StandardError when iptables reports an error.
37
+ def purge_rules
38
+ raise NotImplementedError
39
+ end
40
+
41
+ # Implement method to list rules in CATFLAP-ALLOW chain.
42
+ # @return void
43
+ # @raise StandardError when iptables reports an error.
44
+ def list_rules
45
+ raise NotImplementedError
46
+ end
47
+
48
+ # Implement method to check the CATFLAP-ALLOW chain for an allowed IP.
49
+ # @return [Boolean] true indicates that IP address already has access.
50
+ def check_address(_)
51
+ raise NotImplementedError
52
+ end
53
+
54
+ # Implement method to add/grant an IP access in the CATFLAP-ALLOW chain.
55
+ # @return void
56
+ # @raise StandardError when iptables reports an error.
57
+ def add_address(_)
58
+ raise NotImplementedError
59
+ end
60
+
61
+ # Implement method to delete/revoke access in the CATFLAP-ALLOW chain.
62
+ # @return void
63
+ # @raise StandardError when iptables reports an error.
64
+ def delete_address(_)
65
+ raise NotImplementedError
66
+ end
67
+ end
@@ -0,0 +1,5 @@
1
+ # This is the version bumper.
2
+ class Catflap
3
+ # Current version of Catflap gem.
4
+ VERSION = '1.0.1'
5
+ end
@@ -0,0 +1,125 @@
1
+ require 'catflap/firewall'
2
+ include Firewall
3
+
4
+ # Mixin module to add rule handling functions to netfilter-based drivers.
5
+ #
6
+ # @author Nyk Cowham <nykcowham@gmail.com>
7
+ module NetfilterWriter
8
+ # Class providing a DSL for defining netfilter rules
9
+ # @author Nyk Cowham <nykcowham@gmail.com>
10
+ class Rules
11
+ attr_accessor :noop, :verbose
12
+
13
+ def initialize(table, ports = nil)
14
+ @table = table
15
+ @ports = ports
16
+ @buffer = ''
17
+ end
18
+
19
+ def table(table)
20
+ @table = table
21
+ self
22
+ end
23
+
24
+ def ports(ports)
25
+ @ports = ports
26
+ self
27
+ end
28
+
29
+ def match(match)
30
+ @match = match
31
+ self
32
+ end
33
+
34
+ # Create, flush and delete chains
35
+ # @param [String] cmd the operation to perform (add, delete, flush)
36
+ # @param [String] chain name of the chain (e.g. INPUT, CATFLAP-DENY, etc.)
37
+ # @return self
38
+ def chain(cmd, chain, a = {})
39
+ cmds = {
40
+ new: '-N', rename: '-E', delete: '-X', flush: '-F',
41
+ list_rules: '-S', list: '-L', zero: '-Z', policy: '-P'
42
+ }
43
+ table = build_option('-t', @table)
44
+ numeric = build_option('-n', a[:numeric])
45
+ rulenum = build_option(true, a[:rulenum])
46
+ to = build_option(true, a[:to])
47
+ @buffer << [
48
+ 'iptables', table, numeric, cmds[cmd], chain, rulenum, to
49
+ ].compact.join(' ') << "\n"
50
+ self
51
+ end
52
+
53
+ # Create, flush and delete chains
54
+ # @param [String] cmd the operation to perform (add, delete, insert, etc.)
55
+ # @param [String] chain name of the chain (e.g. INPUT, CATFLAP-DENY, etc.)
56
+ # @return self
57
+ def rule(cmd, a, &block)
58
+ # Evaluate a block expression and return early if it evaluates to false.
59
+ # If no block is passed it is equivalent to the block: { true }.
60
+ return self if block_given? && !instance_eval(&block)
61
+
62
+ raise ArgumentError, 'chain is a required argument' unless a[:chain]
63
+ assert_valid_ipaddr(a[:src]) if a[:src]
64
+ assert_valid_ipaddr(a[:dst]) if a[:dst]
65
+
66
+ # Map of commands for rules
67
+ cmds = {
68
+ add: '-A', delete: '-D', insert: '-I', replace: '-R',
69
+ check: '-C'
70
+ }
71
+
72
+ a[:proto] ||= 'tcp'
73
+ table = build_option('-t', @table)
74
+ jump = build_option('-j', a[:jump])
75
+ goto = build_option('-g', a[:goto])
76
+ proto = build_option('-p', a[:proto])
77
+ inface = build_option('-i', a[:in])
78
+ outface = build_option('-o', a[:out])
79
+ src = build_option('-s', a[:src])
80
+ dst = build_option('-d', a[:dst])
81
+ match = build_option('-m', a[:match] || @match)
82
+ ports = build_option('--dport', @ports)
83
+ to_port = build_option('--to-port', a[:to_port])
84
+ @buffer << [
85
+ 'iptables', table, cmds[cmd], a[:chain], src, dst, outface,
86
+ inface, proto, match, ports, jump || goto, to_port
87
+ ].compact.join(' ') << "\n"
88
+ self
89
+ end
90
+ end
91
+
92
+ def build_option(flag, value)
93
+ return flag if value.is_a?(TrueClass)
94
+ return value if flag.is_a?(TrueClass)
95
+ return flag << ' ' << value.to_s if flag && value
96
+ end
97
+
98
+ # Add a raw text rule, (e.g.: iptables -t nat CATFLAP-ALLOW ...)
99
+ # @param [String] raw_rule custom raw iptables command.
100
+ # @return self
101
+ def raw(raw_rule)
102
+ @buffer = raw_rule
103
+ self
104
+ end
105
+
106
+ # Flush the rule buffer and output the resulting iptables commands.
107
+ # @return [String] rule text that can be sent iptables user-space client.
108
+ def flush
109
+ out = @buffer
110
+ @buffer = ''
111
+ out
112
+ end
113
+
114
+ # Flush the rule and execute in iptables user-space client.
115
+ # @return void
116
+ def do
117
+ execute flush
118
+ end
119
+
120
+ # Flush the rule and execute commands and return success/fail value.
121
+ # @return [Boolean] true if the execution was successful.
122
+ def do?
123
+ execute_true? flush
124
+ end
125
+ end
@@ -0,0 +1,44 @@
1
+
2
+ .centered {
3
+ margin: 0px auto;
4
+ display: block;
5
+ }
6
+
7
+ .hidden {
8
+ display: none;
9
+ }
10
+
11
+ input[type="text"]:focus.failed {
12
+ background-color: pink;
13
+ border-color: red;
14
+ color: black;
15
+ }
16
+
17
+ input[type="text"] {
18
+ display: block;
19
+ margin: 0px auto;
20
+ margin-top: 1em;
21
+ padding-left: 0.4em;
22
+ height: 1.7em;
23
+ width: 50%;
24
+ color: #999;
25
+ font-family: sans-serif;
26
+ font-size: 2.2em;
27
+ border: solid 2px #dcdcdc;
28
+ transition: box-shadow 0.3s, border 0.3s;
29
+ box-shadow: inset 1px 1px 2px 0 #707070;
30
+ appearance: none;
31
+ border-radius: 2px;
32
+ }
33
+
34
+ input[type="text"]:focus {
35
+ border: solid 2px #707070;
36
+ box-shadow: inset 1px 1px 2px 0 #c9c9c9;
37
+ }
38
+
39
+ .message {
40
+ width: 50%;
41
+ font-size: 2em;
42
+ margin-top: 1.5em;
43
+ color: #860000;
44
+ }