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"
32 typedef struct private_parser_context_s private_parser_context_t
;
34 struct private_parser_context_s
{
38 parser_context_t
public;
41 * Current bit for reading in input data
46 * Current byte for reading in input data
63 static status_t
parser_context_destroy(private_parser_context_t
*this)
70 static private_parser_context_t
*parser_context_create(chunk_t input
)
72 private_parser_context_t
*this = allocator_alloc_thing(private_parser_context_t
);
78 this->public.destroy
= (status_t(*)(parser_context_t
*)) parser_context_destroy
;
80 this->input
= input
.ptr
;
81 this->byte_pos
= input
.ptr
;
83 this->input_roof
= input
.ptr
+ input
.len
;
91 * Private data of a parser_t object
93 typedef struct private_parser_s private_parser_t
;
95 struct private_parser_s
{
97 * Public part of a generator object
102 * list of payloads and their description
104 payload_info_t
**payload_infos
;
114 static private_parser_context_t
*create_context(private_parser_t
*this, chunk_t data
)
116 private_parser_context_t
*context
= parser_context_create(data
);
121 static status_t
parse_payload(private_parser_t
*this, private_parser_context_t
*context
, payload_type_t payload_type
, void **data_struct
)
123 payload_info_t
*payload_info
= NULL
;
125 /* find payload in null terminated list*/
126 payload_info
= *(this->payload_infos
);
129 if (payload_info
->payload_type
== payload_type
)
134 /* ok, do the parsing */
135 output
= allocator_alloc(payload_info
->data_struct_length
);
137 for (current
= 0; current
< payload_info
->encoding_rules_count
; current
++)
139 encoding_rule_t
*rule
= &(payload_info
->ecoding_rules
[current
]);
144 u_int8_t
*output_pos
= output
+ rule
->offset
;
145 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
147 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_4");
148 allocator_free(output
);
151 switch (context
->bit_pos
)
154 *output_pos
= *(context
->byte_pos
) >> 4;
155 context
->bit_pos
= 4;
158 *output_pos
= *(context
->byte_pos
) & 0x0F;
159 context
->bit_pos
= 0;
163 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_4 on bitpos %d", context
->bit_pos
);
164 allocator_free(output
);
171 u_int8_t
*output_pos
= output
+ rule
->offset
;
172 if (context
->byte_pos
+ sizeof(u_int8_t
) > context
->input_roof
)
174 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_8");
175 allocator_free(output
);
178 if (context
->bit_pos
)
180 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_8 on bitpos %d", context
->bit_pos
);
181 allocator_free(output
);
185 *output_pos
= *(context
->byte_pos
);
191 u_int16_t
*output_pos
= output
+ rule
->offset
;
192 if (context
->byte_pos
+ sizeof(u_int16_t
) > context
->input_roof
)
194 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_16");
195 allocator_free(output
);
198 if (context
->bit_pos
)
200 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on bitpos %d", context
->bit_pos
);
201 allocator_free(output
);
204 if ((int)context
->byte_pos
% 2)
206 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on odd bytepos");
207 allocator_free(output
);
210 *output_pos
= ntohs(*((u_int16_t
*)context
->byte_pos
));
211 context
->byte_pos
+= 2;
216 u_int32_t
*output_pos
= output
+ rule
->offset
;
217 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
219 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_32");
220 allocator_free(output
);
223 if (context
->bit_pos
)
225 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on bitpos %d", context
->bit_pos
);
226 allocator_free(output
);
229 if ((int)context
->byte_pos
% 4)
231 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on unaligned bytepos");
232 allocator_free(output
);
235 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
236 context
->byte_pos
+= 4;
241 u_int32_t
*output_pos
= output
+ rule
->offset
;
242 if (context
->byte_pos
+ 2 * sizeof(u_int32_t
) > context
->input_roof
)
244 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_64");
245 allocator_free(output
);
248 if (context
->bit_pos
)
250 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on bitpos %d", context
->bit_pos
);
251 allocator_free(output
);
254 if ((int)context
->byte_pos
% 8)
256 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on unaligned bytepos");
257 allocator_free(output
);
260 /* assuming little endian host order */
261 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)context
->byte_pos
));
262 context
->byte_pos
+= 4;
263 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
264 context
->byte_pos
+= 4;
270 if (context
->byte_pos
> context
->input_roof
)
272 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BIT");
273 allocator_free(output
);
276 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
277 if (context
->bit_pos
== 0)
285 if (context
->byte_pos
> context
->input_roof
)
287 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BYTE");
288 allocator_free(output
);
291 if (context
->bit_pos
)
293 this->logger
->log(this->logger
, ERROR
, "found rule RESERVED_BYTE on bitpos %d", context
->bit_pos
);
294 allocator_free(output
);
302 bool *output_pos
= output
+ rule
->offset
;
304 if (context
->byte_pos
> context
->input_roof
)
306 this->logger
->log(this->logger
, ERROR
, "not enough input to parse FLAG");
307 allocator_free(output
);
310 mask
= 0x01 << (7 - context
->bit_pos
);
311 *output_pos
= *context
->byte_pos
& mask
;
315 /* set to a "clean", comparable true */
318 context
->bit_pos
= (context
->bit_pos
+ 1) % 8;
319 if (context
->bit_pos
== 0)
327 u_int32_t
*output_pos
= output
+ rule
->offset
;
328 if (context
->byte_pos
+ sizeof(u_int32_t
) > context
->input_roof
)
330 this->logger
->log(this->logger
, ERROR
, "not enough input to parse LENGTH");
331 allocator_free(output
);
334 if (context
->bit_pos
)
336 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on bitpos %d", context
->bit_pos
);
337 allocator_free(output
);
340 if ((int)context
->byte_pos
% 4)
342 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on unaligned bytepos");
343 allocator_free(output
);
346 *output_pos
= ntohl(*((u_int32_t
*)context
->byte_pos
));
347 context
->byte_pos
+= 4;
357 this->logger
->log(this->logger
, ERROR
, "parser found unknown type");
358 allocator_free(output
);
364 *data_struct
= output
;
370 this->logger
->log(this->logger
, ERROR
, "Payload not supported");
371 return NOT_SUPPORTED
;
374 static status_t
destroy(private_parser_t
*this)
376 this->logger
->destroy(this->logger
);
377 allocator_free(this);
382 parser_t
*parser_create(payload_info_t
**payload_infos
)
384 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
391 this->logger
= logger_create("parser", ALL
);
392 if (this->logger
== NULL
)
394 allocator_free(this);
397 this->public.create_context
= (parser_context_t
*(*)(parser_t
*,chunk_t
)) create_context
;
398 this->public.parse_payload
= (status_t(*)(parser_t
*,parser_context_t
*,payload_type_t
,void**)) parse_payload
;
399 this->public.destroy
= (status_t(*)(parser_t
*)) destroy
;
401 this->payload_infos
= payload_infos
;
404 return (parser_t
*)this;