- parser succesfully parses sa payload
[strongswan.git] / Source / charon / parser.c
1 /**
2 * @file parser.c
3 *
4 * @brief Generic parser class used to parse IKEv2-Header and Payload
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
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>.
16 *
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
20 * for more details.
21 */
22
23 #include <stdlib.h>
24 #include <arpa/inet.h>
25
26 #include "parser.h"
27
28 #include "types.h"
29 #include "definitions.h"
30 #include "globals.h"
31 #include "utils/allocator.h"
32 #include "utils/logger.h"
33 #include "utils/linked_list.h"
34 #include "payloads/payload.h"
35
36
37
38 /**
39 * @private data stored in a context
40 *
41 * contains pointers and counters to store current state
42 */
43 typedef struct private_parser_s private_parser_t;
44
45 struct private_parser_s {
46 /**
47 * Public members
48 */
49 parser_t public;
50
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);
60
61 /**
62 * Current bit for reading in input data
63 */
64 u_int8_t bit_pos;
65
66 /**
67 * Current byte for reading in input data
68 */
69 u_int8_t *byte_pos;
70
71 /**
72 * input data to parse
73 */
74 u_int8_t *input;
75
76 /**
77 * roof of input
78 */
79 u_int8_t *input_roof;
80
81
82 /**
83 * logger object
84 */
85 logger_t *logger;
86 };
87
88
89 static status_t parse_uint4(private_parser_t *this, encoding_rule_t *rule, int rule_number, u_int8_t *output_pos)
90 {
91 if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
92 {
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));
95 return PARSE_ERROR;
96 }
97 switch (this->bit_pos)
98 {
99 case 0:
100 /* caller interested in result ? */
101 if (output_pos != NULL)
102 {
103 *output_pos = *(this->byte_pos) >> 4;
104 }
105 this->bit_pos = 4;
106 break;
107 case 4:
108 /* caller interested in result ? */
109 if (output_pos != NULL)
110 {
111 *output_pos = *(this->byte_pos) & 0x0F;
112 }
113 this->bit_pos = 0;
114 this->byte_pos++;
115 break;
116 default:
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);
119 return PARSE_ERROR;
120 }
121
122 if (output_pos != NULL)
123 {
124 this->logger->log(this->logger, RAW, " => %d", *output_pos);
125 }
126
127
128 return SUCCESS;
129 }
130
131 static status_t parse_uint8(private_parser_t *this, encoding_rule_t *rule, int rule_number, u_int8_t *output_pos)
132 {
133 if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
134 {
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));
137 return PARSE_ERROR;
138 }
139 if (this->bit_pos)
140 {
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);
143 return PARSE_ERROR;
144 }
145
146 /* caller interested in result ? */
147 if (output_pos != NULL)
148 {
149 *output_pos = *(this->byte_pos);
150 this->logger->log(this->logger, RAW, " => %d", *output_pos);
151 }
152 this->byte_pos++;
153
154
155
156 return SUCCESS;
157 }
158
159 static status_t parse_uint15(private_parser_t *this, encoding_rule_t *rule, int rule_number, u_int16_t *output_pos)
160 {
161 if (this->byte_pos + sizeof(u_int16_t) > this->input_roof)
162 {
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));
165 return PARSE_ERROR;
166 }
167 if (this->bit_pos != 1)
168 {
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);
171 return PARSE_ERROR;
172 }
173 /* caller interested in result ? */
174 if (output_pos != NULL)
175 {
176 *output_pos = ntohs(*((u_int16_t*)this->byte_pos)) & 0xEFFF;
177 this->logger->log(this->logger, RAW, " => %d", *output_pos);
178 }
179 this->byte_pos += 2;
180 this->bit_pos = 0;
181
182
183
184 return SUCCESS;
185 }
186
187
188 static status_t parse_uint16(private_parser_t *this, encoding_rule_t *rule, int rule_number, u_int16_t *output_pos)
189 {
190 if (this->byte_pos + sizeof(u_int16_t) > this->input_roof)
191 {
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));
194 return PARSE_ERROR;
195 }
196 if (this->bit_pos)
197 {
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);
200 return PARSE_ERROR;
201 }
202 /* caller interested in result ? */
203 if (output_pos != NULL)
204 {
205 *output_pos = ntohs(*((u_int16_t*)this->byte_pos));
206
207 this->logger->log(this->logger, RAW, " => %d", *output_pos);
208 }
209 this->byte_pos += 2;
210
211
212 return SUCCESS;
213 }
214
215 static status_t parse_uint32(private_parser_t *this, encoding_rule_t *rule, int rule_number, u_int32_t *output_pos)
216 {
217 if (this->byte_pos + sizeof(u_int32_t) > this->input_roof)
218 {
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));
221 return PARSE_ERROR;
222 }
223 if (this->bit_pos)
224 {
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);
227 return PARSE_ERROR;
228 }
229 /* caller interested in result ? */
230 if (output_pos != NULL)
231 {
232 *output_pos = ntohl(*((u_int32_t*)this->byte_pos));
233
234 this->logger->log(this->logger, RAW, " => %d", *output_pos);
235 }
236 this->byte_pos += 4;
237
238
239 return SUCCESS;
240 }
241
242 static status_t parse_uint64(private_parser_t *this, encoding_rule_t *rule, int rule_number, u_int32_t *output_pos)
243 {
244 if (this->byte_pos + 2 * sizeof(u_int32_t) > this->input_roof)
245 {
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));
248 return PARSE_ERROR;
249 }
250 if (this->bit_pos)
251 {
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);
254 return PARSE_ERROR;
255 }
256 /* caller interested in result ? */
257 if (output_pos != NULL)
258 {
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));
262
263 this->logger->log_bytes(this->logger, RAW, " =>", (void*)output_pos, 8);
264 }
265 this->byte_pos += 8;
266
267
268
269 return SUCCESS;
270 }
271
272
273 static status_t parse_bit(private_parser_t *this, encoding_rule_t *rule, int rule_number, bool *output_pos)
274 {
275 if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
276 {
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));
279 return PARSE_ERROR;
280 }
281 /* caller interested in result ? */
282 if (output_pos != NULL)
283 {
284 u_int8_t mask;
285 mask = 0x01 << (7 - this->bit_pos);
286 *output_pos = *this->byte_pos & mask;
287
288 if (*output_pos)
289 {
290 /* set to a "clean", comparable true */
291 *output_pos = TRUE;
292 }
293
294 this->logger->log(this->logger, RAW, " => %d", *output_pos);
295 }
296 this->bit_pos = (this->bit_pos + 1) % 8;
297 if (this->bit_pos == 0)
298 {
299 this->byte_pos++;
300 }
301
302
303 return SUCCESS;
304 }
305
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)
307 {
308 linked_list_t * list = *output_pos;
309
310 if (length < 0)
311 {
312 this->logger->log(this->logger, ERROR, " invalid length for rule %d %s",
313 rule_number, mapping_find(encoding_type_t_mappings, rule->type));
314 return PARSE_ERROR;
315 }
316
317 if (this->bit_pos)
318 {
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);
321 return PARSE_ERROR;
322 }
323
324 while (length > 0)
325 {
326 u_int8_t *pos_before = this->byte_pos;
327 payload_t *payload;
328 status_t status;
329 status = this->public.parse_payload((parser_t*)this, payload_type, &payload);
330 if (status != SUCCESS)
331 {
332 return status;
333 }
334 list->insert_last(list, payload);
335 length -= this->byte_pos - pos_before;
336 }
337 *output_pos = list;
338 return SUCCESS;
339 }
340
341
342 static status_t parse_chunk(private_parser_t *this, encoding_rule_t *rule, int rule_number, chunk_t *output_pos, size_t length)
343 {
344 if (this->byte_pos + length > this->input_roof)
345 {
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);
348 return PARSE_ERROR;
349 }
350 if (this->bit_pos)
351 {
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);
354 return PARSE_ERROR;
355 }
356 if (output_pos != NULL)
357 {
358 output_pos->len = length;
359 output_pos->ptr = allocator_alloc(length);
360 if (output_pos->ptr == NULL)
361 {
362 return OUT_OF_RES;
363 }
364 memcpy(output_pos->ptr, this->byte_pos, length);
365
366 this->logger->log_bytes(this->logger, RAW, " =>", output_pos->ptr, length);
367 }
368 this->byte_pos += length;
369
370 return SUCCESS;
371 }
372
373 /**
374 * implementation of parser_context_t.parse_payload
375 */
376 static status_t parse_payload(private_parser_t *this, payload_type_t payload_type, payload_t **payload)
377 {
378 payload_t *pld;
379 void *output;
380 size_t rule_count, payload_length, spi_size, attribute_length;
381 bool attribute_format;
382 int current;
383 encoding_rule_t *rule;
384
385 this->logger->log(this->logger, CONTROL, "parsing %s payload", mapping_find(payload_type_t_mappings, payload_type));
386
387 /* ok, do the parsing */
388 pld = payload_create(payload_type);
389 if (pld == NULL)
390 {
391 this->logger->log(this->logger, ERROR, " payload %s not supported", mapping_find(payload_type_t_mappings, payload_type));
392 return NOT_SUPPORTED;
393 }
394 /* base pointer for output, avoids casting in every rule */
395 output = pld;
396
397 pld->get_encoding_rules(pld, &rule, &rule_count);
398
399 for (current = 0; current < rule_count; current++)
400 {
401 this->logger->log(this->logger, CONTROL_MORE, " parsing rule %d %s",
402 current, mapping_find(encoding_type_t_mappings, rule->type));
403 switch (rule->type)
404 {
405 case U_INT_4:
406 {
407 if (this->parse_uint4(this, rule, current, output + rule->offset) != SUCCESS)
408 {
409 pld->destroy(pld);
410 return PARSE_ERROR;
411 }
412 break;
413 }
414 case U_INT_8:
415 {
416 if (this->parse_uint8(this, rule, current, output + rule->offset) != SUCCESS)
417 {
418 pld->destroy(pld);
419 return PARSE_ERROR;
420 }
421 break;
422 }
423 case U_INT_16:
424 {
425 if (this->parse_uint16(this, rule, current, output + rule->offset) != SUCCESS)
426 {
427 pld->destroy(pld);
428 return PARSE_ERROR;
429 }
430 break;
431 }
432 case U_INT_32:
433 {
434 if (this->parse_uint32(this, rule, current, output + rule->offset) != SUCCESS)
435 {
436 pld->destroy(pld);
437 return PARSE_ERROR;
438 }
439 break;
440 }
441 case U_INT_64:
442 {
443 if (this->parse_uint64(this, rule, current, output + rule->offset) != SUCCESS)
444 {
445 pld->destroy(pld);
446 return PARSE_ERROR;
447 }
448 break;
449 }
450 case RESERVED_BIT:
451 {
452 if (this->parse_bit(this, rule, current, NULL) != SUCCESS)
453 {
454 pld->destroy(pld);
455 return PARSE_ERROR;
456 }
457 break;
458 }
459 case RESERVED_BYTE:
460 {
461 if (this->parse_uint8(this, rule, current, NULL) != SUCCESS)
462 {
463 pld->destroy(pld);
464 return PARSE_ERROR;
465 }
466 break;
467 }
468 case FLAG:
469 {
470 if (this->parse_bit(this, rule, current, output + rule->offset) != SUCCESS)
471 {
472 pld->destroy(pld);
473 return PARSE_ERROR;
474 }
475 break;
476 }
477 case PAYLOAD_LENGTH:
478 {
479 if (this->parse_uint16(this, rule, current, output + rule->offset) != SUCCESS)
480 {
481 pld->destroy(pld);
482 return PARSE_ERROR;
483 }
484 payload_length = *(u_int16_t*)(output + rule->offset);
485 break;
486 }
487 case HEADER_LENGTH:
488 {
489 if (this->parse_uint32(this, rule, current, output + rule->offset) != SUCCESS)
490 {
491 pld->destroy(pld);
492 return PARSE_ERROR;
493 }
494 break;
495 }
496 case SPI_SIZE:
497 {
498 if (this->parse_uint8(this, rule, current, output + rule->offset) != SUCCESS)
499 {
500 pld->destroy(pld);
501 return PARSE_ERROR;
502 }
503 spi_size = *(u_int8_t*)(output + rule->offset);
504 break;
505 }
506 case SPI:
507 {
508 if (this->parse_chunk(this, rule, current, output + rule->offset, spi_size) != SUCCESS)
509 {
510 pld->destroy(pld);
511 return PARSE_ERROR;
512 }
513 break;
514 }
515 case PROPOSALS:
516 {
517 size_t proposals_length = payload_length - 4;
518 if (this->parse_list(this, rule, current, output + rule->offset, PROPOSAL_SUBSTRUCTURE, proposals_length) != SUCCESS)
519 {
520 pld->destroy(pld);
521 return PARSE_ERROR;
522 }
523 //TODO check if next_payloads are correct?
524 break;
525 }
526 case TRANSFORMS:
527 {
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)
530 {
531 pld->destroy(pld);
532 return PARSE_ERROR;
533 }
534 //TODO check if we have the desired transforms count
535 break;
536 }
537 case TRANSFORM_ATTRIBUTES:
538 {
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)
541 {
542 pld->destroy(pld);
543 return PARSE_ERROR;
544 }
545 break;
546 }
547 case ATTRIBUTE_FORMAT:
548 {
549 if (this->parse_bit(this, rule, current, output + rule->offset) != SUCCESS)
550 {
551 pld->destroy(pld);
552 return PARSE_ERROR;
553 }
554 attribute_format = *(bool*)(output + rule->offset);
555 break;
556 }
557 case ATTRIBUTE_TYPE:
558 {
559 if (this->parse_uint15(this, rule, current, output + rule->offset) != SUCCESS)
560 {
561 pld->destroy(pld);
562 return PARSE_ERROR;
563 }
564 attribute_format = *(bool*)(output + rule->offset);
565 break;
566 }
567 case ATTRIBUTE_LENGTH_OR_VALUE:
568 {
569 this->logger->log_bytes(this->logger, RAW, "ATTRIBUTE_LENGTH_OR_VALUE", this->byte_pos, 2);
570
571 if (this->parse_uint16(this, rule, current, output + rule->offset) != SUCCESS)
572 {
573 pld->destroy(pld);
574 return PARSE_ERROR;
575 }
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);
578
579 break;
580 }
581 case ATTRIBUTE_VALUE:
582 {
583 if (attribute_format == FALSE)
584 {
585 if (this->parse_chunk(this, rule, current, output + rule->offset, attribute_length) != SUCCESS)
586 {
587 pld->destroy(pld);
588 return PARSE_ERROR;
589 }
590 }
591 break;
592 }
593 default:
594 {
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);
596 pld->destroy(pld);
597 return PARSE_ERROR;
598 }
599 }
600 /* process next rulue */
601 rule++;
602 }
603
604 *payload = pld;
605
606 this->logger->log(this->logger, CONTROL, "parsing %s successful", mapping_find(payload_type_t_mappings, payload_type));
607 return SUCCESS;
608 }
609
610 /**
611 * implementation of parser_t.destroy
612 */
613 static status_t destroy(private_parser_t *this)
614 {
615 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
616 allocator_free(this);
617
618 return SUCCESS;
619 }
620
621 /*
622 * see header file
623 */
624 parser_t *parser_create(chunk_t data)
625 {
626 private_parser_t *this = allocator_alloc_thing(private_parser_t);
627
628 if (this == NULL)
629 {
630 return NULL;
631 }
632
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);
635
636
637 if (this->logger == NULL)
638 {
639 allocator_free(this);
640 return NULL;
641 }
642
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;
645
646
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;
656
657
658 this->input = data.ptr;
659 this->byte_pos = data.ptr;
660 this->bit_pos = 0;
661 this->input_roof = data.ptr + data.len;
662
663 return (parser_t*)this;
664 }
665