iptable 0.0.1 → 0.0.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +20 -0
- data/iptable.gemspec +1 -1
- data/lib/iptable/ip.rb +76 -9
- data/test/test.rb +47 -1
- metadata +3 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5f4f3b42e0340211d5f76976dcacc8a93634f90
|
4
|
+
data.tar.gz: 384ae7df7d10bd7e9843bf0ba8426d62a0b738b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a831bb0c4de7c088e51452086c468a4ef8bac4a317abacaa78365da22360f75d1e693e77ac5959e8f68ef4adf11ae3f5ebc0f6318f9eedcbedd29c6e7d7ef84
|
7
|
+
data.tar.gz: 06fdcec05df266c35efca59f6c8a0ed745bb58f06668c7fbc13dff8ced7735d0006a2840c90a26203c86dbc0d063442409c0ffb495aca4b38a51fc5dd0833f5d
|
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
iptable
|
2
|
+
=======
|
3
|
+
|
4
|
+
Manipulate iptables with ruby, for packet accounting of ports
|
5
|
+
|
6
|
+
Must be run as root, typically with rvmsudo
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
require 'iptable'
|
10
|
+
# load the current iptables
|
11
|
+
table = IP::Table.new
|
12
|
+
chain = table.add_chain :name => "nginx_in"
|
13
|
+
table.chains["INPUT"].append_jump_to chain
|
14
|
+
chain.add_rule :protocol => :tcp, :src => "208.51.40.2", :dport => 34576
|
15
|
+
sleep 5
|
16
|
+
chain.reload
|
17
|
+
puts chain.packets
|
18
|
+
puts chain.bytes
|
19
|
+
chain.delete
|
20
|
+
```
|
data/iptable.gemspec
CHANGED
data/lib/iptable/ip.rb
CHANGED
@@ -24,10 +24,16 @@ module IP
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
def add_chain(options)
|
28
|
+
new_chain = Chain.new(options)
|
29
|
+
new_chain.save
|
30
|
+
@chains[options[:name]] = new_chain
|
31
|
+
end
|
32
|
+
|
27
33
|
def match_chain(line)
|
28
34
|
if match = line.match(CHAIN_RE)
|
29
35
|
name = match[1]
|
30
|
-
@current_chain = @chains[name] = Chain.new(name)
|
36
|
+
@current_chain = @chains[name] = Chain.new(:name => name)
|
31
37
|
return true
|
32
38
|
end
|
33
39
|
false
|
@@ -35,30 +41,91 @@ module IP
|
|
35
41
|
end
|
36
42
|
|
37
43
|
class Chain
|
38
|
-
attr_reader :rules
|
44
|
+
attr_reader :rules, :name
|
45
|
+
attr_accessor :reference
|
39
46
|
|
40
|
-
def initialize(
|
41
|
-
@name = name
|
47
|
+
def initialize(options)
|
48
|
+
@name = options[:name]
|
42
49
|
@rules = []
|
50
|
+
@reference = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def save
|
54
|
+
IO.popen("/sbin/iptables -N #{@name}") do |output|
|
55
|
+
if output.read =~ /Chain already exists/
|
56
|
+
return false
|
57
|
+
else
|
58
|
+
return true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def append_jump_to chain
|
64
|
+
chain.reference = self
|
65
|
+
IO.popen("/sbin/iptables -I #{@name} -j #{chain.name}") do |output|
|
66
|
+
puts output.read
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def init_rule(options)
|
71
|
+
@rules << Rule.new(options.merge(:chain => self))
|
43
72
|
end
|
44
73
|
|
45
|
-
def add_rule(
|
46
|
-
|
74
|
+
def add_rule(options)
|
75
|
+
new_rule = Rule.new(options.merge(:chain => self))
|
76
|
+
new_rule.save
|
77
|
+
@rules << new_rule
|
47
78
|
end
|
48
79
|
|
49
80
|
def match_rule(string)
|
50
81
|
if match = string.match(RULE_RE)
|
51
|
-
|
82
|
+
init_rule :packets => match[1], :protocol => match[2]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def delete
|
87
|
+
@rules.each do |rule|
|
88
|
+
IO.popen("/sbin/iptables -D #{@name} 1") do |output|
|
89
|
+
puts output.read
|
90
|
+
end
|
91
|
+
end
|
92
|
+
if @reference
|
93
|
+
IO.popen("/sbin/iptables -D #{@reference.name} -j #{@name}") do |output|
|
94
|
+
puts output.read
|
95
|
+
end
|
96
|
+
end
|
97
|
+
IO.popen("/sbin/iptables -X #{@name}") do |output|
|
98
|
+
puts output.read
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def reload
|
103
|
+
@rules = []
|
104
|
+
IO.popen("/sbin/iptables -L #{@name} -n -v -x") do |output|
|
105
|
+
output.readlines.each do |line|
|
106
|
+
match_rule(line)
|
107
|
+
end
|
52
108
|
end
|
53
109
|
end
|
54
110
|
end
|
55
111
|
|
56
112
|
class Rule
|
57
113
|
attr_accessor :chain, :target
|
114
|
+
attr_reader :packets
|
58
115
|
|
59
|
-
def initialize(
|
60
|
-
@chain =
|
116
|
+
def initialize(options)
|
117
|
+
@chain = options[:chain]
|
118
|
+
raise "Rule needs a chain" unless @chain
|
119
|
+
@packets = options[:packets].to_i
|
61
120
|
@target = nil
|
121
|
+
@dport = options[:dport]
|
122
|
+
@protocol = options[:protocol] || "all"
|
123
|
+
end
|
124
|
+
|
125
|
+
def save
|
126
|
+
IO.popen("/sbin/iptables -A #{@chain.name} -p #{@protocol} --dport #{@dport}") do |output|
|
127
|
+
puts output.read
|
128
|
+
end
|
62
129
|
end
|
63
130
|
end
|
64
131
|
end
|
data/test/test.rb
CHANGED
@@ -2,10 +2,11 @@ gem 'mocha'
|
|
2
2
|
require 'minitest/autorun'
|
3
3
|
require 'iptable'
|
4
4
|
require 'mocha/mini_test'
|
5
|
+
require 'socket'
|
5
6
|
|
6
7
|
class Tests < Minitest::Test
|
7
8
|
def test_rule_matching
|
8
|
-
chain = IP::Chain.new "hey"
|
9
|
+
chain = IP::Chain.new :name => "hey"
|
9
10
|
str = "607939 956613034 TRAFFIC_ACCT_OUT all -- * * 0.0.0.0/0 0.0.0.0/0 "
|
10
11
|
chain.match_rule str
|
11
12
|
assert chain.rules.size == 1
|
@@ -22,4 +23,49 @@ class Tests < Minitest::Test
|
|
22
23
|
table = IP::Table.new
|
23
24
|
assert table.match_chain "Chain TRAFFIC_ACCT (0 references)"
|
24
25
|
end
|
26
|
+
|
27
|
+
def test_add_chain_tcp
|
28
|
+
table = IP::Table.new
|
29
|
+
chain = table.add_chain :name => "nginx_in"
|
30
|
+
table.chains["INPUT"].append_jump_to chain
|
31
|
+
rule = chain.add_rule :protocol => :tcp, :dport => 1999
|
32
|
+
server_thread = Thread.new do
|
33
|
+
server = TCPServer.new 1999
|
34
|
+
server.accept
|
35
|
+
sleep 0.1
|
36
|
+
end
|
37
|
+
client_thread = Thread.new do
|
38
|
+
client = TCPSocket.new 'localhost', 1999
|
39
|
+
sleep 0.1
|
40
|
+
client.puts "hey"
|
41
|
+
end
|
42
|
+
client_thread.join
|
43
|
+
server_thread.join
|
44
|
+
chain.reload
|
45
|
+
assert_equal 4, chain.rules.first.packets
|
46
|
+
ensure
|
47
|
+
chain.delete
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_add_chain_udp
|
51
|
+
table = IP::Table.new
|
52
|
+
chain = table.add_chain :name => "nginx_in"
|
53
|
+
table.chains["INPUT"].append_jump_to chain
|
54
|
+
rule = chain.add_rule :protocol => :udp, :dport => 1998
|
55
|
+
server_thread = Thread.new do
|
56
|
+
server = UDPSocket.new
|
57
|
+
server.bind "localhost", 1998
|
58
|
+
text, sender = server.recvfrom(1)
|
59
|
+
end
|
60
|
+
client_thread = Thread.new do
|
61
|
+
client = UDPSocket.new
|
62
|
+
client.send("hello", 0, 'localhost', 1998)
|
63
|
+
end
|
64
|
+
client_thread.join
|
65
|
+
server_thread.join
|
66
|
+
chain.reload
|
67
|
+
assert_equal 1, chain.rules.first.packets
|
68
|
+
ensure
|
69
|
+
chain.delete
|
70
|
+
end
|
25
71
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iptable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- towski
|
@@ -16,6 +16,8 @@ executables: []
|
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
18
18
|
files:
|
19
|
+
- .gitignore
|
20
|
+
- README.md
|
19
21
|
- Rakefile
|
20
22
|
- iptable.gemspec
|
21
23
|
- lib/iptable.rb
|