packetgen 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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