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
18 #include <arpa/inet.h>
25 #include <utils/linked_list.h>
26 #include <encoding/payloads/encodings.h>
27 #include <encoding/payloads/payload.h>
28 #include <encoding/payloads/sa_payload.h>
29 #include <encoding/payloads/proposal_substructure.h>
30 #include <encoding/payloads/transform_substructure.h>
31 #include <encoding/payloads/transform_attribute.h>
32 #include <encoding/payloads/ke_payload.h>
33 #include <encoding/payloads/nonce_payload.h>
34 #include <encoding/payloads/id_payload.h>
35 #include <encoding/payloads/notify_payload.h>
36 #include <encoding/payloads/encryption_payload.h>
37 #include <encoding/payloads/auth_payload.h>
38 #include <encoding/payloads/cert_payload.h>
39 #include <encoding/payloads/certreq_payload.h>
40 #include <encoding/payloads/ts_payload.h>
41 #include <encoding/payloads/delete_payload.h>
42 #include <encoding/payloads/vendor_id_payload.h>
43 #include <encoding/payloads/cp_payload.h>
44 #include <encoding/payloads/configuration_attribute.h>
45 #include <encoding/payloads/eap_payload.h>
46 #include <encoding/payloads/unknown_payload.h>
49 typedef struct private_parser_t private_parser_t
;
52 * Private data stored in a context.
54 * Contains pointers and counters to store current state.
56 struct private_parser_t
{
58 * Public members, see parser_t.
63 * Current bit for reading in input data.
68 * Current byte for reading in input data.
73 * Input data to parse.
78 * Roof of input, used for length-checking.
83 * Set of encoding rules for this parsing session.
85 encoding_rule_t
*rules
;
89 * Log invalid length error
91 static bool short_input(private_parser_t
*this, int number
)
93 DBG1(DBG_ENC
, " not enough input to parse rule %d %N",
94 number
, encoding_type_names
, this->rules
[number
].type
);
101 static bool bad_bitpos(private_parser_t
*this, int number
)
103 DBG1(DBG_ENC
, " found rule %d %N on bitpos %d",
104 number
, encoding_type_names
, this->rules
[number
].type
, this->bit_pos
);
109 * Parse a 4-Bit unsigned integer from the current parsing position.
111 static bool parse_uint4(private_parser_t
*this, int rule_number
,
112 u_int8_t
*output_pos
)
114 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
116 return short_input(this, rule_number
);
118 switch (this->bit_pos
)
123 *output_pos
= *(this->byte_pos
) >> 4;
130 *output_pos
= *(this->byte_pos
) & 0x0F;
136 return bad_bitpos(this, rule_number
);
140 DBG3(DBG_ENC
, " => %d", *output_pos
);
146 * Parse a 8-Bit unsigned integer from the current parsing position.
148 static bool parse_uint8(private_parser_t
*this, int rule_number
,
149 u_int8_t
*output_pos
)
151 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
153 return short_input(this, rule_number
);
157 return bad_bitpos(this, rule_number
);
161 *output_pos
= *(this->byte_pos
);
162 DBG3(DBG_ENC
, " => %d", *output_pos
);
169 * Parse a 15-Bit unsigned integer from the current parsing position.
171 static bool parse_uint15(private_parser_t
*this, int rule_number
,
172 u_int16_t
*output_pos
)
174 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
176 return short_input(this, rule_number
);
178 if (this->bit_pos
!= 1)
180 return bad_bitpos(this, rule_number
);
184 memcpy(output_pos
, this->byte_pos
, sizeof(u_int16_t
));
185 *output_pos
= ntohs(*output_pos
) & ~0x8000;
186 DBG3(DBG_ENC
, " => %d", *output_pos
);
188 this->byte_pos
+= sizeof(u_int16_t
);
194 * Parse a 16-Bit unsigned integer from the current parsing position.
196 static bool parse_uint16(private_parser_t
*this, int rule_number
,
197 u_int16_t
*output_pos
)
199 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
201 return short_input(this, rule_number
);
205 return bad_bitpos(this, rule_number
);
209 memcpy(output_pos
, this->byte_pos
, sizeof(u_int16_t
));
210 *output_pos
= ntohs(*output_pos
);
211 DBG3(DBG_ENC
, " => %d", *output_pos
);
213 this->byte_pos
+= sizeof(u_int16_t
);
217 * Parse a 32-Bit unsigned integer from the current parsing position.
219 static bool parse_uint32(private_parser_t
*this, int rule_number
,
220 u_int32_t
*output_pos
)
222 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
224 return short_input(this, rule_number
);
228 return bad_bitpos(this, rule_number
);
232 memcpy(output_pos
, this->byte_pos
, sizeof(u_int32_t
));
233 *output_pos
= ntohl(*output_pos
);
234 DBG3(DBG_ENC
, " => %d", *output_pos
);
236 this->byte_pos
+= sizeof(u_int32_t
);
241 * Parse a given amount of bytes and writes them to a specific location
243 static bool parse_bytes(private_parser_t
*this, int rule_number
,
244 u_int8_t
*output_pos
, int bytes
)
246 if (this->byte_pos
+ bytes
> this->input_roof
)
248 return short_input(this, rule_number
);
252 return bad_bitpos(this, rule_number
);
256 memcpy(output_pos
, this->byte_pos
, bytes
);
257 DBG3(DBG_ENC
, " => %b", output_pos
, bytes
);
259 this->byte_pos
+= bytes
;
264 * Parse a single Bit from the current parsing position
266 static bool parse_bit(private_parser_t
*this, int rule_number
,
269 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
271 return short_input(this, rule_number
);
276 mask
= 0x01 << (7 - this->bit_pos
);
277 *output_pos
= *this->byte_pos
& mask
;
280 { /* set to a "clean", comparable true */
283 DBG3(DBG_ENC
, " => %d", *output_pos
);
285 this->bit_pos
= (this->bit_pos
+ 1) % 8;
286 if (this->bit_pos
== 0)
294 * Parse substructures in a list.
296 static bool parse_list(private_parser_t
*this, int rule_number
,
297 linked_list_t
**output_pos
, payload_type_t payload_type
, int length
)
299 linked_list_t
*list
= *output_pos
;
303 return short_input(this, rule_number
);
307 return bad_bitpos(this, rule_number
);
311 u_int8_t
*pos_before
= this->byte_pos
;
314 DBG2(DBG_ENC
, " %d bytes left, parsing recursively %N",
315 length
, payload_type_names
, payload_type
);
317 if (this->public.parse_payload(&this->public, payload_type
,
318 &payload
) != SUCCESS
)
320 DBG1(DBG_ENC
, " parsing of a %N substructure failed",
321 payload_type_names
, payload_type
);
324 list
->insert_last(list
, payload
);
325 length
-= this->byte_pos
- pos_before
;
328 { /* must yield exactly to zero */
329 DBG1(DBG_ENC
, " length of %N substructure list invalid",
330 payload_type_names
, payload_type
);
338 * Parse data from current parsing position in a chunk.
340 static bool parse_chunk(private_parser_t
*this, int rule_number
,
341 chunk_t
*output_pos
, int length
)
343 if (this->byte_pos
+ length
> this->input_roof
)
345 return short_input(this, rule_number
);
349 return bad_bitpos(this, rule_number
);
353 *output_pos
= chunk_alloc(length
);
354 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
355 DBG3(DBG_ENC
, " => %b", output_pos
->ptr
, length
);
357 this->byte_pos
+= length
;
362 * Map a encoding type to a encoded payload
364 static payload_type_t
map_wrapped_payload(encoding_type_t type
)
369 return PROPOSAL_SUBSTRUCTURE
;
371 return PROPOSAL_SUBSTRUCTURE_V1
;
373 return TRANSFORM_SUBSTRUCTURE
;
375 return TRANSFORM_SUBSTRUCTURE_V1
;
376 case TRANSFORM_ATTRIBUTES
:
377 return TRANSFORM_ATTRIBUTE
;
378 case TRANSFORM_ATTRIBUTES_V1
:
379 return TRANSFORM_ATTRIBUTE_V1
;
380 case CONFIGURATION_ATTRIBUTES
:
381 return CONFIGURATION_ATTRIBUTE
;
382 case TRAFFIC_SELECTORS
:
383 return TRAFFIC_SELECTOR_SUBSTRUCTURE
;
389 METHOD(parser_t
, parse_payload
, status_t
,
390 private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
394 int payload_length
= 0, spi_size
= 0, attribute_length
= 0, header_length
;
395 u_int16_t ts_type
= 0;
396 bool attribute_format
= FALSE
;
397 int rule_number
, rule_count
;
398 encoding_rule_t
*rule
;
400 /* create instance of the payload to parse */
401 pld
= payload_create(payload_type
);
403 DBG2(DBG_ENC
, "parsing %N payload, %d bytes left",
404 payload_type_names
, payload_type
, this->input_roof
- this->byte_pos
);
406 DBG3(DBG_ENC
, "parsing payload from %b",
407 this->byte_pos
, this->input_roof
- this->byte_pos
);
409 /* base pointer for output, avoids casting in every rule */
412 header_length
= pld
->get_header_length(pld
);
413 /* parse the payload with its own rulse */
414 rule_count
= pld
->get_encoding_rules(pld
, &this->rules
);
415 for (rule_number
= 0; rule_number
< rule_count
; rule_number
++)
417 rule
= &(this->rules
[rule_number
]);
418 DBG2(DBG_ENC
, " parsing rule %d %N",
419 rule_number
, encoding_type_names
, rule
->type
);
424 if (!parse_uint4(this, rule_number
, output
+ rule
->offset
))
434 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
443 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
453 if (!parse_uint32(this, rule_number
, output
+ rule
->offset
))
462 if (!parse_bytes(this, rule_number
, output
+ rule
->offset
, 8))
472 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
481 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
486 /* parsed u_int16 should be aligned */
487 payload_length
= *(u_int16_t
*)(output
+ rule
->offset
);
488 /* all payloads must have at least 4 bytes header */
489 if (payload_length
< 4)
498 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
503 spi_size
= *(u_int8_t
*)(output
+ rule
->offset
);
508 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
521 case TRANSFORM_ATTRIBUTES
:
522 case TRANSFORM_ATTRIBUTES_V1
:
523 case TRAFFIC_SELECTORS
:
525 if (payload_length
< header_length
||
526 !parse_list(this, rule_number
, output
+ rule
->offset
,
527 map_wrapped_payload(rule
->type
),
528 payload_length
- header_length
))
544 case CONFIGURATION_ATTRIBUTE_VALUE
:
545 case KEY_EXCHANGE_DATA
:
546 case KEY_EXCHANGE_DATA_V1
:
547 case NOTIFICATION_DATA
:
551 if (payload_length
< header_length
||
552 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
553 payload_length
- header_length
))
560 case ATTRIBUTE_FORMAT
:
562 if (!parse_bit(this, rule_number
, output
+ rule
->offset
))
567 attribute_format
= *(bool*)(output
+ rule
->offset
);
572 if (!parse_uint15(this, rule_number
, output
+ rule
->offset
))
579 case CONFIGURATION_ATTRIBUTE_LENGTH
:
581 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
586 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
589 case ATTRIBUTE_LENGTH_OR_VALUE
:
591 if (!parse_uint16(this, rule_number
, output
+ rule
->offset
))
596 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
599 case ATTRIBUTE_VALUE
:
601 if (attribute_format
== FALSE
&&
602 !parse_chunk(this, rule_number
, output
+ rule
->offset
,
612 if (!parse_uint8(this, rule_number
, output
+ rule
->offset
))
617 ts_type
= *(u_int8_t
*)(output
+ rule
->offset
);
622 int address_length
= (ts_type
== TS_IPV4_ADDR_RANGE
) ? 4 : 16;
624 if (!parse_chunk(this, rule_number
, output
+ rule
->offset
,
634 DBG1(DBG_ENC
, " no rule to parse rule %d %N",
635 rule_number
, encoding_type_names
, rule
->type
);
640 /* process next rulue */
645 DBG2(DBG_ENC
, "parsing %N payload finished",
646 payload_type_names
, payload_type
);
650 METHOD(parser_t
, get_remaining_byte_count
, int,
651 private_parser_t
*this)
653 return this->input_roof
- this->byte_pos
;
656 METHOD(parser_t
, reset_context
, void,
657 private_parser_t
*this)
659 this->byte_pos
= this->input
;
663 METHOD(parser_t
, destroy
, void,
664 private_parser_t
*this)
670 * Described in header.
672 parser_t
*parser_create(chunk_t data
)
674 private_parser_t
*this;
678 .parse_payload
= _parse_payload
,
679 .reset_context
= _reset_context
,
680 .get_remaining_byte_count
= _get_remaining_byte_count
,
684 .byte_pos
= data
.ptr
,
685 .input_roof
= data
.ptr
+ data
.len
,
688 return &this->public;