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 <encoding/payloads/encodings.h>
35 #include <encoding/payloads/payload.h>
36 #include <encoding/payloads/sa_payload.h>
37 #include <encoding/payloads/proposal_substructure.h>
38 #include <encoding/payloads/transform_substructure.h>
39 #include <encoding/payloads/transform_attribute.h>
40 #include <encoding/payloads/ke_payload.h>
41 #include <encoding/payloads/nonce_payload.h>
42 #include <encoding/payloads/notify_payload.h>
43 #include <encoding/payloads/encryption_payload.h>
48 typedef struct private_parser_t private_parser_t
;
51 * @private data stored in a context
53 * contains pointers and counters to store current state
55 struct private_parser_t
{
57 * Public members, see parser_t
62 * @brief parse a 4-Bit unsigned integer from the current parsing position.
64 * @param this parser object
65 * @param rule_number number of current rule
66 * @param[out] output_pos pointer where to write the parsed result
69 * - PARSE_ERROR when not successful
71 status_t (*parse_uint4
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
);
74 * @brief parse a 8-Bit unsigned integer from the current parsing position.
76 * @param this parser object
77 * @param rule_number number of current rule
78 * @param[out] output_pos pointer where to write the parsed result
81 * - PARSE_ERROR when not successful
83 status_t (*parse_uint8
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
);
86 * @brief parse a 15-Bit unsigned integer from the current parsing position.
88 * This is a special case used for ATTRIBUTE_TYPE.
89 * Big-/Little-endian conversion is done here.
91 * @param this parser object
92 * @param rule_number number of current rule
93 * @param[out] output_pos pointer where to write the parsed result
96 * - PARSE_ERROR when not successful
98 status_t (*parse_uint15
) (private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
);
101 * @brief parse a 16-Bit unsigned integer from the current parsing position.
103 * Big-/Little-endian conversion is done here.
105 * @param this parser object
106 * @param rule_number number of current rule
107 * @param[out] output_pos pointer where to write the parsed result
110 * - PARSE_ERROR when not successful
112 status_t (*parse_uint16
) (private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
);
115 * @brief parse a 32-Bit unsigned integer from the current parsing position.
117 * Big-/Little-endian conversion is done here.
119 * @param this parser object
120 * @param rule_number number of current rule
121 * @param[out] output_pos pointer where to write the parsed result
124 * - PARSE_ERROR when not successful
126 status_t (*parse_uint32
) (private_parser_t
*this, int rule_number
, u_int32_t
*output_pos
);
129 * @brief parse a 64-Bit unsigned integer from the current parsing position.
131 * @todo add support for big-endian machines.
133 * @param this parser object
134 * @param rule_number number of current rule
135 * @param[out] output_pos pointer where to write the parsed result
138 * - PARSE_ERROR when not successful
140 status_t (*parse_uint64
) (private_parser_t
*this, int rule_number
, u_int64_t
*output_pos
);
143 * @brief parse a given amount of bytes and writes them to a specific location
145 * @param this parser object
146 * @param rule_number number of current rule
147 * @param[out] output_pos pointer where to write the parsed result
148 * @param bytes number of bytes to parse
151 * - PARSE_ERROR when not successful
153 status_t (*parse_bytes
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
,size_t bytes
);
156 * @brief parse a single Bit from the current parsing position
158 * @param this parser object
159 * @param rule_number number of current rule
160 * @param[out] output_pos pointer where to write the parsed result
163 * - PARSE_ERROR when not successful
165 status_t (*parse_bit
) (private_parser_t
*this, int rule_number
, bool *output_pos
);
168 * @brief parse substructures in a list
170 * This function calls the parser recursivly to parse contained substructures
171 * in a linked_list_t. The list must already be created. Payload defines
172 * the type of the substructures. parsing is continued until the specified length
173 * is completely parsed.
175 * @param this parser object
176 * @param rule_number number of current rule
177 * @param[out] output_pos pointer of a linked_list where substructures are added
178 * @param payload_type type of the contained substructures to parse
179 * @param length number of bytes to parse in this list
182 * - PARSE_ERROR when not successful
184 status_t (*parse_list
) (private_parser_t
*this, int rule_number
, linked_list_t
**output_pos
, payload_type_t payload_ype
, size_t length
);
187 * @brief parse data from current parsing position in a chunk.
189 * This function clones length number of bytes to output_pos, without
190 * modifiyng them. Space will be allocated and must be freed by caller.
192 * @param this parser object
193 * @param rule_number number of current rule
194 * @param[out] output_pos pointer of a chunk which will point to the allocated data
195 * @param length number of bytes to clone
198 * - PARSE_ERROR when not successful
200 status_t (*parse_chunk
) (private_parser_t
*this, int rule_number
, chunk_t
*output_pos
, size_t length
);
203 * Current bit for reading in input data
208 * Current byte for reading in input data
213 * input data to parse
218 * roof of input, used for length-checking
220 u_int8_t
*input_roof
;
223 * set of encoding rules for this parsing session
225 encoding_rule_t
*rules
;
234 * implementation of private_parser_t.parse_uint4
236 static status_t
parse_uint4(private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
)
238 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
240 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
241 rule_number
, mapping_find(encoding_type_m
,
242 this->rules
[rule_number
].type
));
245 switch (this->bit_pos
)
248 /* caller interested in result ? */
249 if (output_pos
!= NULL
)
251 *output_pos
= *(this->byte_pos
) >> 4;
256 /* caller interested in result ? */
257 if (output_pos
!= NULL
)
259 *output_pos
= *(this->byte_pos
) & 0x0F;
265 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
266 rule_number
, mapping_find(encoding_type_m
,
267 this->rules
[rule_number
].type
), this->bit_pos
);
271 if (output_pos
!= NULL
)
273 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
281 * implementation of private_parser_t.parse_uint8
283 static status_t
parse_uint8(private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
)
285 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
287 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
288 rule_number
, mapping_find(encoding_type_m
,
289 this->rules
[rule_number
].type
));
294 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
295 rule_number
, mapping_find(encoding_type_m
,
296 this->rules
[rule_number
].type
), this->bit_pos
);
300 /* caller interested in result ? */
301 if (output_pos
!= NULL
)
303 *output_pos
= *(this->byte_pos
);
304 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
314 * implementation of private_parser_t.parse_uint15
316 static status_t
parse_uint15(private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
)
318 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
320 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
321 rule_number
, mapping_find(encoding_type_m
,
322 this->rules
[rule_number
].type
));
325 if (this->bit_pos
!= 1)
327 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
328 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
332 /* caller interested in result ? */
333 if (output_pos
!= NULL
)
335 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
)) & ~0x8000;
336 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
347 * implementation of private_parser_t.parse_uint16
349 static status_t
parse_uint16(private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
)
351 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
353 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
354 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
359 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
360 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
364 /* caller interested in result ? */
365 if (output_pos
!= NULL
)
367 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
));
369 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
377 * implementation of private_parser_t.parse_uint32
379 static status_t
parse_uint32(private_parser_t
*this, int rule_number
, u_int32_t
*output_pos
)
381 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
383 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
384 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
389 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
390 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
394 /* caller interested in result ? */
395 if (output_pos
!= NULL
)
397 *output_pos
= ntohl(*((u_int32_t
*)this->byte_pos
));
399 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
408 * implementation of private_parser_t.parse_uint64
410 static status_t
parse_uint64(private_parser_t
*this, int rule_number
, u_int64_t
*output_pos
)
412 if (this->byte_pos
+ sizeof(u_int64_t
) > this->input_roof
)
414 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
415 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
420 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
421 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
425 /* caller interested in result ? */
426 if (output_pos
!= NULL
)
428 /* assuming little endian host order */
429 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)this->byte_pos
));
430 *output_pos
= ntohl(*(((u_int32_t
*)this->byte_pos
) + 1));
432 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
, 8);
441 static status_t
parse_bytes (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
,size_t bytes
)
443 if (this->byte_pos
+ bytes
> this->input_roof
)
445 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
446 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
451 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
452 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
457 /* caller interested in result ? */
458 if (output_pos
!= NULL
)
460 memcpy(output_pos
,this->byte_pos
,bytes
);
462 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
, bytes
);
464 this->byte_pos
+= bytes
;
470 * implementation of private_parser_t.parse_bit
472 static status_t
parse_bit(private_parser_t
*this, int rule_number
, bool *output_pos
)
474 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
476 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
477 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
480 /* caller interested in result ? */
481 if (output_pos
!= NULL
)
484 mask
= 0x01 << (7 - this->bit_pos
);
485 *output_pos
= *this->byte_pos
& mask
;
489 /* set to a "clean", comparable true */
493 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
495 this->bit_pos
= (this->bit_pos
+ 1) % 8;
496 if (this->bit_pos
== 0)
506 * implementation of private_parser_t.parse_list
508 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
)
510 linked_list_t
* list
= *output_pos
;
514 this->logger
->log(this->logger
, ERROR
, " invalid length for rule %d %s",
515 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
521 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
522 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
), this->bit_pos
);
528 u_int8_t
*pos_before
= this->byte_pos
;
531 this->logger
->log(this->logger
, CONTROL
|MORE
, " %d bytes left, parsing recursivly %s",
532 length
, mapping_find(payload_type_m
, payload_type
));
533 status
= this->public.parse_payload((parser_t
*)this, payload_type
, &payload
);
534 if (status
!= SUCCESS
)
536 this->logger
->log(this->logger
, ERROR
, " parsing of a %s substructure failed",
537 mapping_find(payload_type_m
, payload_type
));
540 list
->insert_last(list
, payload
);
541 length
-= this->byte_pos
- pos_before
;
548 * implementation of private_parser_t.parse_chunk
550 static status_t
parse_chunk(private_parser_t
*this, int rule_number
, chunk_t
*output_pos
, size_t length
)
552 if (this->byte_pos
+ length
> this->input_roof
)
554 this->logger
->log(this->logger
, ERROR
, " not enough input (%d bytes) to parse rule %d %s",
555 length
, rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
560 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
561 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
), this->bit_pos
);
564 if (output_pos
!= NULL
)
566 output_pos
->len
= length
;
567 output_pos
->ptr
= allocator_alloc(length
);
568 if (output_pos
->ptr
== NULL
)
570 this->logger
->log(this->logger
, ERROR
, " allocation of chunk (%d bytes) failed", length
);
573 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
575 this->byte_pos
+= length
;
576 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
->ptr
, length
);
582 * implementation of parser_context_t.parse_payload
584 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
588 size_t rule_count
, payload_length
, spi_size
, attribute_length
;
589 bool attribute_format
;
591 encoding_rule_t
*rule
;
593 this->logger
->log(this->logger
, CONTROL
, "parsing %s payload, %d bytes left",
594 mapping_find(payload_type_m
, payload_type
),
595 this->input_roof
-this->byte_pos
);
597 this->logger
->log_bytes(this->logger
, RAW
, "parsing payload from", this->byte_pos
,
598 this->input_roof
-this->byte_pos
);
600 /* ok, do the parsing */
601 pld
= payload_create(payload_type
);
604 this->logger
->log(this->logger
, ERROR
, " payload %s not supported", mapping_find(payload_type_m
, payload_type
));
605 return NOT_SUPPORTED
;
607 /* base pointer for output, avoids casting in every rule */
610 pld
->get_encoding_rules(pld
, &(this->rules
), &rule_count
);
612 for (rule_number
= 0; rule_number
< rule_count
; rule_number
++)
614 rule
= &(this->rules
[rule_number
]);
615 this->logger
->log(this->logger
, CONTROL
|MORE
, " parsing rule %d %s",
616 rule_number
, mapping_find(encoding_type_m
, rule
->type
));
621 if (this->parse_uint4(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
630 if (this->parse_uint8(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
639 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
648 if (this->parse_uint32(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
657 if (this->parse_uint64(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
666 if (this->parse_bytes(this, rule_number
, output
+ rule
->offset
,8) != SUCCESS
)
675 if (this->parse_bit(this, rule_number
, NULL
) != SUCCESS
)
684 if (this->parse_uint8(this, rule_number
, NULL
) != SUCCESS
)
693 if (this->parse_bit(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
702 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
707 payload_length
= *(u_int16_t
*)(output
+ rule
->offset
);
712 if (this->parse_uint32(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
721 if (this->parse_uint8(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
726 spi_size
= *(u_int8_t
*)(output
+ rule
->offset
);
731 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, spi_size
) != SUCCESS
)
740 size_t proposals_length
= payload_length
- SA_PAYLOAD_HEADER_LENGTH
;
741 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, PROPOSAL_SUBSTRUCTURE
, proposals_length
) != SUCCESS
)
750 size_t transforms_length
= payload_length
- spi_size
- PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
;
751 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, TRANSFORM_SUBSTRUCTURE
, transforms_length
) != SUCCESS
)
758 case TRANSFORM_ATTRIBUTES
:
760 size_t transform_a_length
= payload_length
- TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
;
761 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, TRANSFORM_ATTRIBUTE
, transform_a_length
) != SUCCESS
)
768 case ATTRIBUTE_FORMAT
:
770 if (this->parse_bit(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
775 attribute_format
= *(bool*)(output
+ rule
->offset
);
780 if (this->parse_uint15(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
785 attribute_format
= *(bool*)(output
+ rule
->offset
);
788 case ATTRIBUTE_LENGTH_OR_VALUE
:
790 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
795 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
798 case ATTRIBUTE_VALUE
:
800 if (attribute_format
== FALSE
)
802 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, attribute_length
) != SUCCESS
)
812 size_t nonce_length
= payload_length
- NONCE_PAYLOAD_HEADER_LENGTH
;
813 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, nonce_length
) != SUCCESS
)
820 case KEY_EXCHANGE_DATA
:
822 size_t keydata_length
= payload_length
- KE_PAYLOAD_HEADER_LENGTH
;
823 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, keydata_length
) != SUCCESS
)
830 case NOTIFICATION_DATA
:
832 size_t notify_length
= payload_length
- NOTIFY_PAYLOAD_HEADER_LENGTH
- spi_size
;
833 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, notify_length
) != SUCCESS
)
842 size_t data_length
= payload_length
- ENCRYPTION_PAYLOAD_HEADER_LENGTH
;
843 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, data_length
) != SUCCESS
)
852 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
);
857 /* process next rulue */
867 * implementation of parser_t.reset_context
869 static status_t
reset_context (private_parser_t
*this)
871 this->byte_pos
= this->input
;
877 * implementation of parser_t.destroy
879 static status_t
destroy(private_parser_t
*this)
881 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
882 allocator_free(this);
890 parser_t
*parser_create(chunk_t data
)
892 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
899 this->logger
= global_logger_manager
->create_logger(global_logger_manager
, PARSER
, NULL
);
902 if (this->logger
== NULL
)
904 global_logger_manager
->destroy_logger(global_logger_manager
, this->logger
);
905 allocator_free(this);
909 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,payload_t
**)) parse_payload
;
910 this->public.reset_context
= (status_t(*)(parser_t
*)) reset_context
;
911 this->public.destroy
= (status_t(*)(parser_t
*)) destroy
;
914 this->parse_uint4
= parse_uint4
;
915 this->parse_uint8
= parse_uint8
;
916 this->parse_uint15
= parse_uint15
;
917 this->parse_uint16
= parse_uint16
;
918 this->parse_uint32
= parse_uint32
;
919 this->parse_uint64
= parse_uint64
;
920 this->parse_bytes
= parse_bytes
;
921 this->parse_bit
= parse_bit
;
922 this->parse_list
= parse_list
;
923 this->parse_chunk
= parse_chunk
;
925 this->input
= data
.ptr
;
926 this->byte_pos
= data
.ptr
;
928 this->input_roof
= data
.ptr
+ data
.len
;
930 return (parser_t
*)this;