pio 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +46 -12
- data/README.md +131 -116
- data/Rakefile +7 -92
- data/examples/arp_new.rb +16 -0
- data/examples/arp_read.rb +4 -0
- data/examples/dhcp_new.rb +30 -0
- data/examples/dhcp_read.rb +4 -0
- data/examples/icmp_new.rb +21 -0
- data/examples/icmp_read.rb +4 -0
- data/examples/lldp_new.rb +4 -0
- data/examples/lldp_read.rb +4 -0
- data/lib/pio.rb +6 -12
- data/lib/pio/arp.rb +7 -19
- data/lib/pio/arp/frame.rb +8 -12
- data/lib/pio/arp/message.rb +12 -25
- data/lib/pio/arp/reply.rb +30 -30
- data/lib/pio/arp/request.rb +30 -29
- data/lib/pio/dhcp.rb +58 -0
- data/lib/pio/dhcp/ack.rb +12 -0
- data/lib/pio/dhcp/boot_reply.rb +16 -0
- data/lib/pio/dhcp/boot_reply_options.rb +75 -0
- data/lib/pio/dhcp/boot_request.rb +16 -0
- data/lib/pio/dhcp/boot_request_options.rb +69 -0
- data/lib/pio/dhcp/common_options.rb +71 -0
- data/lib/pio/dhcp/csum_util.rb +83 -0
- data/lib/pio/dhcp/dhcp_field.rb +48 -0
- data/lib/pio/dhcp/dhcp_tlv_options.rb +84 -0
- data/lib/pio/dhcp/discover.rb +12 -0
- data/lib/pio/dhcp/field_util.rb +102 -0
- data/lib/pio/dhcp/frame.rb +95 -0
- data/lib/pio/dhcp/message.rb +79 -0
- data/lib/pio/dhcp/offer.rb +12 -0
- data/lib/pio/dhcp/optional_tlv.rb +74 -0
- data/lib/pio/dhcp/request.rb +12 -0
- data/lib/pio/dhcp/type/dhcp_client_id.rb +21 -0
- data/lib/pio/dhcp/type/dhcp_param_list.rb +22 -0
- data/lib/pio/dhcp/type/dhcp_string.rb +21 -0
- data/lib/pio/icmp.rb +7 -18
- data/lib/pio/icmp/frame.rb +38 -40
- data/lib/pio/icmp/message.rb +10 -61
- data/lib/pio/icmp/options.rb +25 -0
- data/lib/pio/icmp/reply.rb +34 -7
- data/lib/pio/icmp/request.rb +43 -7
- data/lib/pio/ipv4_address.rb +5 -8
- data/lib/pio/lldp.rb +22 -62
- data/lib/pio/lldp/chassis_id_tlv.rb +7 -13
- data/lib/pio/lldp/end_of_lldpdu_value.rb +3 -9
- data/lib/pio/lldp/frame.rb +6 -12
- data/lib/pio/lldp/management_address_value.rb +4 -10
- data/lib/pio/lldp/optional_tlv.rb +5 -10
- data/lib/pio/lldp/options.rb +37 -0
- data/lib/pio/lldp/organizationally_specific_value.rb +2 -8
- data/lib/pio/lldp/port_description_value.rb +2 -8
- data/lib/pio/lldp/port_id_tlv.rb +6 -12
- data/lib/pio/lldp/system_capabilities_value.rb +2 -8
- data/lib/pio/lldp/system_description_value.rb +2 -8
- data/lib/pio/lldp/system_name_value.rb +2 -8
- data/lib/pio/lldp/ttl_tlv.rb +5 -11
- data/lib/pio/mac.rb +4 -9
- data/lib/pio/message_type_selector.rb +22 -0
- data/lib/pio/options.rb +65 -0
- data/lib/pio/parse_error.rb +6 -0
- data/lib/pio/type/ethernet_header.rb +3 -2
- data/lib/pio/type/ip_address.rb +4 -9
- data/lib/pio/type/ipv4_header.rb +12 -17
- data/lib/pio/type/mac_address.rb +5 -10
- data/lib/pio/type/udp_header.rb +18 -0
- data/lib/pio/version.rb +3 -8
- data/pio.gemspec +12 -10
- data/spec/pio/arp/reply/options_spec.rb +145 -0
- data/spec/pio/arp/reply_spec.rb +77 -113
- data/spec/pio/arp/request/options_spec.rb +115 -0
- data/spec/pio/arp/request_spec.rb +74 -96
- data/spec/pio/arp_spec.rb +71 -105
- data/spec/pio/dhcp/ack_spec.rb +189 -0
- data/spec/pio/dhcp/discover_spec.rb +165 -0
- data/spec/pio/dhcp/offer_spec.rb +189 -0
- data/spec/pio/dhcp/request_spec.rb +173 -0
- data/spec/pio/dhcp_spec.rb +609 -0
- data/spec/pio/icmp/reply_spec.rb +102 -95
- data/spec/pio/icmp/request_spec.rb +86 -78
- data/spec/pio/icmp_spec.rb +153 -146
- data/spec/pio/ipv4_address_spec.rb +2 -7
- data/spec/pio/lldp/options_spec.rb +188 -0
- data/spec/pio/lldp_spec.rb +181 -208
- data/spec/pio/mac_spec.rb +3 -8
- data/spec/spec_helper.rb +4 -10
- metadata +69 -17
- data/.gitignore +0 -20
- data/.rspec +0 -3
- data/.rubocop.yml +0 -1
- data/.travis.yml +0 -13
- data/Gemfile +0 -37
- data/Guardfile +0 -24
- data/lib/pio/message_util.rb +0 -19
- data/lib/pio/type/config.reek +0 -4
- data/lib/pio/util.rb +0 -21
- data/pio.org +0 -668
- data/pio.org_archive +0 -943
- data/rubocop-todo.yml +0 -9
data/examples/arp_new.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'pio'
|
2
|
+
|
3
|
+
request = Pio::Arp::Request.new(
|
4
|
+
source_mac: '00:26:82:eb:ea:d1',
|
5
|
+
sender_protocol_address: '192.168.83.3',
|
6
|
+
target_protocol_address: '192.168.83.254'
|
7
|
+
)
|
8
|
+
request.to_binary # => Arp Request frame in binary format.
|
9
|
+
|
10
|
+
reply = Pio::Arp::Reply.new(
|
11
|
+
source_mac: '00:16:9d:1d:9c:c4',
|
12
|
+
destination_mac: '00:26:82:eb:ea:d1',
|
13
|
+
sender_protocol_address: '192.168.83.254',
|
14
|
+
target_protocol_address: '192.168.83.3'
|
15
|
+
)
|
16
|
+
reply.to_binary # => Arp Reply frame in binary format.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'pio'
|
2
|
+
|
3
|
+
discover = Pio::Dhcp::Discover.new(source_mac: '24:db:ac:41:e5:5b')
|
4
|
+
discover.to_binary # => DHCP Discover frame in binary format
|
5
|
+
|
6
|
+
offer = Pio::Dhcp::Offer.new(
|
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
|
+
transaction_id: discover.transaction_id
|
12
|
+
)
|
13
|
+
offer.to_binary # => DHCP Offer frame in binary format
|
14
|
+
|
15
|
+
request = Pio::Dhcp::Request.new(
|
16
|
+
source_mac: '24:db:ac:41:e5:5b',
|
17
|
+
server_identifier: '192.168.0.100',
|
18
|
+
requested_ip_address: '192.168.0.1',
|
19
|
+
transaction_id: offer.transaction_id
|
20
|
+
)
|
21
|
+
request.to_binary # => DHCP Request frame in binary format
|
22
|
+
|
23
|
+
ack = Pio::Dhcp::Ack.new(
|
24
|
+
source_mac: '00:26:82:eb:ea:d1',
|
25
|
+
destination_mac: '24:db:ac:41:e5:5b',
|
26
|
+
ip_source_address: '192.168.0.100',
|
27
|
+
ip_destination_address: '192.168.0.1',
|
28
|
+
transaction_id: request.transaction_id
|
29
|
+
)
|
30
|
+
ack.to_binary # => DHCP Ack frame in binary format
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'pio'
|
2
|
+
|
3
|
+
request = Pio::Icmp::Request.new(
|
4
|
+
source_mac: '00:16:9d:1d:9c:c4',
|
5
|
+
destination_mac: '00:26:82:eb:ea:d1',
|
6
|
+
ip_source_address: '192.168.83.3',
|
7
|
+
ip_destination_address: '192.168.83.254'
|
8
|
+
)
|
9
|
+
request.to_binary # => ICMP Request frame in binary format.
|
10
|
+
|
11
|
+
reply = Pio::Icmp::Reply.new(
|
12
|
+
source_mac: '00:26:82:eb:ea:d1',
|
13
|
+
destination_mac: '00:16:9d:1d:9c:c4',
|
14
|
+
ip_source_address: '192.168.83.254',
|
15
|
+
ip_destination_address: '192.168.83.3',
|
16
|
+
# The ICMP Identifier and the ICMP Sequence number
|
17
|
+
# should be same as those of the request.
|
18
|
+
identifier: request.icmp_identifier,
|
19
|
+
sequence_number: request.icmp_sequence_number
|
20
|
+
)
|
21
|
+
reply.to_binary # => ICMP Reply frame in binary format.
|
data/lib/pio.rb
CHANGED
@@ -1,15 +1,9 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'pio/parse_error'
|
4
|
+
|
2
5
|
require 'pio/arp'
|
3
6
|
require 'pio/lldp'
|
4
7
|
require 'pio/icmp'
|
5
|
-
|
6
|
-
|
7
|
-
# Raised when the packet data is in wrong format.
|
8
|
-
class ParseError < StandardError; end
|
9
|
-
end
|
10
|
-
|
11
|
-
### Local variables:
|
12
|
-
### mode: Ruby
|
13
|
-
### coding: utf-8-unix
|
14
|
-
### indent-tabs-mode: nil
|
15
|
-
### End:
|
8
|
+
require 'pio/mac'
|
9
|
+
require 'pio/dhcp'
|
data/lib/pio/arp.rb
CHANGED
@@ -1,28 +1,16 @@
|
|
1
|
-
#
|
2
|
-
require 'English'
|
3
|
-
require 'rubygems'
|
4
|
-
require 'bindata'
|
1
|
+
# encoding: utf-8
|
5
2
|
|
3
|
+
require 'pio/arp/frame'
|
6
4
|
require 'pio/arp/request'
|
7
5
|
require 'pio/arp/reply'
|
8
|
-
require 'pio/
|
6
|
+
require 'pio/message_type_selector'
|
9
7
|
|
8
|
+
# Packet parser and generator library.
|
10
9
|
module Pio
|
11
10
|
# ARP parser and generator.
|
12
|
-
|
13
11
|
class Arp
|
14
|
-
|
15
|
-
|
16
|
-
Reply::OPERATION => Reply
|
17
|
-
}
|
18
|
-
class << self
|
19
|
-
include Util
|
20
|
-
end
|
12
|
+
extend MessageTypeSelector
|
13
|
+
message_type Request::OPERATION => Request, Reply::OPERATION => Reply
|
21
14
|
end
|
15
|
+
ARP = Arp
|
22
16
|
end
|
23
|
-
|
24
|
-
### Local variables:
|
25
|
-
### mode: Ruby
|
26
|
-
### coding: utf-8-unix
|
27
|
-
### indent-tabs-mode: nil
|
28
|
-
### End:
|
data/lib/pio/arp/frame.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'bindata'
|
2
4
|
require 'pio/type/ethernet_header'
|
3
5
|
require 'pio/type/ip_address'
|
4
6
|
require 'pio/type/mac_address'
|
@@ -11,11 +13,11 @@ module Pio
|
|
11
13
|
|
12
14
|
endian :big
|
13
15
|
|
14
|
-
ethernet_header :
|
15
|
-
uint16 :hardware_type, :
|
16
|
-
uint16 :protocol_type, :
|
17
|
-
uint8 :hardware_length, :
|
18
|
-
uint8 :protocol_length, :
|
16
|
+
ethernet_header ether_type: 0x0806
|
17
|
+
uint16 :hardware_type, value: 1
|
18
|
+
uint16 :protocol_type, value: 0x0800
|
19
|
+
uint8 :hardware_length, value: 6
|
20
|
+
uint8 :protocol_length, value: 4
|
19
21
|
uint16 :operation
|
20
22
|
mac_address :sender_hardware_address
|
21
23
|
ip_address :sender_protocol_address
|
@@ -32,9 +34,3 @@ module Pio
|
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
35
|
-
|
36
|
-
### Local variables:
|
37
|
-
### mode: Ruby
|
38
|
-
### coding: utf-8-unix
|
39
|
-
### indent-tabs-mode: nil
|
40
|
-
### End:
|
data/lib/pio/arp/message.rb
CHANGED
@@ -1,26 +1,13 @@
|
|
1
|
-
#
|
1
|
+
# encoding: utf-8
|
2
|
+
|
2
3
|
require 'forwardable'
|
3
4
|
require 'pio/arp/frame'
|
4
|
-
require 'pio/ipv4_address'
|
5
|
-
require 'pio/message_util'
|
6
5
|
|
7
6
|
module Pio
|
8
7
|
class Arp
|
9
8
|
# Base class of ARP Request and Reply
|
10
9
|
class Message
|
11
10
|
extend Forwardable
|
12
|
-
include MessageUtil
|
13
|
-
|
14
|
-
def self.create_from(frame)
|
15
|
-
message = allocate
|
16
|
-
message.instance_variable_set :@frame, frame
|
17
|
-
message
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize(options)
|
21
|
-
@options = options
|
22
|
-
@frame = Arp::Frame.new(option_hash)
|
23
|
-
end
|
24
11
|
|
25
12
|
def_delegators :@frame, :destination_mac
|
26
13
|
def_delegators :@frame, :source_mac
|
@@ -36,17 +23,17 @@ module Pio
|
|
36
23
|
def_delegators :@frame, :target_protocol_address
|
37
24
|
def_delegators :@frame, :to_binary
|
38
25
|
|
39
|
-
|
26
|
+
def self.create_from(frame)
|
27
|
+
message = allocate
|
28
|
+
message.instance_variable_set :@frame, frame
|
29
|
+
message
|
30
|
+
end
|
31
|
+
|
32
|
+
private_class_method :new
|
40
33
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
:destination_mac => Mac,
|
45
|
-
:sender_hardware_address => Mac,
|
46
|
-
:target_hardware_address => Mac,
|
47
|
-
:sender_protocol_address => IPv4Address,
|
48
|
-
:target_protocol_address => IPv4Address,
|
49
|
-
}
|
34
|
+
def initialize(user_options)
|
35
|
+
options = self.class.const_get(:Options).new(user_options.dup.freeze)
|
36
|
+
@frame = Arp::Frame.new(options.to_hash)
|
50
37
|
end
|
51
38
|
end
|
52
39
|
end
|
data/lib/pio/arp/reply.rb
CHANGED
@@ -1,45 +1,45 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
3
|
require 'pio/arp/message'
|
4
4
|
require 'pio/mac'
|
5
|
+
require 'pio/options'
|
5
6
|
|
6
7
|
module Pio
|
7
8
|
class Arp
|
8
9
|
# ARP Reply packet generator
|
9
10
|
class Reply < Message
|
10
11
|
OPERATION = 2
|
12
|
+
public_class_method :new
|
11
13
|
|
12
|
-
|
14
|
+
# User options for creating an Arp Reply.
|
15
|
+
class Options < Pio::Options
|
16
|
+
mandatory_option :source_mac
|
17
|
+
mandatory_option :destination_mac
|
18
|
+
mandatory_option :sender_protocol_address
|
19
|
+
mandatory_option :target_protocol_address
|
13
20
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
21
|
+
def initialize(options)
|
22
|
+
validate options
|
23
|
+
@source_mac = Mac.new(options[:source_mac]).freeze
|
24
|
+
@destination_mac = Mac.new(options[:destination_mac]).freeze
|
25
|
+
@sender_protocol_address =
|
26
|
+
IPv4Address.new(options[:sender_protocol_address]).freeze
|
27
|
+
@target_protocol_address =
|
28
|
+
IPv4Address.new(options[:target_protocol_address]).freeze
|
29
|
+
end
|
19
30
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
:sender_hardware_address,
|
32
|
-
:target_hardware_address,
|
33
|
-
:sender_protocol_address,
|
34
|
-
:target_protocol_address,
|
35
|
-
]
|
31
|
+
def to_hash
|
32
|
+
{
|
33
|
+
operation: OPERATION,
|
34
|
+
source_mac: @source_mac,
|
35
|
+
destination_mac: @destination_mac,
|
36
|
+
sender_hardware_address: @source_mac,
|
37
|
+
target_hardware_address: @destination_mac,
|
38
|
+
sender_protocol_address: @sender_protocol_address,
|
39
|
+
target_protocol_address: @target_protocol_address
|
40
|
+
}.freeze
|
41
|
+
end
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
39
45
|
end
|
40
|
-
|
41
|
-
### Local variables:
|
42
|
-
### mode: Ruby
|
43
|
-
### coding: utf-8-unix
|
44
|
-
### indent-tabs-mode: nil
|
45
|
-
### End:
|
data/lib/pio/arp/request.rb
CHANGED
@@ -1,45 +1,46 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
3
|
require 'pio/arp/message'
|
4
4
|
require 'pio/mac'
|
5
|
+
require 'pio/options'
|
5
6
|
|
6
7
|
module Pio
|
7
8
|
class Arp
|
8
9
|
# ARP Request packet generator
|
9
10
|
class Request < Message
|
10
11
|
OPERATION = 1
|
12
|
+
public_class_method :new
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
# User options for creating an Arp Request.
|
15
|
+
class Options < Pio::Options
|
16
|
+
mandatory_option :source_mac
|
17
|
+
mandatory_option :sender_protocol_address
|
18
|
+
mandatory_option :target_protocol_address
|
14
19
|
|
15
|
-
|
20
|
+
BROADCAST_MAC = Mac.new(0xffffffffffff).freeze
|
21
|
+
ALL_ZERO_MAC = Mac.new(0).freeze
|
16
22
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
def initialize(options)
|
24
|
+
validate options
|
25
|
+
@source_mac = Mac.new(options[:source_mac]).freeze
|
26
|
+
@sender_protocol_address =
|
27
|
+
IPv4Address.new(options[:sender_protocol_address]).freeze
|
28
|
+
@target_protocol_address =
|
29
|
+
IPv4Address.new(options[:target_protocol_address]).freeze
|
30
|
+
end
|
24
31
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def to_hash
|
33
|
+
{
|
34
|
+
operation: OPERATION,
|
35
|
+
source_mac: @source_mac,
|
36
|
+
destination_mac: BROADCAST_MAC,
|
37
|
+
sender_hardware_address: @source_mac,
|
38
|
+
target_hardware_address: ALL_ZERO_MAC,
|
39
|
+
sender_protocol_address: @sender_protocol_address,
|
40
|
+
target_protocol_address: @target_protocol_address
|
41
|
+
}.freeze
|
42
|
+
end
|
36
43
|
end
|
37
44
|
end
|
38
45
|
end
|
39
46
|
end
|
40
|
-
|
41
|
-
### Local variables:
|
42
|
-
### mode: Ruby
|
43
|
-
### coding: utf-8-unix
|
44
|
-
### indent-tabs-mode: nil
|
45
|
-
### End:
|
data/lib/pio/dhcp.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Packet parser and generator library.
|
4
|
+
module Pio
|
5
|
+
# Dhcp parser and generator.
|
6
|
+
class Dhcp
|
7
|
+
MESSAGE_TYPE_TLV = 53
|
8
|
+
SERVER_IDENTIFIER_TLV = 54
|
9
|
+
CLIENT_IDENTIFIER_TLV = 61
|
10
|
+
RENEWAL_TIME_VALUE_TLV = 58
|
11
|
+
REBINDING_TIME_VALUE_TLV = 59
|
12
|
+
REQUESTED_IP_ADDRESS_TLV = 50
|
13
|
+
PARAMETERS_LIST_TLV = 55
|
14
|
+
IP_ADDRESS_LEASE_TIME_TLV = 51
|
15
|
+
SUBNET_MASK_TLV = 1
|
16
|
+
ROUTER_TLV = 3
|
17
|
+
NTP_SERVERS_TLV = 42
|
18
|
+
DNS_TLV = 6
|
19
|
+
END_OF_TLV = 255
|
20
|
+
|
21
|
+
PARAMETER_REQUEST_LIST =
|
22
|
+
[
|
23
|
+
SUBNET_MASK_TLV,
|
24
|
+
ROUTER_TLV,
|
25
|
+
DNS_TLV,
|
26
|
+
NTP_SERVERS_TLV
|
27
|
+
]
|
28
|
+
end
|
29
|
+
DHCP = Dhcp
|
30
|
+
end
|
31
|
+
|
32
|
+
require 'bindata'
|
33
|
+
require 'pio/dhcp/discover'
|
34
|
+
require 'pio/dhcp/offer'
|
35
|
+
require 'pio/dhcp/request'
|
36
|
+
require 'pio/dhcp/ack'
|
37
|
+
|
38
|
+
module Pio
|
39
|
+
# Dhcp parser and generator.
|
40
|
+
class Dhcp
|
41
|
+
MESSAGE_TYPE = {
|
42
|
+
Discover::TYPE => Discover,
|
43
|
+
Offer::TYPE => Offer,
|
44
|
+
Request::TYPE => Request,
|
45
|
+
Ack::TYPE => Ack
|
46
|
+
}
|
47
|
+
|
48
|
+
def self.read(raw_data)
|
49
|
+
begin
|
50
|
+
frame = const_get('Frame').read(raw_data)
|
51
|
+
rescue
|
52
|
+
raise Pio::ParseError, $ERROR_INFO.message
|
53
|
+
end
|
54
|
+
|
55
|
+
const_get('MESSAGE_TYPE')[frame.message_type].create_from(frame)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|