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>
26 #include "allocator.h"
27 #include "definitions.h"
34 * @private data stored in a context
36 * contains pointers and counters to store current state
38 typedef struct private_parser_context_s private_parser_context_t
;
40 struct private_parser_context_s
{
44 parser_context_t
public;
47 * Current bit for reading in input data
52 * Current byte for reading in input data
70 * implementation of parser_context_t.destroy
72 static status_t
parser_context_destroy(private_parser_context_t
*this)
81 * @brief Private data of a parser_t object
83 typedef struct private_parser_s private_parser_t
;
85 struct private_parser_s
{
87 * Public part of a generator object
92 * list of payloads and their description
94 payload_info_t
**payload_infos
;
103 * implementation of parser_t.create_context
105 static private_parser_context_t
*create_context(private_parser_t
*this, chunk_t data
)
107 private_parser_context_t
*context
= allocator_alloc_thing(private_parser_context_t
);
113 context
->public.destroy
= (status_t(*)(parser_context_t
*)) parser_context_destroy
;
115 context
->input
= data
.ptr
;
116 context
->byte_pos
= data
.ptr
;
117 context
->bit_pos
= 0;
118 context
->input_roof
= data
.ptr
+ data
.len
;
124 * implementation of parser_context_t.parse_payload
126 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, void **data_struct
, private_parser_context_t
*context
)
128 payload_info_t
*payload_info
= NULL
;
130 this->logger
->log(this->logger
, CONTROL
, "Parsing a %s payload", mapping_find(payload_type_t_mappings
, payload_type
));
132 /* find payload in null terminated list*/
133 payload_info
= *(this->payload_infos
);
136 if (payload_info
->payload_type
== payload_type
)
141 /* ok, do the parsing */
142 output
= allocator_alloc(payload_info
->data_struct_length
);
144 for (current
= 0; current
< payload_info
->encoding_rules_count
; current
++)
146 encoding_rule_t
*rule
= &(payload_info
->ecoding_rules
[current
]);
151 u_int8_t
*output_pos
= output
+ rule
->offset
;
152 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
154 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_4");
155 allocator_free(output
);
158 switch (context
->bit_pos
)
161 *output_pos
= *(context
->byte_pos
) >> 4;
162 context
->bit_pos
= 4;
165 *output_pos
= *(context
->byte_pos
) & 0x0F;
166 context
->bit_pos
= 0;
170 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_4 on bitpos %d", context
->bit_pos
);
171 allocator_free(output
);
178 u_int8_t
*output_pos
= output
+ rule
->offset
;
179 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
181 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_8");
182 allocator_free(output
);
185 if (context
->bit_pos
)
187 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_8 on bitpos %d", context
->bit_pos
);
188 allocator_free(output
);
192 *output_pos
= *(context
->byte_pos
);
198 u_int16_t
*output_pos
= output
+ rule
->offset
;
199 if (context
->byte_pos
+ sizeof(u_int16_t
) > context
->input_roof
)
201 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_16");
202 allocator_free(output
);
205 if (context
->bit_pos
)
207 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on bitpos %d", context
->bit_pos
);
208 allocator_free(output
);
211 if ((int)context
->byte_pos
% 2)
213 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on odd bytepos");
214 allocator_free(output
);
217 *output_pos
= ntohs(*((u_int16_t
*)context
->byte_pos
));
218 context
->byte_pos
+= 2;
223 u_int32_t
*output_pos
= output
+ rule
->offset
;
224 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
226 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_32");
227 allocator_free(output
);
230 if (context
->bit_pos
)
232 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on bitpos %d", context
->bit_pos
);
233 allocator_free(output
);
236 if ((int)context
->byte_pos
% 4)
238 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on unaligned bytepos");
239 allocator_free(output
);
242 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
243 context
->byte_pos
+= 4;
248 u_int32_t
*output_pos
= output
+ rule
->offset
;
249 if (context
->byte_pos
+ 2 * sizeof(u_int32_t
) > context
->input_roof
)
251 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_64");
252 allocator_free(output
);
255 if (context
->bit_pos
)
257 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on bitpos %d", context
->bit_pos
);
258 allocator_free(output
);
261 if ((int)context
->byte_pos
% 8)
263 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on unaligned bytepos");
264 allocator_free(output
);
267 /* assuming little endian host order */
268 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)context
->byte_pos
));
269 context
->byte_pos
+= 4;
270 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
271 context
->byte_pos
+= 4;
277 if (context
->byte_pos
> context
->input_roof
)
279 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BIT");
280 allocator_free(output
);
283 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
284 if (context
->bit_pos
== 0)
292 if (context
->byte_pos
> context
->input_roof
)
294 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BYTE");
295 allocator_free(output
);
298 if (context
->bit_pos
)
300 this->logger
->log(this->logger
, ERROR
, "found rule RESERVED_BYTE on bitpos %d", context
->bit_pos
);
301 allocator_free(output
);
309 bool *output_pos
= output
+ rule
->offset
;
311 if (context
->byte_pos
> context
->input_roof
)
313 this->logger
->log(this->logger
, ERROR
, "not enough input to parse FLAG");
314 allocator_free(output
);
317 mask
= 0x01 << (7 - context
->bit_pos
);
318 *output_pos
= *context
->byte_pos
& mask
;
322 /* set to a "clean", comparable true */
325 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
326 if (context
->bit_pos
== 0)
334 u_int32_t
*output_pos
= output
+ rule
->offset
;
335 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
337 this->logger
->log(this->logger
, ERROR
, "not enough input to parse LENGTH");
338 allocator_free(output
);
341 if (context
->bit_pos
)
343 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on bitpos %d", context
->bit_pos
);
344 allocator_free(output
);
347 if ((int)context
->byte_pos
% 4)
349 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on unaligned bytepos");
350 allocator_free(output
);
353 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
354 context
->byte_pos
+= 4;
364 this->logger
->log(this->logger
, ERROR
, "parser found unknown type");
365 allocator_free(output
);
371 *data_struct
= output
;
377 this->logger
->log(this->logger
, ERROR
, "Payload not supported");
378 return NOT_SUPPORTED
;
382 * implementation of parser_t.destroy
384 static status_t
destroy(private_parser_t
*this)
386 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
387 allocator_free(this);
395 parser_t
*parser_create(payload_info_t
**payload_infos
)
397 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
404 global_logger_manager
->get_logger(global_logger_manager
,PARSER
,&(this->logger
), NULL
);
406 if (this->logger
== NULL
)
408 allocator_free(this);
411 this->public.create_context
= (parser_context_t
*(*)(parser_t
*,chunk_t
)) create_context
;
412 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,void**,parser_context_t
*)) parse_payload
;
413 this->public.destroy
= (status_t(*)(parser_t
*)) destroy
;
415 this->payload_infos
= payload_infos
;
418 return (parser_t
*)this;