packetgen-plugin-ipsec 1.0.2 → 1.0.3

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,241 +1,242 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of IPsec packetgen plugin.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
3
5
  # Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
- module PacketGen
9
- module Plugin
10
- # This class handles a pseudo-Plugin used to differentiate ESP from IKE Plugins
11
- # in a UDP datagram with port 4500.
12
- # @author Sylvain Daubert
13
- class NonESPMarker < PacketGen::Header::Base
14
- # @!attribute non_esp_marker
15
- # 32-bit zero marker to differentiate IKE packet over UDP port 4500 from ESP ones
16
- # @return [Integer]
17
- define_field :non_esp_marker, PacketGen::Types::Int32, default: 0
18
- # @!attribute body
19
- # @return [PacketGen::Types::String,PacketGen::Header::Base]
20
- define_field :body, PacketGen::Types::String
21
-
22
- # Check non_esp_marker field
23
- # @see [PacketGen::Header::Base#parse?]
24
- def parse?
25
- non_esp_marker.zero?
26
- end
8
+ module PacketGen::Plugin
9
+ # This class handles a pseudo-Plugin used to differentiate ESP from IKE Plugins
10
+ # in a UDP datagram with port 4500.
11
+ # @author Sylvain Daubert
12
+ class NonESPMarker < PacketGen::Header::Base
13
+ # @!attribute non_esp_marker
14
+ # 32-bit zero marker to differentiate IKE packet over UDP port 4500 from ESP ones
15
+ # @return [Integer]
16
+ define_field :non_esp_marker, PacketGen::Types::Int32, default: 0
17
+ # @!attribute body
18
+ # @return [PacketGen::Types::String,PacketGen::Header::Base]
19
+ define_field :body, PacketGen::Types::String
20
+
21
+ # Check non_esp_marker field
22
+ # @see [PacketGen::Header::Base#parse?]
23
+ def parse?
24
+ non_esp_marker.zero?
27
25
  end
26
+ end
28
27
 
