4 * @brief Implementation of parser_t.
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>
47 typedef struct private_parser_t private_parser_t
;
50 * Private data stored in a context.
52 * Contains pointers and counters to store current state.
54 struct private_parser_t
{
56 * Public members, see parser_t.
61 * @brief Parse a 4-Bit unsigned integer from the current parsing position.
63 * @param this parser_t object
64 * @param rule_number number of current rule
65 * @param[out] output_pos pointer where to write the parsed result
68 * - PARSE_ERROR when not successful
70 status_t (*parse_uint4
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
);
73 * @brief Parse a 8-Bit unsigned integer from the current parsing position.
75 * @param this parser_t object
76 * @param rule_number number of current rule
77 * @param[out] output_pos pointer where to write the parsed result
80 * - PARSE_ERROR when not successful
82 status_t (*parse_uint8
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
);
85 * @brief Parse a 15-Bit unsigned integer from the current parsing position.
87 * This is a special case used for ATTRIBUTE_TYPE.
88 * Big-/Little-endian conversion is done here.
90 * @param this parser_t object
91 * @param rule_number number of current rule
92 * @param[out] output_pos pointer where to write the parsed result
95 * - PARSE_ERROR when not successful
97 status_t (*parse_uint15
) (private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
);
100 * @brief Parse a 16-Bit unsigned integer from the current parsing position.
102 * Big-/Little-endian conversion is done here.
104 * @param this parser_t object
105 * @param rule_number number of current rule
106 * @param[out] output_pos pointer where to write the parsed result
109 * - PARSE_ERROR when not successful
111 status_t (*parse_uint16
) (private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
);
114 * @brief Parse a 32-Bit unsigned integer from the current parsing position.
116 * Big-/Little-endian conversion is done here.
118 * @param this parser_t object
119 * @param rule_number number of current rule
120 * @param[out] output_pos pointer where to write the parsed result
123 * - PARSE_ERROR when not successful
125 status_t (*parse_uint32
) (private_parser_t
*this, int rule_number
, u_int32_t
*output_pos
);
128 * @brief Parse a 64-Bit unsigned integer from the current parsing position.
130 * @todo add support for big-endian machines.
132 * @param this parser_t object
133 * @param rule_number number of current rule
134 * @param[out] output_pos pointer where to write the parsed result
137 * - PARSE_ERROR when not successful
139 status_t (*parse_uint64
) (private_parser_t
*this, int rule_number
, u_int64_t
*output_pos
);
142 * @brief Parse a given amount of bytes and writes them to a specific location
144 * @param this parser_t object
145 * @param rule_number number of current rule
146 * @param[out] output_pos pointer where to write the parsed result
147 * @param bytes number of bytes to parse
150 * - PARSE_ERROR when not successful
152 status_t (*parse_bytes
) (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
,size_t bytes
);
155 * @brief Parse a single Bit from the current parsing position
157 * @param this parser_t object
158 * @param rule_number number of current rule
159 * @param[out] output_pos pointer where to write the parsed result
162 * - PARSE_ERROR when not successful
164 status_t (*parse_bit
) (private_parser_t
*this, int rule_number
, bool *output_pos
);
167 * @brief Parse substructures in a list
169 * This function calls the parser recursivly to parse contained substructures
170 * in a linked_list_t. The list must already be created. Payload defines
171 * the type of the substructures. parsing is continued until the specified length
172 * is completely parsed.
174 * @param this parser_t object
175 * @param rule_number number of current rule
176 * @param[out] output_pos pointer of a linked_list where substructures are added
177 * @param payload_type type of the contained substructures to parse
178 * @param length number of bytes to parse in this list
181 * - PARSE_ERROR when not successful
183 status_t (*parse_list
) (private_parser_t
*this, int rule_number
, linked_list_t
**output_pos
, payload_type_t payload_ype
, size_t length
);
186 * @brief Parse data from current parsing position in a chunk.
188 * This function clones length number of bytes to output_pos, without
189 * modifiyng them. Space will be allocated and must be freed by caller.
191 * @param this parser_t object
192 * @param rule_number number of current rule
193 * @param[out] output_pos pointer of a chunk which will point to the allocated data
194 * @param length number of bytes to clone
197 * - PARSE_ERROR when not successful
199 status_t (*parse_chunk
) (private_parser_t
*this, int rule_number
, chunk_t
*output_pos
, size_t length
);
202 * Current bit for reading in input data.
207 * Current byte for reading in input data.
212 * Input data to parse.
217 * Roof of input, used for length-checking.
219 u_int8_t
*input_roof
;
222 * Set of encoding rules for this parsing session.
224 encoding_rule_t
*rules
;
227 * Assigned logger_t object.
233 * Implementation of private_parser_t.parse_uint4.
235 static status_t
parse_uint4(private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
)
237 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
239 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
240 rule_number
, mapping_find(encoding_type_m
,
241 this->rules
[rule_number
].type
));
244 switch (this->bit_pos
)
247 /* caller interested in result ? */
248 if (output_pos
!= NULL
)
250 *output_pos
= *(this->byte_pos
) >> 4;
255 /* caller interested in result ? */
256 if (output_pos
!= NULL
)
258 *output_pos
= *(this->byte_pos
) & 0x0F;
264 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
265 rule_number
, mapping_find(encoding_type_m
,
266 this->rules
[rule_number
].type
), this->bit_pos
);
270 if (output_pos
!= NULL
)
272 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
279 * Implementation of private_parser_t.parse_uint8.
281 static status_t
parse_uint8(private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
)
283 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
285 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
286 rule_number
, mapping_find(encoding_type_m
,
287 this->rules
[rule_number
].type
));
292 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
293 rule_number
, mapping_find(encoding_type_m
,
294 this->rules
[rule_number
].type
), this->bit_pos
);
298 /* caller interested in result ? */
299 if (output_pos
!= NULL
)
301 *output_pos
= *(this->byte_pos
);
302 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
310 * Implementation of private_parser_t.parse_uint15.
312 static status_t
parse_uint15(private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
)
314 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
316 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
317 rule_number
, mapping_find(encoding_type_m
,
318 this->rules
[rule_number
].type
));
321 if (this->bit_pos
!= 1)
323 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
324 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
328 /* caller interested in result ? */
329 if (output_pos
!= NULL
)
331 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
)) & ~0x8000;
332 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
341 * Implementation of private_parser_t.parse_uint16.
343 static status_t
parse_uint16(private_parser_t
*this, int rule_number
, u_int16_t
*output_pos
)
345 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
347 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
348 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
353 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
354 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
358 /* caller interested in result ? */
359 if (output_pos
!= NULL
)
361 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
));
363 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
370 * Implementation of private_parser_t.parse_uint32.
372 static status_t
parse_uint32(private_parser_t
*this, int rule_number
, u_int32_t
*output_pos
)
374 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
376 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
377 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
382 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
383 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
387 /* caller interested in result ? */
388 if (output_pos
!= NULL
)
390 *output_pos
= ntohl(*((u_int32_t
*)this->byte_pos
));
392 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
400 * Implementation of private_parser_t.parse_uint64.
402 static status_t
parse_uint64(private_parser_t
*this, int rule_number
, u_int64_t
*output_pos
)
404 if (this->byte_pos
+ sizeof(u_int64_t
) > this->input_roof
)
406 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
407 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
412 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
413 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
417 /* caller interested in result ? */
418 if (output_pos
!= NULL
)
420 /* assuming little endian host order */
421 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)this->byte_pos
));
422 *output_pos
= ntohl(*(((u_int32_t
*)this->byte_pos
) + 1));
424 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
, 8);
432 * Implementation of private_parser_t.parse_bytes.
434 static status_t
parse_bytes (private_parser_t
*this, int rule_number
, u_int8_t
*output_pos
,size_t bytes
)
436 if (this->byte_pos
+ bytes
> this->input_roof
)
438 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
439 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
444 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
445 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
),
450 /* caller interested in result ? */
451 if (output_pos
!= NULL
)
453 memcpy(output_pos
,this->byte_pos
,bytes
);
455 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
, bytes
);
457 this->byte_pos
+= bytes
;
463 * Implementation of private_parser_t.parse_bit.
465 static status_t
parse_bit(private_parser_t
*this, int rule_number
, bool *output_pos
)
467 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
469 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
470 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
473 /* caller interested in result ? */
474 if (output_pos
!= NULL
)
477 mask
= 0x01 << (7 - this->bit_pos
);
478 *output_pos
= *this->byte_pos
& mask
;
482 /* set to a "clean", comparable true */
486 this->logger
->log(this->logger
, RAW
|MOST
, " => %d", *output_pos
);
488 this->bit_pos
= (this->bit_pos
+ 1) % 8;
489 if (this->bit_pos
== 0)
498 * Implementation of private_parser_t.parse_list.
500 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
)
502 linked_list_t
* list
= *output_pos
;
506 this->logger
->log(this->logger
, ERROR
, " invalid length for rule %d %s",
507 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
513 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
514 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
), this->bit_pos
);
520 u_int8_t
*pos_before
= this->byte_pos
;
523 this->logger
->log(this->logger
, CONTROL
|MORE
, " %d bytes left, parsing recursivly %s",
524 length
, mapping_find(payload_type_m
, payload_type
));
525 status
= this->public.parse_payload((parser_t
*)this, payload_type
, &payload
);
526 if (status
!= SUCCESS
)
528 this->logger
->log(this->logger
, ERROR
, " parsing of a %s substructure failed",
529 mapping_find(payload_type_m
, payload_type
));
532 list
->insert_last(list
, payload
);
533 length
-= this->byte_pos
- pos_before
;
540 * Implementation of private_parser_t.parse_chunk.
542 static status_t
parse_chunk(private_parser_t
*this, int rule_number
, chunk_t
*output_pos
, size_t length
)
544 if (this->byte_pos
+ length
> this->input_roof
)
546 this->logger
->log(this->logger
, ERROR
, " not enough input (%d bytes) to parse rule %d %s",
547 length
, rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
));
552 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
553 rule_number
, mapping_find(encoding_type_m
, this->rules
[rule_number
].type
), this->bit_pos
);
556 if (output_pos
!= NULL
)
558 output_pos
->len
= length
;
559 output_pos
->ptr
= allocator_alloc(length
);
560 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
562 this->byte_pos
+= length
;
563 this->logger
->log_bytes(this->logger
, RAW
|MOST
, " =>", (void*)output_pos
->ptr
, length
);
569 * Implementation of parser_t.parse_payload.
571 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
575 size_t rule_count
, payload_length
, spi_size
, attribute_length
;
576 bool attribute_format
;
578 encoding_rule_t
*rule
;
580 this->logger
->log(this->logger
, CONTROL
, "parsing %s payload, %d bytes left",
581 mapping_find(payload_type_m
, payload_type
),
582 this->input_roof
-this->byte_pos
);
584 this->logger
->log_bytes(this->logger
, RAW
, "parsing payload from", this->byte_pos
,
585 this->input_roof
-this->byte_pos
);
587 /* ok, do the parsing */
588 pld
= payload_create(payload_type
);
591 this->logger
->log(this->logger
, ERROR
, " payload %s not supported", mapping_find(payload_type_m
, payload_type
));
592 return NOT_SUPPORTED
;
594 /* base pointer for output, avoids casting in every rule */
597 pld
->get_encoding_rules(pld
, &(this->rules
), &rule_count
);
599 for (rule_number
= 0; rule_number
< rule_count
; rule_number
++)
601 rule
= &(this->rules
[rule_number
]);
602 this->logger
->log(this->logger
, CONTROL
|MORE
, " parsing rule %d %s",
603 rule_number
, mapping_find(encoding_type_m
, rule
->type
));
608 if (this->parse_uint4(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
617 if (this->parse_uint8(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
626 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
635 if (this->parse_uint32(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
644 if (this->parse_uint64(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
653 if (this->parse_bytes(this, rule_number
, output
+ rule
->offset
,8) != SUCCESS
)
662 if (this->parse_bit(this, rule_number
, NULL
) != SUCCESS
)
671 if (this->parse_uint8(this, rule_number
, NULL
) != SUCCESS
)
680 if (this->parse_bit(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
689 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
694 payload_length
= *(u_int16_t
*)(output
+ rule
->offset
);
699 if (this->parse_uint32(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
708 if (this->parse_uint8(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
713 spi_size
= *(u_int8_t
*)(output
+ rule
->offset
);
718 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, spi_size
) != SUCCESS
)
727 size_t proposals_length
= payload_length
- SA_PAYLOAD_HEADER_LENGTH
;
728 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, PROPOSAL_SUBSTRUCTURE
, proposals_length
) != SUCCESS
)
737 size_t transforms_length
= payload_length
- spi_size
- PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH
;
738 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, TRANSFORM_SUBSTRUCTURE
, transforms_length
) != SUCCESS
)
745 case TRANSFORM_ATTRIBUTES
:
747 size_t transform_a_length
= payload_length
- TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH
;
748 if (this->parse_list(this, rule_number
, output
+ rule
->offset
, TRANSFORM_ATTRIBUTE
, transform_a_length
) != SUCCESS
)
755 case ATTRIBUTE_FORMAT
:
757 if (this->parse_bit(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
762 attribute_format
= *(bool*)(output
+ rule
->offset
);
767 if (this->parse_uint15(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
772 attribute_format
= *(bool*)(output
+ rule
->offset
);
775 case ATTRIBUTE_LENGTH_OR_VALUE
:
777 if (this->parse_uint16(this, rule_number
, output
+ rule
->offset
) != SUCCESS
)
782 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
785 case ATTRIBUTE_VALUE
:
787 if (attribute_format
== FALSE
)
789 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, attribute_length
) != SUCCESS
)
799 size_t nonce_length
= payload_length
- NONCE_PAYLOAD_HEADER_LENGTH
;
800 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, nonce_length
) != SUCCESS
)
807 case KEY_EXCHANGE_DATA
:
809 size_t keydata_length
= payload_length
- KE_PAYLOAD_HEADER_LENGTH
;
810 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, keydata_length
) != SUCCESS
)
817 case NOTIFICATION_DATA
:
819 size_t notify_length
= payload_length
- NOTIFY_PAYLOAD_HEADER_LENGTH
- spi_size
;
820 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, notify_length
) != SUCCESS
)
829 size_t data_length
= payload_length
- ENCRYPTION_PAYLOAD_HEADER_LENGTH
;
830 if (this->parse_chunk(this, rule_number
, output
+ rule
->offset
, data_length
) != SUCCESS
)
839 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
);
844 /* process next rulue */
854 * Implementation of parser_t.reset_context.
856 static void reset_context (private_parser_t
*this)
858 this->byte_pos
= this->input
;
863 * Implementation of parser_t.destroy.
865 static void destroy(private_parser_t
*this)
867 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
868 allocator_free(this);
872 * Described in header.
874 parser_t
*parser_create(chunk_t data
)
876 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
878 this->logger
= global_logger_manager
->create_logger(global_logger_manager
, PARSER
, NULL
);
880 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,payload_t
**)) parse_payload
;
881 this->public.reset_context
= (void(*)(parser_t
*)) reset_context
;
882 this->public.destroy
= (void(*)(parser_t
*)) destroy
;
885 this->parse_uint4
= parse_uint4
;
886 this->parse_uint8
= parse_uint8
;
887 this->parse_uint15
= parse_uint15
;
888 this->parse_uint16
= parse_uint16
;
889 this->parse_uint32
= parse_uint32
;
890 this->parse_uint64
= parse_uint64
;
891 this->parse_bytes
= parse_bytes
;
892 this->parse_bit
= parse_bit
;
893 this->parse_list
= parse_list
;
894 this->parse_chunk
= parse_chunk
;
896 this->input
= data
.ptr
;
897 this->byte_pos
= data
.ptr
;
899 this->input_roof
= data
.ptr
+ data
.len
;
901 return (parser_t
*)this;