netfilter-ruby 4.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c06c6b3915a80142bc0d8a782a2d06a290040759
4
+ data.tar.gz: bdf9373f496a4a8e7f567e2ae82e831427e7ab7a
5
+ SHA512:
6
+ metadata.gz: 3539f2ef54357aca38eda3a68af8d8eb2f80bdddc3eb339704cb5f18792532e489cec60b69dd5e5bb8b55e9ee85bfbed05d5945788aa43b60bde7c216c07860e
7
+ data.tar.gz: f3fafe63c39a387d81379c78d2c010c02dd990c21fbd609075838d2c5fb12d3ce1b1b5d6d7feadc8ec885ff958546daecb463d142408a57215fb6dd97d4d4fde
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in netfilter.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Netskin GmbH
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,63 @@
1
+ # Netfilter::Ruby
2
+
3
+ Awesome Netfilter (iptables & ebtables) management using ruby.
4
+
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'netfilter-ruby'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install netfilter-ruby
19
+
20
+
21
+ ## Usage
22
+
23
+ require "netfilter"
24
+
25
+ Netfilter.new("example") do |eb, ip4, ip6|
26
+ eb.table :filter do |t|
27
+ t.chain "eth1-o" do |c|
28
+ # allow dhcp requests
29
+ c.filter :protocol => :ipv4, :ip_proto => :udp, :ip_src => "0.0.0.0", :ip_sport => 68, :ip_dst => "255.255.255.255", :ip_dport => 67, :jump => :return
30
+
31
+ # drop everything else
32
+ c.filter :jump => :drop
33
+ end
34
+
35
+ # capture all outgoing traffic (all traffic to the interface)
36
+ t.chain :input do |c|
37
+ c.filter :in_interface => "eth1", :jump => "eth1-o"
38
+ end
39
+
40
+ t.chain :forward do |c|
41
+ c.filter :in_interface => "eth1", :jump => "eth1-o"
42
+ end
43
+ end
44
+ end
45
+
46
+
47
+ ## Known bugs
48
+
49
+ * None
50
+
51
+
52
+ ## Contributing
53
+
54
+ 1. Fork it
55
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
56
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
57
+ 4. Push to the branch (`git push origin my-new-feature`)
58
+ 5. Create new Pull Request
59
+
60
+
61
+ ## Copyright
62
+
63
+ Copyright (c) 2012 - 2013 [Netskin GmbH](http://www.netskin.com). Released unter the MIT license.
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new("spec")
5
+ task :default => :spec
@@ -0,0 +1,107 @@
1
+ # encoding: utf-8
2
+
3
+ # see http://livesin.digitalmalaya.net/wp-content/uploads/2011/10/PacketFlow.png?9d7bd4
4
+
5
+ require "active_support/core_ext/module/delegation"
6
+ require "active_support/hash_with_indifferent_access"
7
+ require "active_support/inflector"
8
+
9
+ require "netfilter/filter"
10
+ require "netfilter/chain"
11
+ require "netfilter/table"
12
+ require "netfilter/tool"
13
+ require "netfilter/eb_tables"
14
+ require "netfilter/ip_tables"
15
+ require "netfilter/ip6_tables"
16
+ require "netfilter/version"
17
+
18
+ class Netfilter
19
+ NATIVE_TABLES = %w(filter nat mangle raw)
20
+ NATIVE_CHAINS = %w(input output forward prerouting postrouting)
21
+ NATIVE_TARGETS = %w(accept drop continue return reject dnat snat arpreply ct mark)
22
+
23
+ SystemError = Class.new(StandardError)
24
+
25
+ attr_accessor :eb_tables, :ip_tables, :ip6_tables
26
+
27
+ def self.import(data)
28
+ data = data.symbolize_keys
29
+ new.tap do |netfilter|
30
+ netfilter.eb_tables = data[:eb_tables] ? EbTables.import(data[:eb_tables]) : EbTables.new
31
+ netfilter.ip_tables = data[:ip_tables] ? IpTables.import(data[:ip_tables]) : IpTables.new
32
+ netfilter.ip6_tables = data[:ip6_tables] ? Ip6Tables.import(data[:ip6_tables]) : Ip6Tables.new
33
+ end
34
+ end
35
+
36
+ def initialize(namespace = nil)
37
+ self.eb_tables = EbTables.new(namespace)
38
+ self.ip_tables = IpTables.new(namespace)
39
+ self.ip6_tables = Ip6Tables.new(namespace)
40
+ yield(eb_tables, ip_tables, ip6_tables) if block_given?
41
+ end
42
+
43
+ def ip_tables
44
+ return yield(@ip_tables) if block_given?
45
+ @ip_tables
46
+ end
47
+
48
+ def ip6_tables
49
+ return yield(@ip6_tables) if block_given?
50
+ @ip6_tables
51
+ end
52
+
53
+ def eb_tables
54
+ return yield(@eb_tables) if block_given?
55
+ @eb_tables
56
+ end
57
+
58
+ def up
59
+ done = []
60
+ [:eb_tables, :ip_tables, :ip6_tables].each do |tool|
61
+ send(tool).up
62
+ done << tool
63
+ end
64
+ rescue => e
65
+ done.reverse.each{ |tool| send(tool).down }
66
+ raise e
67
+ end
68
+
69
+ def down
70
+ done = []
71
+ [:eb_tables, :ip_tables, :ip6_tables].each do |tool|
72
+ send(tool).down
73
+ done << tool
74
+ end
75
+ rescue => e
76
+ done.reverse.each{ |tool| send(tool).up }
77
+ raise e
78
+ end
79
+
80
+ def pp
81
+ puts "Eb-Tables"
82
+ puts "-" * 80
83
+ eb_tables.pp
84
+ puts
85
+ puts "Ip-Tables"
86
+ puts "-" * 80
87
+ ip_tables.pp
88
+ puts
89
+ puts "Ip6-Tables"
90
+ puts "-" * 80
91
+ ip6_tables.pp
92
+ end
93
+
94
+ def namespace=(name)
95
+ eb_tables.namespace = name
96
+ ip_tables.namespace = name
97
+ ip6_tables.namespace = name
98
+ end
99
+
100
+ def export
101
+ {
102
+ :eb_tables => eb_tables.export,
103
+ :ip_tables => ip_tables.export,
104
+ :ip6_tables => ip6_tables.export,
105
+ }
106
+ end
107
+ end
@@ -0,0 +1,61 @@
1
+ class Netfilter
2
+ class Chain
3
+ attr_accessor :table
4
+ attr_accessor :name, :filters
5
+
6
+ delegate :namespace, :to => :table
7
+
8
+ def self.import(table, data)
9
+ data = data.symbolize_keys
10
+ new(table, data[:name]).tap do |chain|
11
+ data[:filters].each do |data|
12
+ chain.filters << Filter.import(chain, data)
13
+ end
14
+ end
15
+ end
16
+
17
+ def initialize(table, name)
18
+ self.table = table
19
+ self.name = name.to_s
20
+ self.filters = []
21
+ self.name.upcase! if native?
22
+ yield(self) if block_given?
23
+ end
24
+
25
+ def append(definition)
26
+ filters << Filter.new(self, "append", definition)
27
+ end
28
+
29
+ def insert(definition)
30
+ filters.unshift Filter.new(self, "append", definition)
31
+ end
32
+
33
+ def filter(definition)
34
+ append(definition)
35
+ end
36
+
37
+ def native?
38
+ NATIVE_CHAINS.include?(name.downcase)
39
+ end
40
+
41
+ def name_as_argument
42
+ (namespace && !native?) ? "#{namespace}-#{name}" : name
43
+ end
44
+
45
+ def commands
46
+ [].tap do |commands|
47
+ commands << ["--new-chain #{name_as_argument}"] unless native?
48
+ filters.each do |filter|
49
+ commands << ["--#{filter.type} #{name_as_argument}", *filter.args]
50
+ end
51
+ end
52
+ end
53
+
54
+ def export
55
+ {
56
+ :name => name,
57
+ :filters => filters.map{ |filter| filter.export },
58
+ }
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+ class Netfilter
3
+ class EbTables < Tool
4
+ def self.parse
5
+ {}.tap do |data|
6
+ string = execute("#{executable} --list").strip << "\n"
7
+ string.split(/^Bridge table:\s+/).select{ |s| s != "" }.each do |string|
8
+ table, string = string.match(/(.+?)\n\n(.*)/m).to_a[1..-1]
9
+ data[table] = {}
10
+ string.split(/^Bridge chain:\s+/).select{ |s| s != "" }.each do |string|
11
+ chain, string = string.match(/(.+?),.+?\n(.*)/m).to_a[1..-1]
12
+ data[table][chain] = string.split("\n").map(&:strip)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,52 @@
1
+ class Netfilter
2
+ class Filter
3
+ attr_accessor :chain
4
+ attr_accessor :type
5
+ attr_accessor :definition
6
+
7
+ delegate :namespace, :to => :chain
8
+
9
+ def self.import(chain, data)
10
+ data = data.symbolize_keys
11
+ new(chain, data[:type], data[:definition])
12
+ end
13
+
14
+ def initialize(chain, type, definition)
15
+ self.chain = chain
16
+ self.type = type
17
+ self.definition = definition
18
+ end
19
+
20
+ def to_s
21
+ args*" "
22
+ end
23
+
24
+ def args
25
+ [].tap do |args|
26
+ definition.each_pair do |key, value|
27
+ key = object_to_argument(key)
28
+ value = object_to_argument(value)
29
+ value = "#{namespace}-#{value}" if key == "jump" && namespace && !NATIVE_TARGETS.include?(value.downcase)
30
+ args << "--#{key} #{value}"
31
+ end
32
+ end
33
+ end
34
+
35
+ def export
36
+ {
37
+ :type => type,
38
+ :definition => definition,
39
+ }
40
+ end
41
+
42
+ private
43
+
44
+ def object_to_argument(data)
45
+ data = data.to_s
46
+ data = data.gsub("_", "-")
47
+ data = data.upcase if NATIVE_TARGETS.include?(data.downcase)
48
+ data = data.downcase if %w(arpreply mark).include?(data.downcase)
49
+ data
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+ class Netfilter
3
+ class Ip6Tables < IpTables
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ class Netfilter
3
+ class IpTables < Tool
4
+ def self.parse
5
+ {}.tap do |data|
6
+ string = execute("#{executable}-save").strip << "\n"
7
+ string = string.split("\n").reject{ |s| s[0] == "#" }.join("\n")
8
+ string.split(/^\*/).select{ |s| s != "" }.each do |string|
9
+ table, string = string.match(/(.+?)\n(.*)/m).to_a[1..-1]
10
+ data[table] = {}
11
+
12
+ string.scan(/^:(.+?)\s+/).each do |match|
13
+ data[table][match[0]] = []
14
+ end
15
+
16
+ string.scan(/^-A (.+?) (.+?)\n/).each do |match|
17
+ data[table][match[0]] << match[1]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,62 @@
1
+ class Netfilter
2
+ class Table
3
+ attr_accessor :tool
4
+ attr_accessor :name, :chains
5
+
6
+ delegate :namespace, :to => :tool
7
+
8
+ def self.import(tool, data)
9
+ data = data.symbolize_keys
10
+ new(tool, data[:name]).tap do |table|
11
+ data[:chains].each do |data|
12
+ chain = Chain.import(table, data)
13
+ table.chains[chain.name.to_s.downcase] = chain
14
+ end
15
+ end
16
+ end
17
+
18
+ def initialize(tool, name)
19
+ self.tool = tool
20
+ self.name = name.to_s
21
+ self.chains = {}
22
+ raise ArgumentError, "unsupported table '#{name}'" unless native?
23
+ yield(self) if block_given?
24
+ end
25
+
26
+ def chain(name, &block)
27
+ key = name.to_s.downcase
28
+ (chains[key] || Chain.new(self, name)).tap do |chain|
29
+ chains[key] = chain
30
+ block.call(chain) if block
31
+ end
32
+ end
33
+
34
+ def native?
35
+ NATIVE_TABLES.include?(name)
36
+ end
37
+
38
+ def commands
39
+ [].tap do |commands|
40
+ chains.values.each do |chain|
41
+ chain.commands.each do |command|
42
+ commands << command.unshift("--table #{name}")
43
+ end
44
+ end
45
+
46
+ cmds = [[], []]
47
+ commands.each do |cmd|
48
+ index = cmd[1].include?("--new-chain") ? 0 : 1
49
+ cmds[index] << cmd
50
+ end
51
+ commands.replace(cmds[0] + cmds[1])
52
+ end
53
+ end
54
+
55
+ def export
56
+ {
57
+ :name => name,
58
+ :chains => chains.values.map{ |chain| chain.export },
59
+ }
60
+ end
61
+ end
62
+ end