29
- # IKE is the Internet Key Exchange protocol (RFC 7296). Ony IKEv2 is supported.
30
- #
31
- # A IKE Plugin consists of a Plugin, and a set of payloads. This class
32
- # handles IKE Plugin. For payloads, see {IKE::Payload}.
33
- #
34
- # == IKE Plugin
35
- # The format of a IKE Plugin is shown below:
36
- # 1 2 3
37
- # 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
38
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39
- # | IKE SA Initiator's SPI |
40
- # | |
41
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42
- # | IKE SA Responder's SPI |
43
- # | |
44
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45
- # | Next Payload | MjVer | MnVer | Exchange Type | Flags |
46
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47
- # | Message ID |
48
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49
- # | Length |
50
- # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51
- # A IKE Plugin consists of:
52
- # * a IKE SA initiator SPI ({#init_spi}, {PacketGen::Types::Int64} type),
53
- # * a IKE SA responder SPI ({#resp_spi}, {PacketGen::Types::Int64} type),
54
- # * a Next Payload field ({#next}, {PacketGen::Types::Int8} type),
55
- # * a Version field ({#version}, {PacketGen::Types::Int8} type, with first 4-bit field
56
- # as major number, and last 4-bit field as minor number),
57
- # * a Exchange type ({#exchange_type}, {PacketGen::Types::Int8} type),
58
- # * a {#flags} field ({PacketGen::Types::Int8} type),
59
- # * a Message ID ({#message_id}, {PacketGen::Types::Int32} type),
60
- # * and a {#length} ({PacketGen::Types::Int32} type).
61
- #
62
- # == Create a IKE Plugin
63
- # === Standalone
64
- # ike = PacketGen::Plugin::IKE.new
65
- # === Classical IKE packet
66
- # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
67
- # # access to IKE Plugin
68
- # pkt.ike # => PacketGen::Plugin::IKE
69
- # === NAT-T IKE packet
70
- # # NonESPMarker is used to insert a 32-bit null field between UDP Plugin
71
- # # and IKE one to differentiate it from ESP-in-UDP (see RFC 3948)
72
- # pkt = PacketGen.gen('IP').add('UDP').add('NonESPMarker').add('IKE)
73
- # @author Sylvain Daubert
74
- class IKE < PacketGen::Header::Base
75
- # Classical well-known UDP port for IKE
76
- UDP_PORT1 = 500
77
- # Well-known UDP port for IKE when NAT is detected
78
- UDP_PORT2 = 4500
79
-
80
- PROTOCOLS = {
81
- 'IKE' => 1,
82
- 'AH' => 2,
83
- 'ESP' => 3
84
- }.freeze
85
-
86
- EXCHANGE_TYPES = {
87
- 'IKE_SA_INIT' => 34,
88
- 'IKE_AUTH' => 35,
89
- 'CREATE_CHILD_SA' => 36,
90
- 'INFORMATIONAL' => 37
91
- }.freeze
92
-
93
- # @!attribute init_spi
94
- # 64-bit initiator SPI
95
- # @return [Integer]
96
- define_field :init_spi, PacketGen::Types::Int64
97
- # @!attribute resp_spi
98
- # 64-bit responder SPI
99
- # @return [Integer]
100
- define_field :resp_spi, PacketGen::Types::Int64
101
- # @!attribute next
102
- # 8-bit next payload type
103
- # @return [Integer]
104
- define_field :next, PacketGen::Types::Int8
105
- # @!attribute version
106
- # 8-bit IKE version
107
- # @return [Integer]
108
- define_field :version, PacketGen::Types::Int8, default: 0x20
109
- # @!attribute [r] exchange_type
110
- # 8-bit exchange type
111
- # @return [Integer]
112
- define_field :exchange_type, PacketGen::Types::Int8Enum, enum: EXCHANGE_TYPES
113
- # @!attribute flags
114
- # 8-bit flags
115
- # @return [Integer]
116
- define_field :flags, PacketGen::Types::Int8
117
- # @!attribute message_id
118
- # 32-bit message ID
119
- # @return [Integer]
120
- define_field :message_id, PacketGen::Types::Int32
121
- # @!attribute length
122
- # 32-bit length of total message (Plugin + payloads)
123
- # @return [Integer]
124
- define_field :length, PacketGen::Types::Int32
125
-
126
- # Defining a body permits using Packet#parse to parse IKE payloads.
127
- # But this method is hidden as prefered way to access payloads is via #payloads
128
- define_field :body, PacketGen::Types::String
129
-
130
- # @!attribute mjver
131
- # 4-bit major version value
132
- # @return [Integer]
133
- # @!attribute mnver
134
- # 4-bit minor version value
135
- # @return [Integer]
136
- define_bit_fields_on :version, :mjver, 4, :mnver, 4
137
-
138
- # @!attribute rsv1
139
- # @return [Integer]
140
- # @!attribute rsv2
141
- # @return [Integer]
142
- # @!attribute flag_i
143
- # bit set in message sent by the original initiator
144
- # @return [Boolean]
145
- # @!attribute flag_r
146
- # indicate this message is a response to a message containing the same Message ID
147
- # @return [Boolean]
148
- # @!attribute flag_v
149
- # version flag. Ignored by IKEv2 peers, and should be set to 0
150
- # @return [Boolean]
151
- define_bit_fields_on :flags, :rsv1, 2, :flag_r, :flag_v, :flag_i, :rsv2, 3
152
-
153
- # @param [Hash] options
154
- # @see PacketGen::Header::Base#initialize
155
- def initialize(options={})
156
- super
157
- calc_length unless options[:length]
158
- self.type = options[:type] if options[:type]
159
- self.type = options[:exchange_type] if options[:exchange_type]
160
- end
28
+ # IKE is the Internet Key Exchange protocol (RFC 7296). Ony IKEv2 is supported.
29
+ #
30
+ # A IKE Plugin consists of a Plugin, and a set of payloads. This class
31
+ # handles IKE Plugin. For payloads, see {IKE::Payload}.
32
+ #
33
+ # == IKE Plugin
34
+ # The format of a IKE Plugin is shown below:
35
+ # 1 2 3
36
+ # 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
37
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38
+ # | IKE SA Initiator's SPI |
39
+ # | |
40
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41
+ # | IKE SA Responder's SPI |
42
+ # | |
43
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44
+ # | Next Payload | MjVer | MnVer | Exchange Type | Flags |
45
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46
+ # | Message ID |
47
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48
+ # | Length |
49
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50
+ # A IKE Plugin consists of:
51
+ # * a IKE SA initiator SPI ({#init_spi}, {PacketGen::Types::Int64} type),
52
+ # * a IKE SA responder SPI ({#resp_spi}, {PacketGen::Types::Int64} type),
53
+ # * a Next Payload field ({#next}, {PacketGen::Types::Int8} type),
54
+ # * a Version field ({#version}, {PacketGen::Types::Int8} type, with first 4-bit field
55
+ # as major number, and last 4-bit field as minor number),
56
+ # * a Exchange type ({#exchange_type}, {PacketGen::Types::Int8} type),
57
+ # * a {#flags} field ({PacketGen::Types::Int8} type),
58
+ # * a Message ID ({#message_id}, {PacketGen::Types::Int32} type),
59
+ # * and a {#length} ({PacketGen::Types::Int32} type).
60
+ #
61
+ # == Create a IKE Plugin
62
+ # === Standalone
63
+ # ike = PacketGen::Plugin::IKE.new
64
+ # === Classical IKE packet
65
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
66
+ # # access to IKE Plugin
67
+ # pkt.ike # => PacketGen::Plugin::IKE
68
+ # === NAT-T IKE packet
69
+ # # NonESPMarker is used to insert a 32-bit null field between UDP Plugin
70
+ # # and IKE one to differentiate it from ESP-in-UDP (see RFC 3948)
71
+ # pkt = PacketGen.gen('IP').add('UDP').add('NonESPMarker').add('IKE)
72
+ # @author Sylvain Daubert
73
+ class IKE < PacketGen::Header::Base
74
+ # Classical well-known UDP port for IKE
75
+ UDP_PORT1 = 500
76
+ # Well-known UDP port for IKE when NAT is detected
77
+ UDP_PORT2 = 4500
78
+
79
+ # Protocols supported by IKE
80
+ PROTOCOLS = {
81
+ 'IKE' => 1,
82
+ 'AH' => 2,
83
+ 'ESP' => 3
84
+ }.freeze
85
+
86
+ # Known echange types
87
+ EXCHANGE_TYPES = {
88
+ 'IKE_SA_INIT' => 34,
89
+ 'IKE_AUTH' => 35,
90
+ 'CREATE_CHILD_SA' => 36,
91
+ 'INFORMATIONAL' => 37
92
+ }.freeze
93
+
94
+ # @!attribute init_spi
95
+ # 64-bit initiator SPI
96
+ # @return [Integer]
97
+ define_field :init_spi, PacketGen::Types::Int64
98
+ # @!attribute resp_spi
99
+ # 64-bit responder SPI
100
+ # @return [Integer]
101
+ define_field :resp_spi, PacketGen::Types::Int64
102
+ # @!attribute next
103
+ # 8-bit next payload type
104
+ # @return [Integer]
105
+ define_field :next, PacketGen::Types::Int8
106
+ # @!attribute version
107
+ # 8-bit IKE version
108
+ # @return [Integer]
109
+ define_field :version, PacketGen::Types::Int8, default: 0x20
110
+ # @!attribute [r] exchange_type
111
+ # 8-bit exchange type
112
+ # @return [Integer]
113
+ define_field :exchange_type, PacketGen::Types::Int8Enum, enum: EXCHANGE_TYPES
114
+ # @!attribute flags
115
+ # 8-bit flags
116
+ # @return [Integer]
117
+ define_field :flags, PacketGen::Types::Int8
118
+ # @!attribute message_id
119
+ # 32-bit message ID
120
+ # @return [Integer]
121
+ define_field :message_id, PacketGen::Types::Int32
122
+ # @!attribute length
123
+ # 32-bit length of total message (Plugin + payloads)
124
+ # @return [Integer]
125
+ define_field :length, PacketGen::Types::Int32
126
+
127
+ # Defining a body permits using Packet#parse to parse IKE payloads.
128
+ # But this method is hidden as prefered way to access payloads is via #payloads
129
+ define_field :body, PacketGen::Types::String
130
+
131
+ # @!attribute mjver
132
+ # 4-bit major version value
133
+ # @return [Integer]
134
+ # @!attribute mnver
135
+ # 4-bit minor version value
136
+ # @return [Integer]
137
+ define_bit_fields_on :version, :mjver, 4, :mnver, 4
138
+
139
+ # @!attribute rsv1
140
+ # @return [Integer]
141
+ # @!attribute rsv2
142
+ # @return [Integer]
143
+ # @!attribute flag_i
144
+ # bit set in message sent by the original initiator
145
+ # @return [Boolean]
146
+ # @!attribute flag_r
147
+ # indicate this message is a response to a message containing the same Message ID
148
+ # @return [Boolean]
149
+ # @!attribute flag_v
150
+ # version flag. Ignored by IKEv2 peers, and should be set to 0
151
+ # @return [Boolean]
152
+ define_bit_fields_on :flags, :rsv1, 2, :flag_r, :flag_v, :flag_i, :rsv2, 3
153
+
154
+ # @param [Hash] options
155
+ # @see PacketGen::Header::Base#initialize
156
+ def initialize(options={})
157
+ super
158
+ calc_length unless options[:length]
159
+ self.type = options[:type] if options[:type]
160
+ self.type = options[:exchange_type] if options[:exchange_type]
161
+ end
161
162
 
