pio 0.1.1 → 0.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 42e4ddeb113721d1515042c5b21242f7f5f49f76
4
- data.tar.gz: 4d135571f99d94db9e3b0f534e8154669da4360d
3
+ metadata.gz: a99eb3c57f09bc9a82c53d916636509695770620
4
+ data.tar.gz: 5da352b9a4cbe2660ce0fc71e086f15c697f52b2
5
5
  SHA512:
6
- metadata.gz: bae38aa9d987cfd6965b4657222e8713dc4e019d655bcc4fc2b81c1bdee8fa03d5b9795324b8915290e56d78ae4b8b93584d071b0cc65ab921b64da47b7cb61c
7
- data.tar.gz: 0ff3e93fc9a7159807c3ed2bb01fb8ff045e948e34ee32a1956b6856fa9ec24c8734b2287bffd5fe77d66194e29c5e5d85f63db329495cfa480af23971e3bf9f
6
+ metadata.gz: 50e299558aea50ece6f430e007b428b9b5cc53439883043aca7128fe67ed3d08c50ec2e8ffac4f5d115735e77eb09289d25a249ee22f812edfbca2f91289aacc
7
+ data.tar.gz: b01bab2207f6556d2ca45ff72281c1475195511767d64b6b4847100961ada881b3406aeee2cd068d6998881f08d07dc026ca6c991a594a87d84aa2e722dd419e
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format Fuubar
2
+ --color
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" if RUBY_VERSION < "1.9.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/lib/pio/#{m[1]}_spec.rb" }
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
- * [LLDP](http://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol)
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: to parse an LLDP frame for example, use the
34
- API `Pio::Lldp.read` and you can access each field of the parsed LLDP
35
- frame.
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 ) # dpid and port_number
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 do | task |
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 = true
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
- raise "#{ bad_methods.size } methods have a flog complexity > #{ threshold }"
54
+ $stderr.puts "#{ bad_methods.size } methods have a flog complexity > #{ threshold }"
73
55
  end
74
56
  end
75
57
 
@@ -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:
@@ -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: