8737157db313dadd8fa3b7ec90feda0208218a20
[strongswan.git] / Source / charon / generator.c
1 /**
2 * @file generator.c
3 *
4 * @brief Generic generator class used to generate IKEv2-header and payloads.
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 <string.h>
25 #include <arpa/inet.h>
26 #include <stdio.h>
27
28
29 #include "generator.h"
30
31 #include "types.h"
32 #include "utils/allocator.h"
33 #include "utils/linked_list.h"
34 #include "utils/logger_manager.h"
35 #include "payloads/payload.h"
36 #include "payloads/transform_substructure.h"
37
38
39 extern logger_manager_t *global_logger_manager;
40
41 /**
42 * Private part of a generator_t object
43 */
44 typedef struct private_generator_s private_generator_t;
45
46 struct private_generator_s {
47 /**
48 * Public part of a generator_t object
49 */
50 generator_t public;
51
52 /* private functions and fields */
53
54
55 /**
56 * Generates a U_INT-Field type
57 *
58 * @param this private_generator_t object
59 * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.)
60 * @param offset offset of value in data struct
61 * @param generator_contexts generator_contexts_t object where the context is written or read from
62 * @return - SUCCESS if succeeded
63 * - OUT_OF_RES if out of ressources
64 */
65 status_t (*generate_u_int_type) (private_generator_t *this,encoding_type_t int_type,u_int32_t offset);
66
67 /**
68 * Generates a RESERVED BIT field or a RESERVED BYTE field
69 *
70 * @param this private_generator_t object
71 * @param generator_contexts generator_contexts_t object where the context is written or read from
72 * @param bits number of bits to generate
73 * @return - SUCCESS if succeeded
74 * - OUT_OF_RES if out of ressources
75 * - FAILED if bit count not supported
76 */
77 status_t (*generate_reserved_field) (private_generator_t *this,int bits);
78
79 /**
80 * Generates a FLAG field
81 *
82 * @param this private_generator_t object
83 * @param generator_contexts generator_contexts_t object where the context is written or read from
84 * @param offset offset of flag value in data struct
85 * @return - SUCCESS if succeeded
86 * - OUT_OF_RES if out of ressources
87 */
88 status_t (*generate_flag) (private_generator_t *this,u_int32_t offset);
89
90 /**
91 * Writes the current buffer content into a chunk_t
92 *
93 * Memory of specific chunk_t gets allocated.
94 *
95 * @param this calling private_generator_t object
96 * @param data pointer of chunk_t to write to
97 * @return
98 * - SUCCESSFUL if succeeded
99 * - OUT_OF_RES otherwise
100 */
101 status_t (*write_chunk) (private_generator_t *this,chunk_t *data);
102
103 /**
104 * Generates a bytestream from a chunk_t
105 *
106 * @param this private_generator_t object
107 * @param offset offset of chunk_t value in data struct
108 * @return - SUCCESS if succeeded
109 * - OUT_OF_RES if out of ressources
110 */
111 status_t (*generate_from_chunk) (private_generator_t *this,u_int32_t offset);
112
113 /**
114 * Makes sure enough space is available in buffer to store amount of bits.
115 *
116 * If buffer is to small to hold the specific amount of bits it
117 * is increased using reallocation function of allocator.
118 *
119 * @param this calling private_generator_t object
120 * @param bits number of bits to make available in buffer
121 * @return
122 * - SUCCESSFUL if succeeded
123 * - OUT_OF_RES otherwise
124 */
125 status_t (*make_space_available) (private_generator_t *this,size_t bits);
126
127 /**
128 * Writes a specific amount of byte into the buffer.
129 *
130 * If buffer is to small to hold the specific amount of bytes it
131 * is increased.
132 *
133 * @param this calling private_generator_t object
134 * @param bytes pointer to bytes to write
135 * @param number_of_bytes number of bytes to write into buffer
136 * @return
137 * - SUCCESSFUL if succeeded
138 * - OUT_OF_RES otherwise
139 */
140 status_t (*write_bytes_to_buffer) (private_generator_t *this,void * bytes,size_t number_of_bytes);
141
142
143 /**
144 * Writes a specific amount of byte into the buffer at a specific offset.
145 *
146 * @warning buffer size is not check to hold the data if offset is to large.
147 *
148 * @param this calling private_generator_t object
149 * @param bytes pointer to bytes to write
150 * @param number_of_bytes number of bytes to write into buffer
151 * @param offset offset to write the data into
152 * @return
153 * - SUCCESSFUL if succeeded
154 * - OUT_OF_RES otherwise
155 */
156 status_t (*write_bytes_to_buffer_at_offset) (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset);
157
158 /**
159 * Buffer used to generate the data into.
160 */
161 u_int8_t *buffer;
162
163 /**
164 * Current write position in buffer (one byte aligned).
165 */
166 u_int8_t *out_position;
167
168 /**
169 * Position of last byte in buffer.
170 */
171 u_int8_t *roof_position;
172
173 /**
174 * Current bit writing to in current byte (between 0 and 7).
175 */
176 size_t current_bit;
177
178 /**
179 * Associated data struct to read informations from.
180 */
181 void * data_struct;
182
183 /*
184 * Last payload length position offset in the buffer
185 */
186 u_int32_t last_payload_length_position_offset;
187
188 /*
189 * Attribute format of the last generated transform attribute
190 *
191 * Used to check if a variable value field is used or not for
192 * the transform attribute value.
193 */
194 bool attribute_format;
195
196 /*
197 * Depending on the value of attribute_format this field is used
198 * to hold the length of the transform attribute in bytes
199 */
200
201 u_int16_t attribute_length;
202
203 /**
204 * Associated Logger
205 */
206 logger_t *logger;
207 };
208
209 /**
210 * Implements private_generator_t's generate_u_int_type function.
211 * See #private_generator_s.generate_u_int_type.
212 */
213 static status_t generate_u_int_type (private_generator_t *this,encoding_type_t int_type,u_int32_t offset)
214 {
215 size_t number_of_bits = 0;
216 status_t status;
217
218
219 switch (int_type)
220 {
221 case U_INT_4:
222 number_of_bits = 4;
223 break;
224 case U_INT_8:
225 number_of_bits = 8;
226 break;
227 case U_INT_16:
228 number_of_bits = 16;
229 break;
230 case U_INT_32:
231 number_of_bits = 32;
232 break;
233 case U_INT_64:
234 number_of_bits = 64;
235 break;
236 case ATTRIBUTE_TYPE:
237 number_of_bits = 15;
238 break;
239 default:
240 return FAILED;
241 }
242 if (((number_of_bits % 8) == 0) && (this->current_bit != 0))
243 {
244 /* current bit has to be zero for values multiple of 8 bits */
245 return FAILED;
246 }
247
248 status = this->make_space_available(this,number_of_bits);
249
250 if (status != SUCCESS)
251 {
252 return status;
253 }
254
255 switch (int_type)
256 {
257 case U_INT_4:
258 {
259 if (this->current_bit == 0)
260 {
261 u_int8_t high_val = *((u_int8_t *)(this->data_struct + offset)) << 4;
262 u_int8_t low_val = *(this->out_position) & 0x0F;
263
264 *(this->out_position) = high_val | low_val;
265 /* write position is not changed, just bit position is moved */
266 this->current_bit = 4;
267 }
268 else if (this->current_bit == 4)
269 {
270 u_int high_val = *(this->out_position) & 0xF0;
271 u_int low_val = *((u_int8_t *)(this->data_struct + offset)) & 0x0F;
272 *(this->out_position) = high_val | low_val;
273 this->out_position++;
274 this->current_bit = 0;
275
276 }
277 else
278 {
279 /* 4 Bit integers must have a 4 bit alignment */
280 return FAILED;
281 };
282 break;
283 }
284
285 case U_INT_8:
286 {
287 *this->out_position = *((u_int8_t *)(this->data_struct + offset));
288 this->out_position++;
289 break;
290
291 }
292 case ATTRIBUTE_TYPE:
293 {
294 if (this->current_bit != 1)
295 {
296 return FAILED;
297 }
298 u_int8_t attribute_format_flag = *(this->out_position) & 0x80;
299
300 u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
301
302 int16_val = int16_val & 0xFF7F;
303
304 int16_val = int16_val | attribute_format_flag;
305
306 this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
307 this->current_bit = 0;
308 break;
309
310 }
311
312 case U_INT_16:
313 {
314 u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset)));
315 this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t));
316
317 break;
318 }
319 case U_INT_32:
320 {
321 u_int32_t int32_val = htonl(*((u_int32_t*)(this->data_struct + offset)));
322 this->write_bytes_to_buffer(this,&int32_val,sizeof(u_int32_t));
323 break;
324 }
325 case U_INT_64:
326 {
327 u_int32_t int32_val_low = htonl(*((u_int32_t*)(this->data_struct + offset)));
328 u_int32_t int32_val_high = htonl(*((u_int32_t*)(this->data_struct + offset) + 1));
329 this->write_bytes_to_buffer(this,&int32_val_high,sizeof(u_int32_t));
330 this->write_bytes_to_buffer(this,&int32_val_low,sizeof(u_int32_t));
331 break;
332 }
333
334 default:
335 return FAILED;
336
337 }
338
339 return SUCCESS;
340 }
341
342 /**
343 * Implements private_generator_t's generate_reserved_field function.
344 * See #private_generator_s.generate_reserved_field.
345 */
346 static status_t generate_reserved_field (private_generator_t *this,int bits)
347 {
348 status_t status;
349
350 if ((bits != 1) && (bits != 8))
351 {
352 return FAILED;
353 }
354 status = this->make_space_available(this,bits);
355 if (status != SUCCESS)
356 {
357 return status;
358 }
359
360 if (bits == 1)
361 {
362 u_int8_t reserved_bit = ~(1 << (7 - this->current_bit));
363
364 *(this->out_position) = *(this->out_position) & reserved_bit;
365 this->current_bit++;
366 if (this->current_bit >= 8)
367 {
368 this->current_bit = this->current_bit % 8;
369 this->out_position++;
370 }
371 }
372 else
373 {
374 /* one byte */
375 if (this->current_bit > 0)
376 {
377 return FAILED;
378 }
379 *(this->out_position) = 0x00;
380 this->out_position++;
381 }
382
383 return SUCCESS;
384
385
386 }
387
388 /**
389 * Implements private_generator_t's generate_flag function.
390 * See #private_generator_s.generate_flag.
391 */
392 static status_t generate_flag (private_generator_t *this,u_int32_t offset)
393 {
394 status_t status;
395 u_int8_t flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0;
396 u_int8_t flag = (flag_value << (7 - this->current_bit));
397
398 status = this->make_space_available(this,1);
399 if (status != SUCCESS)
400 {
401 return status;
402 }
403
404 *(this->out_position) = *(this->out_position) | flag;
405
406 this->current_bit++;
407 if (this->current_bit >= 8)
408 {
409 this->current_bit = this->current_bit % 8;
410 this->out_position++;
411 }
412 return SUCCESS;
413 }
414
415 /**
416 * Implements private_generator_t's generate_from_chunk function.
417 * See #private_generator_s.generate_from_chunk.
418 */
419 static status_t generate_from_chunk (private_generator_t *this,u_int32_t offset)
420 {
421 if (this->current_bit != 0)
422 {
423 return FAILED;
424 }
425 chunk_t *attribute_value = (chunk_t *)(this->data_struct + offset);
426
427 return this->write_bytes_to_buffer (this,attribute_value->ptr,attribute_value->len);
428
429 }
430
431 /**
432 * Implements private_generator_t's generator_context_make_space_available function.
433 * See #private_generator_s.generator_context_make_space_available.
434 */
435 static status_t make_space_available (private_generator_t *this, size_t bits)
436 {
437 while ((((this->roof_position - this->out_position) * 8) - this->current_bit) < bits)
438 {
439 size_t old_buffer_size = ((this->roof_position) - ( this->buffer));
440 size_t new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
441 size_t out_position_offset = ((this->out_position) - (this->buffer));
442 u_int8_t *new_buffer;
443
444 new_buffer = allocator_realloc(this->buffer,new_buffer_size);
445 if (new_buffer == NULL)
446 {
447 return OUT_OF_RES;
448 }
449
450 this->buffer = new_buffer;
451
452 this->out_position = (this->buffer + out_position_offset);
453 this->roof_position = (this->buffer + new_buffer_size);
454
455 }
456
457 return SUCCESS;
458 }
459
460 /**
461 * Implements private_generator_t's write_bytes_to_buffer function.
462 * See #private_generator_s.write_bytes_to_buffer.
463 */
464 static status_t write_bytes_to_buffer (private_generator_t *this,void * bytes,size_t number_of_bytes)
465 {
466 u_int8_t *read_position = (u_int8_t *) bytes;
467 int i;
468 status_t status;
469
470 status = this->make_space_available(this,number_of_bytes * 8);
471
472 if (status != SUCCESS)
473 {
474 return status;
475 }
476
477 for (i = 0; i < number_of_bytes; i++)
478 {
479 *(this->out_position) = *(read_position);
480 read_position++;
481 this->out_position++;
482 }
483 return status;
484 }
485
486 /**
487 * Implements private_generator_t's write_bytes_to_buffer_at_offset function.
488 * See #private_generator_s.write_bytes_to_buffer_at_offset.
489 * TODO automatic buffer increasing!
490 */
491 static status_t write_bytes_to_buffer_at_offset (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset)
492 {
493 u_int8_t *read_position = (u_int8_t *) bytes;
494 int i;
495 u_int8_t *write_position = this->buffer + offset;
496
497 for (i = 0; i < number_of_bytes; i++)
498 {
499 *(write_position) = *(read_position);
500 read_position++;
501 write_position++;
502 }
503 return SUCCESS;
504 }
505
506 /**
507 * Implements generator_t's write_chunk function.
508 * See #generator_s.write_chunk.
509 */
510 static status_t write_to_chunk (private_generator_t *this,chunk_t *data)
511 {
512 size_t data_length = this->out_position - this->buffer;
513
514 if (this->current_bit > 0)
515 data_length++;
516 data->ptr = allocator_alloc(data_length);
517 if (data->ptr == NULL)
518 {
519 data->len = 0;
520 return OUT_OF_RES;
521 }
522 memcpy(data->ptr,this->buffer,data_length);
523 data->len = data_length;
524 return SUCCESS;
525 }
526
527
528
529 /**
530 * Implements generator_t's generate_payload function.
531 * See #generator_s.generate_payload.
532 */
533 static status_t generate_payload (private_generator_t *this,payload_t *payload)
534 {
535 int i;
536 status_t status;
537 this->data_struct = payload;
538 size_t rule_count;
539 encoding_rule_t *rules;
540
541
542 payload_type_t payload_type = payload->get_type(payload);
543
544 this->logger->log(this->logger,CONTROL,"Start generating payload of type %s",mapping_find(payload_type_t_mappings,payload_type));
545
546 payload->get_encoding_rules(payload,&rules,&rule_count);
547
548 for (i = 0; i < rule_count;i++)
549 {
550 status = SUCCESS;
551 switch (rules[i].type)
552 {
553 /* all u int values are generated in generate_u_int_type */
554 case U_INT_4:
555 case U_INT_8:
556 case U_INT_16:
557 case U_INT_32:
558 case U_INT_64:
559 status = this->generate_u_int_type(this,rules[i].type,rules[i].offset);
560 break;
561 case RESERVED_BIT:
562 {
563 status = this->generate_reserved_field(this,1);
564
565 break;
566 }
567 case RESERVED_BYTE:
568 {
569 status = this->generate_reserved_field(this,8);
570 break;
571 }
572 case FLAG:
573 {
574 status = this->generate_flag(this,rules[i].offset);
575 break;
576 }
577 case PAYLOAD_LENGTH:
578 /* payload length is generated like an U_INT_16 */
579 this->last_payload_length_position_offset = (this->out_position - this->buffer);
580 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
581 break;
582
583 case HEADER_LENGTH:
584 /* header length is generated like an U_INT_32 */
585 status = this->generate_u_int_type(this,U_INT_32,rules[i].offset);
586 break;
587 case SPI_SIZE:
588 /* currently not implemented */
589 break;
590 case TRANSFORM_ATTRIBUTES:
591 {
592 this->logger->log(this->logger,CONTROL_MORE,"Generate Transform attributes");
593 /* before iterative generate the transforms, store the current length position */
594 u_int32_t transform_length_position_offset = this->last_payload_length_position_offset;
595
596 u_int16_t length_of_transform = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
597 u_int16_t int16_val;
598 linked_list_t *transform_attributes =*((linked_list_t **)(this->data_struct + rules[i].offset));
599
600 linked_list_iterator_t *iterator;
601 /* create forward iterator */
602 status = transform_attributes->create_iterator(transform_attributes,&iterator,TRUE);
603 if (status != SUCCESS)
604 {
605 return status;
606 }
607 while (iterator->has_next(iterator))
608 {
609 payload_t *current_attribute;
610 u_int32_t before_generate_position_offset;
611 u_int32_t after_generate_position_offset;
612 status = iterator->current(iterator,(void **)&current_attribute);
613 if (status != SUCCESS)
614 {
615 iterator->destroy(iterator);
616 return status;
617 }
618
619 before_generate_position_offset = (this->out_position - this->buffer);
620 this->public.generate_payload(&(this->public),current_attribute);
621 after_generate_position_offset = (this->out_position - this->buffer);
622
623 /* increase size of transform */
624 length_of_transform += (after_generate_position_offset - before_generate_position_offset);
625 }
626
627 iterator->destroy(iterator);
628
629 this->logger->log(this->logger,CONTROL_MORE,"Length of Transform is %d, offset is %d",length_of_transform,transform_length_position_offset);
630
631 int16_val = htons(length_of_transform);
632 this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),transform_length_position_offset);
633
634 break;
635 }
636 case ATTRIBUTE_FORMAT:
637 {
638 this->logger->log(this->logger,CONTROL_MORE,"Generate Attribute Format flag");
639 /* Attribute format is a flag which is stored in context*/
640
641 status = this->generate_flag(this,rules[i].offset);
642 this->attribute_format = *((bool *) (this->data_struct + rules[i].offset));
643 break;
644 }
645 case ATTRIBUTE_TYPE:
646 {
647 this->logger->log(this->logger,CONTROL_MORE,"Generate Attribute Type field");
648 // the attribute type is a 15 bit integer so it has to be generated special
649 status = this->generate_u_int_type(this,ATTRIBUTE_TYPE,rules[i].offset);
650 break;
651 }
652 case ATTRIBUTE_LENGTH_OR_VALUE:
653 {
654 this->logger->log(this->logger,CONTROL_MORE,"Generate Attribute Length or Value field");
655 if (this->attribute_format == FALSE)
656 {
657 status = this->generate_u_int_type(this,U_INT_16,rules[i].offset);
658 /* this field hold the length of the attribute */
659 this->attribute_length = *((u_int16_t *)(this->data_struct + rules[i].offset));
660 }
661 else
662 {
663 status = this->write_bytes_to_buffer(this,(this->data_struct + rules[i].offset),2);
664 }
665 break;
666 }
667 case ATTRIBUTE_VALUE:
668 {
669 if (this->attribute_format == FALSE)
670 {
671 this->logger->log(this->logger,CONTROL_MORE,"Attribute value has not fixed size");
672 /* the attribute value is generated */
673 status = this->generate_from_chunk(this,rules[i].offset);
674 }
675 break;
676 }
677 default:
678 return NOT_SUPPORTED;
679 }
680 }
681
682 return status;
683 }
684
685 /**
686 * Implements generator_t's destroy function.
687 * See #generator_s.destroy.
688 */
689 static status_t destroy(private_generator_t *this)
690 {
691 allocator_free(this->buffer);
692 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
693 allocator_free(this);
694 return SUCCESS;
695 }
696
697 /*
698 * Described in header
699 */
700 generator_t * generator_create()
701 {
702 private_generator_t *this;
703
704 this = allocator_alloc_thing(private_generator_t);
705 if (this == NULL)
706 {
707 return NULL;
708 }
709
710 /* initiate public functions */
711 this->public.generate_payload = (status_t(*)(generator_t*, payload_t *)) generate_payload;
712 this->public.destroy = (status_t(*)(generator_t*)) destroy;
713 this->public.write_to_chunk = (status_t (*) (generator_t *,chunk_t *)) write_to_chunk;
714
715
716 /* initiate private functions */
717 // this->generate = generate;
718 this->generate_u_int_type = generate_u_int_type;
719 this->generate_reserved_field = generate_reserved_field;
720 this->generate_flag = generate_flag;
721 this->generate_from_chunk = generate_from_chunk;
722 this->make_space_available = make_space_available;
723 this->write_bytes_to_buffer = write_bytes_to_buffer;
724 this->write_bytes_to_buffer_at_offset = write_bytes_to_buffer_at_offset;
725
726
727 /* allocate memory for buffer */
728 this->buffer = allocator_alloc(GENERATOR_DATA_BUFFER_SIZE);
729 if (this->buffer == NULL)
730 {
731 allocator_free(this);
732 return NULL;
733 }
734
735 /* initiate private variables */
736 this->out_position = this->buffer;
737 this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE;
738 this->data_struct = NULL;
739 this->current_bit = 0;
740 this->last_payload_length_position_offset = 0;
741 this->logger = global_logger_manager->create_logger(global_logger_manager,GENERATOR,NULL);
742 return &(this->public);
743 }