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 "payloads/payload.h"
39 * @private data stored in a context
41 * contains pointers and counters to store current state
43 typedef struct private_parser_s private_parser_t
;
45 struct private_parser_s
{
51 status_t (*parse_uint4
) (private_parser_t
*,encoding_rule_t
*,int,u_int8_t
*);
52 status_t (*parse_uint8
) (private_parser_t
*,encoding_rule_t
*,int,u_int8_t
*);
53 status_t (*parse_uint15
) (private_parser_t
*,encoding_rule_t
*,int,u_int16_t
*);
54 status_t (*parse_uint16
) (private_parser_t
*,encoding_rule_t
*,int,u_int16_t
*);
55 status_t (*parse_uint32
) (private_parser_t
*,encoding_rule_t
*,int,u_int32_t
*);
56 status_t (*parse_uint64
) (private_parser_t
*,encoding_rule_t
*,int,u_int32_t
*);
57 status_t (*parse_bit
) (private_parser_t
*,encoding_rule_t
*,int,bool*);
58 status_t (*parse_list
) (private_parser_t
*,encoding_rule_t
*,int,linked_list_t
**,payload_type_t
,size_t);
59 status_t (*parse_chunk
) (private_parser_t
*,encoding_rule_t
*,int,chunk_t
*,size_t);
62 * Current bit for reading in input data
67 * Current byte for reading in input data
89 static status_t
parse_uint4(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, u_int8_t
*output_pos
)
91 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
93 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
94 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
97 switch (this->bit_pos
)
100 /* caller interested in result ? */
101 if (output_pos
!= NULL
)
103 *output_pos
= *(this->byte_pos
) >> 4;
108 /* caller interested in result ? */
109 if (output_pos
!= NULL
)
111 *output_pos
= *(this->byte_pos
) & 0x0F;
117 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
118 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
122 if (output_pos
!= NULL
)
124 this->logger
->log(this->logger
, RAW
, " => %d", *output_pos
);
131 static status_t
parse_uint8(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, u_int8_t
*output_pos
)
133 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
135 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
136 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
141 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
142 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
146 /* caller interested in result ? */
147 if (output_pos
!= NULL
)
149 *output_pos
= *(this->byte_pos
);
150 this->logger
->log(this->logger
, RAW
, " => %d", *output_pos
);
159 static status_t
parse_uint15(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, u_int16_t
*output_pos
)
161 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
163 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
164 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
167 if (this->bit_pos
!= 1)
169 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
170 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
173 /* caller interested in result ? */
174 if (output_pos
!= NULL
)
176 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
)) & 0xEFFF;
177 this->logger
->log(this->logger
, RAW
, " => %d", *output_pos
);
188 static status_t
parse_uint16(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, u_int16_t
*output_pos
)
190 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
192 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
193 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
198 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
199 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
202 /* caller interested in result ? */
203 if (output_pos
!= NULL
)
205 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
));
207 this->logger
->log(this->logger
, RAW
, " => %d", *output_pos
);
215 static status_t
parse_uint32(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, u_int32_t
*output_pos
)
217 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
219 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
220 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
225 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
226 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
229 /* caller interested in result ? */
230 if (output_pos
!= NULL
)
232 *output_pos
= ntohl(*((u_int32_t
*)this->byte_pos
));
234 this->logger
->log(this->logger
, RAW
, " => %d", *output_pos
);
242 static status_t
parse_uint64(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, u_int32_t
*output_pos
)
244 if (this->byte_pos
+ 2 * sizeof(u_int32_t
) > this->input_roof
)
246 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
247 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
252 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
253 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
256 /* caller interested in result ? */
257 if (output_pos
!= NULL
)
259 /* assuming little endian host order */
260 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)this->byte_pos
));
261 *output_pos
= ntohl(*(((u_int32_t
*)this->byte_pos
) + 1));
263 this->logger
->log_bytes(this->logger
, RAW
, " =>", (void*)output_pos
, 8);
273 static status_t
parse_bit(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, bool *output_pos
)
275 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
277 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s",
278 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
281 /* caller interested in result ? */
282 if (output_pos
!= NULL
)
285 mask
= 0x01 << (7 - this->bit_pos
);
286 *output_pos
= *this->byte_pos
& mask
;
290 /* set to a "clean", comparable true */
294 this->logger
->log(this->logger
, RAW
, " => %d", *output_pos
);
296 this->bit_pos
= (this->bit_pos
+ 1) % 8;
297 if (this->bit_pos
== 0)
306 static status_t
parse_list(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, linked_list_t
**output_pos
, payload_type_t payload_type
, size_t length
)
308 linked_list_t
* list
= *output_pos
;
312 this->logger
->log(this->logger
, ERROR
, " invalid length for rule %d %s",
313 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
));
319 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
320 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
326 u_int8_t
*pos_before
= this->byte_pos
;
329 status
= this->public.parse_payload((parser_t
*)this, payload_type
, &payload
);
330 if (status
!= SUCCESS
)
334 list
->insert_last(list
, payload
);
335 length
-= this->byte_pos
- pos_before
;
342 static status_t
parse_chunk(private_parser_t
*this, encoding_rule_t
*rule
, int rule_number
, chunk_t
*output_pos
, size_t length
)
344 if (this->byte_pos
+ length
> this->input_roof
)
346 this->logger
->log(this->logger
, ERROR
, " not enough input to parse rule %d %s, SPI_LENGTH: %d",
347 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), length
);
352 this->logger
->log(this->logger
, ERROR
, " found rule %d %s on bitpos %d",
353 rule_number
, mapping_find(encoding_type_t_mappings
, rule
->type
), this->bit_pos
);
356 if (output_pos
!= NULL
)
358 output_pos
->len
= length
;
359 output_pos
->ptr
= allocator_alloc(length
);
360 if (output_pos
->ptr
== NULL
)
364 memcpy(output_pos
->ptr
, this->byte_pos
, length
);
366 this->logger
->log_bytes(this->logger
, RAW
, " =>", output_pos
->ptr
, length
);
368 this->byte_pos
+= length
;
374 * implementation of parser_context_t.parse_payload
376 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
380 size_t rule_count
, payload_length
, spi_size
, attribute_length
;
381 bool attribute_format
;
383 encoding_rule_t
*rule
;
385 this->logger
->log(this->logger
, CONTROL
, "parsing %s payload", mapping_find(payload_type_t_mappings
, payload_type
));
387 /* ok, do the parsing */
388 pld
= payload_create(payload_type
);
391 this->logger
->log(this->logger
, ERROR
, " payload %s not supported", mapping_find(payload_type_t_mappings
, payload_type
));
392 return NOT_SUPPORTED
;
394 /* base pointer for output, avoids casting in every rule */
397 pld
->get_encoding_rules(pld
, &rule
, &rule_count
);
399 for (current
= 0; current
< rule_count
; current
++)
401 this->logger
->log(this->logger
, CONTROL_MORE
, " parsing rule %d %s",
402 current
, mapping_find(encoding_type_t_mappings
, rule
->type
));
407 if (this->parse_uint4(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
416 if (this->parse_uint8(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
425 if (this->parse_uint16(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
434 if (this->parse_uint32(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
443 if (this->parse_uint64(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
452 if (this->parse_bit(this, rule
, current
, NULL
) != SUCCESS
)
461 if (this->parse_uint8(this, rule
, current
, NULL
) != SUCCESS
)
470 if (this->parse_bit(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
479 if (this->parse_uint16(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
484 payload_length
= *(u_int16_t
*)(output
+ rule
->offset
);
489 if (this->parse_uint32(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
498 if (this->parse_uint8(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
503 spi_size
= *(u_int8_t
*)(output
+ rule
->offset
);
508 if (this->parse_chunk(this, rule
, current
, output
+ rule
->offset
, spi_size
) != SUCCESS
)
517 size_t proposals_length
= payload_length
- 4;
518 if (this->parse_list(this, rule
, current
, output
+ rule
->offset
, PROPOSAL_SUBSTRUCTURE
, proposals_length
) != SUCCESS
)
523 //TODO check if next_payloads are correct?
528 size_t transforms_length
= payload_length
- spi_size
- 8;
529 if (this->parse_list(this, rule
, current
, output
+ rule
->offset
, TRANSFORM_SUBSTRUCTURE
, transforms_length
) != SUCCESS
)
534 //TODO check if we have the desired transforms count
537 case TRANSFORM_ATTRIBUTES
:
539 size_t transform_a_length
= payload_length
- 8;
540 if (this->parse_list(this, rule
, current
, output
+ rule
->offset
, TRANSFORM_ATTRIBUTE
, transform_a_length
) != SUCCESS
)
547 case ATTRIBUTE_FORMAT
:
549 if (this->parse_bit(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
554 attribute_format
= *(bool*)(output
+ rule
->offset
);
559 if (this->parse_uint15(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
564 attribute_format
= *(bool*)(output
+ rule
->offset
);
567 case ATTRIBUTE_LENGTH_OR_VALUE
:
569 this->logger
->log_bytes(this->logger
, RAW
, "ATTRIBUTE_LENGTH_OR_VALUE", this->byte_pos
, 2);
571 if (this->parse_uint16(this, rule
, current
, output
+ rule
->offset
) != SUCCESS
)
576 attribute_length
= *(u_int16_t
*)(output
+ rule
->offset
);
577 this->logger
->log_bytes(this->logger
, RAW
, "ATTRIBUTE_LENGTH_OR_VALUE", output
+ rule
->offset
, 2);
581 case ATTRIBUTE_VALUE
:
583 if (attribute_format
== FALSE
)
585 if (this->parse_chunk(this, rule
, current
, output
+ rule
->offset
, attribute_length
) != SUCCESS
)
595 this->logger
->log(this->logger
, ERROR
, " no rule to parse rule %d %s (%d)", current
, mapping_find(encoding_type_t_mappings
, rule
->type
), rule
->type
);
600 /* process next rulue */
606 this->logger
->log(this->logger
, CONTROL
, "parsing %s successful", mapping_find(payload_type_t_mappings
, payload_type
));
611 * implementation of parser_t.destroy
613 static status_t
destroy(private_parser_t
*this)
615 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
616 allocator_free(this);
624 parser_t
*parser_create(chunk_t data
)
626 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
633 this->logger
= global_logger_manager
->create_logger(global_logger_manager
, PARSER
, NULL
);
634 this->logger
->enable_level(this->logger
, CONTROL
|CONTROL_MORE
|ERROR
|RAW
);
637 if (this->logger
== NULL
)
639 allocator_free(this);
643 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,payload_t
**)) parse_payload
;
644 this->public.destroy
= (status_t(*)(parser_t
*)) destroy
;
647 this->parse_uint4
= parse_uint4
;
648 this->parse_uint8
= parse_uint8
;
649 this->parse_uint15
= parse_uint15
;
650 this->parse_uint16
= parse_uint16
;
651 this->parse_uint32
= parse_uint32
;
652 this->parse_uint64
= parse_uint64
;
653 this->parse_bit
= parse_bit
;
654 this->parse_list
= parse_list
;
655 this->parse_chunk
= parse_chunk
;
658 this->input
= data
.ptr
;
659 this->byte_pos
= data
.ptr
;
661 this->input_roof
= data
.ptr
+ data
.len
;
663 return (parser_t
*)this;