4 * @brief Generic parser class used to parse IKEv2-Header and Payload
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include <arpa/inet.h>
29 #include "definitions.h"
31 #include "utils/allocator.h"
32 #include "utils/logger.h"
33 #include "utils/linked_list.h"
34 #include "payloads/encodings.h"
35 #include "payloads/payload.h"
36 #include "payloads/sa_payload.h"
37 #include "payloads/proposal_substructure.h"
38 #include "payloads/transform_substructure.h"
39 #include "payloads/transform_attribute.h"
40 #include "payloads/ke_payload.h"
41 #include "payloads/nonce_payload.h"
42 #include "payloads/notify_payload.h"
47 * @private data stored in a context
49 * contains pointers and counters to store current state
51 typedef struct private_parser_s private_parser_t
;
53 struct private_parser_s
{
55 * Public members, see parser_t
60 * @brief parse a 4-Bit unsigned integer from the current parsing position.
62 * @param this parser object
63 * @param rule_number number of current rule
64 * @param[out] output_pos pointer where to write the parsed result
67 * - PARSE_ERROR when not successful
69 status_t (*parse_uint4
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
);
72 * @brief parse a 8-Bit unsigned integer from the current parsing position.
74 * @param this parser object
75 * @param rule_number number of current rule
76 * @param[out] output_pos pointer where to write the parsed result
79 * - PARSE_ERROR when not successful
81 status_t (*parse_uint8
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
);
84 * @brief parse a 15-Bit unsigned integer from the current parsing position.
86 * This is a special case used for ATTRIBUTE_TYPE.
87 * Big-/Little-endian conversion is done here.
89 * @param this parser object
90 * @param rule_number number of current rule
91 * @param[out] output_pos pointer where to write the parsed result
94 * - PARSE_ERROR when not successful
96 status_t (*parse_uint15
) (private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
);
99 * @brief parse a 16-Bit unsigned integer from the current parsing position.
101 * Big-/Little-endian conversion is done here.
103 * @param this parser object
104 * @param rule_number number of current rule
105 * @param[out] output_pos pointer where to write the parsed result
108 * - PARSE_ERROR when not successful
110 status_t (*parse_uint16
) (private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
);
113 * @brief parse a 32-Bit unsigned integer from the current parsing position.
115 * Big-/Little-endian conversion is done here.
117 * @param this parser object
118 * @param rule_number number of current rule
119 * @param[out] output_pos pointer where to write the parsed result
122 * - PARSE_ERROR when not successful
124 status_t (*parse_uint32
) (private_parser_t
*this, int rule_number
, u_int32_t
*output_pos
);
127 * @brief parse a 64-Bit unsigned integer from the current parsing position.
129 * @todo add support for big-endian machines.
131 * @param this parser object
132 * @param rule_number number of current rule
133 * @param[out] output_pos pointer where to write the parsed result
136 * - PARSE_ERROR when not successful
138 status_t (*parse_uint64
) (private_parser_t
*this, int rule_number
, u_int64_t
*output_pos
);
141 * @brief parse a single Bit from the current parsing position
143 * @param this parser object
144 * @param rule_number number of current rule
145 * @param[out] output_pos pointer where to write the parsed result
148 * - PARSE_ERROR when not successful
150 status_t (*parse_bit
) (private_parser_t
*this, int rule_number
, bool *output_pos
);
153 * @brief parse substructures in a list
155 * This function calls the parser recursivly to parse contained substructures
156 * in a linked_list_t. The list must already be created. Payload defines
157 * the type of the substructures. parsing is continued until the specified length
158 * is completely parsed.
160 * @param this parser object
161 * @param rule_number number of current rule
162 * @param[out] output_pos pointer of a linked_list where substructures are added
163 * @param payload_type type of the contained substructures to parse
164 * @param length number of bytes to parse in this list
167 * - PARSE_ERROR when not successful
169 status_t (*parse_list
) (private_parser_t
*this, int rule_number
, linked_list_t
**output_pos
, payload_type_t payload_ype
, size_t length
);
172 * @brief parse data from current parsing position in a chunk.
174 * This function clones length number of bytes to output_pos, without
175 * modifiyng them. Space will be allocated and must be freed by caller.
177 * @param this parser object
178 * @param rule_number number of current rule
179 * @param[out] output_pos pointer of a chunk which will point to the allocated data
180 * @param length number of bytes to clone
183 * - PARSE_ERROR when not successful
185 status_t (*parse_chunk
) (private_parser_t
*this, int rule_number
, chunk_t
*output_pos
, size_t length
);
188 * Current bit for reading in input data
193 * Current byte for reading in input data
198 * input data to parse
203 * roof of input, used for length-checking
205 u_int8_t
*input_roof
;
208 * set of encoding rules for this parsing session
210 encoding_rule_t
*rules
;
219 * implementation of private_parser_t.parse_uint4
221 static status_t
parse_uint4(private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
)
223 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
225 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
226 rule_number
, mapping_find(encoding_type_m
,
227 this->rules
[rule_number
].type
));
230 switch (this->bit_pos
)
233 /* caller interested in result ? */
234 if (output_pos
!= NULL
)
236 *output_pos
= *(this->byte_pos
) >> 4;
241 /* caller interested in result ? */
242 if (output_pos
!= NULL
)
244 *output_pos
= *(this->byte_pos
) & 0x0F;
250 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
251 rule_number
, mapping_find(encoding_type_m
,
252 this->rules
[rule_number
].type
), this->bit_pos
);
256 if (output_pos
!= NULL
)
258 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
266 * implementation of private_parser_t.parse_uint8
268 static status_t
parse_uint8(private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
)
270 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
272 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
273 rule_number
, mapping_find(encoding_type_m
,
274 this->rules
[rule_number
].type
));
279 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
280 rule_number
, mapping_find(encoding_type_m
,
281 this->rules
[rule_number
].type
), this->bit_pos
);
285 /* caller interested in result ? */
286 if (output_pos
!= NULL
)
288 *output_pos
= *(this->byte_pos
);
289 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
299 * implementation of private_parser_t.parse_uint15
301 static status_t
parse_uint15(private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
)
303 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
305 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
306 rule_number
, mapping_find(encoding_type_m
,
307 this->rules
[rule_number
].type
));
310 if (this->bit_pos
!= 1)
312 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
313 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
317 /* caller interested in result ? */
318 if (output_pos
!= NULL
)
320 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
)) & ~0x8000;
321 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
332 * implementation of private_parser_t.parse_uint16
334 static status_t
parse_uint16(private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
)
336 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
338 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
339 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
344 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
345 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
349 /* caller interested in result ? */
350 if (output_pos
!= NULL
)
352 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
));
354 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
362 * implementation of private_parser_t.parse_uint32
364 static status_t
parse_uint32(private_parser_t
*this, int rule_number
, u_int32_t
*output_pos
)
366 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
368 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
369 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
374 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
375 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
379 /* caller interested in result ? */
380 if (output_pos
!= NULL
)
382 *output_pos
= ntohl(*((u_int32_t
*)this->byte_pos
));
384 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
393 * implementation of private_parser_t.parse_uint64
395 static status_t
parse_uint64(private_parser_t
*this, int rule_number
, u_int64_t
*output_pos
)
397 if (this->byte_pos
+ sizeof(u_int64_t
) > this->input_roof
)
399 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
400 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
405 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
406 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
410 /* caller interested in result ? */
411 if (output_pos
!= NULL
)
413 /* assuming little endian host order */
414 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)this->byte_pos
));
415 *output_pos
= ntohl(*(((u_int32_t
*)this->byte_pos
) + 1));
417 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
, 8);
427 * implementation of private_parser_t.parse_bit
429 static status_t
parse_bit(private_parser_t
*this, int rule_number
, bool *output_pos
)
431 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
433 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
434 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
437 /* caller interested in result ? */
438 if (output_pos
!= NULL
)
441 mask
= 0x01 << (7 - this->bit_pos
);
442 *output_pos
= *this->byte_pos
& mask
;
446 /* set to a "clean", comparable true */
450 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
452 this->bit_pos
= (this->bit_pos
+ 1) % 8;
453 if (this->bit_pos
== 0)
463 * implementation of private_parser_t.parse_list
465 static status_t
parse_list(private_parser_t
*this, int rule_number
, linked_list_t
**output_pos
, payload_type_t payload_type
, size_t length
)
467 linked_list_t
* list
= *output_pos
;
471 this->logger
->log(this->logger
, ERROR
, " invalid length for rule %d %s",
472 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
478 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
479 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
), this->bit_pos
);
485 u_int8_t
*pos_before
= this->byte_pos
;
488 this->logger
->log(this->logger
, CONTROL
|MORE
, " %d bytes left, parsing recursivly %s",
489 length
, mapping_find(payload_type_m
, payload_type
));
490 status
= this->public.parse_payload((parser_t
*)this, payload_type
, &payload
);
491 if (status
!= SUCCESS
)
493 this->logger
->log(this->logger
, ERROR
, " parsing of a %s substructure failed",
494 mapping_find(payload_type_m
, payload_type
));
497 list
->insert_last(list
, payload
);
498 length
-= this->byte_pos
- pos_before
;
505 * implementation of private_parser_t.parse_chunk
507 static status_t
parse_chunk(private_parser_t
*this, int rule_number
, chunk_t
*output_pos
, size_t length
)
509 if (this->byte_pos
+ length
> this->input_roof
)
511 this->logger
->log(this->logger
, ERROR
, " not enough input (%d bytes) to parse rule %d %s",
512 length
, rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
517 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
518 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
), this->bit_pos
);
521 if (output_pos
!= NULL
)
523 output_pos
->len
= length
;
524 output_pos
->ptr
= allocator_alloc(length
);
525 if (output_pos
->ptr
== NULL
)
527 this->logger
->log(this->logger
, ERROR
, " allocation of chunk (%d bytes) failed", length
);
530 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
532 this->byte_pos
+= length
;
533 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
->ptr
, length
);
539 * implementation of parser_context_t.parse_payload
541 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
545 size_t rule_count
, payload_length
, spi_size
, attribute_length
;
546 bool attribute_format
;
548 encoding_rule_t
*rule
;
550 this->logger
->log(this->logger
, CONTROL
, "parsing %s payload, %d bytes left",
551 mapping_find(payload_type_m
, payload_type
),
552 this->input_roof
-this->byte_pos
);
554 this->logger
->log_bytes(this->logger
, RAW
, "parsing payload from", this->byte_pos
,
555 this->input_roof
-this->byte_pos
);
557 /* ok, do the parsing */
558 pld
= payload_create(payload_type
);
561 this->logger
->log(this->logger
, ERROR
, " payload %s not supported", mapping_find(payload_type_m
, payload_type
));
562 return NOT_SUPPORTED
;
564 /* base pointer for output, avoids casting in every rule */
567 pld
->get_encoding_rules(pld
, &(this->rules
), &rule_count
);
569 for (rule_number
= 0; rule_number
< rule_count
; rule_number
++)
571 rule
= &(this->rules
[rule_number
]);
572 this->logger
->log(this->logger
, CONTROL
|MORE
, " parsing rule %d %s",
573 rule_number
, mapping_find(encoding_type_m
, rule
->type
));
578 if (this->parse_uint4(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
587 if (this->parse_uint8(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
596 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
605 if (this->parse_uint32(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
614 if (this->parse_uint64(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
623 if (this->parse_bit(this, rule_number
, NULL
) != SUCCESS
)
632 if (this->parse_uint8(this, rule_number
, NULL
) != SUCCESS
)
641 if (this->parse_bit(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
650 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
655 payload_length
= *(u_int16_t
*)(output
+ rule
->offset
);
660 if (this->parse_uint32(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
669 if (this->parse_uint8(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
674 spi_size
= *(u_int8_t
*)(output
+ rule
->offset
);
679 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, spi_size
) != SUCCESS
)
688 size_t proposals_length
= payload_length
- SA_PAYLOAD_HEADER_LENGTH
;
689 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, PROPOSAL_SUBSTRUCTURE
, proposals_length
) != SUCCESS
)
698 size_t transforms_length
= payload_length
- spi_size
- PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
;
699 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, TRANSFORM_SUBSTRUCTURE
, transforms_length
) != SUCCESS
)
706 case TRANSFORM_ATTRIBUTES
:
708 size_t transform_a_length
= payload_length
- TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
;
709 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, TRANSFORM_ATTRIBUTE
, transform_a_length
) != SUCCESS
)
716 case ATTRIBUTE_FORMAT
:
718 if (this->parse_bit(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
723 attribute_format
= *(bool*)(output
+ rule
->offset
);
728 if (this->parse_uint15(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
733 attribute_format
= *(bool*)(output
+ rule
->offset
);
736 case ATTRIBUTE_LENGTH_OR_VALUE
:
738 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
743 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
746 case ATTRIBUTE_VALUE
:
748 if (attribute_format
== FALSE
)
750 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, attribute_length
) != SUCCESS
)
760 size_t nonce_length
= payload_length
- NONCE_PAYLOAD_HEADER_LENGTH
;
761 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, nonce_length
) != SUCCESS
)
768 case KEY_EXCHANGE_DATA
:
770 size_t keydata_length
= payload_length
- KE_PAYLOAD_HEADER_LENGTH
;
771 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, keydata_length
) != SUCCESS
)
778 case NOTIFICATION_DATA
:
780 size_t notify_length
= payload_length
- NOTIFY_PAYLOAD_HEADER_LENGTH
- spi_size
;
781 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, notify_length
) != SUCCESS
)
790 this->logger
->log(this->logger
, ERROR
, " no rule to parse rule %d %s (%d)", rule_number
, mapping_find(encoding_type_m
, rule
->type
), rule
->type
);
795 /* process next rulue */
801 this->logger
->log(this->logger
, CONTROL
, "parsing %s successful", mapping_find(payload_type_m
, payload_type
));
806 * implementation of parser_t.reset_context
808 static status_t
reset_context (private_parser_t
*this)
810 this->byte_pos
= this->input
;
816 * implementation of parser_t.destroy
818 static status_t
destroy(private_parser_t
*this)
820 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
821 allocator_free(this);
829 parser_t
*parser_create(chunk_t data
)
831 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
838 this->logger
= global_logger_manager
->create_logger(global_logger_manager
, PARSER
, NULL
);
839 this->logger
->disable_level(this->logger
, FULL
);
840 this->logger
->enable_level(this->logger
, CONTROL
);
843 if (this->logger
== NULL
)
845 global_logger_manager
->destroy_logger(global_logger_manager
, this->logger
);
846 allocator_free(this);
850 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,payload_t
**)) parse_payload
;
851 this->public.reset_context
= (status_t(*)(parser_t
*)) reset_context
;
852 this->public.destroy
= (status_t(*)(parser_t
*)) destroy
;
855 this->parse_uint4
= parse_uint4
;
856 this->parse_uint8
= parse_uint8
;
857 this->parse_uint15
= parse_uint15
;
858 this->parse_uint16
= parse_uint16
;
859 this->parse_uint32
= parse_uint32
;
860 this->parse_uint64
= parse_uint64
;
861 this->parse_bit
= parse_bit
;
862 this->parse_list
= parse_list
;
863 this->parse_chunk
= parse_chunk
;
865 this->input
= data
.ptr
;
866 this->byte_pos
= data
.ptr
;
868 this->input_roof
= data
.ptr
+ data
.len
;
870 return (parser_t
*)this;