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