Skip to content

Commit

Permalink
Merge ece8cae into 5e139a8
Browse files Browse the repository at this point in the history
  • Loading branch information
yasuhito committed Jul 8, 2016
2 parents 5e139a8 + ece8cae commit b2dc4f1
Show file tree
Hide file tree
Showing 11 changed files with 135 additions and 8 deletions.
1 change: 1 addition & 0 deletions features/.nav
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- dhcp.feature
- udp.feature
- ethernet_header.feature
- ipv4_header.feature
- open_flow10:
- hello.feature
- hello_failed.feature
Expand Down
78 changes: 78 additions & 0 deletions features/ipv4_header.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
Feature: IPv4Header
Scenario: create an IPv4 header
When I create a packet with:
"""ruby
IPv4Header.new(source_ip_address: '1.2.3.4',
destination_ip_address: '4.3.2.1')
"""
Then the packet has the following fields and values:
| field | value |
| class | Pio::IPv4Header |
| ip_version | 4 |
| ip_header_length | 5 |
| ip_type_of_service | 0 |
| ip_total_length | 20 |
| ip_identifier | 0 |
| ip_flag | 0 |
| ip_fragment | 0 |
| ip_ttl | 128 |
| ip_protocol | 0 |
| ip_header_checksum | 12513 |
| source_ip_address | 1.2.3.4 |
| destination_ip_address | 4.3.2.1 |
| ip_option | |

Scenario: read an IPv4 header
Given I use the fixture "ipv4_header"
When I create a packet with:
"""ruby
Pio::IPv4Header.read(eval(IO.read('ipv4_header.rb')))
"""
Then the packet has the following fields and values:
| field | value |
| class | Pio::IPv4Header |
| ip_version | 4 |
| ip_header_length | 5 |
| ip_type_of_service | 0 |
| ip_total_length | 20 |
| ip_identifier | 0 |
| ip_flag | 0 |
| ip_fragment | 0 |
| ip_ttl | 128 |
| ip_protocol | 0 |
| ip_header_checksum | 12513 |
| source_ip_address | 1.2.3.4 |
| destination_ip_address | 4.3.2.1 |
| ip_option | |

Scenario: convert IPv4 header to Ruby code
When I eval the following Ruby code:
"""ruby
IPv4Header.new(source_ip_address: '1.2.3.4',
destination_ip_address: '4.3.2.1').to_ruby
"""
Then the result of eval should be:
"""ruby
[
0b0100_0101, # ip_version, ip_header_length
0x00, # ip_type_of_service
0x00, 0x14, # ip_total_length
0x00, 0x00, # ip_identifier
0b000_0000000000000, # ip_flag, ip_fragment
0x80, # ip_ttl
0x00, # ip_protocol
0x30, 0xe1, # ip_header_checksum
0x01, 0x02, 0x03, 0x04, # source_ip_address
0x04, 0x03, 0x02, 0x01, # destination_ip_address
].pack('C6nC12')
"""

Scenario: IPv4Header class inspection
When I eval the following Ruby code:
"""ruby
Pio::IPv4Header.inspect
"""
Then the result of eval should be:
"""
IPv4Header(ip_version: bit4, ip_header_length: bit4, ip_type_of_service: uint8, ip_total_length: uint16, ip_identifier: uint16, ip_flag: bit3, ip_fragment: bit13, ip_ttl: uint8, ip_protocol: uint8, ip_header_checksum: uint16, source_ip_address: ip_address, destination_ip_address: ip_address, ip_option: string)
"""
12 changes: 12 additions & 0 deletions fixtures/ipv4_header/ipv4_header.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
0b0100_0101, # ip_version, ip_header_length
0x00, # ip_type_of_service
0x00, 0x14, # ip_total_length
0x00, 0x00, # ip_identifier
0b000_0000000000000, # ip_flag, ip_fragment
0x80, # ip_ttl
0x00, # ip_protocol
0x30, 0xe1, # ip_header_checksum
0x01, 0x02, 0x03, 0x04, # source_ip_address
0x04, 0x03, 0x02, 0x01, # destination_ip_address
].pack('C6nC12')
2 changes: 1 addition & 1 deletion lib/pio/dhcp/frame.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Frame < BinData::Record
OPTION_FIELD_LENGTH = 60

