- renamed logger_manager method get_logger to create_logger
[strongswan.git] / Source / charon / parser.c
1 /**
2 * @file parser.c
3 *
4 * @brief Generic parser class used to parse IKEv2-Header and Payload
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
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>.
16 *
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
20 * for more details.
21 */
22
23 #include <stdlib.h>
24 #include <arpa/inet.h>
25
26 #include "allocator.h"
27 #include "definitions.h"
28 #include "globals.h"
29 #include "types.h"
30 #include "parser.h"
31 #include "logger.h"
32
33 /**
34 * @private data stored in a context
35 *
36 * contains pointers and counters to store current state
37 */
38 typedef struct private_parser_context_s private_parser_context_t;
39
40 struct private_parser_context_s {
41 /**
42 * Public members
43 */
44 parser_context_t public;
45
46 /**
47 * Current bit for reading in input data
48 */
49 u_int8_t bit_pos;
50
51 /**
52 * Current byte for reading in input data
53 */
54 u_int8_t *byte_pos;
55
56 /**
57 * input data to parse
58 */
59 u_int8_t *input;
60
61 /**
62 * roof of input
63 */
64 u_int8_t *input_roof;
65
66
67 };
68
69 /**
70 * implementation of parser_context_t.destroy
71 */
72 static status_t parser_context_destroy(private_parser_context_t *this)
73 {
74 allocator_free(this);
75
76 return SUCCESS;
77 }
78
79
80 /**
81 * @brief Private data of a parser_t object
82 */
83 typedef struct private_parser_s private_parser_t;
84
85 struct private_parser_s {
86 /**
87 * Public part of a generator object
88 */
89 parser_t public;
90
91 /**
92 * list of payloads and their description
93 */
94 payload_info_t **payload_infos;
95
96 /**
97 * logger object
98 */
99 logger_t *logger;
100 };
101
102 /**
103 * implementation of parser_t.create_context
104 */
105 static private_parser_context_t *create_context(private_parser_t *this, chunk_t data)
106 {
107 private_parser_context_t *context = allocator_alloc_thing(private_parser_context_t);
108 if (this == NULL)
109 {
110 return NULL;
111 }
112
113 context->public.destroy = (status_t(*)(parser_context_t*)) parser_context_destroy;
114
115 context->input = data.ptr;
116 context->byte_pos = data.ptr;
117 context->bit_pos = 0;
118 context->input_roof = data.ptr + data.len;
119
120 return context;
121 }
122
123 /**
124 * implementation of parser_context_t.parse_payload
125 */
126 static status_t parse_payload(private_parser_t *this, payload_type_t payload_type, void **data_struct, private_parser_context_t *context)
127 {
128 payload_info_t *payload_info = NULL;
129
130 this->logger->log(this->logger, CONTROL, "Parsing a %s payload", mapping_find(payload_type_t_mappings, payload_type));
131
132 /* find payload in null terminated list*/
133 payload_info = *(this->payload_infos);
134 while (payload_info)
135 {
136 if (payload_info->payload_type == payload_type)
137 {
138 void *output;
139 int current;
140
141 /* ok, do the parsing */
142 output = allocator_alloc(payload_info->data_struct_length);
143
144 for (current = 0; current < payload_info->encoding_rules_count; current++)
145 {
146 encoding_rule_t *rule = &(payload_info->ecoding_rules[current]);
147 switch (rule->type)
148 {
149 case U_INT_4:
150 {
151 u_int8_t *output_pos = output + rule->offset;
152 if (context->byte_pos + sizeof(u_int8_t) > context->input_roof)
153 {
154 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_4");
155 allocator_free(output);
156 return PARSE_ERROR;
157 }
158 switch (context->bit_pos)
159 {
160 case 0:
161 *output_pos = *(context->byte_pos) >> 4;
162 context->bit_pos = 4;
163 break;
164 case 4:
165 *output_pos = *(context->byte_pos) & 0x0F;
166 context->bit_pos = 0;
167 context->byte_pos++;
168 break;
169 default:
170 this->logger->log(this->logger, ERROR, "found rule U_INT_4 on bitpos %d", context->bit_pos);
171 allocator_free(output);
172 return PARSE_ERROR;
173 }
174 break;
175 }
176 case U_INT_8:
177 {
178 u_int8_t *output_pos = output + rule->offset;
179 if (context->byte_pos + sizeof(u_int8_t) > context->input_roof)
180 {
181 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_8");
182 allocator_free(output);
183 return PARSE_ERROR;
184 }
185 if (context->bit_pos)
186 {
187 this->logger->log(this->logger, ERROR, "found rule U_INT_8 on bitpos %d", context->bit_pos);
188 allocator_free(output);
189 return PARSE_ERROR;
190 }
191
192 *output_pos = *(context->byte_pos);
193 context->byte_pos++;
194 break;
195 }
196 case U_INT_16:
197 {
198 u_int16_t *output_pos = output + rule->offset;
199 if (context->byte_pos + sizeof(u_int16_t) > context->input_roof)
200 {
201 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_16");
202 allocator_free(output);
203 return PARSE_ERROR;
204 }
205 if (context->bit_pos)
206 {
207 this->logger->log(this->logger, ERROR, "found rule U_INT_16 on bitpos %d", context->bit_pos);
208 allocator_free(output);
209 return PARSE_ERROR;
210 }
211 if ((int)context->byte_pos % 2)
212 {
213 this->logger->log(this->logger, ERROR, "found rule U_INT_16 on odd bytepos");
214 allocator_free(output);
215 return PARSE_ERROR;
216 }
217 *output_pos = ntohs(*((u_int16_t*)context->byte_pos));
218 context->byte_pos += 2;
219 break;
220 }
221 case U_INT_32:
222 {
223 u_int32_t *output_pos = output + rule->offset;
224 if (context->byte_pos + sizeof(u_int32_t) > context->input_roof)
225 {
226 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_32");
227 allocator_free(output);
228 return PARSE_ERROR;
229 }
230 if (context->bit_pos)
231 {
232 this->logger->log(this->logger, ERROR, "found rule U_INT_32 on bitpos %d", context->bit_pos);
233 allocator_free(output);
234 return PARSE_ERROR;
235 }
236 if ((int)context->byte_pos % 4)
237 {
238 this->logger->log(this->logger, ERROR, "found rule U_INT_32 on unaligned bytepos");
239 allocator_free(output);
240 return PARSE_ERROR;
241 }
242 *output_pos = ntohl(*((u_int32_t*)context->byte_pos));
243 context->byte_pos += 4;
244 break;
245 }
246 case U_INT_64:
247 {
248 u_int32_t *output_pos = output + rule->offset;
249 if (context->byte_pos + 2 * sizeof(u_int32_t) > context->input_roof)
250 {
251 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_64");
252 allocator_free(output);
253 return PARSE_ERROR;
254 }
255 if (context->bit_pos)
256 {
257 this->logger->log(this->logger, ERROR, "found rule U_INT_64 on bitpos %d", context->bit_pos);
258 allocator_free(output);
259 return PARSE_ERROR;
260 }
261 if ((int)context->byte_pos % 8)
262 {
263 this->logger->log(this->logger, ERROR, "found rule U_INT_64 on unaligned bytepos");
264 allocator_free(output);
265 return PARSE_ERROR;
266 }
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;
272
273 break;
274 }
275 case RESERVED_BIT:
276 {
277 if (context->byte_pos > context->input_roof)
278 {
279 this->logger->log(this->logger, ERROR, "not enough input to parse RESERVED_BIT");
280 allocator_free(output);
281 return PARSE_ERROR;
282 }
283 context->bit_pos = (context->bit_pos + 1) % 8;
284 if (context->bit_pos == 0)
285 {
286 context->byte_pos++;
287 }
288 break;
289 }
290 case RESERVED_BYTE:
291 {
292 if (context->byte_pos > context->input_roof)
293 {
294 this->logger->log(this->logger, ERROR, "not enough input to parse RESERVED_BYTE");
295 allocator_free(output);
296 return PARSE_ERROR;
297 }
298 if (context->bit_pos)
299 {
300 this->logger->log(this->logger, ERROR, "found rule RESERVED_BYTE on bitpos %d", context->bit_pos);
301 allocator_free(output);
302 return PARSE_ERROR;
303 }
304 context->byte_pos++;
305 break;
306 }
307 case FLAG:
308 {
309 bool *output_pos = output + rule->offset;
310 u_int8_t mask;
311 if (context->byte_pos > context->input_roof)
312 {
313 this->logger->log(this->logger, ERROR, "not enough input to parse FLAG");
314 allocator_free(output);
315 return PARSE_ERROR;
316 }
317 mask = 0x01 << (7 - context->bit_pos);
318 *output_pos = *context->byte_pos & mask;
319
320 if (*output_pos)
321 {
322 /* set to a "clean", comparable true */
323 *output_pos = TRUE;
324 }
325 context->bit_pos = (context->bit_pos + 1) % 8;
326 if (context->bit_pos == 0)
327 {
328 context->byte_pos++;
329 }
330 break;
331 }
332 case LENGTH:
333 {
334 u_int32_t *output_pos = output + rule->offset;
335 if (context->byte_pos + sizeof(u_int32_t) > context->input_roof)
336 {
337 this->logger->log(this->logger, ERROR, "not enough input to parse LENGTH");
338 allocator_free(output);
339 return PARSE_ERROR;
340 }
341 if (context->bit_pos)
342 {
343 this->logger->log(this->logger, ERROR, "found rule LENGTH on bitpos %d", context->bit_pos);
344 allocator_free(output);
345 return PARSE_ERROR;
346 }
347 if ((int)context->byte_pos % 4)
348 {
349 this->logger->log(this->logger, ERROR, "found rule LENGTH on unaligned bytepos");
350 allocator_free(output);
351 return PARSE_ERROR;
352 }
353 *output_pos = ntohl(*((u_int32_t*)context->byte_pos));
354 context->byte_pos += 4;
355 break;
356
357 }
358 case SPI_SIZE:
359 {
360
361 }
362 default:
363 {
364 this->logger->log(this->logger, ERROR, "parser found unknown type");
365 allocator_free(output);
366 return PARSE_ERROR;
367 }
368 }
369 }
370
371 *data_struct = output;
372 return SUCCESS;
373 }
374 payload_info++;
375 }
376
377 this->logger->log(this->logger, ERROR, "Payload not supported");
378 return NOT_SUPPORTED;
379 }
380
381 /**
382 * implementation of parser_t.destroy
383 */
384 static status_t destroy(private_parser_t *this)
385 {
386 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
387 allocator_free(this);
388
389 return SUCCESS;
390 }
391
392 /*
393 * see header file
394 */
395 parser_t *parser_create(payload_info_t **payload_infos)
396 {
397 private_parser_t *this = allocator_alloc_thing(private_parser_t);
398
399 if (this == NULL)
400 {
401 return NULL;
402 }
403
404 this->logger = global_logger_manager->create_logger(global_logger_manager,PARSER, NULL);
405
406 if (this->logger == NULL)
407 {
408 allocator_free(this);
409 return NULL;
410 }
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;
414
415 this->payload_infos = payload_infos;
416
417
418 return (parser_t*)this;
419 }