2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include <arpa/inet.h>
20 #include "ha_message.h"
24 #define ALLOCATION_BLOCK 64
26 typedef struct private_ha_message_t private_ha_message_t
;
29 * Private data of an ha_message_t object.
31 struct private_ha_message_t
{
34 * Public ha_message_t interface.
39 * Allocated size of buf
44 * Buffer containing encoded data
49 ENUM(ha_message_type_names
, HA_IKE_ADD
, HA_IKE_IV
,
64 typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t
;
67 * Encoding if an ike_sa_id_t
69 struct ike_sa_id_encoding_t
{
71 u_int64_t initiator_spi
;
72 u_int64_t responder_spi
;
74 } __attribute__((packed
));
76 typedef struct identification_encoding_t identification_encoding_t
;
79 * Encoding of a identification_t
81 struct identification_encoding_t
{
85 } __attribute__((packed
));
87 typedef struct host_encoding_t host_encoding_t
;
90 * encoding of a host_t
92 struct host_encoding_t
{
96 } __attribute__((packed
));
98 typedef struct ts_encoding_t ts_encoding_t
;
101 * encoding of a traffic_selector_t
103 struct ts_encoding_t
{
110 } __attribute__((packed
));
112 METHOD(ha_message_t
, get_type
, ha_message_type_t
,
113 private_ha_message_t
*this)
115 return this->buf
.ptr
[1];
119 * check for space in buffer, increase if necessary
121 static void check_buf(private_ha_message_t
*this, size_t len
)
125 while (this->buf
.len
+ len
> this->allocated
)
127 this->allocated
+= ALLOCATION_BLOCK
;
132 this->buf
.ptr
= realloc(this->buf
.ptr
, this->allocated
);
136 METHOD(ha_message_t
, add_attribute
, void,
137 private_ha_message_t
*this, ha_message_attribute_t attribute
, ...)
142 check_buf(this, sizeof(u_int8_t
));
143 this->buf
.ptr
[this->buf
.len
] = attribute
;
144 this->buf
.len
+= sizeof(u_int8_t
);
146 va_start(args
, attribute
);
151 case HA_IKE_REKEY_ID
:
153 ike_sa_id_encoding_t
*enc
;
156 id
= va_arg(args
, ike_sa_id_t
*);
157 check_buf(this, sizeof(ike_sa_id_encoding_t
));
158 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
159 this->buf
.len
+= sizeof(ike_sa_id_encoding_t
);
160 enc
->initiator
= id
->is_initiator(id
);
161 enc
->ike_version
= id
->get_ike_version(id
);
162 enc
->initiator_spi
= id
->get_initiator_spi(id
);
163 enc
->responder_spi
= id
->get_responder_spi(id
);
166 /* identification_t* */
169 case HA_REMOTE_EAP_ID
:
171 identification_encoding_t
*enc
;
172 identification_t
*id
;
175 id
= va_arg(args
, identification_t
*);
176 data
= id
->get_encoding(id
);
177 check_buf(this, sizeof(identification_encoding_t
) + data
.len
);
178 enc
= (identification_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
179 this->buf
.len
+= sizeof(identification_encoding_t
) + data
.len
;
180 enc
->type
= id
->get_type(id
);
182 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
192 host_encoding_t
*enc
;
196 host
= va_arg(args
, host_t
*);
197 data
= host
->get_address(host
);
198 check_buf(this, sizeof(host_encoding_t
) + data
.len
);
199 enc
= (host_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
200 this->buf
.len
+= sizeof(host_encoding_t
) + data
.len
;
201 enc
->family
= host
->get_family(host
);
202 enc
->port
= htons(host
->get_port(host
));
203 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
211 str
= va_arg(args
, char*);
212 len
= strlen(str
) + 1;
213 check_buf(this, len
);
214 memcpy(this->buf
.ptr
+ this->buf
.len
, str
, len
);
215 this->buf
.len
+= len
;
226 val
= va_arg(args
, u_int
);
227 check_buf(this, sizeof(val
));
228 this->buf
.ptr
[this->buf
.len
] = val
;
229 this->buf
.len
+= sizeof(val
);
236 case HA_ALG_ENCR_LEN
:
239 case HA_OUTBOUND_CPI
:
245 val
= va_arg(args
, u_int
);
246 check_buf(this, sizeof(val
));
247 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(val
);
248 this->buf
.len
+= sizeof(val
);
255 case HA_OUTBOUND_SPI
:
260 val
= va_arg(args
, u_int
);
261 check_buf(this, sizeof(val
));
262 *(u_int32_t
*)(this->buf
.ptr
+ this->buf
.len
) = htonl(val
);
263 this->buf
.len
+= sizeof(val
);
278 chunk
= va_arg(args
, chunk_t
);
279 check_buf(this, chunk
.len
+ sizeof(u_int16_t
));
280 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(chunk
.len
);
281 memcpy(this->buf
.ptr
+ this->buf
.len
+ sizeof(u_int16_t
),
282 chunk
.ptr
, chunk
.len
);
283 this->buf
.len
+= chunk
.len
+ sizeof(u_int16_t
);;
286 /** traffic_selector_t */
291 traffic_selector_t
*ts
;
294 ts
= va_arg(args
, traffic_selector_t
*);
295 data
= chunk_cata("cc", ts
->get_from_address(ts
),
296 ts
->get_to_address(ts
));
297 check_buf(this, sizeof(ts_encoding_t
) + data
.len
);
298 enc
= (ts_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
299 this->buf
.len
+= sizeof(ts_encoding_t
) + data
.len
;
300 enc
->type
= ts
->get_type(ts
);
301 enc
->protocol
= ts
->get_protocol(ts
);
302 enc
->from_port
= htons(ts
->get_from_port(ts
));
303 enc
->to_port
= htons(ts
->get_to_port(ts
));
304 enc
->dynamic
= ts
->is_dynamic(ts
);
305 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
310 DBG1(DBG_CFG
, "unable to encode, attribute %d unknown", attribute
);
311 this->buf
.len
-= sizeof(u_int8_t
);
319 * Attribute enumerator implementation
322 /** implementes enumerator_t */
324 /** position in message */
326 /** cleanup handler of current element, if any */
327 void (*cleanup
)(void* data
);
328 /** data to pass to cleanup handler */
330 } attribute_enumerator_t
;
332 METHOD(enumerator_t
, attribute_enumerate
, bool,
333 attribute_enumerator_t
*this, ha_message_attribute_t
*attr_out
,
334 ha_message_value_t
*value
)
336 ha_message_attribute_t attr
;
340 this->cleanup(this->cleanup_data
);
341 this->cleanup
= NULL
;
343 if (this->buf
.len
< 1)
347 attr
= this->buf
.ptr
[0];
348 this->buf
= chunk_skip(this->buf
, 1);
353 case HA_IKE_REKEY_ID
:
355 ike_sa_id_encoding_t
*enc
;
357 if (this->buf
.len
< sizeof(ike_sa_id_encoding_t
))
361 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
);
362 value
->ike_sa_id
= ike_sa_id_create(enc
->ike_version
,
363 enc
->initiator_spi
, enc
->responder_spi
,
366 this->cleanup
= (void*)value
->ike_sa_id
->destroy
;
367 this->cleanup_data
= value
->ike_sa_id
;
368 this->buf
= chunk_skip(this->buf
, sizeof(ike_sa_id_encoding_t
));
371 /* identification_t* */
374 case HA_REMOTE_EAP_ID
:
376 identification_encoding_t
*enc
;
378 enc
= (identification_encoding_t
*)(this->buf
.ptr
);
379 if (this->buf
.len
< sizeof(identification_encoding_t
) ||
380 this->buf
.len
< sizeof(identification_encoding_t
) + enc
->len
)
384 value
->id
= identification_create_from_encoding(enc
->type
,
385 chunk_create(enc
->encoding
, enc
->len
));
387 this->cleanup
= (void*)value
->id
->destroy
;
388 this->cleanup_data
= value
->id
;
389 this->buf
= chunk_skip(this->buf
,
390 sizeof(identification_encoding_t
) + enc
->len
);
400 host_encoding_t
*enc
;
402 enc
= (host_encoding_t
*)(this->buf
.ptr
);
403 if (this->buf
.len
< sizeof(host_encoding_t
))
407 value
->host
= host_create_from_chunk(enc
->family
,
408 chunk_create(enc
->encoding
,
409 this->buf
.len
- sizeof(host_encoding_t
)),
416 this->cleanup
= (void*)value
->host
->destroy
;
417 this->cleanup_data
= value
->host
;
418 this->buf
= chunk_skip(this->buf
, sizeof(host_encoding_t
) +
419 value
->host
->get_address(value
->host
).len
);
427 len
= strnlen(this->buf
.ptr
, this->buf
.len
);
428 if (len
>= this->buf
.len
)
432 value
->str
= this->buf
.ptr
;
434 this->buf
= chunk_skip(this->buf
, len
+ 1);
443 if (this->buf
.len
< sizeof(u_int8_t
))
447 value
->u8
= *(u_int8_t
*)this->buf
.ptr
;
449 this->buf
= chunk_skip(this->buf
, sizeof(u_int8_t
));
456 case HA_ALG_ENCR_LEN
:
459 case HA_OUTBOUND_CPI
:
463 if (this->buf
.len
< sizeof(u_int16_t
))
467 value
->u16
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
469 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
476 case HA_OUTBOUND_SPI
:
479 if (this->buf
.len
< sizeof(u_int32_t
))
483 value
->u32
= ntohl(*(u_int32_t
*)this->buf
.ptr
);
485 this->buf
= chunk_skip(this->buf
, sizeof(u_int32_t
));
500 if (this->buf
.len
< sizeof(u_int16_t
))
504 len
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
505 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
506 if (this->buf
.len
< len
)
510 value
->chunk
.len
= len
;
511 value
->chunk
.ptr
= this->buf
.ptr
;
513 this->buf
= chunk_skip(this->buf
, len
);
523 enc
= (ts_encoding_t
*)(this->buf
.ptr
);
524 if (this->buf
.len
< sizeof(ts_encoding_t
))
530 case TS_IPV4_ADDR_RANGE
:
532 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
537 case TS_IPV6_ADDR_RANGE
:
539 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
549 host
= host_create_from_chunk(0,
550 chunk_create(enc
->encoding
, addr_len
), 0);
555 value
->ts
= traffic_selector_create_dynamic(enc
->protocol
,
556 ntohs(enc
->from_port
), ntohs(enc
->to_port
));
557 value
->ts
->set_address(value
->ts
, host
);
562 value
->ts
= traffic_selector_create_from_bytes(enc
->protocol
,
563 enc
->type
, chunk_create(enc
->encoding
, addr_len
),
564 ntohs(enc
->from_port
),
565 chunk_create(enc
->encoding
+ addr_len
, addr_len
),
566 ntohs(enc
->to_port
));
573 this->cleanup
= (void*)value
->ts
->destroy
;
574 this->cleanup_data
= value
->ts
;
575 this->buf
= chunk_skip(this->buf
, sizeof(ts_encoding_t
)
586 METHOD(enumerator_t
, enum_destroy
, void,
587 attribute_enumerator_t
*this)
591 this->cleanup(this->cleanup_data
);
596 METHOD(ha_message_t
, create_attribute_enumerator
, enumerator_t
*,
597 private_ha_message_t
*this)
599 attribute_enumerator_t
*e
;
603 .enumerate
= (void*)_attribute_enumerate
,
604 .destroy
= _enum_destroy
,
606 .buf
= chunk_skip(this->buf
, 2),
612 METHOD(ha_message_t
, get_encoding
, chunk_t
,
613 private_ha_message_t
*this)
618 METHOD(ha_message_t
, destroy
, void,
619 private_ha_message_t
*this)
626 static private_ha_message_t
*ha_message_create_generic()
628 private_ha_message_t
*this;
632 .get_type
= _get_type
,
633 .add_attribute
= _add_attribute
,
634 .create_attribute_enumerator
= _create_attribute_enumerator
,
635 .get_encoding
= _get_encoding
,
645 ha_message_t
*ha_message_create(ha_message_type_t type
)
647 private_ha_message_t
*this = ha_message_create_generic();
649 this->allocated
= ALLOCATION_BLOCK
;
650 this->buf
.ptr
= malloc(this->allocated
);
652 this->buf
.ptr
[0] = HA_MESSAGE_VERSION
;
653 this->buf
.ptr
[1] = type
;
655 return &this->public;
661 ha_message_t
*ha_message_parse(chunk_t data
)
663 private_ha_message_t
*this;
667 DBG1(DBG_CFG
, "HA message too short");
670 if (data
.ptr
[0] != HA_MESSAGE_VERSION
)
672 DBG1(DBG_CFG
, "HA message has version %d, expected %d",
673 data
.ptr
[0], HA_MESSAGE_VERSION
);
677 this = ha_message_create_generic();
678 this->buf
= chunk_clone(data
);
679 this->allocated
= this->buf
.len
;
681 return &this->public;