puffy 1.0.0 → 1.1.0.pre.rc1
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -10
- data/.rubocop.yml +14 -0
- data/README.md +8 -0
- data/Rakefile +4 -0
- data/lib/puffy/cli.rb +2 -2
- data/lib/puffy/formatters/base.rb +3 -3
- data/lib/puffy/formatters/iptables.rb +35 -15
- data/lib/puffy/formatters/iptables4.rb +3 -3
- data/lib/puffy/formatters/iptables6.rb +3 -3
- data/lib/puffy/formatters/pf.rb +12 -5
- data/lib/puffy/parser.tab.rb +499 -431
- data/lib/puffy/puppet.rb +2 -2
- data/lib/puffy/resolver.rb +13 -0
- data/lib/puffy/rule.rb +1 -1
- data/lib/puffy/rule_factory.rb +2 -2
- data/lib/puffy/version.rb +1 -1
- data/puffy.gemspec +2 -2
- metadata +3 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 212bbb0b9badf3e5595984f60e85f1739c907434fa65b6498279803111499fd7
|
|
4
|
+
data.tar.gz: 148f4d57788cc7db0fdee92a6758be60c698a8d59f76e89804875f5424ab52e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 96a3238a90ebb5625ad18279b9b72ec1f122cde54463a6377238091a5e4a5ac8ebb6488fd0de0d176b2b73589e41991eecb53c824c26d5d62f8e7f5c17300d07
|
|
7
|
+
data.tar.gz: 97a3e613aa975b7e0828bc467f5d485b81eb24eef6771cc90927f3fa6dfdedfa3a142de61ac22c3952c8a042b41788b18270100df0639102de2fd4441a157c36
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -14,7 +14,7 @@ jobs:
|
|
|
14
14
|
rubocop:
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
17
|
+
- uses: actions/checkout@v6
|
|
18
18
|
- name: Setup ruby
|
|
19
19
|
uses: ruby/setup-ruby@v1
|
|
20
20
|
with:
|
|
@@ -36,7 +36,7 @@ jobs:
|
|
|
36
36
|
- "3.3"
|
|
37
37
|
name: Ruby ${{ matrix.ruby }}
|
|
38
38
|
steps:
|
|
39
|
-
- uses: actions/checkout@
|
|
39
|
+
- uses: actions/checkout@v6
|
|
40
40
|
- name: Setup ruby
|
|
41
41
|
uses: ruby/setup-ruby@v1
|
|
42
42
|
with:
|
|
@@ -45,12 +45,4 @@ jobs:
|
|
|
45
45
|
- name: Generate the parser
|
|
46
46
|
run: bundle exec rake gen_parser
|
|
47
47
|
- name: Run tests without uploading code coverage
|
|
48
|
-
if: ${{ matrix.ruby != '3.0' }}
|
|
49
48
|
run: bundle exec rake
|
|
50
|
-
- name: Run tests and upload coverage to Code Climate
|
|
51
|
-
if: ${{ matrix.ruby == '3.0' }}
|
|
52
|
-
uses: paambaati/codeclimate-action@v5.0.0
|
|
53
|
-
env:
|
|
54
|
-
CC_TEST_REPORTER_ID: ${{ secrets.CODECLIMATE_TOKEN }}
|
|
55
|
-
with:
|
|
56
|
-
coverageCommand: bundle exec rake
|
data/.rubocop.yml
CHANGED
|
@@ -7,6 +7,10 @@ AllCops:
|
|
|
7
7
|
- tmp/**/*.rb
|
|
8
8
|
- vendor/bundle/**/*
|
|
9
9
|
|
|
10
|
+
plugins:
|
|
11
|
+
- rubocop-rake
|
|
12
|
+
- rubocop-rspec
|
|
13
|
+
|
|
10
14
|
Layout/HashAlignment:
|
|
11
15
|
EnforcedColonStyle: table
|
|
12
16
|
EnforcedHashRocketStyle: table
|
|
@@ -26,6 +30,16 @@ Metrics/ModuleLength:
|
|
|
26
30
|
Exclude:
|
|
27
31
|
- spec/**/*.rb
|
|
28
32
|
|
|
33
|
+
RSpec/ExampleLength:
|
|
34
|
+
Max: 50
|
|
35
|
+
|
|
36
|
+
RSpec/MultipleExpectations:
|
|
37
|
+
Max: 10
|
|
38
|
+
|
|
39
|
+
RSpec/SpecFilePathFormat:
|
|
40
|
+
Exclude:
|
|
41
|
+
- spec/core_ext_spec.rb
|
|
42
|
+
|
|
29
43
|
Style/Documentation:
|
|
30
44
|
Exclude:
|
|
31
45
|
- features/support/env.rb
|
data/README.md
CHANGED
|
@@ -25,6 +25,13 @@ Rules must appear in either a *node* or *service* definition, *services* being
|
|
|
25
25
|
reusable blocks of related rules:
|
|
26
26
|
|
|
27
27
|
~~~
|
|
28
|
+
policy block in all
|
|
29
|
+
policy block out log all
|
|
30
|
+
|
|
31
|
+
service dns do
|
|
32
|
+
pass proto {tcp udp} to port domain
|
|
33
|
+
end
|
|
34
|
+
|
|
28
35
|
service ntp do
|
|
29
36
|
pass proto udp to port ntp
|
|
30
37
|
end
|
|
@@ -42,6 +49,7 @@ service www do
|
|
|
42
49
|
end
|
|
43
50
|
|
|
44
51
|
service base do
|
|
52
|
+
client dns
|
|
45
53
|
client ntp
|
|
46
54
|
server ssh
|
|
47
55
|
end
|
data/Rakefile
CHANGED
|
@@ -22,7 +22,11 @@ task test: %i[spec features]
|
|
|
22
22
|
|
|
23
23
|
task default: :test
|
|
24
24
|
|
|
25
|
+
# rubocop:disable Rake/Desc
|
|
26
|
+
task feature: :gen_parser
|
|
25
27
|
task build: :gen_parser
|
|
28
|
+
task spec: :gen_parser
|
|
29
|
+
# rubocop:enable Rake/Desc
|
|
26
30
|
|
|
27
31
|
desc 'Generate the puffy language parser'
|
|
28
32
|
task gen_parser: 'lib/puffy/parser.tab.rb'
|
data/lib/puffy/cli.rb
CHANGED
|
@@ -49,10 +49,10 @@ module Puffy
|
|
|
49
49
|
run do |opts, args|
|
|
50
50
|
parser = cli.load_network(args[:network])
|
|
51
51
|
rules = parser.ruleset_for(args[:hostname])
|
|
52
|
-
|
|
52
|
+
policies = parser.policies_for(args[:hostname])
|
|
53
53
|
|
|
54
54
|
formatter = Object.const_get("Puffy::Formatters::#{opts[:formatter]}::Ruleset").new
|
|
55
|
-
puts formatter.emit_ruleset(rules,
|
|
55
|
+
puts formatter.emit_ruleset(rules, policies)
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
58
|
|
|
@@ -34,12 +34,12 @@ module Puffy
|
|
|
34
34
|
["# Generated by puffy v#{Puffy::VERSION} on #{Time.now.strftime('%c')}"]
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
# Returns a String representation of the provided +rules+ Array of Puffy::Rule with the +
|
|
37
|
+
# Returns a String representation of the provided +rules+ Array of Puffy::Rule with the +policies+ policies.
|
|
38
38
|
#
|
|
39
39
|
# @param rules [Array<Puffy::Rule>] array of Puffy::Rule.
|
|
40
|
-
# @param
|
|
40
|
+
# @param _policies [Symbol] ruleset policies.
|
|
41
41
|
# @return [String]
|
|
42
|
-
def emit_ruleset(rules,
|
|
42
|
+
def emit_ruleset(rules, _policies = nil)
|
|
43
43
|
rules.collect { |rule| @rule_formatter.emit_rule(rule) }.join("\n")
|
|
44
44
|
end
|
|
45
45
|
|
|
@@ -27,13 +27,13 @@ module Puffy
|
|
|
27
27
|
}
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
# Returns a Iptables String representation of the provided +rules+ Array of Puffy::Rule with the +
|
|
31
|
-
def emit_ruleset(rules,
|
|
30
|
+
# Returns a Iptables String representation of the provided +rules+ Array of Puffy::Rule with the +policies+ policies.
|
|
31
|
+
def emit_ruleset(rules, policies)
|
|
32
32
|
parts = []
|
|
33
33
|
parts << emit_header
|
|
34
34
|
parts << raw_ruleset(raw_rules(rules))
|
|
35
35
|
parts << nat_ruleset(nat_rules(rules))
|
|
36
|
-
parts << filter_ruleset(filter_rules(rules),
|
|
36
|
+
parts << filter_ruleset(filter_rules(rules), policies)
|
|
37
37
|
ruleset = parts.flatten.compact.join("\n")
|
|
38
38
|
"#{ruleset}\n"
|
|
39
39
|
end
|
|
@@ -61,14 +61,14 @@ module Puffy
|
|
|
61
61
|
parts
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
def filter_ruleset(rules,
|
|
64
|
+
def filter_ruleset(rules, policies)
|
|
65
65
|
return unless rules.any?
|
|
66
66
|
|
|
67
67
|
parts = ['*filter']
|
|
68
|
-
parts << emit_chain_policies(input:
|
|
69
|
-
parts << input_filter_ruleset(rules)
|
|
70
|
-
parts << forward_filter_ruleset(rules)
|
|
71
|
-
parts << output_filter_rulset(rules)
|
|
68
|
+
parts << emit_chain_policies(input: policies.dig(:in, :action), forward: policies.dig(:in, :action), output: policies.dig(:out, :action))
|
|
69
|
+
parts << input_filter_ruleset(rules, policies)
|
|
70
|
+
parts << forward_filter_ruleset(rules, policies)
|
|
71
|
+
parts << output_filter_rulset(rules, policies)
|
|
72
72
|
parts << 'COMMIT'
|
|
73
73
|
parts
|
|
74
74
|
end
|
|
@@ -77,20 +77,32 @@ module Puffy
|
|
|
77
77
|
policies.map { |chain, action| ":#{chain.upcase} #{Puffy::Formatters::Iptables.iptables_action(action)} [0:0]" }
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
def input_filter_ruleset(rules)
|
|
81
|
-
parts = [
|
|
80
|
+
def input_filter_ruleset(rules, policies)
|
|
81
|
+
parts = [
|
|
82
|
+
'-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT',
|
|
83
|
+
'-A INPUT -m conntrack --ctstate INVALID -j DROP',
|
|
84
|
+
]
|
|
82
85
|
parts << input_filter_rules(rules).map { |rule| @rule_formatter.emit_rule(rule) }
|
|
86
|
+
parts << '-A INPUT -j LOG' if policies.dig(:in, :log)
|
|
87
|
+
parts
|
|
83
88
|
end
|
|
84
89
|
|
|
85
|
-
def forward_filter_ruleset(rules)
|
|
86
|
-
parts = [
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
def forward_filter_ruleset(rules, policies)
|
|
91
|
+
parts = [
|
|
92
|
+
'-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT',
|
|
93
|
+
'-A FORWARD -m conntrack --ctstate INVALID -j DROP',
|
|
94
|
+
]
|
|
95
|
+
parts << fwd_filter_rules(rules).map { |rule| @rule_formatter.emit_rule(rule) }
|
|
96
|
+
parts << rdr_filter_rules(rules).map { |rule| @rule_formatter.emit_rule(Puffy::Rule.fwd_rule(rule)) }
|
|
97
|
+
parts << '-A FORWARD -j LOG' if policies.dig(:in, :log)
|
|
98
|
+
parts
|
|
89
99
|
end
|
|
90
100
|
|
|
91
|
-
def output_filter_rulset(rules)
|
|
101
|
+
def output_filter_rulset(rules, policies)
|
|
92
102
|
parts = ['-A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT']
|
|
93
103
|
parts << output_filter_rules(rules).map { |rule| @rule_formatter.emit_rule(rule) }
|
|
104
|
+
parts << '-A OUTPUT -j LOG' if policies.dig(:out, :log)
|
|
105
|
+
parts
|
|
94
106
|
end
|
|
95
107
|
|
|
96
108
|
def raw_rules(rules)
|
|
@@ -113,6 +125,14 @@ module Puffy
|
|
|
113
125
|
end
|
|
114
126
|
end
|
|
115
127
|
|
|
128
|
+
def fwd_filter_rules(rules)
|
|
129
|
+
rules.select(&:fwd?)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def rdr_filter_rules(rules)
|
|
133
|
+
rules.select { |r| r.rdr? && !Puffy::Formatters::Base.loopback_addresses.include?(r.rdr_to_host) }
|
|
134
|
+
end
|
|
135
|
+
|
|
116
136
|
def output_filter_rules(rules)
|
|
117
137
|
rules.select { |r| r.filter? && r.out? }.map do |rule|
|
|
118
138
|
dup = rule.dup
|
|
@@ -5,9 +5,9 @@ module Puffy
|
|
|
5
5
|
module Iptables4 # :nodoc:
|
|
6
6
|
# IPv4 Iptables implementation of a Puffy Ruleset formatter.
|
|
7
7
|
class Ruleset < Puffy::Formatters::Iptables::Ruleset # :nodoc:
|
|
8
|
-
# Return an IPv4 Iptables String representation of the provided +rules+ Puffy::Rule with the +
|
|
9
|
-
def emit_ruleset(rules,
|
|
10
|
-
super(rules.select(&:ipv4?),
|
|
8
|
+
# Return an IPv4 Iptables String representation of the provided +rules+ Puffy::Rule with the +policies+ policies.
|
|
9
|
+
def emit_ruleset(rules, policies)
|
|
10
|
+
super(rules.select(&:ipv4?), policies)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def filename_fragment
|
|
@@ -5,9 +5,9 @@ module Puffy
|
|
|
5
5
|
module Iptables6 # :nodoc:
|
|
6
6
|
# IPv6 Iptables implementation of a Puffy Ruleset formatter.
|
|
7
7
|
class Ruleset < Puffy::Formatters::Iptables::Ruleset # :nodoc:
|
|
8
|
-
# Return an IPv6 Iptables String representation of the provided +rules+ Puffy::Rule with the +
|
|
9
|
-
def emit_ruleset(rules,
|
|
10
|
-
super(rules.select(&:ipv6?),
|
|
8
|
+
# Return an IPv6 Iptables String representation of the provided +rules+ Puffy::Rule with the +policies+ policies.
|
|
9
|
+
def emit_ruleset(rules, policies)
|
|
10
|
+
super(rules.select(&:ipv6?), policies)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def filename_fragment
|
data/lib/puffy/formatters/pf.rb
CHANGED
|
@@ -6,10 +6,10 @@ module Puffy
|
|
|
6
6
|
# Pf implementation of a Puffy Ruleset formatter.
|
|
7
7
|
class Ruleset < Puffy::Formatters::Base::Ruleset # :nodoc:
|
|
8
8
|
# Returns a Pf String representation of the provided +rules+ Array of Puffy::Rule.
|
|
9
|
-
def emit_ruleset(rules,
|
|
9
|
+
def emit_ruleset(rules, policies)
|
|
10
10
|
parts = []
|
|
11
11
|
|
|
12
|
-
parts << emit_header(
|
|
12
|
+
parts << emit_header(policies)
|
|
13
13
|
|
|
14
14
|
parts << super(rules.select(&:nat?))
|
|
15
15
|
parts << super(rules.select(&:rdr?))
|
|
@@ -23,12 +23,14 @@ module Puffy
|
|
|
23
23
|
['pf', 'pf.conf']
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def emit_header(
|
|
26
|
+
def emit_header(policies)
|
|
27
27
|
parts = super()
|
|
28
28
|
parts << 'match in all scrub (no-df)'
|
|
29
29
|
parts << 'set skip on lo'
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
%i[in out].each do |direction|
|
|
31
|
+
policy = policies[direction]
|
|
32
|
+
parts << @rule_formatter.emit_rule(Puffy::Rule.new(action: policy[:action], log: policy[:log], dir: direction, no_quick: true))
|
|
33
|
+
end
|
|
32
34
|
parts
|
|
33
35
|
end
|
|
34
36
|
end
|
|
@@ -40,6 +42,7 @@ module Puffy
|
|
|
40
42
|
parts = []
|
|
41
43
|
parts << emit_action(rule)
|
|
42
44
|
parts << emit_direction(rule)
|
|
45
|
+
parts << emit_log(rule)
|
|
43
46
|
parts << emit_quick(rule)
|
|
44
47
|
parts << emit_on(rule)
|
|
45
48
|
parts << emit_what(rule)
|
|
@@ -62,6 +65,10 @@ module Puffy
|
|
|
62
65
|
'quick' unless rule.no_quick
|
|
63
66
|
end
|
|
64
67
|
|
|
68
|
+
def emit_log(rule)
|
|
69
|
+
'log' if rule.log
|
|
70
|
+
end
|
|
71
|
+
|
|
65
72
|
def emit_on(rule)
|
|
66
73
|
"on #{rule.on.gsub('!', '! ')}" if rule.on
|
|
67
74
|
end
|