2 * Copyright (C) 2005-2009 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * HSR Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 #include <collections/linked_list.h>
25 #include <encoding/payloads/encodings.h>
26 #include <encoding/payloads/payload.h>
27 #include <encoding/payloads/sa_payload.h>
28 #include <encoding/payloads/proposal_substructure.h>
29 #include <encoding/payloads/transform_substructure.h>
30 #include <encoding/payloads/transform_attribute.h>
31 #include <encoding/payloads/ke_payload.h>
32 #include <encoding/payloads/nonce_payload.h>
33 #include <encoding/payloads/id_payload.h>
34 #include <encoding/payloads/notify_payload.h>
35 #include <encoding/payloads/encrypted_payload.h>
36 #include <encoding/payloads/auth_payload.h>
37 #include <encoding/payloads/cert_payload.h>
38 #include <encoding/payloads/certreq_payload.h>
39 #include <encoding/payloads/ts_payload.h>
40 #include <encoding/payloads/delete_payload.h>
41 #include <encoding/payloads/vendor_id_payload.h>
42 #include <encoding/payloads/cp_payload.h>
43 #include <encoding/payloads/configuration_attribute.h>
44 #include <encoding/payloads/eap_payload.h>
45 #include <encoding/payloads/unknown_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.
64 uint8_t major_version
;
67 * Current bit for reading in input data.
72 * Current byte for reading in input data.
77 * Input data to parse.
82 * Roof of input, used for length-checking.
87 * Set of encoding rules for this parsing session.
89 encoding_rule_t
*rules
;
93 * Log invalid length error
95 static bool short_input(private_parser_t
*this, int number
)
97 DBG1(DBG_ENC
, " not enough input to parse rule %d %N",
98 number
, encoding_type_names
, this->rules
[number
].type
);
103 * Log unaligned rules
105 static bool bad_bitpos(private_parser_t
*this, int number
)
107 DBG1(DBG_ENC
, " found rule %d %N on bitpos %d",
108 number
, encoding_type_names
, this->rules
[number
].type
, this->bit_pos
);
113 * Parse a 4-Bit unsigned integer from the current parsing position.
115 static bool parse_uint4(private_parser_t
*this, int rule_number
,
118 if (this->byte_pos
+ sizeof(uint8_t) > this->input_roof
)
120 return short_input(this, rule_number
);
122 switch (this->bit_pos
)
127 *output_pos
= *(this->byte_pos
) >> 4;
134 *output_pos
= *(this->byte_pos
) & 0x0F;
140 return bad_bitpos(this, rule_number
);
144 DBG3(DBG_ENC
, " => %hhu", *output_pos
);
150 * Parse a 8-Bit unsigned integer from the current parsing position.
152 static bool parse_uint8(private_parser_t
*this, int rule_number
,
155 if (this->byte_pos
+ sizeof(uint8_t) > this->input_roof
)
157 return short_input(this, rule_number
);
161 return bad_bitpos(this, rule_number
);
165 *output_pos
= *(this->byte_pos
);
166 DBG3(DBG_ENC
, " => %hhu", *output_pos
);
173 * Parse a 15-Bit unsigned integer from the current parsing position.
175 static bool parse_uint15(private_parser_t
*this, int rule_number
,
176 uint16_t *output_pos
)
178 if (this->byte_pos
+ sizeof(uint16_t) > this->input_roof
)
180 return short_input(this, rule_number
);
182 if (this->bit_pos
!= 1)
184 return bad_bitpos(this, rule_number
);
188 memcpy(output_pos
, this->byte_pos
, sizeof(uint16_t));
189 *output_pos
= ntohs(*output_pos
) & ~0x8000;
190 DBG3(DBG_ENC
, " => %hu", *output_pos
);
192 this->byte_pos
+= sizeof(uint16_t);
198 * Parse a 16-Bit unsigned integer from the current parsing position.
200 static bool parse_uint16(private_parser_t
*this, int rule_number
,
201 uint16_t *output_pos
)
203 if (this->byte_pos
+ sizeof(uint16_t) > this->input_roof
)
205 return short_input(this, rule_number
);
209 return bad_bitpos(this, rule_number
);
213 memcpy(output_pos
, this->byte_pos
, sizeof(uint16_t));
214 *output_pos
= ntohs(*output_pos
);
215 DBG3(DBG_ENC
, " => %hu", *output_pos
);
217 this->byte_pos
+= sizeof(uint16_t);
221 * Parse a 32-Bit unsigned integer from the current parsing position.
223 static bool parse_uint32(private_parser_t
*this, int rule_number
,
224 uint32_t *output_pos
)
226 if (this->byte_pos
+ sizeof(uint32_t) > this->input_roof
)
228 return short_input(this, rule_number
);
232 return bad_bitpos(this, rule_number
);
236 memcpy(output_pos
, this->byte_pos
, sizeof(uint32_t));
237 *output_pos
= ntohl(*output_pos
);
238 DBG3(DBG_ENC
, " => %u", *output_pos
);
240 this->byte_pos
+= sizeof(uint32_t);
245 * Parse a given amount of bytes and writes them to a specific location
247 static bool parse_bytes(private_parser_t
*this, int rule_number
,
248 uint8_t *output_pos
, int bytes
)
250 if (this->byte_pos
+ bytes
> this->input_roof
)
252 return short_input(this, rule_number
);
256 return bad_bitpos(this, rule_number
);
260 memcpy(output_pos
, this->byte_pos
, bytes
);
261 DBG3(DBG_ENC
, " %b", output_pos
, bytes
);
263 this->byte_pos
+= bytes
;
268 * Parse a single Bit from the current parsing position
270 static bool parse_bit(private_parser_t
*this, int rule_number
,
273 if (this->byte_pos
+ sizeof(uint8_t) > this->input_roof
)
275 return short_input(this, rule_number
);
280 mask
= 0x01 << (7 - this->bit_pos
);
281 *output_pos
= *this->byte_pos
& mask
;
284 { /* set to a "clean", comparable true */
287 DBG3(DBG_ENC
, " => %d", *output_pos
);
289 this->bit_pos
= (this->bit_pos
+ 1) % 8;
290 if (this->bit_pos
== 0)
298 * Parse substructures in a list.
300 static bool parse_list(private_parser_t
*this, int rule_number
,
301 linked_list_t
**output_pos
, payload_type_t payload_type
, int length
)
303 linked_list_t
*list
= *output_pos
;
307 return short_input(this, rule_number
);
311 return bad_bitpos(this, rule_number
);
315 uint8_t *pos_before
= this->byte_pos
;
318 DBG2(DBG_ENC
, " %d bytes left, parsing recursively %N",
319 length
, payload_type_names
, payload_type
);
321 if (this->public.parse_payload(&this->public, payload_type
,
322 &payload
) != SUCCESS
)
324 DBG1(DBG_ENC
, " parsing of a %N substructure failed",
325 payload_type_names
, payload_type
);
328 list
->insert_last(list
, payload
);
329 length
-= this->byte_pos
- pos_before
;
332 { /* must yield exactly to zero */
333 DBG1(DBG_ENC
, " length of %N substructure list invalid",
334 payload_type_names
, payload_type
);
342 * Parse data from current parsing position in a chunk.
344 static bool parse_chunk(private_parser_t
*this, int rule_number
,
345 chunk_t
*output_pos
, int length
)
347 if (this->byte_pos
+ length
> this->input_roof
)
349 return short_input(this, rule_number
);
353 return bad_bitpos(this, rule_number
);
357 *output_pos
= chunk_alloc(length
);
358 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
359 DBG3(DBG_ENC
, " %b", output_pos
->ptr
, length
);
361 this->byte_pos
+= length
;
365 METHOD(parser_t
, parse_payload
, status_t
,
366 private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
370 int payload_length
= 0, spi_size
= 0, attribute_length
= 0, header_length
;
371 uint16_t ts_type
= 0;
372 bool attribute_format
= FALSE
;
373 int rule_number
, rule_count
;
374 encoding_rule_t
*rule
;
376 /* create instance of the payload to parse */
377 if (payload_is_known(payload_type
, this->major_version
))
379 pld
= payload_create(payload_type
);
383 pld
= (payload_t
*)unknown_payload_create(payload_type
);
386 DBG2(DBG_ENC
, "parsing %N payload, %d bytes left",
387 payload_type_names
, payload_type
, this->input_roof
- this->byte_pos
);
389 DBG3(DBG_ENC
, "parsing payload from %b",
390 this->byte_pos
, (u_int
)(this->input_roof
- this->byte_pos
));
392 /* base pointer for output, avoids casting in every rule */
394 /* parse the payload with its own rules */
395 rule_count
= pld
->get_encoding_rules(pld
, &this->rules
);
396 for (rule_number
= 0; rule_number
< rule_count
; rule_number
++)
398 /* update header length for each rule, as it is dynamic (SPIs) */
399 header_length
= pld
->get_header_length(pld
);
401 rule
= &(this->rules
[rule_number
]);
402 DBG2(DBG_ENC
, " parsing rule %d %N",
403 rule_number
, encoding_type_names
, rule
->type
);
404 switch ((int)rule
->type
)
408 if (!parse_uint4(this, rule_number
, output
+ rule
->offset
))
418 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
427 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
437 if (!parse_uint32(this, rule_number
, output
+ rule
->offset
))
446 if (!parse_bytes(this, rule_number
, output
+ rule
->offset
, 8))
456 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
465 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
470 /* parsed u_int16 should be aligned */
471 payload_length
= *(uint16_t*)(output
+ rule
->offset
);
472 /* all payloads must have at least 4 bytes header */
473 if (payload_length
< 4)
482 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
487 spi_size
= *(uint8_t*)(output
+ rule
->offset
);
492 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
500 case PAYLOAD_LIST
+ PLV2_PROPOSAL_SUBSTRUCTURE
:
501 case PAYLOAD_LIST
+ PLV1_PROPOSAL_SUBSTRUCTURE
:
502 case PAYLOAD_LIST
+ PLV2_TRANSFORM_SUBSTRUCTURE
:
503 case PAYLOAD_LIST
+ PLV1_TRANSFORM_SUBSTRUCTURE
:
504 case PAYLOAD_LIST
+ PLV2_TRANSFORM_ATTRIBUTE
:
505 case PAYLOAD_LIST
+ PLV1_TRANSFORM_ATTRIBUTE
:
506 case PAYLOAD_LIST
+ PLV2_CONFIGURATION_ATTRIBUTE
:
507 case PAYLOAD_LIST
+ PLV1_CONFIGURATION_ATTRIBUTE
:
508 case PAYLOAD_LIST
+ PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE
:
510 if (payload_length
< header_length
||
511 !parse_list(this, rule_number
, output
+ rule
->offset
,
512 rule
->type
- PAYLOAD_LIST
,
513 payload_length
- header_length
))
522 if (payload_length
< header_length
||
523 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
524 payload_length
- header_length
))
533 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
534 this->input_roof
- this->byte_pos
))
541 case ATTRIBUTE_FORMAT
:
543 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
548 attribute_format
= *(bool*)(output
+ rule
->offset
);
553 if (!parse_uint15(this, rule_number
, output
+ rule
->offset
))
560 case ATTRIBUTE_LENGTH
:
562 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
567 attribute_length
= *(uint16_t*)(output
+ rule
->offset
);
570 case ATTRIBUTE_LENGTH_OR_VALUE
:
572 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
577 attribute_length
= *(uint16_t*)(output
+ rule
->offset
);
580 case ATTRIBUTE_VALUE
:
582 if (attribute_format
== FALSE
&&
583 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
593 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
598 ts_type
= *(uint8_t*)(output
+ rule
->offset
);
603 int address_length
= (ts_type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
605 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
615 DBG1(DBG_ENC
, " no rule to parse rule %d %N",
616 rule_number
, encoding_type_names
, rule
->type
);
621 /* process next rule */
626 DBG2(DBG_ENC
, "parsing %N payload finished",
627 payload_type_names
, payload_type
);
631 METHOD(parser_t
, get_remaining_byte_count
, int,
632 private_parser_t
*this)
634 return this->input_roof
- this->byte_pos
;
637 METHOD(parser_t
, reset_context
, void,
638 private_parser_t
*this)
640 this->byte_pos
= this->input
;
644 METHOD(parser_t
, set_major_version
, void,
645 private_parser_t
*this, uint8_t major_version
)
647 this->major_version
= major_version
;
650 METHOD(parser_t
, destroy
, void,
651 private_parser_t
*this)
657 * Described in header.
659 parser_t
*parser_create(chunk_t data
)
661 private_parser_t
*this;
665 .parse_payload
= _parse_payload
,
666 .reset_context
= _reset_context
,
667 .set_major_version
= _set_major_version
,
668 .get_remaining_byte_count
= _get_remaining_byte_count
,
672 .byte_pos
= data
.ptr
,
673 .input_roof
= data
.ptr
+ data
.len
,
676 return &this->public;