162
- alias type exchange_type
163
- alias type= exchange_type=
163
+ alias type exchange_type
164
+ alias type= exchange_type=
164
165
 
165
- # Get exchange type name
166
- # @return [String
167
- def human_exchange_type
168
- self[:exchange_type].to_human
169
- end
170
- alias human_type human_exchange_type
166
+ # Get exchange type name
167
+ # @return [String
168
+ def human_exchange_type
169
+ self[:exchange_type].to_human
170
+ end
171
+ alias human_type human_exchange_type
171
172
 
172
- # Calculate length field
173
- # @return [Integer]
174
- def calc_length
175
- PacketGen::Header::Base.calculate_and_set_length self
176
- end
173
+ # Calculate length field
174
+ # @return [Integer]
175
+ def calc_length
176
+ PacketGen::Header::Base.calculate_and_set_length self
177
+ end
177
178
 
178
- # IKE payloads
179
- # @return [Array<Payload>]
180
- def payloads
181
- payloads = []
182
- body = self.body
183
- while body.is_a?(Payload)
184
- payloads << body
185
- body = body.body
186
- end
187
- payloads
179
+ # IKE payloads
180
+ # @return [Array<Payload>]
181
+ def payloads
182
+ payloads = []
183
+ body = self.body
184
+ while body.is_a?(Payload)
185
+ payloads << body
186
+ body = body.body
188
187
  end
