ript 0.8.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/.rbenv-version +1 -0
- data/AUTHORS.md +16 -0
- data/CHANGELOG.md +93 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +62 -0
- data/LICENCE +19 -0
- data/README.md +564 -0
- data/Rakefile +136 -0
- data/bin/rbenv-sudo +18 -0
- data/bin/ript +207 -0
- data/dist/init.d +48 -0
- data/examples/accept-multiple-from-and-to.rb +16 -0
- data/examples/accept-with-a-list-of-ports.rb +13 -0
- data/examples/accept-with-specific-port-and-interface.rb +14 -0
- data/examples/accept-without-specific-from.rb +11 -0
- data/examples/accept.rb +12 -0
- data/examples/basic.rb +4 -0
- data/examples/dash-in-partition-name.rb +2 -0
- data/examples/drop.rb +11 -0
- data/examples/duplicate-partition-names/foobar1.rb +2 -0
- data/examples/duplicate-partition-names/foobar2.rb +2 -0
- data/examples/errors-undefined-method-with-no-match.rb +12 -0
- data/examples/errors-undefined-method.rb +12 -0
- data/examples/forward-dnat-with-different-destination-port.rb +16 -0
- data/examples/forward-dnat-with-explicit-from-and-port-mappings.rb +11 -0
- data/examples/forward-dnat-with-explicit-from-and-ports.rb +11 -0
- data/examples/forward-dnat-with-explicit-from.rb +11 -0
- data/examples/forward-dnat-with-explicit-protocols.rb +15 -0
- data/examples/forward-dnat-with-multiple-froms.rb +13 -0
- data/examples/forward-dnat-with-multiple-ports.rb +10 -0
- data/examples/forward-dnat-with-multiple-sources.rb +15 -0
- data/examples/forward-dnat.rb +16 -0
- data/examples/forward-snat-with-explicit-from.rb +16 -0
- data/examples/forward-snat-with-multiple-sources.rb +13 -0
- data/examples/forward-snat.rb +9 -0
- data/examples/log-and-accept.rb +12 -0
- data/examples/log-and-drop.rb +11 -0
- data/examples/log-dnat.rb +10 -0
- data/examples/log-snat.rb +13 -0
- data/examples/log.rb +11 -0
- data/examples/missing-address-definition-in-destination.rb +15 -0
- data/examples/missing-address-definition-in-from.rb +15 -0
- data/examples/multiple-partitions-in-this-file.rb +14 -0
- data/examples/multiple-partitions/bar.rb +11 -0
- data/examples/multiple-partitions/foo.rb +17 -0
- data/examples/partition-name-exactly-20-characters.rb +2 -0
- data/examples/partition-name-longer-than-20-characters.rb +2 -0
- data/examples/postclean.rb +10 -0
- data/examples/preclean.rb +10 -0
- data/examples/raw-with-chain-deletion.rb +9 -0
- data/examples/raw-with-flush.rb +9 -0
- data/examples/raw.rb +50 -0
- data/examples/reject.rb +11 -0
- data/examples/space-in-partition-name.rb +2 -0
- data/features/cli.feature +115 -0
- data/features/dsl/errors.feature +107 -0
- data/features/dsl/filter.feature +187 -0
- data/features/dsl/logging.feature +114 -0
- data/features/dsl/nat.feature +271 -0
- data/features/dsl/raw.feature +28 -0
- data/features/setup.feature +58 -0
- data/features/step_definitions/cli_steps.rb +15 -0
- data/features/step_definitions/example_steps.rb +44 -0
- data/features/support/env.rb +25 -0
- data/lib/ript/bootstrap.rb +20 -0
- data/lib/ript/dsl.rb +14 -0
- data/lib/ript/dsl/primitives.rb +7 -0
- data/lib/ript/dsl/primitives/common.rb +78 -0
- data/lib/ript/dsl/primitives/filter.rb +145 -0
- data/lib/ript/dsl/primitives/nat.rb +206 -0
- data/lib/ript/dsl/primitives/raw.rb +45 -0
- data/lib/ript/exceptions.rb +2 -0
- data/lib/ript/partition.rb +162 -0
- data/lib/ript/patches.rb +10 -0
- data/lib/ript/rule.rb +70 -0
- data/lib/ript/version.rb +3 -0
- data/ript.gemspec +33 -0
- metadata +232 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
Before("@timeout-10") do
|
2
|
+
@aruba_timeout_seconds = 10
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^the output from "([^"]*)" should match:$/ do |cmd, partial_output|
|
6
|
+
output_from(cmd).should =~ /#{partial_output}/
|
7
|
+
end
|
8
|
+
|
9
|
+
Then /^the output from "([^"]*)" should contain exactly:$/ do |cmd, exact_output|
|
10
|
+
output_from(cmd).should == exact_output
|
11
|
+
end
|
12
|
+
|
13
|
+
Given /^I have no iptables rules loaded$/ do
|
14
|
+
run_simple("rake clean_slate")
|
15
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
Before do
|
2
|
+
rules_src = File.join(File.dirname(__FILE__), '..', '..', 'examples', '.')
|
3
|
+
rules_dest = File.join(current_dir, 'examples')
|
4
|
+
FileUtils.mkdir_p(rules_dest)
|
5
|
+
FileUtils.cp_r(rules_src, rules_dest)
|
6
|
+
end
|
7
|
+
|
8
|
+
Then /^the created chain name in all tables should match$/ do
|
9
|
+
lines = all_output.split("\n")
|
10
|
+
|
11
|
+
lines.each do |line|
|
12
|
+
@chain_names ||= []
|
13
|
+
if line =~ /^# /
|
14
|
+
@chain_name = line[2..-1]
|
15
|
+
@chain_names = ['s', 'd', 'a'].map { |table| client, hash = @chain_name.split(/-/); "#{client}-#{table}#{hash}" }
|
16
|
+
end
|
17
|
+
|
18
|
+
next if line.size == 0
|
19
|
+
next if line =~ /--(new-chain|jump) partition-/
|
20
|
+
next if line =~ /--(new-chain|jump) ript_bootstrap-/
|
21
|
+
|
22
|
+
line.should match(%r{(^\# #{@chain_name})|(#{@chain_names.join('|')})}) if line !~ /LOG/
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^I generate rules for packet filtering$/ do
|
27
|
+
examples_path = Pathname.new(__FILE__).parent.parent.parent.join('examples')
|
28
|
+
|
29
|
+
examples = Dir.glob("#{examples_path}/{accept,drop,reject,log}*.rb")
|
30
|
+
examples.each do |example|
|
31
|
+
run_simple("ript rules generate #{example}")
|
32
|
+
commands = all_output.split("\n").find_all {|line| line =~ /^iptables/ }
|
33
|
+
|
34
|
+
@all_outputs ||= []
|
35
|
+
@all_outputs += commands
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
Then /^I should see a protocol specified when a port is specified$/ do
|
40
|
+
dports = @all_outputs.find_all {|line| line =~ /dport/}
|
41
|
+
dports.each do |command|
|
42
|
+
command.should =~ / --protocol /
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'aruba/cucumber'
|
6
|
+
require 'colorize'
|
7
|
+
|
8
|
+
if Process.uid != 0
|
9
|
+
puts "You need to be root to run these tests!"
|
10
|
+
abort
|
11
|
+
end
|
12
|
+
|
13
|
+
def clean_slate_after_2_minutes
|
14
|
+
root = Pathname.new(__FILE__).parent.parent.parent
|
15
|
+
path = ENV['PATH']
|
16
|
+
|
17
|
+
clean_command = "export PATH=#{path} && echo 'cd #{root} && rake clean_slate'"
|
18
|
+
at_command = "at 'now + 2 minutes' >/dev/null 2>&1"
|
19
|
+
command = "#{clean_command} | #{at_command}"
|
20
|
+
|
21
|
+
puts "If these tests lock you out, all iptables rules will be flushed in 2 minutes.\n".yellow
|
22
|
+
system(command)
|
23
|
+
end
|
24
|
+
|
25
|
+
clean_slate_after_2_minutes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Ript
|
2
|
+
class Bootstrap
|
3
|
+
def self.partition
|
4
|
+
rules = []
|
5
|
+
|
6
|
+
rules << Rule.new("table" => "filter", "new-chain" => "partition-a")
|
7
|
+
rules << Rule.new("table" => "filter", "insert" => "INPUT 1", "jump" => "partition-a")
|
8
|
+
rules << Rule.new("table" => "filter", "insert" => "OUTPUT 1", "jump" => "partition-a")
|
9
|
+
rules << Rule.new("table" => "filter", "insert" => "FORWARD 1", "jump" => "partition-a")
|
10
|
+
|
11
|
+
rules << Rule.new("table" => "nat", "new-chain" => "partition-d")
|
12
|
+
rules << Rule.new("table" => "nat", "insert" => "PREROUTING 1", "jump" => "partition-d")
|
13
|
+
|
14
|
+
rules << Rule.new("table" => "nat", "new-chain" => "partition-s")
|
15
|
+
rules << Rule.new("table" => "nat", "insert" => "POSTROUTING 1", "jump" => "partition-s")
|
16
|
+
|
17
|
+
Partition.new('ript_bootstrap', nil, :rules => rules)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/ript/dsl.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if RUBY_VERSION =~ /^1.8/ then
|
4
|
+
puts "Ript requires Ruby 1.9 to run. Exiting."
|
5
|
+
exit 2
|
6
|
+
end
|
7
|
+
|
8
|
+
$: << Pathname.new(__FILE__).dirname.parent.expand_path.to_s
|
9
|
+
|
10
|
+
require 'ript/dsl/primitives'
|
11
|
+
require 'ript/rule'
|
12
|
+
require 'ript/partition'
|
13
|
+
require 'ript/exceptions'
|
14
|
+
require 'ript/patches'
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module Ript
|
4
|
+
module DSL
|
5
|
+
module Primitives
|
6
|
+
module Common
|
7
|
+
def label(label, opts={})
|
8
|
+
@labels[label] = opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def interface(arg)
|
12
|
+
@interface = arg
|
13
|
+
end
|
14
|
+
|
15
|
+
def ports(*args)
|
16
|
+
if args.class == Array
|
17
|
+
args.each do |port|
|
18
|
+
if port.class == Range
|
19
|
+
@ports << "#{port.begin}:#{port.end}"
|
20
|
+
else
|
21
|
+
@ports << port
|
22
|
+
end
|
23
|
+
end
|
24
|
+
else
|
25
|
+
port = args
|
26
|
+
@ports << port
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def from(*label)
|
31
|
+
label.flatten!(2)
|
32
|
+
if label.is_a?(Array)
|
33
|
+
label.each do |l|
|
34
|
+
@froms << l
|
35
|
+
end
|
36
|
+
else
|
37
|
+
@froms << label
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to(*label)
|
42
|
+
label.flatten!(2)
|
43
|
+
if label.is_a?(Array)
|
44
|
+
label.each do |l|
|
45
|
+
@tos << l
|
46
|
+
end
|
47
|
+
else
|
48
|
+
@tos << label
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def protocols(*args)
|
53
|
+
# FIXME: refactor to just use flatten!
|
54
|
+
if args.class == Array
|
55
|
+
args.each do |protocol|
|
56
|
+
@protocols << protocol
|
57
|
+
end
|
58
|
+
else
|
59
|
+
protocol = args
|
60
|
+
@protocols << protocol
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def validate(opts={})
|
65
|
+
opts.each_pair do |type, label|
|
66
|
+
if not label_exists?(label)
|
67
|
+
raise LabelError, "Address '#{label}' (a #{type}) isn't defined"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def label_exists?(label)
|
73
|
+
@labels.has_key?(label)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module Ript
|
4
|
+
module DSL
|
5
|
+
module Primitives
|
6
|
+
module Filter
|
7
|
+
# Accept traffic to/from a destination/source.
|
8
|
+
#
|
9
|
+
# This allows traffic for a particular port/protocol to be passed into
|
10
|
+
# userland on the local machine.
|
11
|
+
def accept(name, opts={}, &block)
|
12
|
+
opts.merge!(:jump => "ACCEPT")
|
13
|
+
build_rule(name, block, opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Reject traffic to/from a destination/source.
|
17
|
+
#
|
18
|
+
# Send an error packet back for traffic that matches.
|
19
|
+
def reject(name, opts={}, &block)
|
20
|
+
opts.merge!(:jump => "REJECT")
|
21
|
+
build_rule(name, block, opts)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Drop traffic to/from a destination/source.
|
25
|
+
#
|
26
|
+
# Silently drop packets that match.
|
27
|
+
def drop(name, opts={}, &block)
|
28
|
+
opts.merge!(:jump => "DROP")
|
29
|
+
build_rule(name, block, opts)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Log traffic to/from a destination/source.
|
33
|
+
#
|
34
|
+
# Log packets that match via the kernel log (read with dmesg or syslog).
|
35
|
+
def log(name, opts={}, &block)
|
36
|
+
opts.merge!(:jump => "LOG")
|
37
|
+
build_rule(name, block, opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
# Construct a rule to be applied to the `filter` table.
|
42
|
+
#
|
43
|
+
# This method is used to construct simple rules on the filter table to
|
44
|
+
# accept/reject/drop/log traffic to and from various addresses.
|
45
|
+
#
|
46
|
+
# Accepts a block of the actual rule definition to evaluate, and
|
47
|
+
# appends the generated rule to the @table instance variable on the
|
48
|
+
# partition instance.
|
49
|
+
#
|
50
|
+
# This method returns nothing.
|
51
|
+
#
|
52
|
+
def build_rule(name, block, opts={})
|
53
|
+
@froms = []
|
54
|
+
@tos = []
|
55
|
+
@ports = []
|
56
|
+
@protocols = []
|
57
|
+
insert = opts[:insert] || "partition-a"
|
58
|
+
jump = opts[:jump] || "DROP"
|
59
|
+
log = opts[:log]
|
60
|
+
|
61
|
+
# Evaluate the block.
|
62
|
+
instance_eval &block
|
63
|
+
|
64
|
+
# Default all rules to apply to TCP packets if no protocol is specified
|
65
|
+
@protocols << 'TCP' if @protocols.size == 0
|
66
|
+
|
67
|
+
@protocols.map! {|protocol| {"protocol" => protocol} }
|
68
|
+
@ports.map! {|port| {"dport" => port} }
|
69
|
+
|
70
|
+
# Provide a default from address, so the @ports => @protocols => @froms
|
71
|
+
# nested iteration below works.
|
72
|
+
@froms << 'all' if @froms.size == 0
|
73
|
+
|
74
|
+
@froms.each do |from|
|
75
|
+
@tos.each do |to|
|
76
|
+
validate(:from => from, :to => to)
|
77
|
+
|
78
|
+
from_address = @labels[from][:address]
|
79
|
+
to_address = @labels[to][:address]
|
80
|
+
|
81
|
+
attributes = {
|
82
|
+
"table" => "filter",
|
83
|
+
"insert" => insert,
|
84
|
+
"destination" => to_address,
|
85
|
+
"jump" => "#{@name}-a",
|
86
|
+
}
|
87
|
+
@input << Rule.new(attributes)
|
88
|
+
@input << Rule.new(attributes.merge("jump" => "LOG")) if log
|
89
|
+
|
90
|
+
attributes = {
|
91
|
+
"table" => "filter",
|
92
|
+
"append" => "#{@name}-a",
|
93
|
+
"destination" => to_address,
|
94
|
+
"source" => from_address,
|
95
|
+
"jump" => jump
|
96
|
+
}
|
97
|
+
attributes.insert_before("destination", "in-interface" => @interface) if @interface
|
98
|
+
|
99
|
+
# Build up a list of arguments we need to build expanded rules.
|
100
|
+
#
|
101
|
+
# This allows us to expand shorthand definitions like:
|
102
|
+
#
|
103
|
+
# accept "multiple rules in one" do
|
104
|
+
# from "foo", "bar", "baz"
|
105
|
+
# to "spoons"
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
# ... into multiple rules, one ACCEPT rule for foo, bar, baz.
|
109
|
+
#
|
110
|
+
case
|
111
|
+
when @ports.size > 0 && @protocols.size > 0
|
112
|
+
# build the rules based on the arguments supplied
|
113
|
+
arguments = @protocols.product(@ports).map {|ary| ary.inject(:merge) }
|
114
|
+
when @ports.size == 0 && @protocols.size > 0
|
115
|
+
arguments = @protocols
|
116
|
+
when @protocols.size == 0 && @ports.size > 0
|
117
|
+
arguments = @ports
|
118
|
+
else
|
119
|
+
arguments = []
|
120
|
+
end
|
121
|
+
|
122
|
+
# If we have arguments, iterate through them
|
123
|
+
if arguments.size > 0
|
124
|
+
arguments.each do |options|
|
125
|
+
options.each_pair do |key, value|
|
126
|
+
attributes = attributes.dup # avoid overwriting existing hash values from previous iterations
|
127
|
+
attributes.insert_before("destination", key => value)
|
128
|
+
end
|
129
|
+
|
130
|
+
@table << Rule.new(attributes.merge("jump" => "LOG")) if log
|
131
|
+
@table << Rule.new(attributes)
|
132
|
+
end
|
133
|
+
else
|
134
|
+
@table << Rule.new(attributes.merge("jump" => "LOG")) if log
|
135
|
+
@table << Rule.new(attributes)
|
136
|
+
end # if
|
137
|
+
end # @tos.each
|
138
|
+
end # @froms.each
|
139
|
+
|
140
|
+
end # def build_rule
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
@@ -0,0 +1,206 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module Ript
|
4
|
+
module DSL
|
5
|
+
module Primitives
|
6
|
+
module NAT
|
7
|
+
def rewrite(name, opts={}, &block)
|
8
|
+
# Reset these so parameters don't leak between calls to forward.
|
9
|
+
@sources = []
|
10
|
+
@destinations = []
|
11
|
+
@ports = []
|
12
|
+
@protocols = []
|
13
|
+
@tos = []
|
14
|
+
@froms = []
|
15
|
+
log = opts[:log]
|
16
|
+
|
17
|
+
@snat_sources = []
|
18
|
+
@snat_destinations = []
|
19
|
+
|
20
|
+
# Evaluate the block.
|
21
|
+
instance_eval &block
|
22
|
+
|
23
|
+
# Default all rules to apply to TCP packets if no protocol is specified
|
24
|
+
@protocols << 'TCP' if @protocols.size == 0
|
25
|
+
|
26
|
+
@snat_sources.zip(@snat_destinations) do |source, destination|
|
27
|
+
validate(:source => source, :destination => destination)
|
28
|
+
|
29
|
+
source_address = @labels[source][:address]
|
30
|
+
destination_address = @labels[destination][:address]
|
31
|
+
|
32
|
+
attributes = { "table" => "nat",
|
33
|
+
"insert" => "partition-s",
|
34
|
+
"source" => source_address,
|
35
|
+
"jump" => "#{@name}-s" }
|
36
|
+
|
37
|
+
fattributes = { "table" => "filter",
|
38
|
+
"insert" => "partition-a",
|
39
|
+
"source" => source_address,
|
40
|
+
"jump" => "#{@name}-a" }
|
41
|
+
|
42
|
+
@postrouting << Rule.new(attributes)
|
43
|
+
@postrouting << Rule.new(attributes.merge("jump" => "LOG")) if log
|
44
|
+
@input << Rule.new(fattributes)
|
45
|
+
@input << Rule.new(fattributes.merge("jump" => "LOG")) if log
|
46
|
+
|
47
|
+
|
48
|
+
attributes = { "table" => "nat",
|
49
|
+
"append" => "#{@name}-s",
|
50
|
+
"source" => source_address,
|
51
|
+
"jump" => "SNAT",
|
52
|
+
"to-source" => destination_address }
|
53
|
+
|
54
|
+
fattributes = { "table" => "filter",
|
55
|
+
"append" => "#{@name}-a",
|
56
|
+
"source" => source_address,
|
57
|
+
"jump" => "ACCEPT" }
|
58
|
+
|
59
|
+
@froms.map {|from| @labels[from][:address]}.each do |address|
|
60
|
+
attributes.insert_before("destination", "source" => address)
|
61
|
+
end
|
62
|
+
|
63
|
+
@table << Rule.new(attributes.merge("jump" => "LOG")) if log
|
64
|
+
@table << Rule.new(attributes)
|
65
|
+
@table << Rule.new(fattributes.merge("jump" => "LOG")) if log
|
66
|
+
@table << Rule.new(fattributes)
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Provide a default from address, so the @ports => @protocols => @froms
|
71
|
+
# nested iteration below works.
|
72
|
+
@froms << 'all' if @froms.size == 0
|
73
|
+
|
74
|
+
# Build up rules based on evaluation.
|
75
|
+
@sources.zip(@destinations).each do |source, destination|
|
76
|
+
validate(:source => source, :destination => destination)
|
77
|
+
|
78
|
+
source_address = @labels[source][:address]
|
79
|
+
destination_address = @labels[destination][:address]
|
80
|
+
|
81
|
+
attributes = { "table" => "nat",
|
82
|
+
"insert" => "partition-d",
|
83
|
+
"destination" => source_address,
|
84
|
+
"jump" => "#{@name}-d" }
|
85
|
+
|
86
|
+
fattributes = { "table" => "filter",
|
87
|
+
"insert" => "partition-a",
|
88
|
+
"destination" => destination_address,
|
89
|
+
"jump" => "#{@name}-a" }
|
90
|
+
|
91
|
+
@prerouting << Rule.new(attributes)
|
92
|
+
@prerouting << Rule.new(attributes.merge("jump" => "LOG")) if log
|
93
|
+
@input << Rule.new(fattributes)
|
94
|
+
@input << Rule.new(fattributes.merge("jump" => "LOG")) if log
|
95
|
+
|
96
|
+
@ports.each do |port|
|
97
|
+
@protocols.each do |protocol|
|
98
|
+
@froms.map {|from| @labels[from][:address]}.each do |from_address|
|
99
|
+
if port.class == Hash
|
100
|
+
port.each_pair do |source_port, destination_port|
|
101
|
+
attributes = { "table" => "nat",
|
102
|
+
"append" => "#{@name}-d",
|
103
|
+
"protocol" => protocol,
|
104
|
+
"destination" => source_address,
|
105
|
+
"dport" => source_port,
|
106
|
+
"jump" => "DNAT",
|
107
|
+
"to-destination" => destination_address + ":#{destination_port}" }
|
108
|
+
|
109
|
+
fattributes = { "table" => "filter",
|
110
|
+
"append" => "#{@name}-a",
|
111
|
+
"protocol" => protocol,
|
112
|
+
"destination" => destination_address,
|
113
|
+
"dport" => destination_port,
|
114
|
+
"jump" => "ACCEPT" }
|
115
|
+
|
116
|
+
attributes.insert_before("destination", "source" => from_address) unless from_address == "0.0.0.0/0"
|
117
|
+
|
118
|
+
@table << Rule.new(attributes.merge("jump" => "LOG")) if log
|
119
|
+
@table << Rule.new(attributes)
|
120
|
+
@table << Rule.new(fattributes.merge("jump" => "LOG")) if log
|
121
|
+
@table << Rule.new(fattributes)
|
122
|
+
end
|
123
|
+
else
|
124
|
+
attributes = { "table" => "nat",
|
125
|
+
"append" => "#{@name}-d",
|
126
|
+
"protocol" => protocol,
|
127
|
+
"destination" => source_address,
|
128
|
+
"dport" => port,
|
129
|
+
"jump" => "DNAT",
|
130
|
+
"to-destination" => destination_address }
|
131
|
+
|
132
|
+
fattributes = { "table" => "filter",
|
133
|
+
"append" => "#{@name}-a",
|
134
|
+
"protocol" => protocol,
|
135
|
+
"destination" => destination_address,
|
136
|
+
"dport" => port,
|
137
|
+
"jump" => "ACCEPT" }
|
138
|
+
|
139
|
+
attributes.insert_before("destination", "source" => from_address) unless from_address == "0.0.0.0/0"
|
140
|
+
|
141
|
+
@table << Rule.new(attributes.merge("jump" => "LOG")) if log
|
142
|
+
@table << Rule.new(attributes)
|
143
|
+
@table << Rule.new(fattributes.merge("jump" => "LOG")) if log
|
144
|
+
@table << Rule.new(fattributes)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def dnat(opts={})
|
153
|
+
opts.each_pair do |source, destination|
|
154
|
+
# If the source argument to dnat is an Array:
|
155
|
+
#
|
156
|
+
# dnat [ "www.bar.com",
|
157
|
+
# "secure.bar.com",
|
158
|
+
# "static.bar.com" ] => "barprod-proxy-01"
|
159
|
+
#
|
160
|
+
# loop through each source, and create the associated destination.
|
161
|
+
if source.is_a?(Array)
|
162
|
+
source.each do |s|
|
163
|
+
@sources << s
|
164
|
+
@destinations << destination
|
165
|
+
end
|
166
|
+
# If the source is just a plain label:
|
167
|
+
#
|
168
|
+
# dnat "www.bar.com" => "barprod-proxy-01"
|
169
|
+
#
|
170
|
+
# simply add it and the destination to the collection.
|
171
|
+
else
|
172
|
+
@sources << source
|
173
|
+
@destinations << destination
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def snat(opts={})
|
179
|
+
opts.each_pair do |source, destination|
|
180
|
+
# If the source argument to snat is an Array:
|
181
|
+
#
|
182
|
+
# snat [ "www.bar.com",
|
183
|
+
# "secure.bar.com",
|
184
|
+
# "static.bar.com" ] => "barprod-proxy-01"
|
185
|
+
#
|
186
|
+
# loop through each source, and create the associated destination.
|
187
|
+
if source.is_a?(Array)
|
188
|
+
source.each do |s|
|
189
|
+
@snat_sources << s
|
190
|
+
@snat_destinations << destination
|
191
|
+
end
|
192
|
+
# If the source is just a plain label:
|
193
|
+
#
|
194
|
+
# snat "www.bar.com" => "barprod-proxy-01"
|
195
|
+
#
|
196
|
+
# simply add it and the destination to the collection.
|
197
|
+
else
|
198
|
+
@snat_sources << source
|
199
|
+
@snat_destinations << destination
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|