netfilter-ruby 4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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