packetgen 2.3.0 → 2.4.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.
@@ -0,0 +1,53 @@
1
+ # This file is part of PacketGen
2
+ # See https://github.com/sdaubert/packetgen for more informations
3
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ module PacketGen
7
+ module Header
8
+ class IP
9
+
10
+ # Class to handle IP options
11
+ # @author Sylvain Daubert
12
+ class Options < Types::Array
13
+ set_of Option
14
+
15
+ HUMAN_SEPARATOR = ';'
16
+
17
+ # Read IP header options from a string
18
+ # @param [String] str binary string
19
+ # @return [self]
20
+ def read(str)
21
+ clear
22
+ return self if str.nil?
23
+ PacketGen.force_binary str
24
+
25
+ i = 0
26
+ types = Option.types
27
+ while i < str.to_s.length
28
+ type = str[i, 1].unpack('C').first
29
+ this_option = if types[type].nil?
30
+ Option.new
31
+ else
32
+ types[type].new
33
+ end
34
+ this_option.read str[i, str.size]
35
+ self << this_option
36
+ i += this_option.sz
37
+ end
38
+ self
39
+ end
40
+
41
+ # Get binary string
42
+ # @return [String]
43
+ def to_s
44
+ str = super
45
+ if str.length % 4 != 0
46
+ str += ([0] * (4 - (str.length % 4))).pack('C*')
47
+ end
48
+ str
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -43,77 +43,11 @@ module PacketGen
43
43
  # ipv6.dst = '2001:1234:5678:abcd::123'
44
44
  # ipv6.body.read 'this is a body'
45
45
  # @author Sylvain Daubert
46
- class IPv6 < Base
47
-
48
- # IPv6 address, as a group of 8 2-byte words
49
- # @author Sylvain Daubert
50
- class Addr < Types::Fields
51
-
52
- # @!attribute a1
53
- # 1st 2-byte word of IPv6 address
54
- # @return [Integer]
55
- define_field :a1, Types::Int16
56
- # @!attribute a2
57
- # 2nd 2-byte word of IPv6 address
58
- # @return [Integer]
59
- define_field :a2, Types::Int16
60
- # @!attribute a3
61
- # 3rd 2-byte word of IPv6 address
62
- # @return [Integer]
63
- define_field :a3, Types::Int16
64
- # @!attribute a4
65
- # 4th 2-byte word of IPv6 address
66
- # @return [Integer]
67
- define_field :a4, Types::Int16
68
- # @!attribute a5
69
- # 5th 2-byte word of IPv6 address
70
- # @return [Integer]
71
- define_field :a5, Types::Int16
72
- # @!attribute a6
73
- # 6th 2-byte word of IPv6 address
74
- # @return [Integer]
75
- define_field :a6, Types::Int16
76
- # @!attribute a7
77
- # 7th 2-byte word of IPv6 address
78
- # @return [Integer]
79
- define_field :a7, Types::Int16
80
- # @!attribute a8
81
- # 8th 2-byte word of IPv6 address
82
- # @return [Integer]
83
- define_field :a8, Types::Int16
84
-
85
- # Read a colon-delimited address
86
- # @param [String] str
87
- # @return [self]
88
- def from_human(str)
89
- return self if str.nil?
90
- addr = IPAddr.new(str)
91
- raise ArgumentError, 'string is not a IPv6 address' unless addr.ipv6?
92
- addri = addr.to_i
93
- self.a1 = addri >> 112
94
- self.a2 = addri >> 96 & 0xffff
95
- self.a3 = addri >> 80 & 0xffff
96
- self.a4 = addri >> 64 & 0xffff
97
- self.a5 = addri >> 48 & 0xffff
98
- self.a6 = addri >> 32 & 0xffff
99
- self.a7 = addri >> 16 & 0xffff
100
- self.a8 = addri & 0xffff
101
- self
102
- end
103
-
104
- # Addr6 in human readable form (colon-delimited hex string)
105
- # @return [String]
106
- def to_human
107
- IPAddr.new(to_a.map { |a| a.to_i.to_s(16) }.join(':')).to_s
108
- end
46
+ class IPv6 < Base;end
109
47
 
110
- # Return an array of address 16-bit words
111
- # @return [Array<Integer>]
112
- def to_a
113
- @fields.values
114
- end
115
- end
48
+ require_relative 'ipv6/addr'
116
49
 
50
+ class IPv6
117
51
  # IPv6 Ether type
118
52
  ETHERTYPE = 0x86dd
119
53
 
@@ -232,3 +166,24 @@ module PacketGen
232
166
  IP.bind_header IPv6, protocol: 41 # 6to4
233
167
  end
234
168
  end
