pio 0.15.2 → 0.16.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.
@@ -1,41 +1,19 @@
1
1
  require 'pio/icmp/format'
2
- require 'forwardable'
3
2
 
4
3
  module Pio
5
4
  class Icmp
6
- # Base class of Request, Reply, TTL Exceeded and destination unreachable.
5
+ # Base class of Icmp::Request and Icmp::Reply.
7
6
  class Message
8
- extend Forwardable
9
-
10
- def_delegators :@format, :destination_mac
11
- def_delegators :@format, :source_mac
12
- def_delegators :@format, :ether_type
13
- def_delegators :@format, :ip_version
14
- def_delegators :@format, :ip_header_length
15
- def_delegators :@format, :ip_type_of_service
16
- def_delegators :@format, :ip_total_length
17
- def_delegators :@format, :ip_identifier
18
- def_delegators :@format, :ip_flag
19
- def_delegators :@format, :ip_fragment
20
- def_delegators :@format, :ip_ttl
21
- def_delegators :@format, :ip_protocol
22
- def_delegators :@format, :ip_header_checksum
23
- def_delegators :@format, :ip_source_address
24
- def_delegators :@format, :ip_destination_address
25
- def_delegators :@format, :icmp_type
26
- def_delegators :@format, :icmp_code
27
- def_delegators :@format, :icmp_checksum
28
- def_delegators :@format, :icmp_identifier
29
- def_delegators :@format, :icmp_sequence_number
30
- def_delegators :@format, :echo_data
31
- def_delegators :@format, :to_binary
32
-
33
7
  private_class_method :new
34
8
 
35
9
  def initialize(user_options)
36
10
  options = self.class.const_get(:Options).new(user_options)
37
11
  @format = Icmp::Format.new(options.to_hash)
38
12
  end
13
+
14
+ def method_missing(method, *args)
15
+ @format.__send__(method, *args)
16
+ end
39
17
  end
40
18
  end
41
19
  end
@@ -4,8 +4,6 @@ module Pio
4
4
  class Icmp
5
5
  # User options for creating an ICMP messages.
6
6
  class Options < Pio::Options
7
- DEFAULT_ECHO_DATA = ''.freeze
8
-
9
7
  def to_hash
