- fixed parser to use new payload mechanisms
[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_s private_parser_t;
41
42 struct private_parser_s {
43 /**
44 * Public members
45 */
46 parser_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 * logger object
70 */
71 logger_t *logger;
72
73
74 };
75
76 /**
77 * implementation of parser_context_t.parse_payload
78 */
79 static status_t parse_payload(private_parser_t *this, payload_type_t payload_type, payload_t **payload)
80 {
81
82 this->logger->log(this->logger, CONTROL, "Parsing a %s payload", mapping_find(payload_type_t_mappings, payload_type));
83
84 /* find payload in null terminated list*/
85
86 payload_t *pld;
87 void *output;
88 int current;
89 encoding_rule_t *rule;
90 size_t rule_count;
91
92 /* ok, do the parsing */
93 pld = payload_create(payload_type);
94 if (pld == NULL)
95 {
96 this->logger->log(this->logger, ERROR, "Payload not supported");
97 return NOT_SUPPORTED;
98 }
99
100 /* base pointer for output, avoids casting in every rule */
101 output = pld;
102
103 pld->get_encoding_rules(pld, &rule, &rule_count);
104
105 for (current = 0; current < rule_count; current++)
106 {
107 switch (rule->type)
108 {
109 case U_INT_4:
110 {
111 u_int8_t *output_pos = output + rule->offset;
112 if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
113 {
114 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_4");
115 pld->destroy(pld);
116 return PARSE_ERROR;
117 }
118 switch (this->bit_pos)
119 {
120 case 0:
121 *output_pos = *(this->byte_pos) >> 4;
122 this->bit_pos = 4;
123 break;
124 case 4:
125 *output_pos = *(this->byte_pos) & 0x0F;
126 this->bit_pos = 0;
127 this->byte_pos++;
128 break;
129 default:
130 this->logger->log(this->logger, ERROR, "found rule U_INT_4 on bitpos %d", this->bit_pos);
131 pld->destroy(pld);
132 return PARSE_ERROR;
133 }
134 break;
135 }
136 case U_INT_8:
137 {
138 u_int8_t *output_pos = output + rule->offset;
139 if (this->byte_pos + sizeof(u_int8_t) > this->input_roof)
140 {
141 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_8");
142 pld->destroy(pld);
143 return PARSE_ERROR;
144 }
145 if (this->bit_pos)
146 {
147 this->logger->log(this->logger, ERROR, "found rule U_INT_8 on bitpos %d", this->bit_pos);
148 pld->destroy(pld);
149 return PARSE_ERROR;
150 }
151
152 *output_pos = *(this->byte_pos);
153 this->byte_pos++;
154 break;
155 }
156 case U_INT_16:
157 {
158 u_int16_t *output_pos = output + rule->offset;
159 if (this->byte_pos + sizeof(u_int16_t) > this->input_roof)
160 {
161 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_16");
162 pld->destroy(pld);
163 return PARSE_ERROR;
164 }
165 if (this->bit_pos)
166 {
167 this->logger->log(this->logger, ERROR, "found rule U_INT_16 on bitpos %d", this->bit_pos);
168 pld->destroy(pld);
169 return PARSE_ERROR;
170 }
171 if ((int)this->byte_pos % 2)
172 {
173 this->logger->log(this->logger, ERROR, "found rule U_INT_16 on odd bytepos");
174 pld->destroy(pld);
175 return PARSE_ERROR;
176 }
177 *output_pos = ntohs(*((u_int16_t*)this->byte_pos));
178 this->byte_pos += 2;
179 break;
180 }
181 case U_INT_32:
182 {
183 u_int32_t *output_pos = output + rule->offset;
184 if (this->byte_pos + sizeof(u_int32_t) > this->input_roof)
185 {
186 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_32");
187 pld->destroy(pld);
188 return PARSE_ERROR;
189 }
190 if (this->bit_pos)
191 {
192 this->logger->log(this->logger, ERROR, "found rule U_INT_32 on bitpos %d", this->bit_pos);
193 pld->destroy(pld);
194 return PARSE_ERROR;
195 }
196 if ((int)this->byte_pos % 4)
197 {
198 this->logger->log(this->logger, ERROR, "found rule U_INT_32 on unaligned bytepos");
199 pld->destroy(pld);
200 return PARSE_ERROR;
201 }
202 *output_pos = ntohl(*((u_int32_t*)this->byte_pos));
203 this->byte_pos += 4;
204 break;
205 }
206 case U_INT_64:
207 {
208 u_int32_t *output_pos = output + rule->offset;
209 if (this->byte_pos + 2 * sizeof(u_int32_t) > this->input_roof)
210 {
211 this->logger->log(this->logger, ERROR, "not enough input to parse U_INT_64");
212 pld->destroy(pld);
213 return PARSE_ERROR;
214 }
215 if (this->bit_pos)
216 {
217 this->logger->log(this->logger, ERROR, "found rule U_INT_64 on bitpos %d", this->bit_pos);
218 pld->destroy(pld);
219 return PARSE_ERROR;
220 }
221 if ((int)this->byte_pos % 8)
222 {
223 this->logger->log(this->logger, ERROR, "found rule U_INT_64 on unaligned bytepos");
224 pld->destroy(pld);
225 return PARSE_ERROR;
226 }
227 /* assuming little endian host order */
228 *(output_pos + 1) = ntohl(*((u_int32_t*)this->byte_pos));
229 this->byte_pos += 4;
230 *output_pos = ntohl(*((u_int32_t*)this->byte_pos));
231 this->byte_pos += 4;
232
233 break;
234 }
235 case RESERVED_BIT:
236 {
237 if (this->byte_pos > this->input_roof)
238 {
239 this->logger->log(this->logger, ERROR, "not enough input to parse RESERVED_BIT");
240 pld->destroy(pld);
241 return PARSE_ERROR;
242 }
243 this->bit_pos = (this->bit_pos + 1) % 8;
244 if (this->bit_pos == 0)
245 {
246 this->byte_pos++;
247 }
248 break;
249 }
250 case RESERVED_BYTE:
251 {
252 if (this->byte_pos > this->input_roof)
253 {
254 this->logger->log(this->logger, ERROR, "not enough input to parse RESERVED_BYTE");
255 pld->destroy(pld);
256 return PARSE_ERROR;
257 }
258 if (this->bit_pos)
259 {
260 this->logger->log(this->logger, ERROR, "found rule RESERVED_BYTE on bitpos %d", this->bit_pos);
261 pld->destroy(pld);
262 return PARSE_ERROR;
263 }
264 this->byte_pos++;
265 break;
266 }
267 case FLAG:
268 {
269 bool *output_pos = output + rule->offset;
270 u_int8_t mask;
271 if (this->byte_pos > this->input_roof)
272 {
273 this->logger->log(this->logger, ERROR, "not enough input to parse FLAG");
274 pld->destroy(pld);
275 return PARSE_ERROR;
276 }
277 mask = 0x01 << (7 - this->bit_pos);
278 *output_pos = *this->byte_pos & mask;
279
280 if (*output_pos)
281 {
282 /* set to a "clean", comparable true */
283 *output_pos = TRUE;
284 }
285 this->bit_pos = (this->bit_pos + 1) % 8;
286 if (this->bit_pos == 0)
287 {
288 this->byte_pos++;
289 }
290 break;
291 }
292 case LENGTH:
293 {
294 u_int32_t *output_pos = output + rule->offset;
295 if (this->byte_pos + sizeof(u_int32_t) > this->input_roof)
296 {
297 this->logger->log(this->logger, ERROR, "not enough input to parse LENGTH");
298 pld->destroy(pld);
299 return PARSE_ERROR;
300 }
301 if (this->bit_pos)
302 {
303 this->logger->log(this->logger, ERROR, "found rule LENGTH on bitpos %d", this->bit_pos);
304 pld->destroy(pld);
305 return PARSE_ERROR;
306 }
307 if ((int)this->byte_pos % 4)
308 {
309 this->logger->log(this->logger, ERROR, "found rule LENGTH on unaligned bytepos");
310 pld->destroy(pld);
311 return PARSE_ERROR;
312 }
313 *output_pos = ntohl(*((u_int32_t*)this->byte_pos));
314 this->byte_pos += 4;
315 break;
316
317 }
318 case SPI_SIZE:
319 {
320
321 }
322 default:
323 {
324 this->logger->log(this->logger, ERROR, "parser found unknown type");
325 pld->destroy(pld);
326 return PARSE_ERROR;
327 }
328 }
329 /* process next rulue */
330 rule++;
331 }
332
333 *payload = pld;
334 return SUCCESS;
335 }
336
337 /**
338 * implementation of parser_t.destroy
339 */
340 static status_t destroy(private_parser_t *this)
341 {
342 global_logger_manager->destroy_logger(global_logger_manager,this->logger);
343 allocator_free(this);
344
345 return SUCCESS;
346 }
347
348 /*
349 * see header file
350 */
351 parser_t *parser_create(chunk_t data)
352 {
353 private_parser_t *this = allocator_alloc_thing(private_parser_t);
354
355 if (this == NULL)
356 {
357 return NULL;
358 }
359
360 this->logger = global_logger_manager->create_logger(global_logger_manager, PARSER, NULL);
361
362 if (this->logger == NULL)
363 {
364 allocator_free(this);
365 return NULL;
366 }
367
368 this->public.parse_payload = (status_t(*)(parser_t*,payload_type_t,payload_t**)) parse_payload;
369 this->public.destroy = (status_t(*)(parser_t*)) destroy;
370
371
372 this->input = data.ptr;
373 this->byte_pos = data.ptr;
374 this->bit_pos = 0;
375 this->input_roof = data.ptr + data.len;
376
377 return (parser_t*)this;
378 }
379