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 "payloads/payload.h"
36 * @private data stored in a context
38 * contains pointers and counters to store current state
40 typedef struct private_parser_context_s private_parser_context_t
;
42 struct private_parser_context_s
{
46 parser_context_t
public;
49 * Current bit for reading in input data
54 * Current byte for reading in input data
72 * implementation of parser_context_t.destroy
74 static status_t
parser_context_destroy(private_parser_context_t
*this)
83 * @brief Private data of a parser_t object
85 typedef struct private_parser_s private_parser_t
;
87 struct private_parser_s
{
89 * Public part of a generator object
94 * list of payloads and their description
96 payload_info_t
**payload_infos
;
105 * implementation of parser_t.create_context
107 static private_parser_context_t
*create_context(private_parser_t
*this, chunk_t data
)
109 private_parser_context_t
*context
= allocator_alloc_thing(private_parser_context_t
);
115 context
->public.destroy
= (status_t(*)(parser_context_t
*)) parser_context_destroy
;
117 context
->input
= data
.ptr
;
118 context
->byte_pos
= data
.ptr
;
119 context
->bit_pos
= 0;
120 context
->input_roof
= data
.ptr
+ data
.len
;
126 * implementation of parser_context_t.parse_payload
128 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, void **data_struct
, private_parser_context_t
*context
)
130 payload_info_t
*payload_info
= NULL
;
132 this->logger
->log(this->logger
, CONTROL
, "Parsing a %s payload", mapping_find(payload_type_t_mappings
, payload_type
));
134 /* find payload in null terminated list*/
135 payload_info
= *(this->payload_infos
);
138 if (payload_info
->payload_type
== payload_type
)
143 /* ok, do the parsing */
144 output
= allocator_alloc(payload_info
->data_struct_length
);
146 for (current
= 0; current
< payload_info
->encoding_rules_count
; current
++)
148 encoding_rule_t
*rule
= &(payload_info
->ecoding_rules
[current
]);
153 u_int8_t
*output_pos
= output
+ rule
->offset
;
154 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
156 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_4");
157 allocator_free(output
);
160 switch (context
->bit_pos
)
163 *output_pos
= *(context
->byte_pos
) >> 4;
164 context
->bit_pos
= 4;
167 *output_pos
= *(context
->byte_pos
) & 0x0F;
168 context
->bit_pos
= 0;
172 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_4 on bitpos %d", context
->bit_pos
);
173 allocator_free(output
);
180 u_int8_t
*output_pos
= output
+ rule
->offset
;
181 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
183 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_8");
184 allocator_free(output
);
187 if (context
->bit_pos
)
189 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_8 on bitpos %d", context
->bit_pos
);
190 allocator_free(output
);
194 *output_pos
= *(context
->byte_pos
);
200 u_int16_t
*output_pos
= output
+ rule
->offset
;
201 if (context
->byte_pos
+ sizeof(u_int16_t
) > context
->input_roof
)
203 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_16");
204 allocator_free(output
);
207 if (context
->bit_pos
)
209 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on bitpos %d", context
->bit_pos
);
210 allocator_free(output
);
213 if ((int)context
->byte_pos
% 2)
215 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on odd bytepos");
216 allocator_free(output
);
219 *output_pos
= ntohs(*((u_int16_t
*)context
->byte_pos
));
220 context
->byte_pos
+= 2;
225 u_int32_t
*output_pos
= output
+ rule
->offset
;
226 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
228 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_32");
229 allocator_free(output
);
232 if (context
->bit_pos
)
234 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on bitpos %d", context
->bit_pos
);
235 allocator_free(output
);
238 if ((int)context
->byte_pos
% 4)
240 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on unaligned bytepos");
241 allocator_free(output
);
244 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
245 context
->byte_pos
+= 4;
250 u_int32_t
*output_pos
= output
+ rule
->offset
;
251 if (context
->byte_pos
+ 2 * sizeof(u_int32_t
) > context
->input_roof
)
253 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_64");
254 allocator_free(output
);
257 if (context
->bit_pos
)
259 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on bitpos %d", context
->bit_pos
);
260 allocator_free(output
);
263 if ((int)context
->byte_pos
% 8)
265 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on unaligned bytepos");
266 allocator_free(output
);
269 /* assuming little endian host order */
270 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)context
->byte_pos
));
271 context
->byte_pos
+= 4;
272 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
273 context
->byte_pos
+= 4;
279 if (context
->byte_pos
> context
->input_roof
)
281 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BIT");
282 allocator_free(output
);
285 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
286 if (context
->bit_pos
== 0)
294 if (context
->byte_pos
> context
->input_roof
)
296 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BYTE");
297 allocator_free(output
);
300 if (context
->bit_pos
)
302 this->logger
->log(this->logger
, ERROR
, "found rule RESERVED_BYTE on bitpos %d", context
->bit_pos
);
303 allocator_free(output
);
311 bool *output_pos
= output
+ rule
->offset
;
313 if (context
->byte_pos
> context
->input_roof
)
315 this->logger
->log(this->logger
, ERROR
, "not enough input to parse FLAG");
316 allocator_free(output
);
319 mask
= 0x01 << (7 - context
->bit_pos
);
320 *output_pos
= *context
->byte_pos
& mask
;
324 /* set to a "clean", comparable true */
327 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
328 if (context
->bit_pos
== 0)
336 u_int32_t
*output_pos
= output
+ rule
->offset
;
337 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
339 this->logger
->log(this->logger
, ERROR
, "not enough input to parse LENGTH");
340 allocator_free(output
);
343 if (context
->bit_pos
)
345 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on bitpos %d", context
->bit_pos
);
346 allocator_free(output
);
349 if ((int)context
->byte_pos
% 4)
351 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on unaligned bytepos");
352 allocator_free(output
);
355 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
356 context
->byte_pos
+= 4;
366 this->logger
->log(this->logger
, ERROR
, "parser found unknown type");
367 allocator_free(output
);
373 *data_struct
= output
;
379 this->logger
->log(this->logger
, ERROR
, "Payload not supported");
380 return NOT_SUPPORTED
;
384 * implementation of parser_t.destroy
386 static status_t
destroy(private_parser_t
*this)
388 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
389 allocator_free(this);
397 parser_t
*parser_create(payload_info_t
**payload_infos
)
399 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
406 this->logger
= global_logger_manager
->create_logger(global_logger_manager
,PARSER
, NULL
);
408 if (this->logger
== NULL
)
410 allocator_free(this);
413 this->public.create_context
= (parser_context_t
*(*)(parser_t
*,chunk_t
)) create_context
;
414 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,void**,parser_context_t
*)) parse_payload
;
415 this->public.destroy
= (status_t(*)(parser_t
*)) destroy
;
417 this->payload_infos
= payload_infos
;
420 return (parser_t
*)this;