10
8
  {
11
9
  icmp_type: @type,
@@ -24,6 +24,7 @@ module Pio
24
24
  def initialize(options)
25
25
  validate options
26
26
  @type = TYPE
27
+
27
28
  @source_mac = Mac.new(options[:source_mac]).freeze
28
29
  @destination_mac = Mac.new(options[:destination_mac]).freeze
29
30
  @ip_source_address =
@@ -32,7 +33,7 @@ module Pio
32
33
  IPv4Address.new(options[:ip_destination_address]).freeze
33
34
  @identifier = options[:identifier]
34
35
  @sequence_number = options[:sequence_number]
35
- @echo_data = options[:echo_data] || DEFAULT_ECHO_DATA
36
+ @echo_data = options[:echo_data] || ''
36
37
  end
37
38
  # rubocop:enable AbcSize
38
39
  # rubocop:enable MethodLength
@@ -22,45 +22,30 @@ module Pio
22
22
  option :sequence_number
23
23
  option :echo_data
24
24
 
25
- def initialize(user_options)
25
+ # rubocop:disable MethodLength
26
+ # rubocop:disable AbcSize
27
+ def initialize(options)
28
+ validate options
26
29
  @type = TYPE
27
30
 
28
- @options = user_options.dup
29
- validate @options
30
- set_mac_and_ip_address_options
31
- set_identifier_option
32
- set_sequence_number_option
33
- set_echo_data_option
34
- end
35
-
36
- private
37
-
38
- def set_mac_and_ip_address_options
39
- @source_mac = Mac.new(@options[:source_mac]).freeze
40
- @destination_mac = Mac.new(@options[:destination_mac]).freeze
31
+ @source_mac = Mac.new(options[:source_mac]).freeze
32
+ @destination_mac = Mac.new(options[:destination_mac]).freeze
41
33
  @ip_source_address =
42
- IPv4Address.new(@options[:ip_source_address]).freeze
34
+ IPv4Address.new(options[:ip_source_address]).freeze
43
35
  @ip_destination_address =
44
- IPv4Address.new(@options[:ip_destination_address]).freeze
45
- end
46
-
47
- def set_identifier_option
36
+ IPv4Address.new(options[:ip_destination_address]).freeze
48
37
  @identifier =
49
- @options[:icmp_identifier] ||
50
- @options[:identifier] ||
38
+ options[:icmp_identifier] ||
39
+ options[:identifier] ||
51
40
  DEFAULT_IDENTIFIER
52
- end
53
-
54
- def set_sequence_number_option
55
41
  @sequence_number =
56
- @options[:icmp_sequence_number] ||
57
- @options[:sequence_number] ||
42
+ options[:icmp_sequence_number] ||
43
+ options[:sequence_number] ||
58
44
  DEFAULT_SEQUENCE_NUMBER
45
+ @echo_data = options[:echo_data] || ''
59
46
  end
60
-
61
- def set_echo_data_option
62
- @echo_data = (@options[:echo_data] || DEFAULT_ECHO_DATA).freeze
63
- end
47
+ # rubocop:enable AbcSize
48
+ # rubocop:enable MethodLength
64
49
  end
65
50
  end
66
51
  end
@@ -0,0 +1,64 @@
1
+ require 'pio/payload'
2
+ require 'pio/type/ip_address'
3
+
4
+ module Pio
5
+ # IP Version 4 Header Format
6
+ module IPv4Header
7
+ include Payload
8
+
9
+ IP_PROTOCOL_ICMP = 1
10
+ IP_PROTOCOL_UDP = 17
11
+
12
+ # rubocop:disable MethodLength
13
+ # rubocop:disable AbcSize
14
+ # This method smells of :reek:TooManyStatements
15
+ def self.included(klass)
16
+ def klass.ipv4_header(options = {})
17
+ bit4 :ip_version, value: 0x4
18
+ bit4 :ip_header_length, initial_value: 0x5
19
+ uint8 :ip_type_of_service, initial_value: 0
20
+ uint16be :ip_total_length, initial_value: :calculate_ip_length
21
+ uint16be :ip_identifier, initial_value: 0
22
+ bit3 :ip_flag, initial_value: 0
23
+ bit13 :ip_fragment, initial_value: 0
24
+ uint8 :ip_ttl, initial_value: 128
25
+ uint8 :ip_protocol, initial_value: options[:ip_protocol] || 0
26
+ uint16be :ip_header_checksum, initial_value: :calculate_ip_checksum
27
+ ip_address :ip_source_address
28
+ ip_address :ip_destination_address
29
+ string :ip_option, read_length: :ip_option_length
30
+ end
31
+ end
32
+ # rubocop:enable MethodLength
33
+ # rubocop:enable AbcSize
34
+
35
+ private
36
+
37
+ def calculate_ip_length
38
+ ip_header_length * 4 + ip_payload_binary.length
39
+ end
40
+
41
+ # rubocop:disable AbcSize
42
+ def calculate_ip_checksum
43
+ sum = [ip_version << 12 | ip_header_length << 8 | ip_type_of_service,
44
+ ip_total_length,
45
+ ip_identifier,
46
+ ip_flag << 13 | ip_fragment,
47
+ ip_ttl << 8 | ip_protocol,
48
+ ip_source_address >> 16,
49
+ ip_source_address & 0xffff,
50
+ ip_destination_address >> 16,
51
+ ip_destination_address & 0xffff].reduce(:+)
52
+ ~((sum & 0xffff) + (sum >> 16)) & 0xffff
53
+ end
54
+ # rubocop:enable AbcSize
55
+
56
+ def ip_payload_binary
57
+ binary_after(:ip_option)
58
+ end
59
+
60
+ def ip_option_length
61
+ 20 - ip_header_length * 4
62
+ end
63
+ end
64
+ end
@@ -1,16 +1,16 @@
1
1
  require 'bindata'
2
2
 
3
+ require 'pio/ethernet_header'
3
4
  require 'pio/lldp/chassis_id_tlv'
4
5
  require 'pio/lldp/optional_tlv'
5
6
  require 'pio/lldp/port_id_tlv'
6
7
  require 'pio/lldp/ttl_tlv'
7
- require 'pio/type/ethernet_header'
8
8
 
9
9
  module Pio
10
10
  class Lldp
11
11
  # LLDP frame
12
12
  class Frame < BinData::Record
13
- extend Type::EthernetHeader
13
+ include EthernetHeader
14
14
 
15
15
  endian :big
16
16
 
data/lib/pio/packet_in.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'bindata'
2
+ require 'pio/ethernet_header'
3
+ require 'pio/ipv4_header'
2
4
  require 'pio/open_flow'
3
5
  require 'pio/parse_error'
4
- require 'pio/type/ethernet_header'
5
- require 'pio/type/ipv4_header'
6
6
 
7
7
  # Base module.
8
8
  module Pio
@@ -49,7 +49,7 @@ module Pio
49
49
  class DataParser
50
50
  # Ethernet header parser
51
51
  class EthernetHeaderParser < BinData::Record
52
- extend Pio::Type::EthernetHeader
52
+ include EthernetHeader
53
53
 
54
54
  endian :big
55
55
 
@@ -59,8 +59,8 @@ module Pio
59
59
 
60
60
  # IPv4 packet parser
61
61
  class IPv4Packet < BinData::Record
62
- extend Pio::Type::EthernetHeader
63
- extend Type::IPv4Header
62
+ include EthernetHeader
63
+ include IPv4Header
64
64
 
65
65
  endian :big
66
66
 
@@ -0,0 +1,11 @@
1
+ module Pio
2
+ # Get payload fields.
3
+ module Payload
4
+ def binary_after(field_name)
5
+ all_fields = field_names(true)
6
+ all_fields[(all_fields.index(field_name) + 1)..-1].map do |each|
7
+ __send__(each).to_binary_s
8
+ end.join
9
+ end
10
+ end
11
+ end
@@ -15,6 +15,14 @@ module Pio
15
15
  IPv4Address.new(octets.map { |each| format('%d', each) }.join('.'))
16
16
  end
17
17
 
18
+ def >>(other)
19
+ get.to_i >> other
20
+ end
21
+
22
+ def &(other)
23
+ get.to_i & other
24
+ end
25
+
18
26
  def ==(other)
19
27
  get == other
20
28
  end
data/lib/pio/udp.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'bindata'
2
+ require 'pio/ethernet_header'
3
+ require 'pio/ipv4_header'
4
+ require 'pio/udp_header'
5
+
6
+ module Pio
7
+ # UDP packet format
8
+ class Udp < BinData::Record
9
+ include EthernetHeader
10
+ include IPv4Header
11
+ include UdpHeader
12
+
13
+ endian :big
14
+ ethernet_header ether_type: EthernetHeader::ETHER_TYPE_IP
15
+ ipv4_header ip_protocol: IPv4Header::IP_PROTOCOL_UDP
16
+ udp_header
17
+ rest :udp_payload
18
+ end
19
+ end
@@ -0,0 +1,56 @@
1
+ require 'pio/payload'
2
+
3
+ module Pio
4
+ # UDP Header Format.
5
+ module UdpHeader
6
+ include Payload
7
+
8
+ # Pseudo UDP header
9
+ class PseudoUdpHeader < BinData::Record
10
+ endian :big
11
+ ip_address :ip_source_address
12
+ ip_address :ip_destination_address
13
+ uint8 :padding
14
+ uint8 :ip_protocol, value: 17
15
+ uint16 :udp_length
16
+ end
17
+
18
+ def self.included(klass)
19
+ def klass.udp_header
20
+ uint16 :udp_source_port
21
+ uint16 :udp_destination_port
22
+ uint16 :udp_length, initial_value: :calculate_udp_length
23
+ uint16 :udp_checksum, initial_value: :calculate_udp_checksum
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def calculate_udp_length
30
+ 8 + udp_payload_binary.length
31
+ end
32
+
33
+ def calculate_udp_checksum
34
+ sum = [*pseudo_udp_header.unpack('n*'),
35
+ udp_source_port,
36
+ udp_destination_port,
37
+ udp_length,
38
+ *udp_payload_multiple_of_2octets.unpack('n*')].inject(:+)
39
+ ~((sum & 0xffff) + (sum >> 16)) & 0xffff
40
+ end
41
+
42
+ def udp_payload_binary
43
+ binary_after :udp_checksum
44
+ end
45
+
46
+ def pseudo_udp_header
47
+ PseudoUdpHeader.new(ip_source_address: ip_source_address,
48
+ ip_destination_address: ip_destination_address,
49
+ udp_length: udp_length).to_binary_s
50
+ end
51
+
52
+ def udp_payload_multiple_of_2octets
53
+ udp_payload_binary + '\x00' * (udp_payload_binary.length.even? ? 0 : 1)
54
+ end
55
+ end
56
+ end
data/lib/pio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # Base module.
2
2
  module Pio
3
3
  # gem version.
4
- VERSION = '0.15.2'.freeze
4
+ VERSION = '0.16.0'.freeze
5
5
  end
@@ -208,13 +208,13 @@ describe Pio::Dhcp, '.read' do
208
208
  end
209
209
  end
210
210
 
211
- describe '#udp_src_port' do
212
- subject { super().udp_src_port }
211
+ describe '#udp_source_port' do
212
+ subject { super().udp_source_port }
213
213
  it { is_expected.to eq 68 }
214
214
  end
215
215
 
216
- describe '#udp_dst_port' do
217
- subject { super().udp_dst_port }
216
+ describe '#udp_destination_port' do
217
+ subject { super().udp_destination_port }
218
218
  it { is_expected.to eq 67 }
219
219
  end
220
220
 
@@ -530,13 +530,13 @@ describe Pio::Dhcp, '.read' do
530
530
  end
531
531
  end
532
532
 
533
- describe '#udp_src_port' do
534
- subject { super().udp_src_port }
533
+ describe '#udp_source_port' do
534
+ subject { super().udp_source_port }
535
535
  it { is_expected.to eq 67 }
536
536
  end
537
537
 
538
- describe '#udp_dst_port' do
539
- subject { super().udp_dst_port }
538
+ describe '#udp_destination_port' do
539
+ subject { super().udp_destination_port }
540
540
  it { is_expected.to eq 68 }
541
541
  end
542
542
 
@@ -860,13 +860,13 @@ describe Pio::Dhcp, '.read' do
860
860
  end
861
861
  end
862
862
 
863
- describe '#udp_src_port' do
864
- subject { super().udp_src_port }
863
+ describe '#udp_source_port' do
864
+ subject { super().udp_source_port }
865
865
  it { is_expected.to eq 68 }
866
866
  end
867
867
 
868
- describe '#udp_dst_port' do
869
- subject { super().udp_dst_port }
868
+ describe '#udp_destination_port' do
869
+ subject { super().udp_destination_port }
870
870
  it { is_expected.to eq 67 }
871
871
  end
872
872
 
@@ -1182,13 +1182,13 @@ describe Pio::Dhcp, '.read' do
1182
1182
  end
1183
1183
  end
1184
1184
 
1185
- describe '#udp_src_port' do
1186
- subject { super().udp_src_port }
1185
+ describe '#udp_source_port' do
1186
+ subject { super().udp_source_port }
1187
1187
  it { is_expected.to eq 67 }
1188
1188
  end
1189
1189
 
1190
- describe '#udp_dst_port' do
1191
- subject { super().udp_dst_port }
1190
+ describe '#udp_destination_port' do
1191
+ subject { super().udp_destination_port }
1192
1192
  it { is_expected.to eq 68 }
1193
1193
  end
1194
1194
 
@@ -4,6 +4,25 @@ describe Pio::ICMP::Request do
4
4
  Then { Pio::ICMP::Request == Pio::Icmp::Request }
5
5
  end
6
6
 
7
+ describe Pio::Icmp do
8
+ Given(:icmp_request) do
9
+ Pio::Icmp::Request.new(
10
+ destination_mac: '24:db:ac:41:e5:5b',
11
+ source_mac: '74:e5:0b:2a:18:f8',
12
+ ip_source_address: '192.168.1.101',
13
+ ip_destination_address: '8.8.8.8',
14
+ identifier: 0x123,
15
+ sequence_number: 0x321,
16
+ echo_data: 'abcdefghijklmnopqrstuvwabcdefghi'
17
+ ).to_binary
18
+ end
19
+
20
+ describe '.read' do
21
+ When(:result) { Pio::Icmp.read icmp_request }
22
+ Then { result.echo_data == 'abcdefghijklmnopqrstuvwabcdefghi' }
23
+ end
24
+ end
25
+
7
26
  describe Pio::Icmp::Request, '.new' do
8
27
  context 'with echo_data' do
9
28
  Given(:icmp_request) do
@@ -22,7 +41,7 @@ describe Pio::Icmp::Request, '.new' do
22
41
  When(:result) { icmp_request.to_binary }
23
42
 
24
43
  Then do
25
- result ==
44
+ result.unpack('C*') ==
26
45
  [
27
46
  # Destination MAC
28
47
  0x24, 0xdb, 0xac, 0x41, 0xe5, 0x5b,
@@ -66,7 +85,7 @@ describe Pio::Icmp::Request, '.new' do
66
85
  0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
67
86
  0x76, 0x77, 0x61, 0x62, 0x63, 0x64, 0x65,
68
87
  0x66, 0x67, 0x68, 0x69
69
- ].pack('C*')
88
+ ]
70
89
  end
71
90
  end
72
91
  end
@@ -87,7 +106,7 @@ describe Pio::Icmp::Request, '.new' do
87
106
  When(:result) { icmp_request.to_binary }
88
107
 
89
108
  Then do
90
- result ==
109
+ result.unpack('C*') ==
91
110
  [
92
111
  # Destination MAC
93
112
  0x24, 0xdb, 0xac, 0x41, 0xe5, 0x5b,
@@ -130,7 +149,7 @@ describe Pio::Icmp::Request, '.new' do
130
149
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131
150
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132
151
  0x00, 0x00, 0x00, 0x00
133
- ].pack('C*')
152
+ ]
134
153
  end
135
154
  end
136
155
  end