1
/* parsing packets: formats and tools
2
* Copyright (C) 1997 Angelos D. Keromytis.
3
* Copyright (C) 1998-2001 D. Hugh Redelmeier.
5
* This program is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License as published by the
7
* Free Software Foundation; either version 2 of the License, or (at your
8
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10
* This program is distributed in the hope that it will be useful, but
11
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15
* RCSID $Id: packet.c,v 1.43.2.1 2004/03/21 05:23:34 mcr Exp $
21
#include <netinet/in.h>
26
#include "constants.h"
30
#include "whack.h" /* for RC_LOG_SERIOUS */
32
/* ISAKMP Header: for all messages
33
* layout from RFC 2408 "ISAKMP" section 3.1
35
* 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
36
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43
* ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
44
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51
static field_desc isa_fields[] = {
52
{ ft_raw, COOKIE_SIZE, "initiator cookie", NULL },
53
{ ft_raw, COOKIE_SIZE, "responder cookie", NULL },
54
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
55
{ ft_enum, 8/BITS_PER_BYTE, "ISAKMP version", &version_names },
56
{ ft_enum, 8/BITS_PER_BYTE, "exchange type", &exchange_names },
57
{ ft_set, 8/BITS_PER_BYTE, "flags", flag_bit_names },
58
{ ft_raw, 32/BITS_PER_BYTE, "message ID", NULL },
59
{ ft_len, 32/BITS_PER_BYTE, "length", NULL },
60
{ ft_end, 0, NULL, NULL }
63
struct_desc isakmp_hdr_desc = { "ISAKMP Message", isa_fields, sizeof(struct isakmp_hdr) };
65
/* Generic portion of all ISAKMP payloads.
66
* layout from RFC 2408 "ISAKMP" section 3.2
67
* This describes the first 32-bit chunk of all payloads.
68
* The previous next payload depends on the actual payload type.
70
* 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
71
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
72
* ! Next Payload ! RESERVED ! Payload Length !
73
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
76
static field_desc isag_fields[] = {
77
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
78
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
79
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
80
{ ft_end, 0, NULL, NULL }
83
struct_desc isakmp_generic_desc = { "ISAKMP Generic Payload", isag_fields, sizeof(struct isakmp_generic) };
86
/* ISAKMP Data Attribute (generic representation within payloads)
87
* layout from RFC 2408 "ISAKMP" section 3.3
88
* This is not a payload type.
89
* In TLV format, this is followed by a value field.
91
* 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
92
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93
* !A! Attribute Type ! AF=0 Attribute Length !
94
* !F! ! AF=1 Attribute Value !
95
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96
* . AF=0 Attribute Value .
97
* . AF=1 Not Transmitted .
98
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101
/* Oakley Attributes */
102
static field_desc isaat_fields_oakley[] = {
103
{ ft_af_enum, 16/BITS_PER_BYTE, "af+type", &oakley_attr_names },
104
{ ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
105
{ ft_end, 0, NULL, NULL }
108
struct_desc isakmp_oakley_attribute_desc = {
109
"ISAKMP Oakley attribute",
110
isaat_fields_oakley, sizeof(struct isakmp_attribute) };
112
/* IPsec DOI Attributes */
113
static field_desc isaat_fields_ipsec[] = {
114
{ ft_af_enum, 16/BITS_PER_BYTE, "af+type", &ipsec_attr_names },
115
{ ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
116
{ ft_end, 0, NULL, NULL }
119
struct_desc isakmp_ipsec_attribute_desc = {
120
"ISAKMP IPsec DOI attribute",
121
isaat_fields_ipsec, sizeof(struct isakmp_attribute) };
123
/* XAUTH Attributes */
124
static field_desc isaat_fields_xauth[] = {
125
{ ft_af_loose_enum, 16/BITS_PER_BYTE, "ModeCfg attr type", &modecfg_attr_names },
126
{ ft_lv, 16/BITS_PER_BYTE, "length/value", NULL },
127
{ ft_end, 0, NULL, NULL }
130
struct_desc isakmp_xauth_attribute_desc = {
131
"ISAKMP ModeCfg attribute",
132
isaat_fields_xauth, sizeof(struct isakmp_attribute) };
134
/* ISAKMP Security Association Payload
135
* layout from RFC 2408 "ISAKMP" section 3.4
136
* A variable length Situation follows.
137
* Previous next payload: ISAKMP_NEXT_SA
139
* 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
140
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
141
* ! Next Payload ! RESERVED ! Payload Length !
142
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
143
* ! Domain of Interpretation (DOI) !
144
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
148
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
150
static field_desc isasa_fields[] = {
151
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
152
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
153
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
154
{ ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
155
{ ft_end, 0, NULL, NULL }
158
struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) };
160
static field_desc ipsec_sit_field[] = {
161
{ ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names },
162
{ ft_end, 0, NULL, NULL }
165
struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) };
167
/* ISAKMP Proposal Payload
168
* layout from RFC 2408 "ISAKMP" section 3.5
169
* A variable length SPI follows.
170
* Previous next payload: ISAKMP_NEXT_P
172
* 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
173
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174
* ! Next Payload ! RESERVED ! Payload Length !
175
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176
* ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
177
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181
static field_desc isap_fields[] = {
182
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
183
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
184
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
185
{ ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL },
186
{ ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names },
187
{ ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
188
{ ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL },
189
{ ft_end, 0, NULL, NULL }
192
struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) };
194
/* ISAKMP Transform Payload
195
* layout from RFC 2408 "ISAKMP" section 3.6
196
* Variable length SA Attributes follow.
197
* Previous next payload: ISAKMP_NEXT_T
199
* 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
200
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
201
* ! Next Payload ! RESERVED ! Payload Length !
202
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
203
* ! Transform # ! Transform-Id ! RESERVED2 !
204
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212
static field_desc isat_fields_isakmp[] = {
213
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
214
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
215
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
216
{ ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
217
{ ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names },
218
{ ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
219
{ ft_end, 0, NULL, NULL }
222
struct_desc isakmp_isakmp_transform_desc = {
223
"ISAKMP Transform Payload (ISAKMP)",
224
isat_fields_isakmp, sizeof(struct isakmp_transform) };
227
static field_desc isat_fields_ah[] = {
228
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
229
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
230
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
231
{ ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
232
{ ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transformid_names },
233
{ ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
234
{ ft_end, 0, NULL, NULL }
237
struct_desc isakmp_ah_transform_desc = {
238
"ISAKMP Transform Payload (AH)",
239
isat_fields_ah, sizeof(struct isakmp_transform) };
241
/* PROTO_IPSEC_ESP */
242
static field_desc isat_fields_esp[] = {
243
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
244
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
245
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
246
{ ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
247
{ ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transformid_names },
248
{ ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
249
{ ft_end, 0, NULL, NULL }
252
struct_desc isakmp_esp_transform_desc = {
253
"ISAKMP Transform Payload (ESP)",
254
isat_fields_esp, sizeof(struct isakmp_transform) };
257
static field_desc isat_fields_ipcomp[] = {
258
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
259
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
260
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
261
{ ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
262
{ ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names },
263
{ ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
264
{ ft_end, 0, NULL, NULL }
267
struct_desc isakmp_ipcomp_transform_desc = {
268
"ISAKMP Transform Payload (COMP)",
269
isat_fields_ipcomp, sizeof(struct isakmp_transform) };
272
/* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones.
273
* layout from RFC 2408 "ISAKMP" section 3.7
274
* Variable Key Exchange Data follow the generic fields.
275
* Previous next payload: ISAKMP_NEXT_KE
277
* 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
278
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279
* ! Next Payload ! RESERVED ! Payload Length !
280
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
282
* ~ Key Exchange Data ~
284
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
286
struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) };
288
/* ISAKMP Identification Payload
289
* layout from RFC 2408 "ISAKMP" section 3.8
290
* See "struct identity" declared later.
291
* Variable length Identification Data follow.
292
* Previous next payload: ISAKMP_NEXT_ID
294
* 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
295
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
296
* ! Next Payload ! RESERVED ! Payload Length !
297
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298
* ! ID Type ! DOI Specific ID Data !
299
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
301
* ~ Identification Data ~
303
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
305
static field_desc isaid_fields[] = {
306
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
307
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
308
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
309
{ ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, /* ??? depends on DOI? */
310
{ ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL }, /* ??? depends on DOI? */
311
{ ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL }, /* ??? depends on DOI? */
312
{ ft_end, 0, NULL, NULL }
315
struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) };
317
/* IPSEC Identification Payload Content
318
* layout from RFC 2407 "IPsec DOI" section 4.6.2
319
* See struct isakmp_id declared earlier.
320
* Note: Hashing skips the ISAKMP generic payload header
321
* Variable length Identification Data follow.
323
* 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
324
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
325
* ! Next Payload ! RESERVED ! Payload Length !
326
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327
* ! ID Type ! Protocol ID ! Port !
328
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
329
* ~ Identification Data ~
330
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
332
static field_desc isaiid_fields[] = {
333
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
334
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
335
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
336
{ ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
337
{ ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL }, /* ??? UDP/TCP or 0? */
338
{ ft_nat, 16/BITS_PER_BYTE, "port", NULL },
339
{ ft_end, 0, NULL, NULL }
342
struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) };
344
/* ISAKMP Certificate Payload: oddball fixed field beyond the generic ones.
345
* layout from RFC 2408 "ISAKMP" section 3.9
346
* Variable length Certificate Data follow the generic fields.
347
* Previous next payload: ISAKMP_NEXT_CERT.
349
* 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
350
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
351
* ! Next Payload ! RESERVED ! Payload Length !
352
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
353
* ! Cert Encoding ! !
354
* +-+-+-+-+-+-+-+-+ !
355
* ~ Certificate Data ~
357
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
359
static field_desc isacert_fields[] = {
360
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
361
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
362
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
363
{ ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names },
364
{ ft_end, 0, NULL, NULL }
367
/* Note: the size field of isakmp_ipsec_certificate_desc cannot be
368
* sizeof(struct isakmp_cert) because that will rounded up for padding.
370
struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE };
372
/* ISAKMP Certificate Request Payload: oddball field beyond the generic ones.
373
* layout from RFC 2408 "ISAKMP" section 3.10
374
* Variable length Certificate Types and Certificate Authorities follow.
375
* Previous next payload: ISAKMP_NEXT_CR.
377
* 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
378
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
379
* ! Next Payload ! RESERVED ! Payload Length !
380
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
382
* +-+-+-+-+-+-+-+-+ !
383
* ~ Certificate Authority ~
385
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
387
static field_desc isacr_fields[] = {
388
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
389
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
390
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
391
{ ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names },
392
{ ft_end, 0, NULL, NULL }
395
/* Note: the size field of isakmp_ipsec_cert_req_desc cannot be
396
* sizeof(struct isakmp_cr) because that will rounded up for padding.
398
struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE };
400
/* ISAKMP Hash Payload: no fixed fields beyond the generic ones.
401
* layout from RFC 2408 "ISAKMP" section 3.11
402
* Variable length Hash Data follow.
403
* Previous next payload: ISAKMP_NEXT_HASH.
405
* 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
406
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
407
* ! Next Payload ! RESERVED ! Payload Length !
408
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
414
struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) };
416
/* ISAKMP Signature Payload: no fixed fields beyond the generic ones.
417
* layout from RFC 2408 "ISAKMP" section 3.12
418
* Variable length Signature Data follow.
419
* Previous next payload: ISAKMP_NEXT_SIG.
421
* 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
422
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
423
* ! Next Payload ! RESERVED ! Payload Length !
424
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
428
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
430
struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) };
432
/* ISAKMP Nonce Payload: no fixed fields beyond the generic ones.
433
* layout from RFC 2408 "ISAKMP" section 3.13
434
* Variable length Nonce Data follow.
435
* Previous next payload: ISAKMP_NEXT_NONCE.
437
* 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
438
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
439
* ! Next Payload ! RESERVED ! Payload Length !
440
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
444
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
446
struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) };
448
/* ISAKMP Notification Payload
449
* layout from RFC 2408 "ISAKMP" section 3.14
450
* This is followed by a variable length SPI
451
* and then possibly by variable length Notification Data.
452
* Previous next payload: ISAKMP_NEXT_N
454
* 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
455
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
456
* ! Next Payload ! RESERVED ! Payload Length !
457
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
458
* ! Domain of Interpretation (DOI) !
459
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
460
* ! Protocol-ID ! SPI Size ! Notify Message Type !
461
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
463
* ~ Security Parameter Index (SPI) ~
465
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
467
* ~ Notification Data ~
469
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
471
static field_desc isan_fields[] = {
472
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
473
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
474
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
475
{ ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
476
{ ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC, ESP, ... */
477
{ ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
478
{ ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", &ipsec_notification_names },
479
{ ft_end, 0, NULL, NULL }
482
struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) };
484
/* ISAKMP Delete Payload
485
* layout from RFC 2408 "ISAKMP" section 3.15
486
* This is followed by a variable length SPI.
487
* Previous next payload: ISAKMP_NEXT_D
489
* 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
490
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
491
* ! Next Payload ! RESERVED ! Payload Length !
492
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
493
* ! Domain of Interpretation (DOI) !
494
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
495
* ! Protocol-Id ! SPI Size ! # of SPIs !
496
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
498
* ~ Security Parameter Index(es) (SPI) ~
500
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
502
static field_desc isad_fields[] = {
503
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
504
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
505
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
506
{ ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
507
{ ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC */
508
{ ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
509
{ ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL },
510
{ ft_end, 0, NULL, NULL }
513
struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) };
515
/* ISAKMP Vendor ID Payload
516
* layout from RFC 2408 "ISAKMP" section 3.15
517
* This is followed by a variable length VID.
518
* Previous next payload: ISAKMP_NEXT_VID
520
* 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
521
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
522
* ! Next Payload ! RESERVED ! Payload Length !
523
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525
* ~ Vendor ID (VID) ~
527
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
529
struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) };
533
* From draft-dukes-ike-mode-cfg
534
3.2. Attribute Payload
536
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
537
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538
! Next Payload ! RESERVED ! Payload Length !
539
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
540
! Type ! RESERVED ! Identifier !
541
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
545
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
547
static field_desc isaattr_fields[] = {
548
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
549
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
550
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
551
{ ft_enum, 8/BITS_PER_BYTE, "Attr Msg Type", &attr_msg_type_names },
552
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
553
{ ft_nat, 16/BITS_PER_BYTE, "Identifier", NULL },
554
{ ft_end, 0, NULL, NULL }
558
/* From draft-dukes-ike-mode-cfg
559
3.2. Attribute Payload
561
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
562
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
563
! Next Payload ! RESERVED ! Payload Length !
564
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
565
! Type ! RESERVED ! Identifier !
566
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
571
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
574
struct_desc isakmp_attr_desc = { "ISAKMP Mode Attribute", isaattr_fields, sizeof(struct isakmp_mode_attr) };
576
/* ISAKMP NAT-Traversal NAT-D
577
* layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2
579
* 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
580
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
581
* ! Next Payload ! RESERVED ! Payload Length !
582
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
583
* ! HASH of the address and port !
584
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
586
struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) };
588
/* ISAKMP NAT-Traversal NAT-OA
589
* layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2
591
* 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
592
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
593
* ! Next Payload ! RESERVED ! Payload Length !
594
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
595
* ! ID Type ! RESERVED ! RESERVED !
596
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
597
* ! IPv4 (4 octets) or IPv6 address (16 octets) !
598
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
600
static field_desc isanat_oa_fields[] = {
601
{ ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
602
{ ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
603
{ ft_len, 16/BITS_PER_BYTE, "length", NULL },
604
{ ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
605
{ ft_mbz, 24/BITS_PER_BYTE, NULL, NULL },
606
{ ft_end, 0, NULL, NULL }
609
struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
611
/* descriptor for each payload type
613
* There is a slight problem in that some payloads differ, depending
614
* on the mode. Since this is table only used for top-level payloads,
615
* Proposal and Transform payloads need not be handled.
616
* That leaves only Identification payloads as a problem.
617
* We make all these entries NULL
619
struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = {
620
NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */
621
&isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */
622
NULL, /* 2 ISAKMP_NEXT_P (Proposal) */
623
NULL, /* 3 ISAKMP_NEXT_T (Transform) */
624
&isakmp_keyex_desc, /* 4 ISAKMP_NEXT_KE (Key Exchange) */
625
NULL, /* 5 ISAKMP_NEXT_ID (Identification) */
626
&isakmp_ipsec_certificate_desc, /* 6 ISAKMP_NEXT_CERT (Certificate) */
627
&isakmp_ipsec_cert_req_desc, /* 7 ISAKMP_NEXT_CR (Certificate Request) */
628
&isakmp_hash_desc, /* 8 ISAKMP_NEXT_HASH (Hash) */
629
&isakmp_signature_desc, /* 9 ISAKMP_NEXT_SIG (Signature) */
630
&isakmp_nonce_desc, /* 10 ISAKMP_NEXT_NONCE (Nonce) */
631
&isakmp_notification_desc, /* 11 ISAKMP_NEXT_N (Notification) */
632
&isakmp_delete_desc, /* 12 ISAKMP_NEXT_D (Delete) */
633
&isakmp_vendor_id_desc, /* 13 ISAKMP_NEXT_VID (Vendor ID) */
634
&isakmp_attr_desc, /* 14 ISAKMP_NEXT_ATTR (ModeCfg) */
635
&isakmp_nat_d, /* 15=130 ISAKMP_NEXT_NATD (NAT-D) */
636
&isakmp_nat_oa, /* 16=131 ISAKMP_NEXT_NATOA (NAT-OA) */
640
init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name)
642
pbs->container = NULL;
645
pbs->start = pbs->cur = start;
646
pbs->roof = start + len;
648
pbs->lenfld_desc = NULL;
653
/* print a host struct
655
* This code assumes that the network and host structure
656
* members have the same alignment and size! This requires
657
* that all padding be explicit.
660
DBG_print_struct(const char *label, const void *struct_ptr
661
, struct_desc *sd, bool len_meaningful)
663
bool immediate = FALSE;
664
const u_int8_t *inp = struct_ptr;
667
DBG_log("%s%s:", label, sd->name);
669
for (fp = sd->fields; fp->field_type != ft_end; fp++)
674
switch (fp->field_type)
676
case ft_mbz: /* must be zero */
679
case ft_nat: /* natural number (may be 0) */
680
case ft_len: /* length of this struct and any following crud */
681
case ft_lv: /* length/value field of attribute */
682
case ft_enum: /* value from an enumeration */
683
case ft_loose_enum: /* value from an enumeration with only some names known */
684
case ft_af_enum: /* Attribute Format + value from an enumeration */
685
case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
686
case ft_set: /* bits representing set */
689
case 8/BITS_PER_BYTE:
690
n = *(const u_int8_t *)inp;
692
case 16/BITS_PER_BYTE:
693
n = *(const u_int16_t *)inp;
695
case 32/BITS_PER_BYTE:
696
n = *(const u_int32_t *)inp;
701
switch (fp->field_type)
703
case ft_len: /* length of this struct and any following crud */
704
case ft_lv: /* length/value field of attribute */
705
if (!immediate && !len_meaningful)
708
case ft_nat: /* natural number (may be 0) */
709
DBG_log(" %s: %lu", fp->name, (unsigned long)n);
712
case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
713
case ft_af_enum: /* Attribute Format + value from an enumeration */
714
if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
717
case ft_enum: /* value from an enumeration */
718
case ft_loose_enum: /* value from an enumeration with only some names known */
719
DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n));
721
case ft_set: /* bits representing set */
722
DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n));
725
bad_case(fp->field_type);
730
case ft_raw: /* bytes to be left in network-order */
732
char m[50]; /* arbitrary limit on name width in log */
734
snprintf(m, sizeof(m), " %s:", fp->name);
740
bad_case(fp->field_type);
746
DBG_prefix_print_struct(const pb_stream *pbs
747
, const char *label, const void *struct_ptr
748
, struct_desc *sd, bool len_meaningful)
750
/* print out a title, with a prefix of asterisks to show
753
char space[40]; /* arbitrary limit on label+flock-of-* */
754
size_t len = strlen(label);
756
if (sizeof(space) <= len)
758
DBG_print_struct(label, struct_ptr, sd, len_meaningful);
762
const pb_stream *p = pbs;
763
char *pre = &space[sizeof(space) - (len + 1)];
767
/* put at least one * out */
777
DBG_print_struct(pre, struct_ptr, sd, len_meaningful);
783
/* "parse" a network struct into a host struct.
785
* This code assumes that the network and host structure
786
* members have the same alignment and size! This requires
787
* that all padding be explicit.
789
* If obj_pbs is supplied, a new pb_stream is created for the
790
* variable part of the structure (this depends on their
791
* being one length field in the structure). The cursor of this
792
* new PBS is set to after the parsed part of the struct.
794
* This routine returns TRUE iff it succeeds.
798
in_struct(void *struct_ptr, struct_desc *sd
799
, pb_stream *ins, pb_stream *obj_pbs)
802
u_int8_t *cur = ins->cur;
804
if (ins->roof - cur < (ptrdiff_t)sd->size)
806
ugh = builddiag("not enough room in input packet for %s", sd->name);
810
u_int8_t *roof = cur + sd->size; /* may be changed by a length field */
811
u_int8_t *outp = struct_ptr;
812
bool immediate = FALSE;
815
for (fp = sd->fields; ugh == NULL; fp++)
819
passert(ins->roof - cur >= (ptrdiff_t)i);
820
passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i));
821
passert(outp - (cur - ins->cur) == struct_ptr);
824
DBG(DBG_PARSING, DBG_log("%d %s"
825
, (int) (cur - ins->cur), fp->name == NULL? "" : fp->name));
827
switch (fp->field_type)
829
case ft_mbz: /* must be zero */
834
ugh = builddiag("byte %d of %s must be zero, but is not"
835
, (int) (cur - ins->cur), sd->name);
838
*outp++ = '\0'; /* probably redundant */
842
case ft_nat: /* natural number (may be 0) */
843
case ft_len: /* length of this struct and any following crud */
844
case ft_lv: /* length/value field of attribute */
845
case ft_enum: /* value from an enumeration */
846
case ft_loose_enum: /* value from an enumeration with only some names known */
847
case ft_af_enum: /* Attribute Format + value from an enumeration */
848
case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
849
case ft_set: /* bits representing set */
854
n = (n << BITS_PER_BYTE) | *cur++;
856
switch (fp->field_type)
858
case ft_len: /* length of this struct and any following crud */
859
case ft_lv: /* length/value field of attribute */
861
u_int32_t len = fp->field_type == ft_len? n
862
: immediate? sd->size : n + sd->size;
866
ugh = builddiag("%s of %s is smaller than minimum"
867
, fp->name, sd->name);
869
else if (pbs_left(ins) < len)
871
ugh = builddiag("%s of %s is larger than can fit"
872
, fp->name, sd->name);
876
roof = ins->cur + len;
880
case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
881
if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
885
case ft_af_enum: /* Attribute Format + value from an enumeration */
886
if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
889
case ft_enum: /* value from an enumeration */
890
if (enum_name(fp->desc, n) == NULL)
892
ugh = builddiag("%s of %s has an unknown value: %lu"
893
, fp->name, sd->name, (unsigned long)n);
896
case ft_loose_enum: /* value from an enumeration with only some names known */
898
case ft_set: /* bits representing set */
899
if (!testset(fp->desc, n))
901
ugh = builddiag("bitset %s of %s has unknown member(s): %s"
902
, fp->name, sd->name, bitnamesof(fp->desc, n));
911
case 8/BITS_PER_BYTE:
912
*(u_int8_t *)outp = n;
914
case 16/BITS_PER_BYTE:
915
*(u_int16_t *)outp = n;
917
case 32/BITS_PER_BYTE:
918
*(u_int32_t *)outp = n;
927
case ft_raw: /* bytes to be left in network-order */
934
case ft_end: /* end of field list */
935
passert(cur == ins->cur + sd->size);
938
init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name);
939
obj_pbs->container = ins;
945
, DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE));
949
bad_case(fp->field_type);
954
/* some failure got us here: report it */
955
loglog(RC_LOG_SERIOUS, ugh);
960
in_raw(void *bytes, size_t len, pb_stream *ins, const char *name)
962
if (pbs_left(ins) < len)
964
loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name);
972
, DBG_log("skipping %u raw bytes of %s (%s)"
973
, (unsigned) len, ins->name, name);
974
DBG_dump(name, ins->cur, len));
978
memcpy(bytes, ins->cur, len);
980
, DBG_log("parsing %u raw bytes of %s into %s"
981
, (unsigned) len, ins->name, name);
982
DBG_dump(name, bytes, len));
989
/* "emit" a host struct into a network packet.
991
* This code assumes that the network and host structure
992
* members have the same alignment and size! This requires
993
* that all padding be explicit.
995
* If obj_pbs is non-NULL, its pbs describes a new output stream set up
996
* to contain the object. The cursor will be left at the variable part.
997
* This new stream must subsequently be finalized by close_output_pbs().
999
* The value of any field of type ft_len is computed, not taken
1000
* from the input struct. The length is actually filled in when
1001
* the object's output stream is finalized. If obj_pbs is NULL,
1002
* finalization is done by out_struct before it returns.
1004
* This routine returns TRUE iff it succeeds.
1008
out_struct(const void *struct_ptr, struct_desc *sd
1009
, pb_stream *outs, pb_stream *obj_pbs)
1012
const u_int8_t *inp = struct_ptr;
1013
u_int8_t *cur = outs->cur;
1016
, DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL));
1018
if (outs->roof - cur < (ptrdiff_t)sd->size)
1020
ugh = builddiag("not enough room left in output packet to place %s"
1025
bool immediate = FALSE;
1029
obj.lenfld = NULL; /* until a length field is discovered */
1030
obj.lenfld_desc = NULL;
1032
for (fp = sd->fields; ugh == NULL; fp++)
1034
size_t i = fp->size;
1036
passert(outs->roof - cur >= (ptrdiff_t)i);
1037
passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i));
1038
passert(inp - (cur - outs->cur) == struct_ptr);
1041
DBG(DBG_EMITTING, DBG_log("%d %s"
1042
, (int) (cur - outs->cur), fp->name == NULL? "" : fp->name);
1044
switch (fp->field_type)
1046
case ft_mbz: /* must be zero */
1051
case ft_nat: /* natural number (may be 0) */
1052
case ft_len: /* length of this struct and any following crud */
1053
case ft_lv: /* length/value field of attribute */
1054
case ft_enum: /* value from an enumeration */
1055
case ft_loose_enum: /* value from an enumeration with only some names known */
1056
case ft_af_enum: /* Attribute Format + value from an enumeration */
1057
case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
1058
case ft_set: /* bits representing set */
1064
case 8/BITS_PER_BYTE:
1065
n = *(const u_int8_t *)inp;
1067
case 16/BITS_PER_BYTE:
1068
n = *(const u_int16_t *)inp;
1070
case 32/BITS_PER_BYTE:
1071
n = *(const u_int32_t *)inp;
1077
switch (fp->field_type)
1079
case ft_len: /* length of this struct and any following crud */
1080
case ft_lv: /* length/value field of attribute */
1082
break; /* not a length */
1083
/* We can't check the length because it will likely
1084
* be filled in after variable part is supplied.
1085
* We do record where this is so that it can be
1086
* filled in by a subsequent close_output_pbs().
1088
passert(obj.lenfld == NULL); /* only one ft_len allowed */
1090
obj.lenfld_desc = fp;
1092
case ft_af_loose_enum: /* Attribute Format + value from an enumeration */
1093
if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
1097
case ft_af_enum: /* Attribute Format + value from an enumeration */
1098
if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
1101
case ft_enum: /* value from an enumeration */
1102
if (enum_name(fp->desc, n) == NULL)
1104
ugh = builddiag("%s of %s has an unknown value: %lu"
1105
, fp->name, sd->name, (unsigned long)n);
1108
case ft_loose_enum: /* value from an enumeration with only some names known */
1110
case ft_set: /* bits representing set */
1111
if (!testset(fp->desc, n))
1113
ugh = builddiag("bitset %s of %s has unknown member(s): %s"
1114
, fp->name, sd->name, bitnamesof(fp->desc, n));
1123
cur[i] = (u_int8_t)n;
1124
n >>= BITS_PER_BYTE;
1130
case ft_raw: /* bytes to be left in network-order */
1134
case ft_end: /* end of field list */
1135
passert(cur == outs->cur + sd->size);
1137
obj.container = outs;
1139
obj.name = sd->name;
1140
obj.start = outs->cur;
1142
obj.roof = outs->roof; /* limit of possible */
1143
/* obj.lenfld and obj.lenfld_desc already set */
1145
if (obj_pbs == NULL)
1147
close_output_pbs(&obj); /* fill in length field, if any */
1151
/* We set outs->cur to outs->roof so that
1152
* any attempt to output something into outs
1153
* before obj is closed will trigger an error.
1155
outs->cur = outs->roof;
1162
bad_case(fp->field_type);
1167
/* some failure got us here: report it */
1168
loglog(RC_LOG_SERIOUS, ugh); /* ??? serious, but errno not relevant */
1173
out_modify_previous_np(u_int8_t np, pb_stream *outs)
1175
size_t len = (outs->cur - outs->start), offset;
1176
if (len < sizeof(struct isakmp_hdr)) {
1179
else if (len == sizeof(struct isakmp_hdr)) {
1180
struct isakmp_hdr *hdr = (struct isakmp_hdr *)outs->start;
1185
struct isakmp_generic *hdr;
1186
for (offset = sizeof(struct isakmp_hdr); offset < len ;
1187
offset += ntohs(hdr->isag_length)) {
1188
if ((len - offset) < sizeof(struct isakmp_generic))
1190
hdr = (struct isakmp_generic *)(outs->start+offset);
1191
if ((len - offset) < ntohs(hdr->isag_length))
1193
if ((len - offset) == ntohs(hdr->isag_length)) {
1203
out_generic(u_int8_t np, struct_desc *sd
1204
, pb_stream *outs, pb_stream *obj_pbs)
1206
struct isakmp_generic gen;
1208
passert(sd->fields == isakmp_generic_desc.fields);
1210
return out_struct(&gen, sd, outs, obj_pbs);
1214
out_generic_raw(u_int8_t np, struct_desc *sd
1215
, pb_stream *outs, const void *bytes, size_t len, const char *name)
1219
if (!out_generic(np, sd, outs, &pbs)
1220
|| !out_raw(bytes, len, &pbs, name))
1222
close_output_pbs(&pbs);
1227
out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name)
1229
if (pbs_left(outs) < len)
1231
loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s"
1232
, (unsigned long) len, name, outs->name);
1238
, DBG_log("emitting %u raw bytes of %s into %s"
1239
, (unsigned) len, name, outs->name);
1240
DBG_dump(name, bytes, len));
1241
memcpy(outs->cur, bytes, len);
1248
out_zero(size_t len, pb_stream *outs, const char *name)
1250
if (pbs_left(outs) < len)
1252
loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name);
1257
DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s"
1258
, (unsigned) len, name, outs->name));
1259
memset(outs->cur, 0x00, len);
1265
/* Record current length.
1266
* Note: currently, this may be repeated any number of times;
1267
* the last one wins.
1270
close_output_pbs(pb_stream *pbs)
1272
if (pbs->lenfld != NULL)
1274
u_int32_t len = pbs_offset(pbs);
1275
int i = pbs->lenfld_desc->size;
1277
if (pbs->lenfld_desc->field_type == ft_lv)
1278
len -= sizeof(struct isakmp_attribute);
1279
DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu"
1280
, pbs->name, (unsigned long) len));
1283
pbs->lenfld[i] = (u_int8_t)len;
1284
len >>= BITS_PER_BYTE;
1287
if (pbs->container != NULL)
1288
pbs->container->cur = pbs->cur; /* pass space utilization up */