2 * Copyright (C) 2005-2009 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * 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/encryption_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.
62 * Current bit for reading in input data.
67 * Current byte for reading in input data.
72 * Input data to parse.
77 * Roof of input, used for length-checking.
82 * Set of encoding rules for this parsing session.
84 encoding_rule_t
*rules
;
88 * Log invalid length error
90 static bool short_input(private_parser_t
*this, int number
)
92 DBG1(DBG_ENC
, " not enough input to parse rule %d %N",
93 number
, encoding_type_names
, this->rules
[number
].type
);
100 static bool bad_bitpos(private_parser_t
*this, int number
)
102 DBG1(DBG_ENC
, " found rule %d %N on bitpos %d",
103 number
, encoding_type_names
, this->rules
[number
].type
, this->bit_pos
);
108 * Parse a 4-Bit unsigned integer from the current parsing position.
110 static bool parse_uint4(private_parser_t
*this, int rule_number
,
111 u_int8_t
*output_pos
)
113 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
115 return short_input(this, rule_number
);
117 switch (this->bit_pos
)
122 *output_pos
= *(this->byte_pos
) >> 4;
129 *output_pos
= *(this->byte_pos
) & 0x0F;
135 return bad_bitpos(this, rule_number
);
139 DBG3(DBG_ENC
, " => %hhu", *output_pos
);
145 * Parse a 8-Bit unsigned integer from the current parsing position.
147 static bool parse_uint8(private_parser_t
*this, int rule_number
,
148 u_int8_t
*output_pos
)
150 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
152 return short_input(this, rule_number
);
156 return bad_bitpos(this, rule_number
);
160 *output_pos
= *(this->byte_pos
);
161 DBG3(DBG_ENC
, " => %hhu", *output_pos
);
168 * Parse a 15-Bit unsigned integer from the current parsing position.
170 static bool parse_uint15(private_parser_t
*this, int rule_number
,
171 u_int16_t
*output_pos
)
173 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
175 return short_input(this, rule_number
);
177 if (this->bit_pos
!= 1)
179 return bad_bitpos(this, rule_number
);
183 memcpy(output_pos
, this->byte_pos
, sizeof(u_int16_t
));
184 *output_pos
= ntohs(*output_pos
) & ~0x8000;
185 DBG3(DBG_ENC
, " => %hu", *output_pos
);
187 this->byte_pos
+= sizeof(u_int16_t
);
193 * Parse a 16-Bit unsigned integer from the current parsing position.
195 static bool parse_uint16(private_parser_t
*this, int rule_number
,
196 u_int16_t
*output_pos
)
198 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
200 return short_input(this, rule_number
);
204 return bad_bitpos(this, rule_number
);
208 memcpy(output_pos
, this->byte_pos
, sizeof(u_int16_t
));
209 *output_pos
= ntohs(*output_pos
);
210 DBG3(DBG_ENC
, " => %hu", *output_pos
);
212 this->byte_pos
+= sizeof(u_int16_t
);
216 * Parse a 32-Bit unsigned integer from the current parsing position.
218 static bool parse_uint32(private_parser_t
*this, int rule_number
,
219 u_int32_t
*output_pos
)
221 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
223 return short_input(this, rule_number
);
227 return bad_bitpos(this, rule_number
);
231 memcpy(output_pos
, this->byte_pos
, sizeof(u_int32_t
));
232 *output_pos
= ntohl(*output_pos
);
233 DBG3(DBG_ENC
, " => %u", *output_pos
);
235 this->byte_pos
+= sizeof(u_int32_t
);
240 * Parse a given amount of bytes and writes them to a specific location
242 static bool parse_bytes(private_parser_t
*this, int rule_number
,
243 u_int8_t
*output_pos
, int bytes
)
245 if (this->byte_pos
+ bytes
> this->input_roof
)
247 return short_input(this, rule_number
);
251 return bad_bitpos(this, rule_number
);
255 memcpy(output_pos
, this->byte_pos
, bytes
);
256 DBG3(DBG_ENC
, " %b", output_pos
, bytes
);
258 this->byte_pos
+= bytes
;
263 * Parse a single Bit from the current parsing position
265 static bool parse_bit(private_parser_t
*this, int rule_number
,
268 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
270 return short_input(this, rule_number
);
275 mask
= 0x01 << (7 - this->bit_pos
);
276 *output_pos
= *this->byte_pos
& mask
;
279 { /* set to a "clean", comparable true */
282 DBG3(DBG_ENC
, " => %d", *output_pos
);
284 this->bit_pos
= (this->bit_pos
+ 1) % 8;
285 if (this->bit_pos
== 0)
293 * Parse substructures in a list.
295 static bool parse_list(private_parser_t
*this, int rule_number
,
296 linked_list_t
**output_pos
, payload_type_t payload_type
, int length
)
298 linked_list_t
*list
= *output_pos
;
302 return short_input(this, rule_number
);
306 return bad_bitpos(this, rule_number
);
310 u_int8_t
*pos_before
= this->byte_pos
;
313 DBG2(DBG_ENC
, " %d bytes left, parsing recursively %N",
314 length
, payload_type_names
, payload_type
);
316 if (this->public.parse_payload(&this->public, payload_type
,
317 &payload
) != SUCCESS
)
319 DBG1(DBG_ENC
, " parsing of a %N substructure failed",
320 payload_type_names
, payload_type
);
323 list
->insert_last(list
, payload
);
324 length
-= this->byte_pos
- pos_before
;
327 { /* must yield exactly to zero */
328 DBG1(DBG_ENC
, " length of %N substructure list invalid",
329 payload_type_names
, payload_type
);
337 * Parse data from current parsing position in a chunk.
339 static bool parse_chunk(private_parser_t
*this, int rule_number
,
340 chunk_t
*output_pos
, int length
)
342 if (this->byte_pos
+ length
> this->input_roof
)
344 return short_input(this, rule_number
);
348 return bad_bitpos(this, rule_number
);
352 *output_pos
= chunk_alloc(length
);
353 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
354 DBG3(DBG_ENC
, " %b", output_pos
->ptr
, length
);
356 this->byte_pos
+= length
;
360 METHOD(parser_t
, parse_payload
, status_t
,
361 private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
365 int payload_length
= 0, spi_size
= 0, attribute_length
= 0, header_length
;
366 u_int16_t ts_type
= 0;
367 bool attribute_format
= FALSE
;
368 int rule_number
, rule_count
;
369 encoding_rule_t
*rule
;
371 /* create instance of the payload to parse */
372 pld
= payload_create(payload_type
);
374 DBG2(DBG_ENC
, "parsing %N payload, %d bytes left",
375 payload_type_names
, payload_type
, this->input_roof
- this->byte_pos
);
377 DBG3(DBG_ENC
, "parsing payload from %b",
378 this->byte_pos
, (u_int
)(this->input_roof
- this->byte_pos
));
380 /* base pointer for output, avoids casting in every rule */
382 /* parse the payload with its own rulse */
383 rule_count
= pld
->get_encoding_rules(pld
, &this->rules
);
384 for (rule_number
= 0; rule_number
< rule_count
; rule_number
++)
386 /* update header length for each rule, as it is dynamic (SPIs) */
387 header_length
= pld
->get_header_length(pld
);
389 rule
= &(this->rules
[rule_number
]);
390 DBG2(DBG_ENC
, " parsing rule %d %N",
391 rule_number
, encoding_type_names
, rule
->type
);
392 switch ((int)rule
->type
)
396 if (!parse_uint4(this, rule_number
, output
+ rule
->offset
))
406 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
415 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
425 if (!parse_uint32(this, rule_number
, output
+ rule
->offset
))
434 if (!parse_bytes(this, rule_number
, output
+ rule
->offset
, 8))
444 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
453 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
458 /* parsed u_int16 should be aligned */
459 payload_length
= *(u_int16_t
*)(output
+ rule
->offset
);
460 /* all payloads must have at least 4 bytes header */
461 if (payload_length
< 4)
470 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
475 spi_size
= *(u_int8_t
*)(output
+ rule
->offset
);
480 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
488 case PAYLOAD_LIST
+ PLV2_PROPOSAL_SUBSTRUCTURE
:
489 case PAYLOAD_LIST
+ PLV1_PROPOSAL_SUBSTRUCTURE
:
490 case PAYLOAD_LIST
+ PLV2_TRANSFORM_SUBSTRUCTURE
:
491 case PAYLOAD_LIST
+ PLV1_TRANSFORM_SUBSTRUCTURE
:
492 case PAYLOAD_LIST
+ PLV2_TRANSFORM_ATTRIBUTE
:
493 case PAYLOAD_LIST
+ PLV1_TRANSFORM_ATTRIBUTE
:
494 case PAYLOAD_LIST
+ PLV2_CONFIGURATION_ATTRIBUTE
:
495 case PAYLOAD_LIST
+ PLV1_CONFIGURATION_ATTRIBUTE
:
496 case PAYLOAD_LIST
+ PLV2_TRAFFIC_SELECTOR_SUBSTRUCTURE
:
498 if (payload_length
< header_length
||
499 !parse_list(this, rule_number
, output
+ rule
->offset
,
500 rule
->type
- PAYLOAD_LIST
,
501 payload_length
- header_length
))
510 if (payload_length
< header_length
||
511 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
512 payload_length
- header_length
))
521 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
522 this->input_roof
- this->byte_pos
))
529 case ATTRIBUTE_FORMAT
:
531 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
536 attribute_format
= *(bool*)(output
+ rule
->offset
);
541 if (!parse_uint15(this, rule_number
, output
+ rule
->offset
))
548 case ATTRIBUTE_LENGTH
:
550 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
555 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
558 case ATTRIBUTE_LENGTH_OR_VALUE
:
560 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
565 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
568 case ATTRIBUTE_VALUE
:
570 if (attribute_format
== FALSE
&&
571 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
581 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
586 ts_type
= *(u_int8_t
*)(output
+ rule
->offset
);
591 int address_length
= (ts_type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
593 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
603 DBG1(DBG_ENC
, " no rule to parse rule %d %N",
604 rule_number
, encoding_type_names
, rule
->type
);
609 /* process next rulue */
614 DBG2(DBG_ENC
, "parsing %N payload finished",
615 payload_type_names
, payload_type
);
619 METHOD(parser_t
, get_remaining_byte_count
, int,
620 private_parser_t
*this)
622 return this->input_roof
- this->byte_pos
;
625 METHOD(parser_t
, reset_context
, void,
626 private_parser_t
*this)
628 this->byte_pos
= this->input
;
632 METHOD(parser_t
, destroy
, void,
633 private_parser_t
*this)
639 * Described in header.
641 parser_t
*parser_create(chunk_t data
)
643 private_parser_t
*this;
647 .parse_payload
= _parse_payload
,
648 .reset_context
= _reset_context
,
649 .get_remaining_byte_count
= _get_remaining_byte_count
,
653 .byte_pos
= data
.ptr
,
654 .input_roof
= data
.ptr
+ data
.len
,
657 return &this->public;