pio 0.6.0 → 0.7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +56 -22
- data/examples/dhcp_new.rb +22 -18
- data/examples/features_new.rb +14 -0
- data/examples/features_read.rb +4 -0
- data/features/arp_read.feature +4 -4
- data/features/dhcp_read.feature +2 -2
- data/features/echo_read.feature +5 -0
- data/features/features_read.feature +10 -0
- data/features/hello_read.feature +5 -0
- data/features/icmp_read.feature +2 -2
- data/features/lldp_read.feature +4 -4
- data/features/{pcap → packet_data}/arp-storm.pcap +0 -0
- data/features/{pcap → packet_data}/arp.pcap +0 -0
- data/features/{pcap → packet_data}/dhcp.pcap +0 -0
- data/features/packet_data/echo.raw +0 -0
- data/features/packet_data/features_reply.raw +0 -0
- data/features/packet_data/features_request.raw +0 -0
- data/features/packet_data/hello.raw +0 -0
- data/features/{pcap → packet_data}/icmp.pcap +0 -0
- data/features/{pcap → packet_data}/lldp.detailed.pcap +0 -0
- data/features/{pcap → packet_data}/lldp.minimal.pcap +0 -0
- data/features/step_definitions/packet_data_steps.rb +32 -0
- data/features/step_definitions/pending_steps.rb +5 -0
- data/lib/pio.rb +1 -0
- data/lib/pio/arp.rb +1 -1
- data/lib/pio/arp/{frame.rb → format.rb} +2 -2
- data/lib/pio/arp/message.rb +2 -2
- data/lib/pio/dhcp/dhcp_field.rb +3 -3
- data/lib/pio/dhcp/frame.rb +6 -6
- data/lib/pio/dhcp/optional_tlv.rb +3 -3
- data/lib/pio/echo.rb +4 -11
- data/lib/pio/echo/format.rb +5 -5
- data/lib/pio/echo/message.rb +13 -4
- data/lib/pio/echo/reply.rb +29 -0
- data/lib/pio/echo/request.rb +29 -0
- data/lib/pio/features.rb +18 -0
- data/lib/pio/features/format.rb +18 -0
- data/lib/pio/features/message.rb +14 -0
- data/lib/pio/features/reply.rb +73 -0
- data/lib/pio/features/request.rb +63 -0
- data/lib/pio/hello.rb +40 -9
- data/lib/pio/icmp.rb +1 -1
- data/lib/pio/icmp/{frame.rb → format.rb} +2 -2
- data/lib/pio/icmp/message.rb +2 -2
- data/lib/pio/icmp/request.rb +30 -14
- data/lib/pio/message_type_selector.rb +4 -7
- data/lib/pio/type/ethernet_header.rb +0 -2
- data/lib/pio/type/ipv4_header.rb +0 -1
- data/lib/pio/type/open_flow.rb +34 -0
- data/lib/pio/type/udp_header.rb +0 -1
- data/lib/pio/version.rb +1 -1
- data/pio.gemspec +2 -2
- data/spec/pio/dhcp/ack_spec.rb +1 -1
- data/spec/pio/dhcp_spec.rb +2 -2
- data/spec/pio/echo/reply_spec.rb +69 -4
- data/spec/pio/echo/request_spec.rb +48 -10
- data/spec/pio/echo_spec.rb +8 -0
- data/spec/pio/features/reply_spec.rb +30 -0
- data/spec/pio/features/request_spec.rb +70 -0
- data/spec/pio/features_spec.rb +78 -0
- data/spec/pio/hello_spec.rb +35 -6
- data/spec/spec_helper.rb +3 -0
- metadata +70 -40
- data/features/step_definitions/pcap_steps.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f5e9be92c12989ecc7bfe94c76a5db47bb5304e
|
4
|
+
data.tar.gz: dc6414ddb0c09cc48489295b5d4c746cfda522e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a5b3da4c83662a1d20002dde48e926c71becb41f22c8efc4151a7966dcc75566333c17cb9d6f14805741d521914bc98caf97c940c7add564a7fb676aec876ed9
|
7
|
+
data.tar.gz: 081cc576cb1481899bd8733462e914f7644ccd1e51138bece41ff93851f432c63c6c56f4872519d297366b9e8c1524d237d40eaeff06f3cd8ab27a92b4df1bac
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.7.0 (4/22/2014)
|
4
|
+
|
5
|
+
### New features
|
6
|
+
* Added new class `Pio::Features`, `Pio::Features::Request` and `Pio::Features::Reply`
|
7
|
+
|
8
|
+
### Changes
|
9
|
+
* Renamed `rake PCAP='foo.pcap' dump_pcap` => `rake PACKET_FILE='foo.pcap' dump`
|
10
|
+
|
11
|
+
|
3
12
|
## 0.6.0 (4/15/2014)
|
4
13
|
|
5
14
|
### New features
|
data/README.md
CHANGED
@@ -18,7 +18,8 @@ supports the following packet formats:
|
|
18
18
|
- DHCP
|
19
19
|
- OpenFlow 1.0
|
20
20
|
- Hello
|
21
|
-
- Echo
|
21
|
+
- Echo
|
22
|
+
- Features
|
22
23
|
- (…currently there are just a few formats supported but I'm sure this list will grow)
|
23
24
|
|
24
25
|
## Features Overview
|
@@ -132,33 +133,37 @@ Also you can use `Pio::Dhcp::Discover#new`,
|
|
132
133
|
|
133
134
|
require 'pio'
|
134
135
|
|
135
|
-
|
136
|
+
dhcp_client_mac_address = '24:db:ac:41:e5:5b'
|
137
|
+
|
138
|
+
dhcp_server_options =
|
139
|
+
{
|
140
|
+
source_mac: '00:26:82:eb:ea:d1',
|
141
|
+
destination_mac: '24:db:ac:41:e5:5b',
|
142
|
+
ip_source_address: '192.168.0.100',
|
143
|
+
ip_destination_address: '192.168.0.1'
|
144
|
+
}
|
145
|
+
|
146
|
+
# Client side
|
147
|
+
discover = Pio::Dhcp::Discover.new(source_mac: dhcp_client_mac_address)
|
136
148
|
discover.to_binary # => DHCP Discover frame in binary format
|
137
149
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
ip_source_address: '192.168.0.100',
|
142
|
-
ip_destination_address: '192.168.0.1',
|
143
|
-
transaction_id: discover.transaction_id
|
144
|
-
)
|
150
|
+
# Server side
|
151
|
+
offer = Pio::Dhcp::Offer.new(dhcp_server_options
|
152
|
+
.merge(transaction_id: discover.transaction_id))
|
145
153
|
offer.to_binary # => DHCP Offer frame in binary format
|
146
154
|
|
155
|
+
# Client side
|
147
156
|
request = Pio::Dhcp::Request.new(
|
148
|
-
source_mac:
|
149
|
-
server_identifier:
|
150
|
-
requested_ip_address:
|
157
|
+
source_mac: dhcp_client_mac_address,
|
158
|
+
server_identifier: dhcp_server_options[:ip_source_address],
|
159
|
+
requested_ip_address: dhcp_server_options[:ip_destination_address],
|
151
160
|
transaction_id: offer.transaction_id
|
152
161
|
)
|
153
162
|
request.to_binary # => DHCP Request frame in binary format
|
154
163
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
ip_source_address: '192.168.0.100',
|
159
|
-
ip_destination_address: '192.168.0.1',
|
160
|
-
transaction_id: request.transaction_id
|
161
|
-
)
|
164
|
+
# Server side
|
165
|
+
ack = Pio::Dhcp::Ack.new(dhcp_server_options
|
166
|
+
.merge(transaction_id: request.transaction_id))
|
162
167
|
ack.to_binary # => DHCP Ack frame in binary format
|
163
168
|
|
164
169
|
### Hello
|
@@ -179,10 +184,10 @@ below:
|
|
179
184
|
hello = Pio::Hello.new(transaction_id: 123)
|
180
185
|
hello.to_binary # => HELLO message in binary format.
|
181
186
|
|
182
|
-
|
187
|
+
### Echo
|
183
188
|
|
184
|
-
To parse an OpenFlow 1.0
|
185
|
-
and you can access each field of the parsed
|
189
|
+
To parse an OpenFlow 1.0 Echo message, use the API `Pio::Echo.read`
|
190
|
+
and you can access each field of the parsed Echo message.
|
186
191
|
|
187
192
|
require 'pio'
|
188
193
|
|
@@ -202,6 +207,35 @@ generate an Echo Request/Reply message like below:
|
|
202
207
|
reply = Pio::Echo::Reply.new(xid: request.xid)
|
203
208
|
reply.to_binary # => ECHO Reply message in binary format.
|
204
209
|
|
210
|
+
### Features
|
211
|
+
|
212
|
+
To parse an OpenFlow 1.0 Features message, use the API
|
213
|
+
`Pio::Features.read` and you can access each field of the parsed
|
214
|
+
Features message.
|
215
|
+
|
216
|
+
require 'pio'
|
217
|
+
|
218
|
+
features = Pio::Features.read(binary_data)
|
219
|
+
features.xid # => 123
|
220
|
+
|
221
|
+
Also you can use `Pio::Features::Request#new` or `Pio::Features::Reply#new` to
|
222
|
+
generate an Features Request/Reply message like below:
|
223
|
+
|
224
|
+
require 'pio'
|
225
|
+
|
226
|
+
request = Pio::Features::Request.new
|
227
|
+
request.to_binary # => Features Request message in binary format.
|
228
|
+
|
229
|
+
# The Features xid (transaction_id)
|
230
|
+
# should be same as that of the request.
|
231
|
+
reply = Pio::Features::Reply.new(xid: request.xid,
|
232
|
+
dpid: 0x123,
|
233
|
+
n_buffers: 0x100,
|
234
|
+
n_tables: 0xfe,
|
235
|
+
capabilities: 0xc7,
|
236
|
+
actions: 0xfff)
|
237
|
+
reply.to_binary # => Features Reply message in binary format.
|
238
|
+
|
205
239
|
## Installation
|
206
240
|
|
207
241
|
The simplest way to install Pio is to use [Bundler](http://gembundler.com/).
|
data/examples/dhcp_new.rb
CHANGED
@@ -1,30 +1,34 @@
|
|
1
1
|
require 'pio'
|
2
2
|
|
3
|
-
|
3
|
+
dhcp_client_mac_address = '24:db:ac:41:e5:5b'
|
4
|
+
|
5
|
+
dhcp_server_options =
|
6
|
+
{
|
7
|
+
source_mac: '00:26:82:eb:ea:d1',
|
8
|
+
destination_mac: '24:db:ac:41:e5:5b',
|
9
|
+
ip_source_address: '192.168.0.100',
|
10
|
+
ip_destination_address: '192.168.0.1'
|
11
|
+
}
|
12
|
+
|
13
|
+
# Client side
|
14
|
+
discover = Pio::Dhcp::Discover.new(source_mac: dhcp_client_mac_address)
|
4
15
|
discover.to_binary # => DHCP Discover frame in binary format
|
5
16
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
ip_source_address: '192.168.0.100',
|
10
|
-
ip_destination_address: '192.168.0.1',
|
11
|
-
transaction_id: discover.transaction_id
|
12
|
-
)
|
17
|
+
# Server side
|
18
|
+
offer = Pio::Dhcp::Offer.new(dhcp_server_options
|
19
|
+
.merge(transaction_id: discover.transaction_id))
|
13
20
|
offer.to_binary # => DHCP Offer frame in binary format
|
14
21
|
|
22
|
+
# Client side
|
15
23
|
request = Pio::Dhcp::Request.new(
|
16
|
-
source_mac:
|
17
|
-
server_identifier:
|
18
|
-
requested_ip_address:
|
24
|
+
source_mac: dhcp_client_mac_address,
|
25
|
+
server_identifier: dhcp_server_options[:ip_source_address],
|
26
|
+
requested_ip_address: dhcp_server_options[:ip_destination_address],
|
19
27
|
transaction_id: offer.transaction_id
|
20
28
|
)
|
21
29
|
request.to_binary # => DHCP Request frame in binary format
|
22
30
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
ip_source_address: '192.168.0.100',
|
27
|
-
ip_destination_address: '192.168.0.1',
|
28
|
-
transaction_id: request.transaction_id
|
29
|
-
)
|
31
|
+
# Server side
|
32
|
+
ack = Pio::Dhcp::Ack.new(dhcp_server_options
|
33
|
+
.merge(transaction_id: request.transaction_id))
|
30
34
|
ack.to_binary # => DHCP Ack frame in binary format
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'pio'
|
2
|
+
|
3
|
+
request = Pio::Features::Request.new
|
4
|
+
request.to_binary # => Features Request message in binary format.
|
5
|
+
|
6
|
+
# The Features xid (transaction_id)
|
7
|
+
# should be same as that of the request.
|
8
|
+
reply = Pio::Features::Reply.new(xid: request.xid,
|
9
|
+
dpid: 0x123,
|
10
|
+
n_buffers: 0x100,
|
11
|
+
n_tables: 0xfe,
|
12
|
+
capabilities: 0xc7,
|
13
|
+
actions: 0xfff)
|
14
|
+
reply.to_binary # => Features Reply message in binary format.
|
data/features/arp_read.feature
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
Feature: Pio::Arp.read
|
2
2
|
Scenario: arp.pcap
|
3
|
-
Given a
|
4
|
-
When I try to parse the
|
3
|
+
Given a packet data file "arp.pcap"
|
4
|
+
When I try to parse the file with "Arp" class
|
5
5
|
Then it should finish successfully
|
6
6
|
|
7
7
|
Scenario: arp-storm.pcap
|
8
|
-
Given a
|
9
|
-
When I try to parse the
|
8
|
+
Given a packet data file "arp-storm.pcap"
|
9
|
+
When I try to parse the file with "Arp" class
|
10
10
|
Then it should finish successfully
|
data/features/dhcp_read.feature
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Pio::Features.read
|
2
|
+
Scenario: features_request.raw
|
3
|
+
Given a packet data file "features_request.raw"
|
4
|
+
When I try to parse the file with "Features" class
|
5
|
+
Then it should finish successfully
|
6
|
+
|
7
|
+
Scenario: features_reply.raw
|
8
|
+
Given a packet data file "features_reply.raw"
|
9
|
+
When I try to parse the file with "Features" class
|
10
|
+
Then it should finish successfully
|
data/features/icmp_read.feature
CHANGED
data/features/lldp_read.feature
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
Feature: Pio::Lldp.read
|
2
2
|
Scenario: lldp.minimal.pcap
|
3
|
-
Given a
|
4
|
-
When I try to parse the
|
3
|
+
Given a packet data file "lldp.minimal.pcap"
|
4
|
+
When I try to parse the file with "Lldp" class
|
5
5
|
Then it should finish successfully
|
6
6
|
|
7
7
|
Scenario: lldp.detailed.pcap
|
8
|
-
Given a
|
9
|
-
When I try to parse the
|
8
|
+
Given a packet data file "lldp.detailed.pcap"
|
9
|
+
When I try to parse the file with "Lldp" class
|
10
10
|
Then it should finish successfully
|
File without changes
|
File without changes
|
File without changes
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
Given(/^a packet data file "(.*?)"$/) do |name|
|
4
|
+
path = File.expand_path(File.join(File.dirname(__FILE__),
|
5
|
+
'..', 'packet_data', name))
|
6
|
+
case File.extname(name)
|
7
|
+
when '.raw'
|
8
|
+
@raw = path
|
9
|
+
when '.pcap'
|
10
|
+
@pcap = path
|
11
|
+
else
|
12
|
+
fail "Unsupported file extension: #{name}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
When(/^I try to parse the file with "(.*?)" class$/) do |parser|
|
17
|
+
parser_klass = Pio.const_get(parser)
|
18
|
+
if @raw
|
19
|
+
parser_klass.read IO.read(@raw)
|
20
|
+
elsif @pcap
|
21
|
+
File.open(@pcap) do |file|
|
22
|
+
pcap = Pio::Pcap::Frame.read(file)
|
23
|
+
pcap.records.each { |each| parser_klass.read each.data }
|
24
|
+
end
|
25
|
+
else
|
26
|
+
fail 'Packet data file is not specified.'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Then(/^it should finish successfully$/) do
|
31
|
+
# Noop.
|
32
|
+
end
|
data/lib/pio.rb
CHANGED
data/lib/pio/arp.rb
CHANGED
data/lib/pio/arp/message.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'forwardable'
|
4
|
-
require 'pio/arp/
|
4
|
+
require 'pio/arp/format'
|
5
5
|
|
6
6
|
module Pio
|
7
7
|
class Arp
|
@@ -33,7 +33,7 @@ module Pio
|
|
33
33
|
|
34
34
|
def initialize(user_options)
|
35
35
|
options = self.class.const_get(:Options).new(user_options.dup.freeze)
|
36
|
-
@frame = Arp::
|
36
|
+
@frame = Arp::Format.new(options.to_hash)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
data/lib/pio/dhcp/dhcp_field.rb
CHANGED
@@ -40,9 +40,9 @@ module Pio
|
|
40
40
|
length: 128
|
41
41
|
uint32be :magic_cookie,
|
42
42
|
value: MAGIC_COOKIE
|
43
|
-
array
|
44
|
-
|
45
|
-
|
43
|
+
array :optional_tlvs,
|
44
|
+
type: :optional_tlv,
|
45
|
+
read_until: -> { element.end_of_dhcptlv? }
|
46
46
|
end
|
47
47
|
end
|
48
48
|
end
|
data/lib/pio/dhcp/frame.rb
CHANGED
@@ -26,12 +26,12 @@ module Pio
|
|
26
26
|
endian :big
|
27
27
|
|
28
28
|
ethernet_header ether_type: ETHER_TYPE_IP
|
29
|
-
ipv4_header
|
30
|
-
|
31
|
-
|
32
|
-
udp_header
|
33
|
-
|
34
|
-
dhcp_field
|
29
|
+
ipv4_header ip_protocol: IP_PROTOCOL_UDP,
|
30
|
+
ip_header_checksum: -> { ip_sum },
|
31
|
+
ip_total_length: -> { ip_len }
|
32
|
+
udp_header udp_length: -> { udp_len },
|
33
|
+
udp_checksum: -> { udp_sum }
|
34
|
+
dhcp_field :dhcp
|
35
35
|
|
36
36
|
def ip_sum
|
37
37
|
~((ip_csum & 0xffff) + (ip_csum >> 16)) & 0xffff
|
@@ -16,9 +16,9 @@ module Pio
|
|
16
16
|
bit8 :tlv_type
|
17
17
|
bit8 :tlv_info_length,
|
18
18
|
onlyif: -> { !(end_of_dhcpdu?) }
|
19
|
-
choice
|
20
|
-
|
21
|
-
|
19
|
+
choice :tlv_value,
|
20
|
+
onlyif: -> { !(end_of_dhcpdu?) },
|
21
|
+
selection: :chooser do
|
22
22
|
uint8 Dhcp::MESSAGE_TYPE_TLV
|
23
23
|
ip_address Dhcp::SERVER_IDENTIFIER_TLV
|
24
24
|
uint32be Dhcp::RENEWAL_TIME_VALUE_TLV
|