soak 0.1.0
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.
- data/Gemfile +2 -0
- data/Gemfile.lock +20 -0
- data/README.md +36 -0
- data/Rakefile +30 -0
- data/bin/soakd +12 -0
- data/lib/soak.rb +9 -0
- data/lib/soak/core.rb +40 -0
- data/lib/soak/lookup.rb +60 -0
- data/lib/soak/packet.rb +38 -0
- data/soak.gemspec +18 -0
- metadata +88 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
soak (0.0.1)
|
5
|
+
asetus (>= 0.0.7)
|
6
|
+
logger (>= 1.2.8)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
asetus (0.0.7)
|
12
|
+
slop
|
13
|
+
logger (1.2.8)
|
14
|
+
slop (3.5.0)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
soak!
|
data/README.md
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
## SOAK
|
2
|
+
|
3
|
+
lightweight ARP sponge.
|
4
|
+
|
5
|
+
## requirements
|
6
|
+
|
7
|
+
+ ruby 1.9.3
|
8
|
+
+ asetus 0.1.2
|
9
|
+
+ logger 1.2.8
|
10
|
+
|
11
|
+
soakd requires root privileges to run.
|
12
|
+
|
13
|
+
# install
|
14
|
+
|
15
|
+
> gem install soak
|
16
|
+
>
|
17
|
+
|
18
|
+
## usage
|
19
|
+
|
20
|
+
> soakd
|
21
|
+
>
|
22
|
+
|
23
|
+
## files
|
24
|
+
|
25
|
+
the configuration file is generated during the first run at: /root/.config/soak/config
|
26
|
+
|
27
|
+
## configuration example
|
28
|
+
|
29
|
+
---
|
30
|
+
interface: eth0
|
31
|
+
local_mac: ff:ff:ff:ff:ff:ff
|
32
|
+
sponge: [ '192.0.2.44', '192.0.2.101', '192.0.2.253' ]
|
33
|
+
debug: true
|
34
|
+
|
35
|
+
|
36
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
begin
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler'
|
4
|
+
Bundler.setup
|
5
|
+
rescue => e
|
6
|
+
warn "FATAL - #{e}"
|
7
|
+
exit 1
|
8
|
+
end
|
9
|
+
|
10
|
+
gemspec = eval(File.read(Dir['*.gemspec'].first))
|
11
|
+
file = [gemspec.name, gemspec.version].join('-') + '.gem'
|
12
|
+
|
13
|
+
task :validate do
|
14
|
+
gemspec.validate
|
15
|
+
end
|
16
|
+
|
17
|
+
task :build do
|
18
|
+
system "gem build #{gemspec.name}.gemspec"
|
19
|
+
FileUtils.mkdir_p 'gems'
|
20
|
+
FileUtils.mv file, 'gems'
|
21
|
+
end
|
22
|
+
|
23
|
+
task :install => [:validate, :build] do
|
24
|
+
system "sudo -E sh -c \'umask 022; gem install gems/#{file} --no-ri --no-rdoc\'"
|
25
|
+
FileUtils.rm_rf 'gems'
|
26
|
+
end
|
27
|
+
|
28
|
+
task :remove do
|
29
|
+
system "sudo -E sh -c \'umask 022; gem uninstall #{gemspec.name}\'"
|
30
|
+
end
|
data/bin/soakd
ADDED
data/lib/soak.rb
ADDED
data/lib/soak/core.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Soak
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
target = STDOUT
|
5
|
+
Log = Logger.new target
|
6
|
+
|
7
|
+
# import user configuration
|
8
|
+
require 'asetus'
|
9
|
+
if File.exists? '/etc/soak/config'
|
10
|
+
Cfg = Asetus.cfg name: 'soak'
|
11
|
+
else
|
12
|
+
CFG = Asetus.new :name=>'soak', :load=>false
|
13
|
+
CFG.default.interface = 'eth0'
|
14
|
+
CFG.default.local_mac = 'ff:ff:ff:ff:ff:ff'
|
15
|
+
CFG.default.sponge = []
|
16
|
+
CFG.default.debug = false
|
17
|
+
CFG.load
|
18
|
+
if CFG.create
|
19
|
+
CFG.save
|
20
|
+
puts '+ base configuration built at: /root/.config/soak/config'
|
21
|
+
exit 0
|
22
|
+
else
|
23
|
+
Cfg = CFG.cfg
|
24
|
+
end
|
25
|
+
end
|
26
|
+
Process.daemon if not Cfg.debug
|
27
|
+
|
28
|
+
# constants
|
29
|
+
ETH_P_ALL = 0x03_00
|
30
|
+
SIOCGIFINDEX = 0x89_33
|
31
|
+
PF_PACKET = 17
|
32
|
+
AF_PACKET = PF_PACKET
|
33
|
+
IFREQ = [ Cfg.interface.dup ].pack 'a32'
|
34
|
+
RawSocket = Socket.open Socket::PF_PACKET, Socket::SOCK_RAW, ETH_P_ALL
|
35
|
+
|
36
|
+
# setup sending device
|
37
|
+
RawSocket.ioctl(SIOCGIFINDEX, IFREQ)
|
38
|
+
RawSocket.bind [AF_PACKET].pack('s') + [ETH_P_ALL].pack('n') + IFREQ[16..20] + ("\x00" * 12)
|
39
|
+
|
40
|
+
end
|
data/lib/soak/lookup.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Soak
|
2
|
+
class Lookup
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@rx_queue = Queue.new
|
6
|
+
@in_sock = Socket.new Socket::PF_PACKET, Socket::SOCK_RAW, 0x03_00
|
7
|
+
listen
|
8
|
+
end
|
9
|
+
|
10
|
+
def listen
|
11
|
+
enqueue = Thread.new do
|
12
|
+
while true do
|
13
|
+
r, w, e = IO.select([@in_sock], nil, nil)
|
14
|
+
if r[0]
|
15
|
+
data = @in_sock.recvfrom_nonblock(1500).first
|
16
|
+
@rx_queue << data
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
worker = Thread.new do
|
21
|
+
while true do
|
22
|
+
begin
|
23
|
+
@data = @rx_queue.pop
|
24
|
+
if @data[0..13].unpack('nnnnnnn')[6].to_s(16).to_i == 806 # process arp packets only
|
25
|
+
pkt_lu
|
26
|
+
end
|
27
|
+
rescue => e
|
28
|
+
Log.warn e if Cfg.debug
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
worker.join
|
33
|
+
end
|
34
|
+
|
35
|
+
def pkt_lu
|
36
|
+
@src_mac = []
|
37
|
+
pkt = @data[14..-1].unpack('nnCCnnnnL>nnnL>')
|
38
|
+
case pkt[4].to_s(16).to_i
|
39
|
+
when 1
|
40
|
+
@dst_ip = IPAddr.new(pkt[12], Socket::AF_INET)
|
41
|
+
if Cfg.sponge.include? @dst_ip.to_s
|
42
|
+
[ pkt[5], pkt[6], pkt[7] ].each do |p|
|
43
|
+
if p.to_s(16).size < 4
|
44
|
+
@src_mac << [ [ '00' ] + [ p.to_s(16) ] ].join
|
45
|
+
else
|
46
|
+
@src_mac << p.to_s(16)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@src_ip = IPAddr.new(pkt[8], Socket::AF_INET)
|
50
|
+
Log.debug [ 'matching arp request - target address:', @dst_ip.to_s, '- sender info:', @src_ip, '@', @src_mac ].join(' ') if Cfg.debug
|
51
|
+
@src_mac = @src_mac.join.scan(/../).join ':'
|
52
|
+
pkt = Packet.new @dst_ip, @src_ip, @src_mac, @data[12..19]
|
53
|
+
else
|
54
|
+
Log.debug [ 'address is not in the database -', @dst_ip.to_s, '.. ignoring ..' ].join(' ') if Cfg.debug
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/lib/soak/packet.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Soak
|
2
|
+
class Packet
|
3
|
+
|
4
|
+
def initialize dst_ip, src_ip, src_mac, head_data
|
5
|
+
@dst_ip = dst_ip
|
6
|
+
@src_ip = src_ip
|
7
|
+
@src_mac = src_mac
|
8
|
+
@head_data = head_data
|
9
|
+
pkt_gen
|
10
|
+
inject
|
11
|
+
end
|
12
|
+
|
13
|
+
def pkt_gen
|
14
|
+
begin
|
15
|
+
smac = Cfg.local_mac.split(':').pack 'H2H2H2H2H2H2'
|
16
|
+
dmac = @src_mac.split(':').pack 'H2H2H2H2H2H2'
|
17
|
+
opcode = [ 2 ].pack 'n'
|
18
|
+
sha = Cfg.local_mac.split(':').pack 'H2H2H2H2H2H2'
|
19
|
+
spa = @dst_ip.to_s.split('.').map{ |s| s.to_i }.pack 'CCCC'
|
20
|
+
tha = @src_mac.split(':').pack 'H2H2H2H2H2H2'
|
21
|
+
tpa = @src_ip.to_s.split('.').map{ |s| s.to_i }.pack 'CCCC'
|
22
|
+
@packet = [ dmac, smac, @head_data, opcode, sha, spa, tha, tpa ].join
|
23
|
+
rescue => e
|
24
|
+
Log.warn e
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def inject
|
29
|
+
begin
|
30
|
+
RawSocket.send @packet, 0
|
31
|
+
Log.debug [ 'arp packet injected - sponge address:', Cfg.local_mac ].join(' ') if Cfg.debug
|
32
|
+
rescue => e
|
33
|
+
Log.warn e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
data/soak.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'soak'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.authors = [ 'Samer Abdel-Hafez' ]
|
6
|
+
s.email = %w( sam@arahant.net )
|
7
|
+
s.homepage = 'http://github.com/nopedial/soak'
|
8
|
+
s.summary = 'soak'
|
9
|
+
s.description = 'just an arp sponge'
|
10
|
+
s.rubyforge_project = s.name
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.executables = %w( soakd )
|
13
|
+
s.require_path = 'lib'
|
14
|
+
|
15
|
+
s.required_ruby_version = '>= 1.9.3'
|
16
|
+
s.add_dependency 'asetus', '>= 0.1.2'
|
17
|
+
s.add_dependency 'logger', '>= 1.2.8'
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: soak
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Samer Abdel-Hafez
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-09-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: asetus
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.1.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: logger
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.2.8
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.2.8
|
46
|
+
description: just an arp sponge
|
47
|
+
email:
|
48
|
+
- sam@arahant.net
|
49
|
+
executables:
|
50
|
+
- soakd
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- Gemfile
|
55
|
+
- Gemfile.lock
|
56
|
+
- README.md
|
57
|
+
- Rakefile
|
58
|
+
- bin/soakd
|
59
|
+
- lib/soak.rb
|
60
|
+
- lib/soak/core.rb
|
61
|
+
- lib/soak/lookup.rb
|
62
|
+
- lib/soak/packet.rb
|
63
|
+
- soak.gemspec
|
64
|
+
homepage: http://github.com/nopedial/soak
|
65
|
+
licenses: []
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.9.3
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
none: false
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project: soak
|
84
|
+
rubygems_version: 1.8.23
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: soak
|
88
|
+
test_files: []
|