packetgen-plugin-ipsec 1.0.2 → 1.1.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.
- checksums.yaml +4 -4
- data/.github/workflows/specs.yml +32 -0
- data/.rubocop.yml +28 -3
- data/Gemfile +18 -0
- data/README.md +12 -6
- data/Rakefile +10 -4
- data/lib/packetgen/plugin/crypto.rb +38 -4
- data/lib/packetgen/plugin/esp.rb +410 -378
- data/lib/packetgen/plugin/ike/auth.rb +153 -140
- data/lib/packetgen/plugin/ike/cert.rb +61 -62
- data/lib/packetgen/plugin/ike/certreq.rb +51 -52
- data/lib/packetgen/plugin/ike/id.rb +80 -81
- data/lib/packetgen/plugin/ike/ke.rb +64 -65
- data/lib/packetgen/plugin/ike/nonce.rb +29 -31
- data/lib/packetgen/plugin/ike/notify.rb +134 -139
- data/lib/packetgen/plugin/ike/payload.rb +75 -76
- data/lib/packetgen/plugin/ike/sa.rb +515 -452
- data/lib/packetgen/plugin/ike/sk.rb +221 -221
- data/lib/packetgen/plugin/ike/ts.rb +226 -223
- data/lib/packetgen/plugin/ike/vendor_id.rb +28 -30
- data/lib/packetgen/plugin/ike.rb +213 -217
- data/lib/packetgen/plugin/ipsec_version.rb +8 -1
- data/lib/packetgen-plugin-ipsec.rb +2 -0
- data/packetgen-plugin-ipsec.gemspec +6 -11
- metadata +11 -88
- data/.travis.yml +0 -14
@@ -1,159 +1,154 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
# This file is part of IPsec packetgen plugin.
|
3
5
|
# See https://github.com/sdaubert/packetgen-plugin-ipsec for more informations
|
4
6
|
# Copyright (c) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
|
5
7
|
# This program is published under MIT license.
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
#
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
#
|
49
|
-
|
50
|
-
class Notify < Payload
|
51
|
-
# Payload type number
|
52
|
-
PAYLOAD_TYPE = 41
|
9
|
+
module PacketGen::Plugin
|
10
|
+
class IKE
|
11
|
+
# This class handles Notify payloads, as defined in RFC 7296 §3.10.
|
12
|
+
#
|
13
|
+
# A Notify payload contains a generic payload Plugin (see {Payload}) and
|
14
|
+
# some specific fields:
|
15
|
+
# 1 2 3
|
16
|
+
# 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
|
17
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
18
|
+
# | Next Payload |C| RESERVED | Payload Length |
|
19
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
20
|
+
# | Protocol ID | SPI Size | Notify Message Type |
|
21
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
22
|
+
# | |
|
23
|
+
# ~ Security Parameter Index (SPI) ~
|
24
|
+
# | |
|
25
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
26
|
+
# | |
|
27
|
+
# ~ Notification Data ~
|
28
|
+
# | |
|
29
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
30
|
+
# These specific fields are:
|
31
|
+
# * {#protocol} (type {BinStruct::Int8}),
|
32
|
+
# * {#spi_size} (type {BinStruct::Int8}),
|
33
|
+
# * {#message_type} (type {BinStruct::Int16}),
|
34
|
+
# * {#spi} (type {BinStruct::String}),
|
35
|
+
# * {#content} (type {BinStruct::String}).
|
36
|
+
#
|
37
|
+
# == Create a Notify payload
|
38
|
+
# # Create a IKE packet with a Notify payload
|
39
|
+
# pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Notify', protocol: 'IKE', type: 'INVALID_SYNTAX')
|
40
|
+
# pkt.ike_notify.spi # => ""
|
41
|
+
# pkt.ike_notify.content # => ""
|
42
|
+
# pkt.calc_length
|
43
|
+
# == Create a Notify payload with a SPI
|
44
|
+
# # Create a IKE packet with a Notify payload
|
45
|
+
# pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Notify', protocol: 'ESP', spi_size: 4, type: 'INVALID_SYNTAX')
|
46
|
+
# pkt.ike_notify.spi.read BinStruct::Int32.new(0x12345678).to_s
|
47
|
+
# pkt.calc_length
|
48
|
+
# @author Sylvain Daubert
|
49
|
+
class Notify < Payload
|
50
|
+
# Payload type number
|
51
|
+
PAYLOAD_TYPE = 41
|
53
52
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
53
|
+
# Message types
|
54
|
+
TYPES = {
|
55
|
+
'UNSUPPORTED_CRITICAL_PAYLOAD' => 1,
|
56
|
+
'INVALID_IKE_SPI' => 4,
|
57
|
+
'INVALID_MAJOR_VERSION' => 5,
|
58
|
+
'INVALID_SYNTAX' => 7,
|
59
|
+
'INVALID_MESSAGE_ID' => 9,
|
60
|
+
'INVALID_SPI' => 11,
|
61
|
+
'NO_PROPOSAL_CHOSEN' => 14,
|
62
|
+
'INVALID_KE_PAYLOAD' => 17,
|
63
|
+
'AUTHENTICATION_FAILED' => 24,
|
64
|
+
'SINGLE_PAIR_REQUIRED' => 34,
|
65
|
+
'NO_ADDITIONAL_SAS' => 35,
|
66
|
+
'INTERNAL_ADDRESS_FAILURE' => 36,
|
67
|
+
'FAILED_CP_REQUIRED' => 37,
|
68
|
+
'TS_UNACCEPTABLE' => 38,
|
69
|
+
'INVALID_SELECTORS' => 39,
|
70
|
+
'TEMPORARY_FAILURE' => 43,
|
71
|
+
'CHILD_SA_NOT_FOUND' => 44,
|
72
|
+
'INITIAL_CONTACT' => 16_384,
|
73
|
+
'SET_WINDOW_SIZE' => 16_385,
|
74
|
+
'ADDITIONAL_TS_POSSIBLE' => 16_386,
|
75
|
+
'IPCOMP_SUPPORTED' => 16_387,
|
76
|
+
'NAT_DETECTION_SOURCE_IP' => 16_388,
|
77
|
+
'NAT_DETECTION_DESTINATION_IP' => 16_389,
|
78
|
+
'COOKIE' => 16_390,
|
79
|
+
'USE_TRANSPORT_MODE' => 16_391,
|
80
|
+
'HTTP_CERT_LOOKUP_SUPPORTED' => 16_392,
|
81
|
+
'REKEY_SA' => 16_393,
|
82
|
+
'ESP_TFC_PADDING_NOT_SUPPORTED' => 16_394,
|
83
|
+
'NON_FIRST_FRAGMENTS_ALSO' => 16_395,
|
84
|
+
}.freeze
|
86
85
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
86
|
+
# @!attribute [r] protocol
|
87
|
+
# 8-bit protocol ID. If this notification concerns an existing
|
88
|
+
# SA whose SPI is given in the SPI field, this field indicates the
|
89
|
+
# type of that SA. For notifications concerning Child SAs, this
|
90
|
+
# field MUST contain either (2) to indicate AH or (3) to indicate
|
91
|
+
# ESP. Of the notifications defined in this document, the SPI is
|
92
|
+
# included only with INVALID_SELECTORS, REKEY_SA, and
|
93
|
+
# CHILD_SA_NOT_FOUND. If the SPI field is empty, this field MUST be
|
94
|
+
# sent as zero and MUST be ignored on receipt.
|
95
|
+
# @return [Integer]
|
96
|
+
define_attr_before :content, :protocol, BinStruct::Int8Enum, enum: PROTOCOLS
|
97
|
+
# @!attribute spi_size
|
98
|
+
# 8-bit SPI size. Give size of SPI field. Length in octets of the SPI as
|
99
|
+
# defined by the IPsec protocol ID or zero if no SPI is applicable. For a
|
100
|
+
# notification concerning the IKE SA, the SPI Size MUST be zero and
|
101
|
+
# the field must be empty.Set to 0 for an initial IKE SA
|
102
|
+
# negotiation, as SPI is obtained from outer Plugin.
|
103
|
+
# @return [Integer]
|
104
|
+
define_attr_before :content, :spi_size, BinStruct::Int8, default: 0
|
105
|
+
# @!attribute message_type
|
106
|
+
# 16-bit notify message type. Specifies the type of notification message.
|
107
|
+
# @return [Integer]
|
108
|
+
define_attr_before :content, :message_type, BinStruct::Int16Enum, enum: TYPES, default: 0
|
109
|
+
# @!attribute spi
|
110
|
+
# the sending entity's SPI. When the {#spi_size} field is zero,
|
111
|
+
# this field is not present in the proposal.
|
112
|
+
# @return [String]
|
113
|
+
define_attr_before :content, :spi, BinStruct::String,
|
114
|
+
builder: ->(h, t) { t.new(length_from: h[:spi_size]) }
|
116
115
|
|
117
|
-
|
116
|
+
alias type message_type
|
118
117
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
self.message_type = options[:type] if options[:type]
|
127
|
-
end
|
118
|
+
def initialize(options={})
|
119
|
+
options[:spi_size] = options[:spi].size if options[:spi] && options[:spi_size].nil?
|
120
|
+
super
|
121
|
+
self.protocol = options[:protocol] if options[:protocol]
|
122
|
+
self.message_type = options[:message_type] if options[:message_type]
|
123
|
+
self.message_type = options[:type] if options[:type]
|
124
|
+
end
|
128
125
|
|
129
|
-
|
126
|
+
alias type= message_type=
|
130
127
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
128
|
+
# Get protocol name
|
129
|
+
# @return [String]
|
130
|
+
def human_protocol
|
131
|
+
self[:protocol].to_human
|
132
|
+
end
|
136
133
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
134
|
+
# Get message type name
|
135
|
+
# @return [String]
|
136
|
+
def human_message_type
|
137
|
+
self[:message_type].to_human
|
138
|
+
end
|
139
|
+
alias human_type human_message_type
|
143
140
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
141
|
+
# @return [String]
|
142
|
+
def inspect
|
143
|
+
super do |attr|
|
144
|
+
next unless attr == :protocol
|
148
145
|
|
149
|
-
|
150
|
-
|
151
|
-
human_protocol]
|
152
|
-
end
|
146
|
+
str = PacketGen::Inspect.shift_level
|
147
|
+
str << (PacketGen::Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr, human_protocol])
|
153
148
|
end
|
154
149
|
end
|
155
150
|
end
|
156
|
-
|
157
|
-
Header.add_class IKE::Notify
|
158
151
|
end
|
152
|
+
|
153
|
+
PacketGen::Header.add_class IKE::Notify
|
159
154
|
end
|
@@ -5,75 +5,74 @@
|
|
5
5
|
|
6
6
|
# frozen_string_literal: true
|
7
7
|
|
8
|
-
module PacketGen
|
9
|
-
|
10
|
-
class IKE
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
return @protocol_name if defined? @protocol_name
|
26
|
-
|
27
|
-
basename = to_s.sub(/.*::/, '')
|
28
|
-
@protocol_name = "IKE::#{basename}"
|
29
|
-
end
|
8
|
+
module PacketGen::Plugin
|
9
|
+
class IKE
|
10
|
+
# PacketGen::Header::Base class for IKE payloads. This class may also be used for unknown payloads.
|
11
|
+
#
|
12
|
+
# This class handles generic IKE payload Plugin:
|
13
|
+
# 1 2 3
|
14
|
+
# 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
|
15
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
16
|
+
# | Next Payload |C| RESERVED | Payload Length |
|
17
|
+
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
18
|
+
# to which a {#content} field is added to handle content of unknown payload types.
|
19
|
+
# @author Sylvain Daubert
|
20
|
+
class Payload < PacketGen::Header::Base
|
21
|
+
# Give protocol name
|
22
|
+
# @return [String]
|
23
|
+
def self.protocol_name
|
24
|
+
return @protocol_name if defined? @protocol_name
|
30
25
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
define_field :next, PacketGen::Types::Int8
|
35
|
-
# @!attribute flags
|
36
|
-
# 8-bit flags
|
37
|
-
# @return [Integer]
|
38
|
-
define_field :flags, PacketGen::Types::Int8
|
39
|
-
# @!attribute length
|
40
|
-
# 16-bit payload total length, including generic payload Plugin
|
41
|
-
# @return [Integer]
|
42
|
-
define_field :length, PacketGen::Types::Int16
|
43
|
-
# @!attribute content
|
44
|
-
# Payload content. Depends on payload. Variable length.
|
45
|
-
# @return [String]
|
46
|
-
define_field :content, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:content) }) }
|
26
|
+
basename = to_s.sub(/.*::/, '')
|
27
|
+
@protocol_name = "IKE::#{basename}"
|
28
|
+
end
|
47
29
|
|
48
|
-
|
49
|
-
|
30
|
+
# @!attribute next
|
31
|
+
# 8-bit next payload
|
32
|
+
# @return [Integer]
|
33
|
+
define_attr :next, BinStruct::Int8
|
34
|
+
# @!attribute flags
|
35
|
+
# 8-bit flags
|
36
|
+
# @return [Integer]
|
37
|
+
# @!attribute critical
|
38
|
+
# critical flag
|
39
|
+
# @return [Boolean]
|
40
|
+
# @!attribute hreserved
|
41
|
+
# reserved part of {#flags} field
|
42
|
+
# @return [Integer]
|
43
|
+
define_bit_attr :flags, critical: 1, hreserved: 7
|
44
|
+
# @!attribute length
|
45
|
+
# 16-bit payload total length, including generic payload Plugin
|
46
|
+
# @return [Integer]
|
47
|
+
define_attr :length, BinStruct::Int16
|
48
|
+
# @!attribute content
|
49
|
+
# Payload content. Depends on payload. Variable length.
|
50
|
+
# @return [String]
|
51
|
+
define_attr :content, BinStruct::String, builder: ->(h, t) { t.new(length_from: -> { h.length - h.offset_of(:content) }) }
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
-
# @return [Boolean]
|
54
|
-
# @!attribute hreserved
|
55
|
-
# reserved part of {#flags} field
|
56
|
-
# @return [Integer]
|
57
|
-
define_bit_fields_on :flags, :critical, :hreserved, 7
|
53
|
+
# Defining a body permits using Packet#parse to parse next IKE payloads.
|
54
|
+
define_attr :body, BinStruct::String
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
def initialize(options={})
|
57
|
+
super
|
58
|
+
if options[:content]
|
59
|
+
self[:content] = BinStruct::String.new
|
60
|
+
self[:content].read options[:content]
|
63
61
|
end
|
62
|
+
calc_length unless options[:length]
|
63
|
+
end
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
65
|
+
# Compute length and set {#length} field
|
66
|
+
# @return [Integer] new length
|
67
|
+
def calc_length
|
68
|
+
# Here, #body is next payload, so body size should not be taken in
|
69
|
+
# account (payload's real body is #content).
|
70
|
+
self.length = sz - self[:body].sz
|
72
71
|
end
|
73
72
|
end
|
74
|
-
|
75
|
-
Header.add_class IKE::Payload
|
76
73
|
end
|
74
|
+
|
75
|
+
PacketGen::Header.add_class IKE::Payload
|
77
76
|
end
|
78
77
|
|
79
78
|
require_relative 'sa'
|
@@ -88,7 +87,7 @@ require_relative 'auth'
|
|
88
87
|
require_relative 'ts'
|
89
88
|
require_relative 'vendor_id'
|
90
89
|
|
91
|
-
module PacketGen::Plugin
|
90
|
+
module PacketGen::Plugin # rubocop:disable Metrics/ModuleLength
|
92
91
|
IKE.bind IKE::SA, next: IKE::SA::PAYLOAD_TYPE
|
93
92
|
IKE::Payload.bind IKE::SA, next: IKE::SA::PAYLOAD_TYPE
|
94
93
|
IKE::KE.bind IKE::SA, next: IKE::SA::PAYLOAD_TYPE
|
@@ -286,19 +285,19 @@ module PacketGen::Plugin
|
|
286
285
|
IKE::TSr.bind IKE::VendorID, next: IKE::VendorID::PAYLOAD_TYPE
|
287
286
|
|
288
287
|
# Last defined. To be used as default if no other may be parsed.
|
289
|
-
IKE::SA.bind IKE::Payload, next:
|
290
|
-
IKE::KE.bind IKE::Payload, next:
|
291
|
-
IKE::Nonce.bind IKE::Payload, next:
|
292
|
-
IKE::Notify.bind IKE::Payload, next:
|
293
|
-
IKE::SK.bind IKE::Payload, next:
|
294
|
-
IKE::IDi.bind IKE::Payload, next:
|
295
|
-
IKE::IDr.bind IKE::Payload, next:
|
296
|
-
IKE::Cert.bind IKE::Payload, next:
|
297
|
-
IKE::CertReq.bind IKE::Payload, next:
|
298
|
-
IKE::Auth.bind IKE::Payload, next:
|
299
|
-
IKE::TSi.bind IKE::Payload, next:
|
300
|
-
IKE::TSr.bind IKE::Payload, next:
|
301
|
-
IKE::VendorID.bind IKE::Payload, next:
|
302
|
-
IKE.bind IKE::Payload, next:
|
303
|
-
IKE::Payload.bind IKE::Payload, next:
|
288
|
+
IKE::SA.bind IKE::Payload, next: lambda(&:positive?)
|
289
|
+
IKE::KE.bind IKE::Payload, next: lambda(&:positive?)
|
290
|
+
IKE::Nonce.bind IKE::Payload, next: lambda(&:positive?)
|
291
|
+
IKE::Notify.bind IKE::Payload, next: lambda(&:positive?)
|
292
|
+
IKE::SK.bind IKE::Payload, next: lambda(&:positive?)
|
293
|
+
IKE::IDi.bind IKE::Payload, next: lambda(&:positive?)
|
294
|
+
IKE::IDr.bind IKE::Payload, next: lambda(&:positive?)
|
295
|
+
IKE::Cert.bind IKE::Payload, next: lambda(&:positive?)
|
296
|
+
IKE::CertReq.bind IKE::Payload, next: lambda(&:positive?)
|
297
|
+
IKE::Auth.bind IKE::Payload, next: lambda(&:positive?)
|
298
|
+
IKE::TSi.bind IKE::Payload, next: lambda(&:positive?)
|
299
|
+
IKE::TSr.bind IKE::Payload, next: lambda(&:positive?)
|
300
|
+
IKE::VendorID.bind IKE::Payload, next: lambda(&:positive?)
|
301
|
+
IKE.bind IKE::Payload, next: lambda(&:positive?)
|
302
|
+
IKE::Payload.bind IKE::Payload, next: lambda(&:positive?)
|
304
303
|
end
|