- parser successfully parses an ike_header
authorMartin Willi <martin@strongswan.org>
Thu, 10 Nov 2005 19:19:56 +0000 (19:19 -0000)
committerMartin Willi <martin@strongswan.org>
Thu, 10 Nov 2005 19:19:56 +0000 (19:19 -0000)
- no doxygen yet

Source/charon/parser.c
Source/charon/parser.h

index 0f4af57..0e01259 100644 (file)
  */
 
 #include <stdlib.h>
+#include <arpa/inet.h>
 
 #include "allocator.h"
 #include "types.h"
 #include "parser.h"
+#include "logger.h"
+
+
+typedef struct private_parser_context_s private_parser_context_t;
+
+struct private_parser_context_s {
+       /**
+        * Public members
+        */
+       parser_context_t public;
+
+       /**
+        * Current bit for reading in input data
+        */
+       u_int8_t bit_pos;
+       
+       /**
+        * Current byte for reading in input data
+        */
+       u_int8_t *byte_pos;
+       
+       /**
+        * input data to parse
+        */
+       u_int8_t *input;
+       
+       /**
+        * roof of input
+        */
+       u_int8_t *input_roof;
+       
+       
+};
+
+static status_t parser_context_destroy(private_parser_context_t *this)
+{
+       allocator_free(this);
+       
+       return SUCCESS; 
+}
+
+static private_parser_context_t *parser_context_create(chunk_t input)
+{
+       private_parser_context_t *this = allocator_alloc_thing(private_parser_context_t);
+       if (this == NULL)
+       {
+               return NULL;    
+       }
+       
+       this->public.destroy = (status_t(*)(parser_context_t*)) parser_context_destroy;
+       
+       this->input = input.ptr;
+       this->byte_pos = input.ptr;
+       this->bit_pos = 0;
+       this->input_roof = input.ptr + input.len;
+       
+       return this;
+}
+
+
 
 /**
  * Private data of a parser_t object
@@ -37,8 +98,308 @@ struct private_parser_s {
         */
         parser_t public;
 
-       /* private functions and fields */
+       /**
+        * list of payloads and their description
+        */
+       payload_info_t **payload_infos;
+       
+       /**
+        * logger object
+        */
+       logger_t *logger;
 
        
 };
 