169
+
170
+ require_relative 'ipv6/extension'
171
+
172
+ module PacketGen
173
+ module Header
174
+ class IPv6
175
+ class << self
176
+ alias old_bind_header bind_header
177
+
178
+ # Bind a upper header to IPv6 and its defined extension headers.
179
+ # @see Base.bind_header
180
+ def bind_header(header_klass, args={})
181
+ IPv6.old_bind_header header_klass, args
182
+ [IPv6::HopByHop].each do |klass|
183
+ klass.bind_header header_klass, args
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,96 @@
1
+ # coding: utf-8
2
+ # This file is part of PacketGen
3
+ # See https://github.com/sdaubert/packetgen for more informations
4
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
5
+ # This program is published under MIT license.
6
+ require 'ipaddr'
7
+
8
+ module PacketGen
9
+ module Header
10
+ class IPv6
11
+ # IPv6 address, as a group of 8 2-byte words
12
+ # @author Sylvain Daubert
13
+ class Addr < Types::Fields
14
+
15
+ # @!attribute a1
16
+ # 1st 2-byte word of IPv6 address
17
+ # @return [Integer]
18
+ define_field :a1, Types::Int16
19
+ # @!attribute a2
20
+ # 2nd 2-byte word of IPv6 address
21
+ # @return [Integer]
22
+ define_field :a2, Types::Int16
23
+ # @!attribute a3
24
+ # 3rd 2-byte word of IPv6 address
25
+ # @return [Integer]
26
+ define_field :a3, Types::Int16
27
+ # @!attribute a4
28
+ # 4th 2-byte word of IPv6 address
29
+ # @return [Integer]
30
+ define_field :a4, Types::Int16
31
+ # @!attribute a5
32
+ # 5th 2-byte word of IPv6 address
33
+ # @return [Integer]
34
+ define_field :a5, Types::Int16
35
+ # @!attribute a6
36
+ # 6th 2-byte word of IPv6 address
37
+ # @return [Integer]
38
+ define_field :a6, Types::Int16
39
+ # @!attribute a7
40
+ # 7th 2-byte word of IPv6 address
41
+ # @return [Integer]
42
+ define_field :a7, Types::Int16
43
+ # @!attribute a8
44
+ # 8th 2-byte word of IPv6 address
45
+ # @return [Integer]
46
+ define_field :a8, Types::Int16
47
+
48
+ # Read a colon-delimited address
49
+ # @param [String] str
50
+ # @return [self]
51
+ def from_human(str)
52
+ return self if str.nil?
53
+ addr = IPAddr.new(str)
54
+ raise ArgumentError, 'string is not a IPv6 address' unless addr.ipv6?
55
+ addri = addr.to_i
56
+ self.a1 = addri >> 112
57
+ self.a2 = addri >> 96 & 0xffff
58
+ self.a3 = addri >> 80 & 0xffff
59
+ self.a4 = addri >> 64 & 0xffff
60
+ self.a5 = addri >> 48 & 0xffff
61
+ self.a6 = addri >> 32 & 0xffff
62
+ self.a7 = addri >> 16 & 0xffff
63
+ self.a8 = addri & 0xffff
64
+ self
65
+ end
66
+
67
+ # Addr6 in human readable form (colon-delimited hex string)
68
+ # @return [String]
69
+ def to_human
70
+ IPAddr.new(to_a.map { |a| a.to_i.to_s(16) }.join(':')).to_s
71
+ end
72
+
73
+ # Return an array of address 16-bit words
74
+ # @return [Array<Integer>]
75
+ def to_a
76
+ @fields.values
77
+ end
78
+ end
79
+
80
+ # Class to handle series of IPv6 addresses
81
+ # @author Sylvain Daubert
82
+ class ArrayOfAddr < Types::Array
83
+ set_of IPv6::Addr
84
+
85
+ # Push a IPv6 address to the array
86
+ # @param [String,Addr] addr
87
+ # @return [self]
88
+ # array << '2001:1234::125'
89
+ def push(addr)
90
+ addr = addr.is_a?(Addr) ? addr : Addr.new.from_human(addr)
91
+ super(addr)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,65 @@
1
+ # This file is part of PacketGen
2
+ # See https://github.com/sdaubert/packetgen for more informations
3
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ module PacketGen
7
+ module Header
8
+ class IPv6
9
+ # Base class to handle IPv6 extensions
10
+ # @abstract You should not use this class but its subclasses.
11
+ # A IPv6 extension header has the following format:
12
+ # 0 1 2 3
13
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | Next Header | Hdr Ext Len | |
16
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
17
+ # | |
18
+ # . .
19
+ # . Options .
20
+ # . .
21
+ # | |
22
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23
+ #
24
+ # Such a header consists of:
25
+ # * a {#next} header field ({Types::Int8}),
26
+ # * a {#length} field ({Types::Int8}),
27
+ # * an {#options} field ({Types::String}),
28
+ # * and a {#body}, containing next header.
29
+ # @author Sylvain Daubert
30
+ class Extension < Base
31
+ # @!attribute next
32
+ # 8-bit Next header field
33
+ # @return [Integer]
34
+ define_field :next, Types::Int8
35
+ # @!attribute length
36
+ # 8-bit extension length, in 8-octets units, not including the
37
+ # first 8 octets.
38
+ # @return [Integer]
39
+ define_field :length, Types::Int8
40
+ # @!attribute options
41
+ # Specific options of extension header
42
+ # @return [String]
43
+ define_field :options, Types::String,
44
+ builder: ->(h, t) { t.new(length_from: ->() { h.real_length }) }
45
+ # @!attribute body
46
+ # @return [String,Base]
47
+ define_field :body, Types::String
48
+
49
+ # Get real extension header length
50
+ # @return [Integer]
51
+ def real_length
52
+ (length + 1) * 8
53
+ end
54
+
55
+ # Compute length and set +len+ field
56
+ # @return [Integer]
57
+ def calc_length
58
+ self.length = (options.sz + 2) / 8 - 1
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ require_relative 'hop_by_hop'
@@ -0,0 +1,132 @@
1
+ # This file is part of PacketGen
2
+ # See https://github.com/sdaubert/packetgen for more informations
3
+ # Copyright (C) 2016 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ module PacketGen
7
+ module Header
8
+ class IPv6
9
+ # Option for {HopByHop} IPv6 extension header
10
+ # @author Sylvain Daubert
11
+ class Option < Types::TLV
12
+ # Known option types
13
+ TYPES = {
14
+ 1 => 'padn',
15
+ 5 => 'router_alert'
16
+ }
17
+
18
+ # @return [String]
19
+ def to_human
20
+ case type
21
+ when 1
22
+ "pad#{self.sz}"
23
+ else
24
+ "#{human_type}(#{value.to_s.inspect})"
25
+ end
26
+ end
27
+ end
28
+
29
+ # Special option pad1, for {HopByHop} IPv6 extension header
30
+ # @author Sylvain Daubert
31
+ class Pad1 < Types::Fields
32
+ # @!attribute pad
33
+ # @return [Integer]
34
+ define_field :pad, Types::Int8, default: 0
35
+
36
+ # @return [String]
37
+ def to_human
38
+ 'pad1'
39
+ end
40
+ end
41
+
42
+ # Array of {Option}, for {HopByHop} IPv6 extension header
43
+ # @author Sylvain Daubert
44
+ class Options < Types::Array
45
+ set_of Option
46
+
47
+ # Populate object from a binary string
48
+ # @param [String] str
49
+ # @return [self]
50
+ def read(str)
51
+ clear
52
+ return self if str.nil?
53
+ force_binary str
54
+ klass = self.class.class_eval { @klass }
55
+ while str.length > 0
56
+ obj = klass.new.read(str)
57
+ if obj.type == 0
58
+ obj = Pad1.new.read(str)
59
+ end
60
+ self.push obj
61
+ str.slice!(0, obj.sz)
62
+ end
63
+ self
64
+ end
65
+
66
+ # Get options as a binary string. Add padding if needed.
67
+ # @return [String]
68
+ def to_s
69
+ str = super
70
+ case str.size % 8
71
+ when 0
72
+ return str
73
+ when 7
74
+ # only on byte needed: use pad1 option
75
+ str << [0].pack('C')
76
+ else
77
+ # use padn option
78
+ len = 8 - (str.size % 8) - 4
79
+ padn = Option.new(type: 'padn', value: "\x00" * len)
80
+ str << padn.to_s
81
+ end
82
+ str
83
+ end
84
+ end
85
+
86
+ # Hop-by-hop IPv6 extension
87
+ #
88
+ # 0 1 2 3
89
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
90
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91
+ # | Next Header | Hdr Ext Len | |
92
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
93
+ # | |
94
+ # . .
95
+ # . Options .
96
+ # . .
97
+ # | |
98
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99
+ #
100
+ # Hop-by-hop IPv6 extension header consists of:
101
+ # * a {#next} header field ({Types::Int8}),
102
+ # * a {#length} field ({Types::Int8}),
103
+ # * an {#options} field ({Options}),
104
+ # * and a {#body}, containing next header.
105
+ # @author Sylvain Daubert
106
+ class HopByHop < Extension
107
+ # redefine options field
108
+ delete_field :options
109
+ # @!attribute options
110
+ # Specific options of extension header
111
+ # @return [Options]
112
+ define_field_before :body, :options, Options
113
+
114
+ # Populate object from a binary string
115
+ # @param [String] str
116
+ # @return [self]
117
+ def read(str)
118
+ return self if str.nil?
119
+ force_binary str
120
+ self[:next].read str[0, 1]
121
+ self[:length].read str[1, 1]
122
+ self[:options].read str[2, real_length - 2]
123
+ self[:body].read str[real_length..-1]
124
+ self
125
+ end
126
+ end
127
+ end
128
+
129
+ self.add_class IPv6::HopByHop
130
+ IPv6.bind_header IPv6::HopByHop, next: 0
131
+ end
132
+ end