packetgen 1.4.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,105 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Certificate payloads.
7
+ #
8
+ # A Cert payload consists of the IKE generic payload header (see {Payload})
9
+ # and some specific fields:
10
+ # 1 2 3
11
+ # 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
12
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13
+ # | Next Payload |C| RESERVED | Payload Length |
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | Cert Encoding | |
16
+ # +-+-+-+-+-+-+-+-+ +
17
+ # | |
18
+ # ~ Certificate Data ~
19
+ # | |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # These specific fields are:
22
+ # * {#encoding},
23
+ # * and {#content} (Certificate Data).
24
+ #
25
+ # == Create a Cert payload
26
+ # # Create a IKE packet with a Cert payload
27
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Cert', encoding: 'X509_CERT_SIG')
28
+ # certs = cert.to_der << ca_cert.to_der
29
+ # pkt.ike_cert.content.read certs
30
+ # pkt.calc_length
31
+ # @author Sylvain Daubert
32
+ class Cert < Payload
33
+
34
+ # Payload type number
35
+ PAYLOAD_TYPE = 37
36
+
37
+ ENCODING_PKCS7_WRAPPED_X509 = 1
38
+ ENCODING_PGP = 2
39
+ ENCODING_DNS_SIGNED_KEY = 3
40
+ ENCODING_X509_CERT_SIG = 4
41
+ ENCODING_KERBEROS_TOKEN = 6
42
+ ENCODING_X509_CRL = 7
43
+ ENCODING_X509_ARL = 8
44
+ ENCODING_SPKI_CERT = 9
45
+ ENCODING_X509_CERT_ATTR = 10
46
+ ENCODING_HASH_URL_X509_CERT = 12
47
+ ENCODING_HASH_URL_X509_BUNDLE = 13
48
+
49
+ # @attribute encoding
50
+ # 8-bit certificate encoding
51
+ # @return [Integer]
52
+ define_field_before :content, :encoding, Types::Int8
53
+
54
+ def initialize(options={})
55
+ super
56
+ self.encoding = options[:encoding] if options[:encoding]
57
+ end
58
+
59
+ # Set encoding
60
+ # @param [Integer,String] value
61
+ # @return [Integer]
62
+ def encoding=(value)
63
+ encoding = case value
64
+ when Integer
65
+ value
66
+ else
67
+ c = self.class.constants.grep(/ENCODING_#{value}/).first
68
+ c ? self.class.const_get(c) : nil
69
+ end
70
+ raise ArgumentError, "unknown ID encoding #{value.inspect}" unless encoding
71
+ self[:encoding].value = encoding
72
+ end
73
+
74
+ # Get encoding name
75
+ # @return [String]
76
+ def human_encoding
77
+ name = self.class.constants.grep(/ENCODING_/).
78
+ select { |c| self.class.const_get(c) == encoding }.
79
+ first || "encoding #{encoding}"
80
+ name.to_s.sub(/ENCODING_/, '')
81
+ end
82
+
83
+ # @return [String]
84
+ def inspect
85
+ str = Inspect.dashed_line(self.class, 2)
86
+ fields.each do |attr|
87
+ case attr
88
+ when :body
89
+ next
90
+ when :encoding
91
+ str << Inspect.shift_level(2)
92
+ str << Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr,
93
+ human_encoding]
94
+ else
95
+ str << Inspect.inspect_attribute(attr, self[attr], 2)
96
+ end
97
+ end
98
+ str
99
+ end
100
+ end
101
+ end
102
+
103
+ self.add_class IKE::Cert
104
+ end
105
+ end
@@ -0,0 +1,69 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Certificate Request payloads.
7
+ #
8
+ # A CertReq payload consists of the IKE generic payload header (see {Payload})
9
+ # and some specific fields:
10
+ # 1 2 3
11
+ # 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
12
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13
+ # | Next Payload |C| RESERVED | Payload Length |
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | Cert Encoding | |
16
+ # +-+-+-+-+-+-+-+-+ +
17
+ # | |
18
+ # ~ Certification Authority ~
19
+ # | |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # These specific fields are:
22
+ # * {#encoding},
23
+ # * and {#content} (Certification Authority).
24
+ #
25
+ # == Create a CertReq payload
26
+ # # Create a IKE packet with a CertReq payload
27
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::CertReq', encoding: 'X509_CERT_SIG')
28
+ # pkt.ike_certreq.content.read OpenSSL::Digest::SHA1.digest(ca_cert.to_der)
29
+ # pkt.calc_length
30
+ # @author Sylvain Daubert
31
+ class CertReq < Cert
32
+
33
+ # Payload type number
34
+ PAYLOAD_TYPE = 38
35
+
36
+ # Get list of 20-byte string (SHA-1 hashes)
37
+ # @return [String]
38
+ def human_content
39
+ strs = []
40
+ idx = 0
41
+ while idx < content.size do
42
+ strs << content[idx, 20]
43
+ idx += 20
44
+ end
45
+ strs.map(&:inspect).join(',')
46
+ end
47
+
48
+ # @return [String]
49
+ def inspect
50
+ str = Inspect.dashed_line(self.class, 2)
51
+ fields.each do |attr|
52
+ case attr
53
+ when :body
54
+ next
55
+ when :content
56
+ str << Inspect.shift_level(2)
57
+ str << Inspect::FMT_ATTR % ['hashes', :content, human_content]
58
+ else
59
+ str << Inspect.inspect_attribute(attr, self[attr], 2)
60
+ end
61
+ end
62
+ str
63
+ end
64
+ end
65
+ end
66
+
67
+ self.add_class IKE::CertReq
68
+ end
69
+ end
@@ -0,0 +1,131 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Identification - Initiator payloads, denoted IDi
7
+ # (see RFC 7296, §3.5).
8
+ #
9
+ # A ID payload consists of the IKE generic payload header (see {Payload})
10
+ # and some specific fields:
11
+ # 1 2 3
12
+ # 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
13
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14
+ # | Next Payload |C| RESERVED | Payload Length |
15
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16
+ # | ID Type | RESERVED |
17
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18
+ # | |
19
+ # ~ Identification Data ~
20
+ # | |
21
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22
+ # These specific fields are:
23
+ # * {#type} (ID type),
24
+ # * {#reserved},
25
+ # * and {#content} (Identification Data).
26
+ #
27
+ # == Create a IDi payload
28
+ # # Create a IKE packet with a IDi payload
29
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::IDi', type: 'FQDN')
30
+ # pkt.ike_idi.content.read 'fqdn.example.org'
31
+ # pkt.calc_length
32
+ # @author Sylvain Daubert
33
+ class IDi < Payload
34
+
35
+ # Payload type number
36
+ PAYLOAD_TYPE = 35
37
+
38
+ TYPE_IPV4_ADDR = 1
39
+ TYPE_FQDN = 2
40
+ TYPE_RFC822_ADDR = 3
41
+ TYPE_IPV6_ADDR = 5
42
+ TYPE_DER_ASN1_DN = 9
43
+ TYPE_DER_ASN1_GN = 10
44
+ TYPE_KEY_ID = 11
45
+
46
+ # @attribute :u32
47
+ # 32-bit word including ID Type and RESERVED fields
48
+ # @return [Integer]
49
+ define_field_before :content, :u32, Types::Int32
50
+ # @attribute [r] type
51
+ # 8-bit ID type
52
+ # @return [Integer]
53
+ # @attribute reserved
54
+ # 24-bit reserved field
55
+ # @return [Integer]
56
+ define_bit_fields_on :u32, :type, 8, :reserved, 24
57
+
58
+ # Set ID type
59
+ # @param [Integer,String] value
60
+ # @return [Integer]
61
+ def type=(value)
62
+ type = case value
63
+ when Integer
64
+ value
65
+ else
66
+ c = self.class.constants.grep(/TYPE_#{value}/).first
67
+ c ? self.class.const_get(c) : nil
68
+ end
69
+ raise ArgumentError, "unknown ID type #{value.inspect}" unless type
70
+ self[:u32].value = (self[:u32].to_i & 0xffffff) | (type << 24)
71
+ end
72
+
73
+ # Get ID type name
74
+ # @return [String]
75
+ def human_type
76
+ name = self.class.constants.grep(/TYPE_/).
77
+ select { |c| self.class.const_get(c) == type }.
78
+ first || "type #{type}"
79
+ name.to_s.sub(/TYPE_/, '')
80
+ end
81
+
82
+ # Get human readable content, from {#type}
83
+ # @return [String]
84
+ def human_content
85
+ case type
86
+ when TYPE_IPV4_ADDR, TYPE_IPV4_ADDR
87
+ IPAddr.ntop(content)
88
+ when TYPE_DER_ASN1_DN, TYPE_DER_ASN1_GN
89
+ OpenSSL::X509::Name.new(content).to_s
90
+ else
91
+ content.inspect
92
+ end
93
+ end
94
+
95
+ # @return [String]
96
+ def inspect
97
+ str = Inspect.dashed_line(self.class, 2)
98
+ fields.each do |attr|
99
+ case attr
100
+ when :body
101
+ next
102
+ when :u32
103
+ str << Inspect.shift_level(2)
104
+ str << Inspect::FMT_ATTR % ['Int8', :type, human_type]
105
+ str << Inspect.inspect_attribute(:reserved, self.reserved, 2)
106
+ else
107
+ str << Inspect.inspect_attribute(attr, self[attr], 2)
108
+ end
109
+ end
110
+ str
111
+ end
112
+ end
113
+
114
+ # This class handles Identification - Responder payloads, denoted IDr.
115
+ # See {IDi}.
116
+ #
117
+ # == Create a IDr payload
118
+ # # Create a IKE packet with a IDr payload
119
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::IDr', type: 'FQDN')
120
+ # pkt.ike_idr.content.read 'fqdn.example.org'
121
+ # @author Sylvain Daubert
122
+ class IDr < IDi
123
+ # Payload type number
124
+ PAYLOAD_TYPE = 36
125
+ end
126
+ end
127
+
128
+ self.add_class IKE::IDi
129
+ self.add_class IKE::IDr
130
+ end
131
+ end
@@ -0,0 +1,74 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Key Exchange payloads, as defined in RFC 7296 §3.4
7
+ #
8
+ # A KE payload contains a generic payload header (see {Payload}) and some
9
+ # specific fields:
10
+ # 1 2 3
11
+ # 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
12
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13
+ # | Next Payload |C| RESERVED | Payload Length |
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | Diffie-Hellman Group Num | RESERVED |
16
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17
+ # | |
18
+ # ~ Key Exchange Data ~
19
+ # | |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # These specific fields are:
22
+ # * {#group_num} (type {Types::Int16}),
23
+ # * {#reserved} (type {Types::Int16}),
24
+ # * and {#content} (type {Types::String}).
25
+ #
26
+ # == Create a KE payload
27
+ # # Create a IKE packet with a KE payload
28
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
29
+ # # group name is taken from Transform::DH_* constants
30
+ # pkt.add('IKE::KE', group: 'MODP4096')
31
+ # # group number may also be used
32
+ # pkt.ike_ke.group = 1
33
+ # pkt.calc_length
34
+ # @author Sylvain Daubert
35
+ class KE < Payload
36
+
37
+ # Payload type number
38
+ PAYLOAD_TYPE = 34
39
+
40
+ # @!attribute group_num
41
+ # 16-bit DH group number
42
+ # @return [Integer]
43
+ define_field_before :content, :group_num, Types::Int16
44
+ # @!attribute reserved
45
+ # 16-bit reserved field
46
+ # @return [Integer]
47
+ define_field_before :content, :reserved, Types::Int16, default: 0
48
+
49
+ def initialize(options={})
50
+ super
51
+ self.group = options[:group] if options[:group]
52
+ end
53
+
54
+ # Set group
55
+ # @param [Integer,String] value may be a String taken from
56
+ # {Transform}+::DH_*+ constant names.
57
+ # @return [Integer]
58
+ def group=(value)
59
+ group = case value
60
+ when Integer
61
+ value
62
+ else
63
+ cname = "DH_#{value}"
64
+ Transform.const_defined?(cname) ? Transform.const_get(cname) : nil
65
+ end
66
+ raise ArgumentError, "unknown group #{value.inspect}" unless group
67
+ self[:group_num].value = group
68
+ end
69
+ end
70
+ end
71
+
72
+ self.add_class IKE::KE
73
+ end
74
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Nonce payloads, as defined in RFC 7296 §3.9.
7
+ #
8
+ # A Nonce payload contains a generic payload header (see {Payload}) and
9
+ # data field (type {Types::String}):
10
+ # 1 2 3
11
+ # 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
12
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13
+ # | Next Payload |C| RESERVED | Payload Length |
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | |
16
+ # ~ Nonce Data ~
17
+ # | |
18
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
+ #
20
+ # == Create a Nonce payload
21
+ # # Create a IKE packet with a Nonce payload
22
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE')
23
+ # pkt.add('IKE::Nonce', data: "abcdefgh")
24
+ # pkt.calc_length
25
+ # @author Sylvain Daubert
26
+ class Nonce < Payload
27
+
28
+ # Payload type number
29
+ PAYLOAD_TYPE = 40
30
+ end
31
+ end
32
+
33
+ self.add_class IKE::Nonce
34
+ end
35
+ end
@@ -0,0 +1,220 @@
1
+ # coding: utf-8
2
+ module PacketGen
3
+ module Header
4
+ class IKE
5
+
6
+ # This class handles Notify payloads, as defined in RFC 7296 §3.10.
7
+ #
8
+ # A Notify payload contains a generic payload header (see {Payload}) and
9
+ # some specific fields:
10
+ # 1 2 3
11
+ # 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
12
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13
+ # | Next Payload |C| RESERVED | Payload Length |
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | Protocol ID | SPI Size | Notify Message Type |
16
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17
+ # | |
18
+ # ~ Security Parameter Index (SPI) ~
19
+ # | |
20
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21
+ # | |
22
+ # ~ Notification Data ~
23
+ # | |
24
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25
+ # These specific fields are:
26
+ # * {#protocol} (type {Types::Int8}),
27
+ # * {#spi_size} (type {Types::Int8}),
28
+ # * {#message_type} (type {Types::Int16}),
29
+ # * {#spi} (type {Types::String}),
30
+ # * {#content} (type {Types::String}).
31
+ #
32
+ # == Create a Notify payload
33
+ # # Create a IKE packet with a Notify payload
34
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Notify', protocol: 'IKE', type: 'INVALID_SYNTAX')
35
+ # pkt.ike_notify.spi # => ""
36
+ # pkt.ike_notify.content # => ""
37
+ # pkt.calc_length
38
+ # == Create a Notify payload with a SPI
39
+ # # Create a IKE packet with a Notify payload
40
+ # pkt = PacketGen.gen('IP').add('UDP').add('IKE').add('IKE::Notify', protocol: 'ESP', spi_size: 4, type: 'INVALID_SYNTAX')
41
+ # pkt.ike_notify.spi.read PacketGen::Types::Int32.new(0x12345678).to_s
42
+ # pkt.calc_length
43
+ # @author Sylvain Daubert
44
+ class Notify < Payload
45
+
46
+ # Payload type number
47
+ PAYLOAD_TYPE = 41
48
+
49
+ # Unsupported critical payload
50
+ TYPE_UNSUPPORTED_CRITICAL_PAYLOAD = 1
51
+ # Invalid IKE SPI
52
+ TYPE_INVALID_IKE_SPI = 4
53
+ # Invalid major version
54
+ TYPE_INVALID_MAJOR_VERSION = 5
55
+ # Invalid syntax
56
+ TYPE_INVALID_SYNTAX = 7
57
+ # Invalid message ID
58
+ TYPE_INVALID_MESSAGE_ID = 9
59
+ # Invalid SPI
60
+ TYPE_INVALID_SPI = 11
61
+ # No proposal chosen (none of the proposed crypto suites was acceptable)
62
+ TYPE_NO_PROPOSAL_CHOSEN = 14
63
+ # Invalid KE payload
64
+ TYPE_INVALID_KE_PAYLOAD = 17
65
+ # Authentication failed
66
+ TYPE_AUTHENTICATION_FAILED = 24
67
+ # Single pair required
68
+ TYPE_SINGLE_PAIR_REQUIRED = 34
69
+ # No additional SAs
70
+ TYPE_NO_ADDITIONAL_SAS = 35
71
+ # Internal address failture
72
+ TYPE_INTERNAL_ADDRESS_FAILURE = 36
73
+ # Failed CP required
74
+ TYPE_FAILED_CP_REQUIRED = 37
75
+ # traffic selectors unacceptable
76
+ TYPE_TS_UNACCEPTABLE = 38
77
+ # invalid selectors
78
+ TYPE_INVALID_SELECTORS = 39
79
+ # Temporary failure
80
+ TYPE_TEMPORARY_FAILURE = 43
81
+ # Child SA not found
82
+ TYPE_CHILD_SA_NOT_FOUND = 44
83
+ # Initial contact
84
+ TYPE_INITIAL_CONTACT = 16384
85
+ # Set window size
86
+ TYPE_SET_WINDOW_SIZE = 16385
87
+ # Additional traffic selector possible
88
+ TYPE_ADDITIONAL_TS_POSSIBLE = 16386
89
+ # IPcomp supported
90
+ TYPE_IPCOMP_SUPPORTED = 16387
91
+ # NAT detection source IP
92
+ TYPE_NAT_DETECTION_SOURCE_IP = 16388
93
+ # NAT detection destination IP
94
+ TYPE_NAT_DETECTION_DESTINATION_IP = 16389
95
+ # Cookie
96
+ TYPE_COOKIE = 16390
97
+ # Use transport mode (tunnel mode is default)
98
+ TYPE_USE_TRANSPORT_MODE = 16391
99
+ # HTTP certificate look up supported
100
+ TYPE_HTTP_CERT_LOOKUP_SUPPORTED = 16392
101
+ # Rekey SA
102
+ TYPE_REKEY_SA = 16393
103
+ # ESP TFC paddin not supported
104
+ TYPE_ESP_TFC_PADDING_NOT_SUPPORTED = 16394
105
+ # Non-first fragment also
106
+ TYPE_NON_FIRST_FRAGMENTS_ALSO = 16395
107
+
108
+ # @!attribute [r] protocol
109
+ # 8-bit protocol ID. If this notification concerns an existing
110
+ # SA whose SPI is given in the SPI field, this field indicates the
111
+ # type of that SA. For notifications concerning Child SAs, this
112
+ # field MUST contain either (2) to indicate AH or (3) to indicate
113
+ # ESP. Of the notifications defined in this document, the SPI is
114
+ # included only with INVALID_SELECTORS, REKEY_SA, and
115
+ # CHILD_SA_NOT_FOUND. If the SPI field is empty, this field MUST be
116
+ # sent as zero and MUST be ignored on receipt.
117
+ # @return [Integer]
118
+ define_field_before :content, :protocol, Types::Int8
119
+ # @!attribute spi_size
120
+ # 8-bit SPI size. Give size of SPI field. Length in octets of the SPI as
121
+ # defined by the IPsec protocol ID or zero if no SPI is applicable. For a
122
+ # notification concerning the IKE SA, the SPI Size MUST be zero and
123
+ # the field must be empty.Set to 0 for an initial IKE SA
124
+ # negotiation, as SPI is obtained from outer header.
125
+ # @return [Integer]
126
+ define_field_before :content, :spi_size, Types::Int8, default: 0
127
+ # @!attribute message_type
128
+ # 16-bit notify message type. Specifies the type of notification message.
129
+ # @return [Integer]
130
+ define_field_before :content, :message_type, Types::Int16
131
+ # @!attribute spi
132
+ # the sending entity's SPI. When the {#spi_size} field is zero,
133
+ # this field is not present in the proposal.
134
+ # @return [String]
135
+ define_field_before :content, :spi, Types::String,
136
+ builder: ->(t) { Types::String.new('', length_from: t[:spi_size]) }
137
+
138
+ alias type message_type
139
+
140
+ def initialize(options={})
141
+ if options[:spi] and options[:spi_size].nil?
142
+ options[:spi_size] = options[:spi].size
143
+ end
144
+ super
145
+ self.protocol = options[:protocol] if options[:protocol]
146
+ self.message_type = options[:message_type] if options[:message_type]
147
+ self.type = options[:type] if options[:type]
148
+ end
149
+
150
+ # Set protocol
151
+ # @param [Integer,String] value
152
+ # @return [Integer]
153
+ def protocol=(value)
154
+ proto = case value
155
+ when Integer
156
+ value
157
+ else
158
+ c = IKE.constants.grep(/PROTO_#{value}/).first
159
+ c ? IKE.const_get(c) : nil
160
+ end
161
+ raise ArgumentError, "unknown protocol #{value.inspect}" unless proto
162
+ self[:protocol].value = proto
163
+ end
164
+
165
+ # Set message type
166
+ # @param [Integer,String] value
167
+ # @return [Integer]
168
+ def message_type=(value)
169
+ type = case value
170
+ when Integer
171
+ value
172
+ else
173
+ c = self.class.constants.grep(/TYPE_#{value}/).first
174
+ c ? self.class.const_get(c) : nil
175
+ end
176
+ raise ArgumentError, "unknown message type #{value.inspect}" unless type
177
+ self[:message_type].value = type
178
+ end
179
+ alias type= message_type=
180
+
181
+ # Get protocol name
182
+ # @return [String]
183
+ def human_protocol
184
+ name = IKE.constants.grep(/PROTO/).
185
+ select { |c| IKE.const_get(c) == protocol }.
186
+ first || "proto #{protocol}"
187
+ name.to_s.sub(/PROTO_/, '')
188
+ end
189
+
190
+ # Get message type name
191
+ # @return [String]
192
+ def human_message_type
193
+ name = self.class.constants.grep(/TYPE_/).
194
+ select { |c| self.class.const_get(c) == type }.
195
+ first || "type #{type}"
196
+ name.to_s.sub(/TYPE_/, '')
197
+ end
198
+ alias human_type human_message_type
199
+
200
+ # @return [String]
201
+ def inspect
202
+ str = Inspect.dashed_line(self.class, 2)
203
+ fields.each do |attr|
204
+ next if attr == :body
205
+ if %i(protocol message_type).include? attr
206
+ str << Inspect.shift_level(2)
207
+ str << Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''), attr,
208
+ send("human_#{attr}")]
209
+ else
210
+ str << Inspect.inspect_attribute(attr, self[attr], 2)
211
+ end
212
+ end
213
+ str
214
+ end
215
+ end
216
+ end
217
+
218
+ self.add_class IKE::Nonce
219
+ end
220
+ end