pio 0.1.1 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Gemfile +3 -2
- data/Guardfile +4 -1
- data/README.md +44 -6
- data/Rakefile +5 -23
- data/lib/pio.rb +15 -0
- data/lib/pio/arp.rb +31 -0
- data/lib/pio/arp/frame.rb +38 -0
- data/lib/pio/arp/message.rb +66 -0
- data/lib/pio/arp/reply.rb +55 -0
- data/lib/pio/arp/request.rb +55 -0
- data/lib/pio/ip.rb +90 -0
- data/lib/pio/lldp.rb +74 -12
- data/lib/pio/lldp/frame.rb +53 -4
- data/lib/pio/lldp/management-address-value.rb +7 -1
- data/lib/pio/lldp/optional-tlv.rb +3 -1
- data/lib/pio/lldp/organizationally-specific-value.rb +23 -0
- data/lib/pio/mac.rb +156 -0
- data/lib/pio/type/ethernet-header.rb +16 -0
- data/lib/pio/type/ip-address.rb +28 -0
- data/lib/pio/{lldp → type}/mac-address.rb +4 -3
- data/lib/pio/version.rb +1 -19
- data/pio.org +518 -0
- data/pio.org_archive +389 -0
- data/spec/pio/arp/reply_spec.rb +150 -0
- data/spec/pio/arp/request_spec.rb +131 -0
- data/spec/pio/arp_spec.rb +136 -0
- data/spec/pio/ip_spec.rb +38 -0
- data/spec/pio/lldp_spec.rb +195 -38
- data/spec/pio/mac_spec.rb +82 -0
- data/spec/spec_helper.rb +9 -0
- metadata +27 -17
- data/spec/pio/lldp/chassis-id-tlv_spec.rb +0 -27
- data/spec/pio/lldp/end-of-lldpdu-value_spec.rb +0 -20
- data/spec/pio/lldp/frame_spec.rb +0 -82
- data/spec/pio/lldp/mac-address_spec.rb +0 -20
- data/spec/pio/lldp/optional-tlv_spec.rb +0 -81
- data/spec/pio/lldp/port-id-tlv_spec.rb +0 -27
- data/spec/pio/lldp/ttl-tlv_spec.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a99eb3c57f09bc9a82c53d916636509695770620
|
4
|
+
data.tar.gz: 5da352b9a4cbe2660ce0fc71e086f15c697f52b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50e299558aea50ece6f430e007b428b9b5cc53439883043aca7128fe67ed3d08c50ec2e8ffac4f5d115735e77eb09289d25a249ee22f812edfbca2f91289aacc
|
7
|
+
data.tar.gz: b01bab2207f6556d2ca45ff72281c1475195511767d64b6b4847100961ada881b3406aeee2cd068d6998881f08d07dc026ca6c991a594a87d84aa2e722dd419e
|
data/.rspec
ADDED
data/Gemfile
CHANGED
@@ -4,14 +4,15 @@ source "https://rubygems.org"
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
|
7
|
-
group :development do
|
7
|
+
group :development, :test do
|
8
8
|
gem "coveralls", "~> 0.6.7", :require => false
|
9
9
|
gem "flay", "~> 2.4.0"
|
10
10
|
gem "flog", "~> 4.1.1"
|
11
|
+
gem "fuubar", "~> 1.2.1"
|
11
12
|
gem "guard", "~> 1.8.2"
|
12
13
|
gem "guard-bundler", "~> 1.0.0"
|
13
14
|
gem "guard-rspec", "~> 3.0.2"
|
14
|
-
gem "json", "~> 1.8.0"
|
15
|
+
gem "json", "~> 1.8.0"
|
15
16
|
gem "rake", "~> 10.1.0"
|
16
17
|
gem "rb-fchange", "~> 0.0.6", :require => false
|
17
18
|
gem "rb-fsevent", "~> 0.9.3", :require => false
|
data/Guardfile
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
+
notification :terminal_notifier
|
5
|
+
notification :tmux, :display_message => true
|
6
|
+
|
4
7
|
|
5
8
|
guard 'bundler' do
|
6
9
|
watch('Gemfile')
|
@@ -11,6 +14,6 @@ end
|
|
11
14
|
|
12
15
|
guard :rspec do
|
13
16
|
watch(%r{^spec/pio/.+_spec\.rb$})
|
14
|
-
watch(%r{^lib/pio/(.+)\.rb$}) { |m| "spec/
|
17
|
+
watch(%r{^lib/pio/(.+)\.rb$}) { |m| "spec/pio/#{m[1]}_spec.rb" }
|
15
18
|
watch('spec/spec_helper.rb') { "spec" }
|
16
19
|
end
|
data/README.md
CHANGED
@@ -10,7 +10,8 @@ Pio
|
|
10
10
|
|
11
11
|
Pio is a ruby gem to easily parse and generate network packets. It supports the following packet formats:
|
12
12
|
|
13
|
-
*
|
13
|
+
* ARP
|
14
|
+
* LLDP
|
14
15
|
* (...currently there are just a few formats supported but I'm sure this list will grow)
|
15
16
|
|
16
17
|
|
@@ -25,14 +26,51 @@ Features Overview
|
|
25
26
|
* Clean Code. Pio is built on
|
26
27
|
[BinData](https://github.com/dmendel/bindata)'s declarative binary
|
27
28
|
format DSL so that it is easy to read and debug by human beings.
|
28
|
-
|
29
|
+
|
29
30
|
|
30
31
|
Example
|
31
32
|
-------
|
32
33
|
|
33
|
-
Its usage is dead simple
|
34
|
-
|
35
|
-
|
34
|
+
Its usage is dead simple.
|
35
|
+
|
36
|
+
### ARP
|
37
|
+
|
38
|
+
To parse an ARP frame, use the API `Pio::Arp.read` and you can access
|
39
|
+
each field of the parsed ARP frame.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
require "pio"
|
43
|
+
|
44
|
+
arp = Pio::Arp.read( binary_data )
|
45
|
+
arp.source_mac.to_s #=> "00:26:82:eb:ea:d1"
|
46
|
+
```
|
47
|
+
|
48
|
+
Also you can use `Pio::Arp::Request#new` or `Pio::Arp::Reply#new` to
|
49
|
+
generate an Arp Request/Reply frame like below:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
require "pio"
|
53
|
+
|
54
|
+
request = Pio::Arp::Request.new(
|
55
|
+
source_mac: "00:26:82:eb:ea:d1",
|
56
|
+
sender_protocol_address: "192.168.83.3",
|
57
|
+
target_protocol_address: "192.168.83.254"
|
58
|
+
)
|
59
|
+
request.to_binary #=> Arp Request frame in binary format.
|
60
|
+
|
61
|
+
reply = Pio::Arp::Reply.new(
|
62
|
+
source_mac: "00:26:82:eb:ea:d1",
|
63
|
+
destination_mac: "00:26:82:eb:ea:d1",
|
64
|
+
sender_protocol_address: "192.168.83.3",
|
65
|
+
target_protocol_address: "192.168.83.254"
|
66
|
+
)
|
67
|
+
reply.to_binary #=> Arp Reply frame in binary format.
|
68
|
+
```
|
69
|
+
|
70
|
+
### LLDP
|
71
|
+
|
72
|
+
To parse an LLDP frame, use the API `Pio::Lldp.read` and you can
|
73
|
+
access each field of the parsed LLDP frame.
|
36
74
|
|
37
75
|
```ruby
|
38
76
|
require "pio"
|
@@ -46,7 +84,7 @@ Also you can use `Pio::Lldp#new` to generate an LLDP frame like below:
|
|
46
84
|
```ruby
|
47
85
|
require "pio"
|
48
86
|
|
49
|
-
lldp = Pio::Lldp.new( 0x123, 12 )
|
87
|
+
lldp = Pio::Lldp.new( dpid: 0x123, port_number: 12 )
|
50
88
|
lldp.to_binary #=> LLDP frame in binary format.
|
51
89
|
```
|
52
90
|
|
data/Rakefile
CHANGED
@@ -1,21 +1,3 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (C) 2013 NEC Corporation
|
3
|
-
#
|
4
|
-
# This program is free software; you can redistribute it and/or modify
|
5
|
-
# it under the terms of the GNU General Public License, version 3, as
|
6
|
-
# published by the Free Software Foundation.
|
7
|
-
#
|
8
|
-
# This program is distributed in the hope that it will be useful,
|
9
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
-
# GNU General Public License for more details.
|
12
|
-
#
|
13
|
-
# You should have received a copy of the GNU General Public License along
|
14
|
-
# with this program; if not, write to the Free Software Foundation, Inc.,
|
15
|
-
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
1
|
require "bundler/gem_tasks"
|
20
2
|
require "coveralls/rake/task"
|
21
3
|
require "flay"
|
@@ -34,19 +16,19 @@ $ruby_source = FileList[ "lib/**/*.rb" ]
|
|
34
16
|
|
35
17
|
task :default => :travis
|
36
18
|
task :travis => [ :spec, :quality, "coveralls:push" ]
|
19
|
+
|
20
|
+
desc "Check for code quality"
|
37
21
|
task :quality => [ :reek, :flog, :flay ]
|
38
22
|
|
39
23
|
|
40
24
|
Coveralls::RakeTask.new
|
41
25
|
|
42
26
|
|
43
|
-
RSpec::Core::RakeTask.new
|
44
|
-
task.rspec_opts = "--format documentation --color"
|
45
|
-
end
|
27
|
+
RSpec::Core::RakeTask.new
|
46
28
|
|
47
29
|
|
48
30
|
Reek::Rake::Task.new do | t |
|
49
|
-
t.fail_on_error =
|
31
|
+
t.fail_on_error = false
|
50
32
|
t.verbose = false
|
51
33
|
t.ruby_opts = [ "-rubygems" ]
|
52
34
|
t.reek_opts = "--quiet"
|
@@ -69,7 +51,7 @@ task :flog do
|
|
69
51
|
puts "%8.1f: %s" % [ score, name ]
|
70
52
|
end
|
71
53
|
unless bad_methods.empty?
|
72
|
-
|
54
|
+
$stderr.puts "#{ bad_methods.size } methods have a flog complexity > #{ threshold }"
|
73
55
|
end
|
74
56
|
end
|
75
57
|
|
data/lib/pio.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "pio/arp"
|
2
|
+
require "pio/lldp"
|
3
|
+
|
4
|
+
|
5
|
+
module Pio
|
6
|
+
# Raised when the packet data is in wrong format.
|
7
|
+
class ParseError < StandardError; end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
### Local variables:
|
12
|
+
### mode: Ruby
|
13
|
+
### coding: utf-8-unix
|
14
|
+
### indent-tabs-mode: nil
|
15
|
+
### End:
|
data/lib/pio/arp.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "bindata"
|
3
|
+
|
4
|
+
require "pio/arp/request"
|
5
|
+
require "pio/arp/reply"
|
6
|
+
|
7
|
+
|
8
|
+
module Pio
|
9
|
+
# ARP parser and generator.
|
10
|
+
class Arp
|
11
|
+
ARP_MESSAGE_TYPE = { Request::OPERATION => Request, Reply::OPERATION => Reply }
|
12
|
+
|
13
|
+
|
14
|
+
def self.read( raw_data )
|
15
|
+
begin
|
16
|
+
frame = Arp::Frame.read( raw_data )
|
17
|
+
rescue
|
18
|
+
raise Pio::ParseError, $!.message
|
19
|
+
end
|
20
|
+
|
21
|
+
ARP_MESSAGE_TYPE[ frame.operation ].create_from frame
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
### Local variables:
|
28
|
+
### mode: Ruby
|
29
|
+
### coding: utf-8-unix
|
30
|
+
### indent-tabs-mode: nil
|
31
|
+
### End:
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "pio/type/ethernet-header"
|
2
|
+
require "pio/type/ip-address"
|
3
|
+
require "pio/type/mac-address"
|
4
|
+
|
5
|
+
|
6
|
+
module Pio
|
7
|
+
class Arp
|
8
|
+
# ARP frame parser.
|
9
|
+
class Frame < BinData::Record
|
10
|
+
extend Type::EthernetHeader
|
11
|
+
|
12
|
+
endian :big
|
13
|
+
|
14
|
+
ethernet_header :ether_type => 0x0806
|
15
|
+
uint16 :hardware_type, :value => 1
|
16
|
+
uint16 :protocol_type, :value => 0x0800
|
17
|
+
uint8 :hardware_length, :value => 6
|
18
|
+
uint8 :protocol_length, :value => 4
|
19
|
+
uint16 :operation
|
20
|
+
mac_address :sender_hardware_address
|
21
|
+
ip_address :sender_protocol_address
|
22
|
+
mac_address :target_hardware_address
|
23
|
+
ip_address :target_protocol_address
|
24
|
+
|
25
|
+
|
26
|
+
def to_binary
|
27
|
+
to_binary_s + "\000" * ( 64 - num_bytes )
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
### Local variables:
|
35
|
+
### mode: Ruby
|
36
|
+
### coding: utf-8-unix
|
37
|
+
### indent-tabs-mode: nil
|
38
|
+
### End:
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require "pio/arp/frame"
|
2
|
+
require "forwardable"
|
3
|
+
|
4
|
+
|
5
|
+
module Pio
|
6
|
+
class Arp
|
7
|
+
# Base class of ARP Request and Reply
|
8
|
+
class Message
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
|
12
|
+
def self.create_from frame
|
13
|
+
message = allocate
|
14
|
+
message.instance_variable_set :@frame, frame
|
15
|
+
message
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def initialize options
|
20
|
+
@options = options
|
21
|
+
@frame = Arp::Frame.new( option_hash )
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def_delegators :@frame, :destination_mac
|
26
|
+
def_delegators :@frame, :source_mac
|
27
|
+
def_delegators :@frame, :ether_type
|
28
|
+
def_delegators :@frame, :hardware_type
|
29
|
+
def_delegators :@frame, :protocol_type
|
30
|
+
def_delegators :@frame, :hardware_length
|
31
|
+
def_delegators :@frame, :protocol_length
|
32
|
+
def_delegators :@frame, :operation
|
33
|
+
def_delegators :@frame, :sender_hardware_address
|
34
|
+
def_delegators :@frame, :sender_protocol_address
|
35
|
+
def_delegators :@frame, :target_hardware_address
|
36
|
+
def_delegators :@frame, :target_protocol_address
|
37
|
+
def_delegators :@frame, :to_binary
|
38
|
+
|
39
|
+
|
40
|
+
##########################################################################
|
41
|
+
private
|
42
|
+
##########################################################################
|
43
|
+
|
44
|
+
|
45
|
+
def option_hash
|
46
|
+
mandatory_options.inject( {} ) do | opt, each |
|
47
|
+
klass = option_to_klass[ each ]
|
48
|
+
opt_pair = { each => klass.new( user_options[ each ] ).to_a }
|
49
|
+
opt.merge opt_pair
|
50
|
+
end.merge default_options
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def option_to_klass
|
55
|
+
{
|
56
|
+
:source_mac => Mac,
|
57
|
+
:destination_mac => Mac,
|
58
|
+
:sender_hardware_address => Mac,
|
59
|
+
:target_hardware_address => Mac,
|
60
|
+
:sender_protocol_address => IP,
|
61
|
+
:target_protocol_address => IP,
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "forwardable"
|
2
|
+
require "pio/arp/message"
|
3
|
+
require "pio/ip"
|
4
|
+
require "pio/mac"
|
5
|
+
|
6
|
+
|
7
|
+
module Pio
|
8
|
+
class Arp
|
9
|
+
# ARP Reply packet generator
|
10
|
+
class Reply < Message
|
11
|
+
OPERATION = 2
|
12
|
+
|
13
|
+
|
14
|
+
##########################################################################
|
15
|
+
private
|
16
|
+
##########################################################################
|
17
|
+
|
18
|
+
|
19
|
+
def default_options
|
20
|
+
{
|
21
|
+
:operation => OPERATION,
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def user_options
|
27
|
+
@options.merge(
|
28
|
+
{
|
29
|
+
:sender_hardware_address => @options[ :source_mac ],
|
30
|
+
:target_hardware_address => @options[ :destination_mac ]
|
31
|
+
}
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def mandatory_options
|
37
|
+
[
|
38
|
+
:source_mac,
|
39
|
+
:destination_mac,
|
40
|
+
:sender_hardware_address,
|
41
|
+
:target_hardware_address,
|
42
|
+
:sender_protocol_address,
|
43
|
+
:target_protocol_address,
|
44
|
+
]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
### Local variables:
|
52
|
+
### mode: Ruby
|
53
|
+
### coding: utf-8-unix
|
54
|
+
### indent-tabs-mode: nil
|
55
|
+
### End:
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "pio/arp/frame"
|
2
|
+
require "pio/arp/message"
|
3
|
+
require "pio/ip"
|
4
|
+
require "pio/mac"
|
5
|
+
|
6
|
+
|
7
|
+
module Pio
|
8
|
+
class Arp
|
9
|
+
# ARP Request packet generator
|
10
|
+
class Request < Message
|
11
|
+
OPERATION = 1
|
12
|
+
|
13
|
+
BROADCAST_MAC_ADDRESS = Mac.new( 0xffffffffffff ).to_a
|
14
|
+
ALL_ZERO_MAC_ADDRESS = Mac.new( 0 ).to_a
|
15
|
+
|
16
|
+
|
17
|
+
########################################################################
|
18
|
+
private
|
19
|
+
########################################################################
|
20
|
+
|
21
|
+
|
22
|
+
def default_options
|
23
|
+
{
|
24
|
+
:operation => OPERATION,
|
25
|
+
:destination_mac => BROADCAST_MAC_ADDRESS,
|
26
|
+
:target_hardware_address => ALL_ZERO_MAC_ADDRESS
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def user_options
|
32
|
+
@options.merge(
|
33
|
+
{ :sender_hardware_address => @options[ :source_mac ] }
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def mandatory_options
|
39
|
+
[
|
40
|
+
:source_mac,
|
41
|
+
:sender_hardware_address,
|
42
|
+
:sender_protocol_address,
|
43
|
+
:target_protocol_address,
|
44
|
+
]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
### Local variables:
|
52
|
+
### mode: Ruby
|
53
|
+
### coding: utf-8-unix
|
54
|
+
### indent-tabs-mode: nil
|
55
|
+
### End:
|