+static private_parser_context_t *create_context(private_parser_t *this, chunk_t data)
+{
+       private_parser_context_t *context = parser_context_create(data);
+       
+       return context;
+}
+
+static status_t parse_payload(private_parser_t *this, private_parser_context_t *context, payload_type_t payload_type, void **data_struct)
+{
+       payload_info_t *payload_info = NULL;
+       
+       /* find payload in null terminated list*/
+       payload_info = *(this->payload_infos);
+       while (payload_info)
+       {
+               if (payload_info->payload_type == payload_type)
+               {
+                       void *output;
+                       int current;
+                       
+                       /* ok, do the parsing */
+                       output = allocator_alloc(payload_info->data_struct_length);
+                       
+                       for (current = 0; current < payload_info->encoding_rules_count; current++)
+                       {
+                               encoding_rule_t *rule = &(payload_info->ecoding_rules[current]);
+                               switch (rule->type)
+                               {
+                                       case U_INT_4:
+                                       {
+                                               u_int8_t *output_pos = output + rule->offset;
+                                               if (context->byte_pos + sizeof(u_int8_t) > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_4");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               switch (context->bit_pos)
+                                               {
+                                                       case 0:
+                                                               *output_pos = *(context->byte_pos) >> 4;
+                                                               context->bit_pos = 4;
+                                                               break;
+                                                       case 4: 
+                                                               *output_pos = *(context->byte_pos) & 0x0F;
+                                                               context->bit_pos = 0;
+                                                               context->byte_pos++;
+                                                               break;
+                                                       default:
+                                                               this->logger->log(this->logger, ERROR, "found rule U_INT_4 on bitpos %d", context->bit_pos);
+                                                               allocator_free(output);
+                                                               return PARSE_ERROR;
+                                               }
+                                               break;
+                                       }
+                                       case U_INT_8:
+                                       {
+                                               u_int8_t *output_pos = output + rule->offset;
+                                               if (context->byte_pos + sizeof(u_int8_t)  > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_8");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if (context->bit_pos)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule U_INT_8 on bitpos %d", context->bit_pos);
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+
+                                               *output_pos = *(context->byte_pos);
+                                               context->byte_pos++;
+                                               break;
+                                       }
+                                       case U_INT_16:
+                                       {
+                                               u_int16_t *output_pos = output + rule->offset;
+                                               if (context->byte_pos + sizeof(u_int16_t) > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_16");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if (context->bit_pos)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule U_INT_16 on bitpos %d", context->bit_pos);
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if ((int)context->byte_pos % 2)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule U_INT_16 on odd bytepos");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               *output_pos = ntohs(*((u_int16_t*)context->byte_pos));
+                                               context->byte_pos += 2;
+                                               break;                                  
+                                       }
+                                       case U_INT_32:
+                                       {
+                                               u_int32_t *output_pos = output + rule->offset;
+                                               if (context->byte_pos + sizeof(u_int32_t) > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_32");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if (context->bit_pos)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule U_INT_32 on bitpos %d", context->bit_pos);
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if ((int)context->byte_pos % 4)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule U_INT_32 on unaligned bytepos");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               *output_pos = ntohl(*((u_int32_t*)context->byte_pos));
+                                               context->byte_pos += 4;
+                                               break;          
+                                       }
+                                       case U_INT_64:
+                                       {
+                                               u_int32_t *output_pos = output + rule->offset;
+                                               if (context->byte_pos + 2 * sizeof(u_int32_t) > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_64");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if (context->bit_pos)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule U_INT_64 on bitpos %d", context->bit_pos);
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if ((int)context->byte_pos % 8)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule U_INT_64 on unaligned bytepos");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               /* assuming little endian host order */
+                                               *(output_pos + 1) = ntohl(*((u_int32_t*)context->byte_pos));
+                                               context->byte_pos += 4;
+                                               *output_pos = ntohl(*((u_int32_t*)context->byte_pos));
+                                               context->byte_pos += 4;
+                                               
+                                               break;  
+                                       }
+                                       case RESERVED_BIT:
+                                       {
+                                               if (context->byte_pos > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse RESERVED_BIT");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               context->bit_pos = (context->bit_pos + 1) % 8;
+                                               if (context->bit_pos == 0) 
+                                               {
+                                                       context->byte_pos++;    
+                                               }
+                                               break;
+                                       }
+                                       case RESERVED_BYTE:
+                                       {
+                                               if (context->byte_pos > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse RESERVED_BYTE");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if (context->bit_pos)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule RESERVED_BYTE on bitpos %d", context->bit_pos);
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               context->byte_pos++;    
+                                               break;
+                                       }
+                                       case FLAG:
+                                       {
+                                               bool *output_pos = output + rule->offset;
+                                               u_int8_t mask;
+                                               if (context->byte_pos > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse FLAG");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               mask = 0x01 << (7 - context->bit_pos);
+                                               *output_pos = *context->byte_pos & mask;
+                                       
+                                               if (*output_pos)
+                                               {
+                                                       /* set to a "clean", comparable true */
+                                                       *output_pos = TRUE;
+                                               } 
+                                               context->bit_pos = (context->bit_pos + 1) % 8;
+                                               if (context->bit_pos == 0) 
+                                               {
+                                                       context->byte_pos++;    
+                                               }
+                                               break;
+                                       }
+                                       case LENGTH:
+                                       {
+                                               u_int32_t *output_pos = output + rule->offset;
+                                               if (context->byte_pos + sizeof(u_int32_t) > context->input_roof)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "not enough input to parse LENGTH");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if (context->bit_pos)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule LENGTH on bitpos %d", context->bit_pos);
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               if ((int)context->byte_pos % 4)
+                                               {
+                                                       this->logger->log(this->logger, ERROR, "found rule LENGTH on unaligned bytepos");
+                                                       allocator_free(output);
+                                                       return PARSE_ERROR;
+                                               }
+                                               *output_pos = ntohl(*((u_int32_t*)context->byte_pos));
+                                               context->byte_pos += 4;
+                                               break;          
+                                       
+                                       }
+                                       case SPI_SIZE:
+                                       {
+                                               
+                                       }
+                                       default:
+                                       {
+                                               this->logger->log(this->logger, ERROR, "parser found unknown type");
+                                               allocator_free(output);
+                                               return PARSE_ERROR;
+                                       }
+                               }       
+                       }
+                       
+                       *data_struct = output;
+                       return SUCCESS;
+               }
+               payload_info++;
+       }
+       
+       this->logger->log(this->logger, ERROR, "Payload not supported");
+       return NOT_SUPPORTED;
+}
+
+static status_t destroy(private_parser_t *this)
+{
+       this->logger->destroy(this->logger);
+       allocator_free(this);   
+       
+       return SUCCESS;
+}
+
+parser_t *parser_create(payload_info_t **payload_infos)
+{
+       private_parser_t *this = allocator_alloc_thing(private_parser_t);
+       
+       if (this == NULL)
+       {
+               return NULL;
+       }
+       
+       this->logger = logger_create("parser", ALL);
+       if (this->logger == NULL)
+       {
+               allocator_free(this);
+               return NULL;
+       }
+       this->public.create_context = (parser_context_t*(*)(parser_t*,chunk_t)) create_context;
+       this->public.parse_payload = (status_t(*)(parser_t*,parser_context_t*,payload_type_t,void**)) parse_payload;
+       this->public.destroy = (status_t(*)(parser_t*)) destroy;
+       
+       this->payload_infos = payload_infos;    
+       
+       
+       return (parser_t*)this;
+}
index b25c94c..893917b 100644 (file)
 #include "encodings.h"
 
 
+typedef struct parser_context_s parser_context_t;
+
+struct parser_context_s {
+
+       status_t (*destroy) (parser_context_t *this);
+       
+};
+
 
 /**
  * @brief A parser_t object which parses payloads of specific type
@@ -36,22 +44,29 @@ typedef struct parser_s parser_t;
 struct parser_s {
 
        /**
-        * @brief Generates a specific payload from given data struct
+        * @brief parses a chunk and generates a usable data struct
         *
         * Remember: Header and substructures are also seen as payloads
         *
-        * @param generator generator object
-        * @return SUCCESSFUL if succeeded,
-        *                 NOT_SUPPORTED if payload_type is not supported
-        *                 OUT_OF_RES if out of ressources
+        * @param parser                parser Object
+        * @param payload_type  definition of payload including encoding_rule
+        * @param data                  chunk of data to parse
+        * @param[out]                  allocated structure with parsed data
+        * @return                      
+        *                                              - SUCCESSFUL if succeeded,
+        *                                              - NOT_SUPPORTED if payload_type is not supported
+        *                                              - OUT_OF_RES if out of ressources
+        *                                              - PARSE_ERROR if corrupted data found
         */
-       status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, chunk_t *data, void *data_struct);
-
+       parser_context_t *(*create_context) (parser_t *this, chunk_t data);
+       status_t (*parse_payload) (parser_t *this, parser_context_t* context, payload_type_t payload_type, void **data_struct);
+       
        /**
-        * @brief Destroys a generator object
+        * @brief Destroys a parser object
         *
-        * @param generator generator object
-        * @return SUCCESSFUL if succeeded, FAILED otherwise
+        * @param parser                parser object
+        * @return                              
+        *                                              - SUCCESSFUL in any case
         */
        status_t (*destroy) (parser_t *this);
 };
@@ -60,6 +75,6 @@ struct parser_s {
  * Constructor to create a parser
  *
  */
-parser_t *parser_create(payload_info_t ** payload_infos);
+parser_t *parser_create(payload_info_t **payload_infos);
 
 #endif /*PARSER_H_*/