packetgen-plugin-ipsec 1.0.2 → 1.0.3

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