packetgen 1.4.3 → 2.0.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/.travis.yml +3 -4
- data/README.md +6 -6
- data/lib/packetgen.rb +0 -1
- data/lib/packetgen/capture.rb +15 -37
- data/lib/packetgen/header.rb +6 -2
- data/lib/packetgen/header/asn1_base.rb +86 -0
- data/lib/packetgen/header/base.rb +68 -44
- data/lib/packetgen/header/crypto.rb +62 -0
- data/lib/packetgen/header/dns.rb +3 -3
- data/lib/packetgen/header/dot11.rb +5 -0
- data/lib/packetgen/header/esp.rb +7 -43
- data/lib/packetgen/header/ike.rb +235 -0
- data/lib/packetgen/header/ike/auth.rb +197 -0
- data/lib/packetgen/header/ike/cert.rb +105 -0
- data/lib/packetgen/header/ike/certreq.rb +69 -0
- data/lib/packetgen/header/ike/id.rb +131 -0
- data/lib/packetgen/header/ike/ke.rb +74 -0
- data/lib/packetgen/header/ike/nonce.rb +35 -0
- data/lib/packetgen/header/ike/notify.rb +220 -0
- data/lib/packetgen/header/ike/payload.rb +307 -0
- data/lib/packetgen/header/ike/sa.rb +577 -0
- data/lib/packetgen/header/ike/sk.rb +255 -0
- data/lib/packetgen/header/ike/ts.rb +287 -0
- data/lib/packetgen/header/ike/vendor_id.rb +34 -0
- data/lib/packetgen/header/ip.rb +4 -4
- data/lib/packetgen/header/ipv6.rb +3 -3
- data/lib/packetgen/header/snmp.rb +283 -0
- data/lib/packetgen/header/tcp.rb +3 -3
- data/lib/packetgen/inspect.rb +35 -9
- data/lib/packetgen/packet.rb +23 -9
- data/lib/packetgen/types/fields.rb +11 -3
- data/lib/packetgen/version.rb +1 -1
- data/packetgen.gemspec +2 -0
- metadata +52 -2
@@ -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
|