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