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"
33 * @private data stored in a context
35 * contains pointers and counters to store current state
37 typedef struct private_parser_context_s private_parser_context_t
;
39 struct private_parser_context_s
{
43 parser_context_t
public;
46 * Current bit for reading in input data
51 * Current byte for reading in input data
69 * implementation of parser_context_t.destroy
71 static status_t
parser_context_destroy(private_parser_context_t
*this)
80 * @brief Private data of a parser_t object
82 typedef struct private_parser_s private_parser_t
;
84 struct private_parser_s
{
86 * Public part of a generator object
91 * list of payloads and their description
93 payload_info_t
**payload_infos
;
102 * implementation of parser_t.create_context
104 static private_parser_context_t
*create_context(private_parser_t
*this, chunk_t data
)
106 private_parser_context_t
*context
= allocator_alloc_thing(private_parser_context_t
);
112 context
->public.destroy
= (status_t(*)(parser_context_t
*)) parser_context_destroy
;
114 context
->input
= data
.ptr
;
115 context
->byte_pos
= data
.ptr
;
116 context
->bit_pos
= 0;
117 context
->input_roof
= data
.ptr
+ data
.len
;
123 * implementation of parser_context_t.parse_payload
125 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, void **data_struct
, private_parser_context_t
*context
)
127 payload_info_t
*payload_info
= NULL
;
129 /* find payload in null terminated list*/
130 payload_info
= *(this->payload_infos
);
133 if (payload_info
->payload_type
== payload_type
)
138 /* ok, do the parsing */
139 output
= allocator_alloc(payload_info
->data_struct_length
);
141 for (current
= 0; current
< payload_info
->encoding_rules_count
; current
++)
143 encoding_rule_t
*rule
= &(payload_info
->ecoding_rules
[current
]);
148 u_int8_t
*output_pos
= output
+ rule
->offset
;
149 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
151 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_4");
152 allocator_free(output
);
155 switch (context
->bit_pos
)
158 *output_pos
= *(context
->byte_pos
) >> 4;
159 context
->bit_pos
= 4;
162 *output_pos
= *(context
->byte_pos
) & 0x0F;
163 context
->bit_pos
= 0;
167 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_4 on bitpos %d", context
->bit_pos
);
168 allocator_free(output
);
175 u_int8_t
*output_pos
= output
+ rule
->offset
;
176 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
178 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_8");
179 allocator_free(output
);
182 if (context
->bit_pos
)
184 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_8 on bitpos %d", context
->bit_pos
);
185 allocator_free(output
);
189 *output_pos
= *(context
->byte_pos
);
195 u_int16_t
*output_pos
= output
+ rule
->offset
;
196 if (context
->byte_pos
+ sizeof(u_int16_t
) > context
->input_roof
)
198 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_16");
199 allocator_free(output
);
202 if (context
->bit_pos
)
204 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on bitpos %d", context
->bit_pos
);
205 allocator_free(output
);
208 if ((int)context
->byte_pos
% 2)
210 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on odd bytepos");
211 allocator_free(output
);
214 *output_pos
= ntohs(*((u_int16_t
*)context
->byte_pos
));
215 context
->byte_pos
+= 2;
220 u_int32_t
*output_pos
= output
+ rule
->offset
;
221 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
223 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_32");
224 allocator_free(output
);
227 if (context
->bit_pos
)
229 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on bitpos %d", context
->bit_pos
);
230 allocator_free(output
);
233 if ((int)context
->byte_pos
% 4)
235 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on unaligned bytepos");
236 allocator_free(output
);
239 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
240 context
->byte_pos
+= 4;
245 u_int32_t
*output_pos
= output
+ rule
->offset
;
246 if (context
->byte_pos
+ 2 * sizeof(u_int32_t
) > context
->input_roof
)
248 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_64");
249 allocator_free(output
);
252 if (context
->bit_pos
)
254 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on bitpos %d", context
->bit_pos
);
255 allocator_free(output
);
258 if ((int)context
->byte_pos
% 8)
260 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on unaligned bytepos");
261 allocator_free(output
);
264 /* assuming little endian host order */
265 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)context
->byte_pos
));
266 context
->byte_pos
+= 4;
267 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
268 context
->byte_pos
+= 4;
274 if (context
->byte_pos
> context
->input_roof
)
276 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BIT");
277 allocator_free(output
);
280 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
281 if (context
->bit_pos
== 0)
289 if (context
->byte_pos
> context
->input_roof
)
291 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BYTE");
292 allocator_free(output
);
295 if (context
->bit_pos
)
297 this->logger
->log(this->logger
, ERROR
, "found rule RESERVED_BYTE on bitpos %d", context
->bit_pos
);
298 allocator_free(output
);
306 bool *output_pos
= output
+ rule
->offset
;
308 if (context
->byte_pos
> context
->input_roof
)
310 this->logger
->log(this->logger
, ERROR
, "not enough input to parse FLAG");
311 allocator_free(output
);
314 mask
= 0x01 << (7 - context
->bit_pos
);
315 *output_pos
= *context
->byte_pos
& mask
;
319 /* set to a "clean", comparable true */
322 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
323 if (context
->bit_pos
== 0)
331 u_int32_t
*output_pos
= output
+ rule
->offset
;
332 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
334 this->logger
->log(this->logger
, ERROR
, "not enough input to parse LENGTH");
335 allocator_free(output
);
338 if (context
->bit_pos
)
340 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on bitpos %d", context
->bit_pos
);
341 allocator_free(output
);
344 if ((int)context
->byte_pos
% 4)
346 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on unaligned bytepos");
347 allocator_free(output
);
350 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
351 context
->byte_pos
+= 4;
361 this->logger
->log(this->logger
, ERROR
, "parser found unknown type");
362 allocator_free(output
);
368 *data_struct
= output
;
374 this->logger
->log(this->logger
, ERROR
, "Payload not supported");
375 return NOT_SUPPORTED
;
379 * implementation of parser_t.destroy
381 static status_t
destroy(private_parser_t
*this)
383 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
384 allocator_free(this);
392 parser_t
*parser_create(payload_info_t
**payload_infos
)
394 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
401 global_logger_manager
->get_logger(global_logger_manager
,PARSER
,&(this->logger
),"");
403 if (this->logger
== NULL
)
405 allocator_free(this);
408 this->public.create_context
= (parser_context_t
*(*)(parser_t
*,chunk_t
)) create_context
;
409 this->public.parse_payload
= (status_t(*)(parser_t
*,payload_type_t
,void**,parser_context_t
*)) parse_payload
;
410 this->public.destroy
= (status_t(*)(parser_t
*)) destroy
;
412 this->payload_infos
= payload_infos
;
415 return (parser_t
*)this;