188
+ payloads
189
+ end
189
190
 
190
- # @return [String]
191
- def inspect
192
- super do |attr|
193
- case attr
194
- when :flags
195
- str_flags = ''.dup
196
- %w[r v i].each do |flag|
197
- str_flags << (send("flag_#{flag}?") ? flag.upcase : '.')
198
- end
199
- str = Inspect.shift_level
200
- str << Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr,
201
- str_flags]
191
+ # @return [String]
192
+ def inspect
193
+ super do |attr|
194
+ case attr
195
+ when :flags
196
+ str_flags = +''
197
+ %w[r v i].each do |flag|
198
+ str_flags << (send("flag_#{flag}?") ? flag.upcase : '.')
202
199
  end
200
+ str = PacketGen::Inspect.shift_level
201
+ str << PacketGen::Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr,
202
+ str_flags]
203
203
  end
204
204
  end
205
+ end
205
206
 
206
- # Toggle +I+ and +R+ flags.
207
- # @return [self]
208
- def reply!
209
- self.flag_r = !self.flag_r?
210
- self.flag_i = !self.flag_i?
211
- self
212
- end
207
+ # Toggle +I+ and +R+ flags.
208
+ # @return [self]
209
+ def reply!
210
+ self.flag_r = !self.flag_r?
211
+ self.flag_i = !self.flag_i?
212
+ self
213
+ end
213
214
 
214
- # @api private
215
- # @note This method is used internally by PacketGen and should not be
216
- # directly called
217
- # @param [Packet] packet
218
- # @return [void]
219
- def added_to_packet(packet)
220
- return unless packet.is? 'UDP'
221
- return unless packet.udp.sport.zero?
222
- packet.udp.sport = if packet.is?('NonESPMarker')
223
- UDP_PORT2
224
- else
225
- UDP_PORT1
226
- end
227
- end
215
+ # @api private
216
+ # @note This method is used internally by PacketGen and should not be
217
+ # directly called
218
+ # @param [Packet] packet
219
+ # @return [void]
220
+ def added_to_packet(packet)
221
+ return unless packet.is? 'UDP'
222
+ return unless packet.udp.sport.zero?
223
+
224
+ packet.udp.sport = if packet.is?('NonESPMarker')
225
+ UDP_PORT2
226
+ else
227
+ UDP_PORT1
228
+ end
228
229
  end
230
+ end
229
231
 
230
- Header.add_class IKE
231
- Header.add_class NonESPMarker
232
+ PacketGen::Header.add_class IKE
233
+ PacketGen::Header.add_class NonESPMarker
232
234
 
233
- PacketGen::Header::UDP.bind IKE, dport: IKE::UDP_PORT1
234
- PacketGen::Header::UDP.bind IKE, sport: IKE::UDP_PORT1
235
- PacketGen::Header::UDP.bind NonESPMarker, dport: IKE::UDP_PORT2
236
- PacketGen::Header::UDP.bind NonESPMarker, sport: IKE::UDP_PORT2
237
- NonESPMarker.bind IKE
238
- end
235
+ PacketGen::Header::UDP.bind IKE, dport: IKE::UDP_PORT1
236
+ PacketGen::Header::UDP.bind IKE, sport: IKE::UDP_PORT1
237
+ PacketGen::Header::UDP.bind NonESPMarker, dport: IKE::UDP_PORT2
238
+ PacketGen::Header::UDP.bind NonESPMarker, sport: IKE::UDP_PORT2
239
+ NonESPMarker.bind IKE
239
240
  end
240
241
 
241
242
  require_relative 'ike/payload'