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.29 2002/03/15 21:27:19 dhr 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 draft-ietf-ipsec-isakmp-09.txt 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 draft-ietf-ipsec-isakmp-09.txt 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 draft-ietf-ipsec-isakmp-09.txt 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 /* ISAKMP Security Association Payload
124 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.4
125 * A variable length Situation follows.
126 * Previous next payload: ISAKMP_NEXT_SA
128 * 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
129 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
130 * ! Next Payload ! RESERVED ! Payload Length !
131 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132 * ! Domain of Interpretation (DOI) !
133 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139 static field_desc isasa_fields[] = {
140 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
141 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
142 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
143 { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
144 { ft_end, 0, NULL, NULL }
147 struct_desc isakmp_sa_desc = { "ISAKMP Security Association Payload", isasa_fields, sizeof(struct isakmp_sa) };
149 static field_desc ipsec_sit_field[] = {
150 { ft_set, 32/BITS_PER_BYTE, "IPsec DOI SIT", &sit_bit_names },
151 { ft_end, 0, NULL, NULL }
154 struct_desc ipsec_sit_desc = { "IPsec DOI SIT", ipsec_sit_field, sizeof(u_int32_t) };
156 /* ISAKMP Proposal Payload
157 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.5
158 * A variable length SPI follows.
159 * Previous next payload: ISAKMP_NEXT_P
161 * 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
162 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163 * ! Next Payload ! RESERVED ! Payload Length !
164 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165 * ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms!
166 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
168 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
170 static field_desc isap_fields[] = {
171 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
172 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
173 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
174 { ft_nat, 8/BITS_PER_BYTE, "proposal number", NULL },
175 { ft_enum, 8/BITS_PER_BYTE, "protocol ID", &protocol_names },
176 { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
177 { ft_nat, 8/BITS_PER_BYTE, "number of transforms", NULL },
178 { ft_end, 0, NULL, NULL }
181 struct_desc isakmp_proposal_desc = { "ISAKMP Proposal Payload", isap_fields, sizeof(struct isakmp_proposal) };
183 /* ISAKMP Transform Payload
184 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.6
185 * Variable length SA Attributes follow.
186 * Previous next payload: ISAKMP_NEXT_T
188 * 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
189 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190 * ! Next Payload ! RESERVED ! Payload Length !
191 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192 * ! Transform # ! Transform-Id ! RESERVED2 !
193 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
197 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
201 static field_desc isat_fields_isakmp[] = {
202 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
203 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
204 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
205 { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
206 { ft_enum, 8/BITS_PER_BYTE, "transform ID", &isakmp_transformid_names },
207 { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
208 { ft_end, 0, NULL, NULL }
211 struct_desc isakmp_isakmp_transform_desc = {
212 "ISAKMP Transform Payload (ISAKMP)",
213 isat_fields_isakmp, sizeof(struct isakmp_transform) };
216 static field_desc isat_fields_ah[] = {
217 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
218 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
219 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
220 { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
221 { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ah_transformid_names },
222 { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
223 { ft_end, 0, NULL, NULL }
226 struct_desc isakmp_ah_transform_desc = {
227 "ISAKMP Transform Payload (AH)",
228 isat_fields_ah, sizeof(struct isakmp_transform) };
230 /* PROTO_IPSEC_ESP */
231 static field_desc isat_fields_esp[] = {
232 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
233 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
234 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
235 { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
236 { ft_enum, 8/BITS_PER_BYTE, "transform ID", &esp_transformid_names },
237 { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
238 { ft_end, 0, NULL, NULL }
241 struct_desc isakmp_esp_transform_desc = {
242 "ISAKMP Transform Payload (ESP)",
243 isat_fields_esp, sizeof(struct isakmp_transform) };
246 static field_desc isat_fields_ipcomp[] = {
247 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
248 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
249 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
250 { ft_nat, 8/BITS_PER_BYTE, "transform number", NULL },
251 { ft_enum, 8/BITS_PER_BYTE, "transform ID", &ipcomp_transformid_names },
252 { ft_mbz, 16/BITS_PER_BYTE, NULL, NULL },
253 { ft_end, 0, NULL, NULL }
256 struct_desc isakmp_ipcomp_transform_desc = {
257 "ISAKMP Transform Payload (COMP)",
258 isat_fields_ipcomp, sizeof(struct isakmp_transform) };
261 /* ISAKMP Key Exchange Payload: no fixed fields beyond the generic ones.
262 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.7
263 * Variable Key Exchange Data follow the generic fields.
264 * Previous next payload: ISAKMP_NEXT_KE
266 * 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
267 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268 * ! Next Payload ! RESERVED ! Payload Length !
269 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
271 * ~ Key Exchange Data ~
273 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
275 struct_desc isakmp_keyex_desc = { "ISAKMP Key Exchange Payload", isag_fields, sizeof(struct isakmp_generic) };
277 /* ISAKMP Identification Payload
278 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.8
279 * See "struct identity" declared later.
280 * Variable length Identification Data follow.
281 * Previous next payload: ISAKMP_NEXT_ID
283 * 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
284 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
285 * ! Next Payload ! RESERVED ! Payload Length !
286 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287 * ! ID Type ! DOI Specific ID Data !
288 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290 * ~ Identification Data ~
292 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
294 static field_desc isaid_fields[] = {
295 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
296 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
297 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
298 { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names }, /* ??? depends on DOI? */
299 { ft_nat, 8/BITS_PER_BYTE, "DOI specific A", NULL }, /* ??? depends on DOI? */
300 { ft_nat, 16/BITS_PER_BYTE, "DOI specific B", NULL }, /* ??? depends on DOI? */
301 { ft_end, 0, NULL, NULL }
304 struct_desc isakmp_identification_desc = { "ISAKMP Identification Payload", isaid_fields, sizeof(struct isakmp_id) };
306 /* IPSEC Identification Payload Content
307 * layout from draft-ietf-ipsec-ipsec-doi-08.txt section 4.6.2
308 * See struct isakmp_id declared earlier.
309 * Note: Hashing skips the ISAKMP generic payload header
310 * Variable length Identification Data follow.
312 * 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
313 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314 * ! Next Payload ! RESERVED ! Payload Length !
315 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316 * ! ID Type ! Protocol ID ! Port !
317 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318 * ~ Identification Data ~
319 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
321 static field_desc isaiid_fields[] = {
322 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
323 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
324 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
325 { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
326 { ft_nat, 8/BITS_PER_BYTE, "Protocol ID", NULL }, /* ??? UDP/TCP or 0? */
327 { ft_nat, 16/BITS_PER_BYTE, "port", NULL },
328 { ft_end, 0, NULL, NULL }
331 struct_desc isakmp_ipsec_identification_desc = { "ISAKMP Identification Payload (IPsec DOI)", isaiid_fields, sizeof(struct isakmp_ipsec_id) };
333 /* ISAKMP Certificate Payload: no fixed fields beyond the generic ones.
334 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.9
335 * Variable length Certificate Data follow the generic fields.
336 * Previous next payload: ISAKMP_NEXT_CERT.
338 * 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
339 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
340 * ! Next Payload ! RESERVED ! Payload Length !
341 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
342 * ! Cert Encoding ! !
343 * +-+-+-+-+-+-+-+-+ !
344 * ~ Certificate Data ~
346 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
348 static field_desc isacert_fields[] = {
349 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
350 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
351 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
352 { ft_enum, 8/BITS_PER_BYTE, "cert encoding", &cert_type_names },
353 { ft_end, 0, NULL, NULL }
356 struct_desc isakmp_ipsec_certificate_desc = { "ISAKMP Certificate Payload", isacert_fields, ISAKMP_CERT_SIZE };
358 /* ISAKMP Certificate Request Payload: no fixed fields beyond the generic ones.
359 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.10
360 * Variable length Certificate Types and Certificate Authorities follow.
361 * Previous next payload: ISAKMP_NEXT_CR.
363 * 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
364 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365 * ! Next Payload ! RESERVED ! Payload Length !
366 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368 * +-+-+-+-+-+-+-+-+ !
369 * ~ Certificate Authority ~
371 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
373 static field_desc isacr_fields[] = {
374 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
375 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
376 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
377 { ft_enum, 8/BITS_PER_BYTE, "cert type", &cert_type_names },
378 { ft_end, 0, NULL, NULL }
381 struct_desc isakmp_ipsec_cert_req_desc = { "ISAKMP Certificate RequestPayload", isacr_fields, ISAKMP_CR_SIZE };
383 /* ISAKMP Hash Payload: no fixed fields beyond the generic ones.
384 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.11
385 * Variable length Hash Data follow.
386 * Previous next payload: ISAKMP_NEXT_HASH.
388 * 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
389 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
390 * ! Next Payload ! RESERVED ! Payload Length !
391 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
395 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 struct_desc isakmp_hash_desc = { "ISAKMP Hash Payload", isag_fields, sizeof(struct isakmp_generic) };
399 /* ISAKMP Signature Payload: no fixed fields beyond the generic ones.
400 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.12
401 * Variable length Signature Data follow.
402 * Previous next payload: ISAKMP_NEXT_SIG.
404 * 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
405 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406 * ! Next Payload ! RESERVED ! Payload Length !
407 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
411 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
413 struct_desc isakmp_signature_desc = { "ISAKMP Signature Payload", isag_fields, sizeof(struct isakmp_generic) };
415 /* ISAKMP Nonce Payload: no fixed fields beyond the generic ones.
416 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.13
417 * Variable length Nonce Data follow.
418 * Previous next payload: ISAKMP_NEXT_NONCE.
420 * 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
421 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422 * ! Next Payload ! RESERVED ! Payload Length !
423 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
429 struct_desc isakmp_nonce_desc = { "ISAKMP Nonce Payload", isag_fields, sizeof(struct isakmp_generic) };
431 /* ISAKMP Notification Payload
432 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.14
433 * This is followed by a variable length SPI
434 * and then possibly by variable length Notification Data.
435 * Previous next payload: ISAKMP_NEXT_N
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
441 * ! Domain of Interpretation (DOI) !
442 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
443 * ! Protocol-ID ! SPI Size ! Notify Message Type !
444 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
446 * ~ Security Parameter Index (SPI) ~
448 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
450 * ~ Notification Data ~
452 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
454 static field_desc isan_fields[] = {
455 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
456 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
457 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
458 { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
459 { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC, ESP, ... */
460 { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
461 { ft_nat, 16/BITS_PER_BYTE, "Notify Message Type", NULL },
463 { ft_enum, 16/BITS_PER_BYTE, "Notify Message Type", &ipsec_notification_names },
465 { ft_end, 0, NULL, NULL }
468 struct_desc isakmp_notification_desc = { "ISAKMP Notification Payload", isan_fields, sizeof(struct isakmp_notification) };
470 /* ISAKMP Delete Payload
471 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.15
472 * This is followed by a variable length SPI.
473 * Previous next payload: ISAKMP_NEXT_D
475 * 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
476 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
477 * ! Next Payload ! RESERVED ! Payload Length !
478 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
479 * ! Domain of Interpretation (DOI) !
480 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
481 * ! Protocol-Id ! SPI Size ! # of SPIs !
482 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
484 * ~ Security Parameter Index(es) (SPI) ~
486 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
488 static field_desc isad_fields[] = {
489 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
490 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
491 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
492 { ft_enum, 32/BITS_PER_BYTE, "DOI", &doi_names },
493 { ft_nat, 8/BITS_PER_BYTE, "protocol ID", NULL }, /* ??? really enum: ISAKMP, IPSEC */
494 { ft_nat, 8/BITS_PER_BYTE, "SPI size", NULL },
495 { ft_nat, 16/BITS_PER_BYTE, "number of SPIs", NULL },
496 { ft_end, 0, NULL, NULL }
499 struct_desc isakmp_delete_desc = { "ISAKMP Delete Payload", isad_fields, sizeof(struct isakmp_delete) };
501 /* ISAKMP Vendor ID Payload
502 * layout from draft-ietf-ipsec-isakmp-09.txt section 3.15
503 * This is followed by a variable length VID.
504 * Previous next payload: ISAKMP_NEXT_VID
506 * 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
507 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
508 * ! Next Payload ! RESERVED ! Payload Length !
509 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
511 * ~ Vendor ID (VID) ~
513 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
515 struct_desc isakmp_vendor_id_desc = { "ISAKMP Vendor ID Payload", isag_fields, sizeof(struct isakmp_generic) };
518 /* ISAKMP NAT-Traversal NAT-D
519 * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 3.2
521 * 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
522 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
523 * ! Next Payload ! RESERVED ! Payload Length !
524 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
525 * ! HASH of the address and port !
526 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
528 struct_desc isakmp_nat_d = { "ISAKMP NAT-D Payload", isag_fields, sizeof(struct isakmp_generic) };
530 /* ISAKMP NAT-Traversal NAT-OA
531 * layout from draft-ietf-ipsec-nat-t-ike-01.txt section 4.2
533 * 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
534 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535 * ! Next Payload ! RESERVED ! Payload Length !
536 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537 * ! ID Type ! RESERVED ! RESERVED !
538 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539 * ! IPv4 (4 octets) or IPv6 address (16 octets) !
540 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542 static field_desc isanat_oa_fields[] = {
543 { ft_enum, 8/BITS_PER_BYTE, "next payload type", &payload_names },
544 { ft_mbz, 8/BITS_PER_BYTE, NULL, NULL },
545 { ft_len, 16/BITS_PER_BYTE, "length", NULL },
546 { ft_enum, 8/BITS_PER_BYTE, "ID type", &ident_names },
547 { ft_mbz, 24/BITS_PER_BYTE, NULL, NULL },
548 { ft_end, 0, NULL, NULL }
551 struct_desc isakmp_nat_oa = { "ISAKMP NAT-OA Payload", isanat_oa_fields, sizeof(struct isakmp_nat_oa) };
554 /* descriptor for each payload type
556 * There is a slight problem in that some payloads differ, depending
557 * on the mode. Since this is table only used for top-level payloads,
558 * Proposal and Transform payloads need not be handled.
559 * That leaves only Identification payloads as a problem.
560 * We make all these entries NULL
562 struct_desc *const payload_descs[ISAKMP_NEXT_ROOF] = {
563 NULL, /* 0 ISAKMP_NEXT_NONE (No other payload following) */
564 &isakmp_sa_desc, /* 1 ISAKMP_NEXT_SA (Security Association) */
565 NULL, /* 2 ISAKMP_NEXT_P (Proposal) */
566 NULL, /* 3 ISAKMP_NEXT_T (Transform) */
567 &isakmp_keyex_desc, /* 4 ISAKMP_NEXT_KE (Key Exchange) */
568 NULL, /* 5 ISAKMP_NEXT_ID (Identification) */
569 &isakmp_ipsec_certificate_desc, /* 6 ISAKMP_NEXT_CERT (Certificate) */
570 &isakmp_ipsec_cert_req_desc, /* 7 ISAKMP_NEXT_CR (Certificate Request) */
571 &isakmp_hash_desc, /* 8 ISAKMP_NEXT_HASH (Hash) */
572 &isakmp_signature_desc, /* 9 ISAKMP_NEXT_SIG (Signature) */
573 &isakmp_nonce_desc, /* 10 ISAKMP_NEXT_NONCE (Nonce) */
574 &isakmp_notification_desc, /* 11 ISAKMP_NEXT_N (Notification) */
575 &isakmp_delete_desc, /* 12 ISAKMP_NEXT_D (Delete) */
576 &isakmp_vendor_id_desc, /* 13 ISAKMP_NEXT_VID (Vendor ID) */
579 &isakmp_nat_d, /* 15=130 ISAKMP_NEXT_NATD (NAT-D) */
580 &isakmp_nat_oa, /* 16=131 ISAKMP_NEXT_NATOA (NAT-OA) */
585 init_pbs(pb_stream *pbs, u_int8_t *start, size_t len, const char *name)
587 pbs->container = NULL;
590 pbs->start = pbs->cur = start;
591 pbs->roof = start + len;
593 pbs->lenfld_desc = NULL;
598 /* print a host struct
600 * This code assumes that the network and host structure
601 * members have the same alignment and size! This requires
602 * that all padding be explicit.
605 DBG_print_struct(const char *label, const void *struct_ptr
606 , struct_desc *sd, bool len_meaningful)
608 bool immediate = FALSE;
609 const u_int8_t *inp = struct_ptr;
612 DBG_log("%s%s:", label, sd->name);
614 for (fp = sd->fields; fp->field_type != ft_end; fp++) {
618 switch (fp->field_type) {
619 case ft_mbz: /* must be zero */
622 case ft_nat: /* natural number (may be 0) */
623 case ft_len: /* length of this struct and any following crud */
624 case ft_lv: /* length/value field of attribute */
625 case ft_enum: /* value from an enumeration */
626 case ft_loose_enum: /* value from an enumeration with only some names known */
627 case ft_af_enum: /* Attribute Format + value from an enumeration */
628 case ft_set: /* bits representing set */
630 case 8/BITS_PER_BYTE:
631 n = *(const u_int8_t *)inp;
633 case 16/BITS_PER_BYTE:
634 n = *(const u_int16_t *)inp;
636 case 32/BITS_PER_BYTE:
637 n = *(const u_int32_t *)inp;
642 switch (fp->field_type) {
643 case ft_len: /* length of this struct and any following crud */
644 case ft_lv: /* length/value field of attribute */
645 if (!immediate && !len_meaningful)
648 case ft_nat: /* natural number (may be 0) */
649 DBG_log(" %s: %lu", fp->name, (unsigned long)n);
651 case ft_af_enum: /* Attribute Format + value from an enumeration */
652 if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
655 case ft_enum: /* value from an enumeration */
656 case ft_loose_enum: /* value from an enumeration with only some names known */
657 DBG_log(" %s: %s", fp->name, enum_show(fp->desc, n));
659 case ft_set: /* bits representing set */
660 DBG_log(" %s: %s", fp->name, bitnamesof(fp->desc, n));
669 case ft_raw: /* bytes to be left in network-order */
671 char m[50]; /* arbitrary limit on name width in log */
673 snprintf(m, sizeof(m), " %s:", fp->name);
686 DBG_prefix_print_struct(const pb_stream *pbs
687 , const char *label, const void *struct_ptr
688 , struct_desc *sd, bool len_meaningful)
690 /* print out a title, with a prefix of asterisks to show
693 char space[40]; /* arbitrary limit on label+flock-of-* */
694 size_t len = strlen(label);
696 if (sizeof(space) <= len)
698 DBG_print_struct(label, struct_ptr, sd, len_meaningful);
702 const pb_stream *p = pbs;
703 char *pre = &space[sizeof(space) - (len + 1)];
707 /* put at least one * out */
717 DBG_print_struct(pre, struct_ptr, sd, len_meaningful);
723 /* "parse" a network struct into a host struct.
725 * This code assumes that the network and host structure
726 * members have the same alignment and size! This requires
727 * that all padding be explicit.
729 * If obj_pbs is supplied, a new pb_stream is created for the
730 * variable part of the structure (this depends on their
731 * being one length field in the structure). The cursor of this
732 * new PBS is set to after the parsed part of the struct.
734 * This routine returns TRUE iff it succeeds.
738 in_struct(void *struct_ptr, struct_desc *sd
739 , pb_stream *ins, pb_stream *obj_pbs)
742 u_int8_t *cur = ins->cur;
744 if (ins->roof - cur < (ptrdiff_t)sd->size) {
745 ugh = builddiag("not enough room in input packet for %s", sd->name);
747 u_int8_t *roof = cur + sd->size; /* may be changed by a length field */
748 u_int8_t *outp = struct_ptr;
749 bool immediate = FALSE;
752 for (fp = sd->fields; ugh == NULL; fp++) {
755 passert(ins->roof - cur >= (ptrdiff_t)i);
756 passert(cur - ins->cur <= (ptrdiff_t)(sd->size - i));
757 passert(outp - (cur - ins->cur) == struct_ptr);
760 DBG(DBG_PARSING, DBG_log("%d %s"
761 , (int) (cur - ins->cur), fp->name == NULL? "" : fp->name));
763 switch (fp->field_type) {
764 case ft_mbz: /* must be zero */
765 for (; i != 0; i--) {
767 ugh = builddiag("byte %d of %s must be zero, but is not"
768 , (int) (cur - ins->cur), sd->name);
771 *outp++ = '\0'; /* probably redundant */
775 case ft_nat: /* natural number (may be 0) */
776 case ft_len: /* length of this struct and any following crud */
777 case ft_lv: /* length/value field of attribute */
778 case ft_enum: /* value from an enumeration */
779 case ft_loose_enum: /* value from an enumeration with only some names known */
780 case ft_af_enum: /* Attribute Format + value from an enumeration */
781 case ft_set: /* bits representing set */
786 n = (n << BITS_PER_BYTE) | *cur++;
788 switch (fp->field_type) {
789 case ft_len: /* length of this struct and any following crud */
790 case ft_lv: /* length/value field of attribute */
792 u_int32_t len = fp->field_type == ft_len? n
793 : immediate? sd->size : n + sd->size;
795 if (len < sd->size) {
796 ugh = builddiag("%s of %s is smaller than minimum"
797 , fp->name, sd->name);
798 } else if (pbs_left(ins) < len) {
799 ugh = builddiag("%s of %s is larger than can fit"
800 , fp->name, sd->name);
802 roof = ins->cur + len;
806 case ft_af_enum: /* Attribute Format + value from an enumeration */
807 if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
810 case ft_enum: /* value from an enumeration */
811 if (enum_name(fp->desc, n) == NULL) {
812 ugh = builddiag("%s of %s has an unknown value: %lu"
813 , fp->name, sd->name, (unsigned long)n);
816 case ft_loose_enum: /* value from an enumeration with only some names known */
818 case ft_set: /* bits representing set */
819 if (!testset(fp->desc, n)) {
820 ugh = builddiag("bitset %s of %s has unknown member(s): %s"
821 , fp->name, sd->name, bitnamesof(fp->desc, n));
829 case 8/BITS_PER_BYTE:
830 *(u_int8_t *)outp = n;
832 case 16/BITS_PER_BYTE:
833 *(u_int16_t *)outp = n;
835 case 32/BITS_PER_BYTE:
836 *(u_int32_t *)outp = n;
845 case ft_raw: /* bytes to be left in network-order */
846 for (; i != 0; i--) {
851 case ft_end: /* end of field list */
852 passert(cur == ins->cur + sd->size);
853 if (obj_pbs != NULL) {
854 init_pbs(obj_pbs, ins->cur, roof - ins->cur, sd->name);
855 obj_pbs->container = ins;
861 , DBG_prefix_print_struct(ins, "parse ", struct_ptr, sd, TRUE));
870 /* some failure got us here: report it */
871 loglog(RC_LOG_SERIOUS, ugh);
876 in_raw(void *bytes, size_t len, pb_stream *ins, const char *name)
878 if (pbs_left(ins) < len)
880 loglog(RC_LOG_SERIOUS, "not enough bytes left to get %s from %s", name, ins->name);
888 , DBG_log("skipping %u raw bytes of %s (%s)"
889 , (unsigned) len, ins->name, name);
890 DBG_dump(name, ins->cur, len));
894 memcpy(bytes, ins->cur, len);
896 , DBG_log("parsing %u raw bytes of %s into %s"
897 , (unsigned) len, ins->name, name);
898 DBG_dump(name, bytes, len));
905 /* "emit" a host struct into a network packet.
907 * This code assumes that the network and host structure
908 * members have the same alignment and size! This requires
909 * that all padding be explicit.
911 * If obj_pbs is non-NULL, its pbs describes a new output stream set up
912 * to contain the object. The cursor will be left at the variable part.
913 * This new stream must subsequently be finalized by close_output_pbs().
915 * The value of any field of type ft_len is computed, not taken
916 * from the input struct. The length is actually filled in when
917 * the object's output stream is finalized. If obj_pbs is NULL,
918 * finalization is done by out_struct before it returns.
920 * This routine returns TRUE iff it succeeds.
924 out_struct(const void *struct_ptr, struct_desc *sd
925 , pb_stream *outs, pb_stream *obj_pbs)
928 const u_int8_t *inp = struct_ptr;
929 u_int8_t *cur = outs->cur;
932 , DBG_prefix_print_struct(outs, "emit ", struct_ptr, sd, obj_pbs==NULL));
934 if (outs->roof - cur < (ptrdiff_t)sd->size) {
935 ugh = builddiag("not enough room left in output packet to place %s"
938 bool immediate = FALSE;
942 obj.lenfld = NULL; /* until a length field is discovered */
943 obj.lenfld_desc = NULL;
945 for (fp = sd->fields; ugh == NULL; fp++) {
948 passert(outs->roof - cur >= (ptrdiff_t)i);
949 passert(cur - outs->cur <= (ptrdiff_t)(sd->size - i));
950 passert(inp - (cur - outs->cur) == struct_ptr);
953 DBG(DBG_EMITTING, DBG_log("%d %s"
954 , (int) (cur - outs->cur), fp->name == NULL? "" : fp->name);
956 switch (fp->field_type) {
957 case ft_mbz: /* must be zero */
962 case ft_nat: /* natural number (may be 0) */
963 case ft_len: /* length of this struct and any following crud */
964 case ft_lv: /* length/value field of attribute */
965 case ft_enum: /* value from an enumeration */
966 case ft_loose_enum: /* value from an enumeration with only some names known */
967 case ft_af_enum: /* Attribute Format + value from an enumeration */
968 case ft_set: /* bits representing set */
973 case 8/BITS_PER_BYTE:
974 n = *(const u_int8_t *)inp;
976 case 16/BITS_PER_BYTE:
977 n = *(const u_int16_t *)inp;
979 case 32/BITS_PER_BYTE:
980 n = *(const u_int32_t *)inp;
986 switch (fp->field_type) {
987 case ft_len: /* length of this struct and any following crud */
988 case ft_lv: /* length/value field of attribute */
990 break; /* not a length */
991 /* We can't check the length because it will likely
992 * be filled in after variable part is supplied.
993 * We do record where this is so that it can be
994 * filled in by a subsequent close_output_pbs().
996 passert(obj.lenfld == NULL); /* only one ft_len allowed */
998 obj.lenfld_desc = fp;
1000 case ft_af_enum: /* Attribute Format + value from an enumeration */
1001 if ((n & ISAKMP_ATTR_AF_MASK) == ISAKMP_ATTR_AF_TV)
1004 case ft_enum: /* value from an enumeration */
1005 if (enum_name(fp->desc, n) == NULL) {
1006 ugh = builddiag("%s of %s has an unknown value: %lu"
1007 , fp->name, sd->name, (unsigned long)n);
1010 case ft_loose_enum: /* value from an enumeration with only some names known */
1012 case ft_set: /* bits representing set */
1013 if (!testset(fp->desc, n)) {
1014 ugh = builddiag("bitset %s of %s has unknown member(s): %s"
1015 , fp->name, sd->name, bitnamesof(fp->desc, n));
1023 cur[i] = (u_int8_t)n;
1024 n >>= BITS_PER_BYTE;
1030 case ft_raw: /* bytes to be left in network-order */
1031 for (; i != 0; i--) {
1035 case ft_end: /* end of field list */
1036 passert(cur == outs->cur + sd->size);
1038 obj.container = outs;
1040 obj.name = sd->name;
1041 obj.start = outs->cur;
1043 obj.roof = outs->roof; /* limit of possible */
1044 /* obj.lenfld and obj.lenfld_desc already set */
1046 if (obj_pbs == NULL) {
1047 close_output_pbs(&obj); /* fill in length field, if any */
1049 /* We set outs->cur to outs->roof so that
1050 * any attempt to output something into outs
1051 * before obj is closed will trigger an error.
1053 outs->cur = outs->roof;
1066 /* some failure got us here: report it */
1067 loglog(RC_LOG_SERIOUS, ugh); /* ??? serious, but errno not relevant */
1072 out_generic(u_int8_t np, struct_desc *sd
1073 , pb_stream *outs, pb_stream *obj_pbs)
1075 struct isakmp_generic gen;
1077 passert(sd->fields == isakmp_generic_desc.fields);
1079 return out_struct(&gen, sd, outs, obj_pbs);
1083 out_generic_raw(u_int8_t np, struct_desc *sd
1084 , pb_stream *outs, const void *bytes, size_t len, const char *name)
1088 if (!out_generic(np, sd, outs, &pbs)
1089 || !out_raw(bytes, len, &pbs, name))
1091 close_output_pbs(&pbs);
1097 out_modify_previous_np(u_int8_t np, pb_stream *outs)
1099 size_t len = (outs->cur - outs->start), offset;
1100 if (len < sizeof(struct isakmp_hdr)) {
1103 else if (len == sizeof(struct isakmp_hdr)) {
1104 struct isakmp_hdr *hdr = (struct isakmp_hdr *)outs->start;
1109 struct isakmp_generic *hdr;
1110 for (offset = sizeof(struct isakmp_hdr); offset < len ;
1111 offset += ntohs(hdr->isag_length)) {
1112 if ((len - offset) < sizeof(struct isakmp_generic))
1114 hdr = (struct isakmp_generic *)(outs->start+offset);
1115 if ((len - offset) < ntohs(hdr->isag_length))
1117 if ((len - offset) == ntohs(hdr->isag_length)) {
1128 out_raw(const void *bytes, size_t len, pb_stream *outs, const char *name)
1130 if (pbs_left(outs) < len)
1132 loglog(RC_LOG_SERIOUS, "not enough room left to place %lu bytes of %s in %s"
1133 , (unsigned long) len, name, outs->name);
1139 , DBG_log("emitting %u raw bytes of %s into %s"
1140 , (unsigned) len, name, outs->name);
1141 DBG_dump(name, bytes, len));
1142 memcpy(outs->cur, bytes, len);
1149 out_zero(size_t len, pb_stream *outs, const char *name)
1151 if (pbs_left(outs) < len)
1153 loglog(RC_LOG_SERIOUS, "not enough room left to place %s in %s", name, outs->name);
1158 DBG(DBG_EMITTING, DBG_log("emitting %u zero bytes of %s into %s"
1159 , (unsigned) len, name, outs->name));
1160 memset(outs->cur, 0x00, len);
1166 /* Record current length.
1167 * Note: currently, this may be repeated any number of times;
1168 * the last one wins.
1171 close_output_pbs(pb_stream *pbs)
1173 if (pbs->lenfld != NULL)
1175 u_int32_t len = pbs_offset(pbs);
1176 int i = pbs->lenfld_desc->size;
1178 if (pbs->lenfld_desc->field_type == ft_lv)
1179 len -= sizeof(struct isakmp_attribute);
1180 DBG(DBG_EMITTING, DBG_log("emitting length of %s: %lu"
1181 , pbs->name, (unsigned long) len));
1183 pbs->lenfld[i] = (u_int8_t)len;
1184 len >>= BITS_PER_BYTE;
1187 if (pbs->container != NULL)
1188 pbs->container->cur = pbs->cur; /* pass space utilization up */