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>
29 #include "definitions.h"
31 #include "utils/allocator.h"
32 #include "utils/logger.h"
33 #include "payloads/payload.h"
36 * @private data stored in a context
38 * contains pointers and counters to store current state
40 typedef struct private_parser_s private_parser_t
;
42 struct private_parser_s
{
49 * Current bit for reading in input data
54 * Current byte for reading in input data
77 * implementation of parser_context_t.parse_payload
79 static status_t
parse_payload(private_parser_t
*this, payload_type_t payload_type
, payload_t
**payload
)
82 this->logger
->log(this->logger
, CONTROL
, "Parsing a %s payload", mapping_find(payload_type_t_mappings
, payload_type
));
84 /* find payload in null terminated list*/
89 encoding_rule_t
*rule
;
92 /* ok, do the parsing */
93 pld
= payload_create(payload_type
);
96 this->logger
->log(this->logger
, ERROR
, "Payload not supported");
100 /* base pointer for output, avoids casting in every rule */
103 pld
->get_encoding_rules(pld
, &rule
, &rule_count
);
105 for (current
= 0; current
< rule_count
; current
++)
111 u_int8_t
*output_pos
= output
+ rule
->offset
;
112 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
114 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_4");
118 switch (this->bit_pos
)
121 *output_pos
= *(this->byte_pos
) >> 4;
125 *output_pos
= *(this->byte_pos
) & 0x0F;
130 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_4 on bitpos %d", this->bit_pos
);
138 u_int8_t
*output_pos
= output
+ rule
->offset
;
139 if (this->byte_pos
+ sizeof(u_int8_t
) > this->input_roof
)
141 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_8");
147 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_8 on bitpos %d", this->bit_pos
);
152 *output_pos
= *(this->byte_pos
);
158 u_int16_t
*output_pos
= output
+ rule
->offset
;
159 if (this->byte_pos
+ sizeof(u_int16_t
) > this->input_roof
)
161 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_16");
167 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on bitpos %d", this->bit_pos
);
171 if ((int)this->byte_pos
% 2)
173 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_16 on odd bytepos");
177 *output_pos
= ntohs(*((u_int16_t
*)this->byte_pos
));
183 u_int32_t
*output_pos
= output
+ rule
->offset
;
184 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
186 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_32");
192 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on bitpos %d", this->bit_pos
);
196 if ((int)this->byte_pos
% 4)
198 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_32 on unaligned bytepos");
202 *output_pos
= ntohl(*((u_int32_t
*)this->byte_pos
));
208 u_int32_t
*output_pos
= output
+ rule
->offset
;
209 if (this->byte_pos
+ 2 * sizeof(u_int32_t
) > this->input_roof
)
211 this->logger
->log(this->logger
, ERROR
, "not enough input to parse U_INT_64");
217 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on bitpos %d", this->bit_pos
);
221 if ((int)this->byte_pos
% 8)
223 this->logger
->log(this->logger
, ERROR
, "found rule U_INT_64 on unaligned bytepos");
227 /* assuming little endian host order */
228 *(output_pos
+ 1) = ntohl(*((u_int32_t
*)this->byte_pos
));
230 *output_pos
= ntohl(*((u_int32_t
*)this->byte_pos
));
237 if (this->byte_pos
> this->input_roof
)
239 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BIT");
243 this->bit_pos
= (this->bit_pos
+ 1) % 8;
244 if (this->bit_pos
== 0)
252 if (this->byte_pos
> this->input_roof
)
254 this->logger
->log(this->logger
, ERROR
, "not enough input to parse RESERVED_BYTE");
260 this->logger
->log(this->logger
, ERROR
, "found rule RESERVED_BYTE on bitpos %d", this->bit_pos
);
269 bool *output_pos
= output
+ rule
->offset
;
271 if (this->byte_pos
> this->input_roof
)
273 this->logger
->log(this->logger
, ERROR
, "not enough input to parse FLAG");
277 mask
= 0x01 << (7 - this->bit_pos
);
278 *output_pos
= *this->byte_pos
& mask
;
282 /* set to a "clean", comparable true */
285 this->bit_pos
= (this->bit_pos
+ 1) % 8;
286 if (this->bit_pos
== 0)
294 u_int32_t
*output_pos
= output
+ rule
->offset
;
295 if (this->byte_pos
+ sizeof(u_int32_t
) > this->input_roof
)
297 this->logger
->log(this->logger
, ERROR
, "not enough input to parse LENGTH");
303 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on bitpos %d", this->bit_pos
);
307 if ((int)this->byte_pos
% 4)
309 this->logger
->log(this->logger
, ERROR
, "found rule LENGTH on unaligned bytepos");
313 *output_pos
= ntohl(*((u_int32_t
*)this->byte_pos
));
324 this->logger
->log(this->logger
, ERROR
, "parser found unknown type");
329 /* process next rulue */
338 * implementation of parser_t.destroy
340 static status_t
destroy(private_parser_t
*this)
342 global_logger_manager
->destroy_logger(global_logger_manager
,this->logger
);
343 allocator_free(this);
351 parser_t
*parser_create(chunk_t data
)
353 private_parser_t
*this = allocator_alloc_thing(private_parser_t
);
360 this->logger
= global_logger_manager
->create_logger(global_logger_manager
, PARSER
, NULL
);
362 if (this->logger
== NULL
)
364 allocator_free(this);
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
;
372 this->input
= data
.ptr
;
373 this->byte_pos
= data
.ptr
;
375 this->input_roof
= data
.ptr
+ data
.len
;
377 return (parser_t
*)this;