include Ethernet
include IPv4Header
include IPv4
include UdpHeader

endian :big
Expand Down
2 changes: 1 addition & 1 deletion lib/pio/icmp/format.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Format < BinData::Record
MINIMUM_IP_PACKET_LENGTH = 50

include Ethernet
include IPv4Header
include IPv4

endian :big

Expand Down
18 changes: 17 additions & 1 deletion lib/pio/ipv4_header.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
require 'pio/monkey_patch/bindata_string'
require 'pio/payload'
require 'pio/ruby_dumper'
require 'pio/type/ip_address'

module Pio
# IP Version 4 Header Format
module IPv4Header
module IPv4
# Internet protocol numbers for ipv4_header.ip_protocol
module ProtocolNumber
ICMP = 1
Expand Down Expand Up @@ -82,4 +84,18 @@ def ip_option_length
20 - ip_header_length * 4
end
end

# IPv4 header generator/parser
class IPv4Header < BinData::Record
include IPv4
include RubyDumper

ipv4_header

# rubocop:disable LineLength
def self.inspect
'IPv4Header(ip_version: bit4, ip_header_length: bit4, ip_type_of_service: uint8, ip_total_length: uint16, ip_identifier: uint16, ip_flag: bit3, ip_fragment: bit13, ip_ttl: uint8, ip_protocol: uint8, ip_header_checksum: uint16, source_ip_address: ip_address, destination_ip_address: ip_address, ip_option: string)'
end
# rubocop:enable LineLength
end
end
10 changes: 10 additions & 0 deletions lib/pio/monkey_patch/bindata_string.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module BinData
# Add BinData::String#to_hex
class String
def to_hex
to_s.unpack('H*').pop.scan(/[0-9a-f]{2}/).map do |each|
"0x#{each}"
end.join(', ')
end
end
end
2 changes: 1 addition & 1 deletion lib/pio/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class EthernetFrame < BinData::Record
# IPv4 packet parser
class IPv4Packet < BinData::Record
include Ethernet
include IPv4Header
include IPv4

endian :big

Expand Down
14 changes: 12 additions & 2 deletions lib/pio/ruby_dumper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ def to_ruby
bytes = ''
bit = false
bit_names = []
total_bit_length = 0
field_names.each do |each|
next unless __send__("#{each}?")
if /Bit(\d+)$/ =~ __send__(each).class.to_s
bit_length = Regexp.last_match(1)
bit_length = Regexp.last_match(1).to_i
total_bit_length += bit_length
if bit
bit_names << each
bytes << format("_%0#{bit_length}b", __send__(each))
Expand All @@ -28,11 +30,19 @@ def to_ruby
else
if bit
bytes << ", # #{bit_names.join(', ')}\n"
pack_template << 'n'
if total_bit_length == 8
pack_template << 'C'
elsif total_bit_length == 16
pack_template << 'n'
else
raise
end
total_bit_length = 0
bit_names = []
bit = false
end
list = __send__(each).to_hex
next if list.empty?
bytes << " #{list}, # #{each}\n"
pack_template << 'C' * (list.count(',') + 1)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/pio/udp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Pio
# UDP packet format
class Udp < BinData::Record
include Ethernet
include IPv4Header
include IPv4
include UdpHeader

endian :big
Expand Down
2 changes: 1 addition & 1 deletion lib/pio/udp_header.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class PseudoUdpHeader < BinData::Record
ip_address :source_ip_address
ip_address :destination_ip_address
uint8 :padding
uint8 :ip_protocol, value: IPv4Header::ProtocolNumber::UDP
uint8 :ip_protocol, value: IPv4::ProtocolNumber::UDP
uint16 :udp_length
end

Expand Down

0 comments on commit b2dc4f1

Please sign in to comment.