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_RESYNC
,
63 typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t
;
66 * Encoding if an ike_sa_id_t
68 struct ike_sa_id_encoding_t
{
69 u_int64_t initiator_spi
;
70 u_int64_t responder_spi
;
72 } __attribute__((packed
));
74 typedef struct identification_encoding_t identification_encoding_t
;
77 * Encoding of a identification_t
79 struct identification_encoding_t
{
83 } __attribute__((packed
));
85 typedef struct host_encoding_t host_encoding_t
;
88 * encoding of a host_t
90 struct host_encoding_t
{
94 } __attribute__((packed
));
96 typedef struct ts_encoding_t ts_encoding_t
;
99 * encoding of a traffic_selector_t
101 struct ts_encoding_t
{
108 } __attribute__((packed
));
110 METHOD(ha_message_t
, get_type
, ha_message_type_t
,
111 private_ha_message_t
*this)
113 return this->buf
.ptr
[1];
117 * check for space in buffer, increase if necessary
119 static void check_buf(private_ha_message_t
*this, size_t len
)
123 while (this->buf
.len
+ len
> this->allocated
)
125 this->allocated
+= ALLOCATION_BLOCK
;
130 this->buf
.ptr
= realloc(this->buf
.ptr
, this->allocated
);
134 METHOD(ha_message_t
, add_attribute
, void,
135 private_ha_message_t
*this, ha_message_attribute_t attribute
, ...)
140 check_buf(this, sizeof(u_int8_t
));
141 this->buf
.ptr
[this->buf
.len
] = attribute
;
142 this->buf
.len
+= sizeof(u_int8_t
);
144 va_start(args
, attribute
);
149 case HA_IKE_REKEY_ID
:
151 ike_sa_id_encoding_t
*enc
;
154 id
= va_arg(args
, ike_sa_id_t
*);
155 check_buf(this, sizeof(ike_sa_id_encoding_t
));
156 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
157 this->buf
.len
+= sizeof(ike_sa_id_encoding_t
);
158 enc
->initiator
= id
->is_initiator(id
);
159 enc
->initiator_spi
= id
->get_initiator_spi(id
);
160 enc
->responder_spi
= id
->get_responder_spi(id
);
163 /* identification_t* */
166 case HA_REMOTE_EAP_ID
:
168 identification_encoding_t
*enc
;
169 identification_t
*id
;
172 id
= va_arg(args
, identification_t
*);
173 data
= id
->get_encoding(id
);
174 check_buf(this, sizeof(identification_encoding_t
) + data
.len
);
175 enc
= (identification_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
176 this->buf
.len
+= sizeof(identification_encoding_t
) + data
.len
;
177 enc
->type
= id
->get_type(id
);
179 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
189 host_encoding_t
*enc
;
193 host
= va_arg(args
, host_t
*);
194 data
= host
->get_address(host
);
195 check_buf(this, sizeof(host_encoding_t
) + data
.len
);
196 enc
= (host_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
197 this->buf
.len
+= sizeof(host_encoding_t
) + data
.len
;
198 enc
->family
= host
->get_family(host
);
199 enc
->port
= htons(host
->get_port(host
));
200 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
208 str
= va_arg(args
, char*);
209 len
= strlen(str
) + 1;
210 check_buf(this, len
);
211 memcpy(this->buf
.ptr
+ this->buf
.len
, str
, len
);
212 this->buf
.len
+= len
;
222 val
= va_arg(args
, u_int
);
223 check_buf(this, sizeof(val
));
224 this->buf
.ptr
[this->buf
.len
] = val
;
225 this->buf
.len
+= sizeof(val
);
232 case HA_ALG_ENCR_LEN
:
235 case HA_OUTBOUND_CPI
:
241 val
= va_arg(args
, u_int
);
242 check_buf(this, sizeof(val
));
243 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(val
);
244 this->buf
.len
+= sizeof(val
);
251 case HA_OUTBOUND_SPI
:
256 val
= va_arg(args
, u_int
);
257 check_buf(this, sizeof(val
));
258 *(u_int32_t
*)(this->buf
.ptr
+ this->buf
.len
) = htonl(val
);
259 this->buf
.len
+= sizeof(val
);
270 chunk
= va_arg(args
, chunk_t
);
271 check_buf(this, chunk
.len
+ sizeof(u_int16_t
));
272 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(chunk
.len
);
273 memcpy(this->buf
.ptr
+ this->buf
.len
+ sizeof(u_int16_t
),
274 chunk
.ptr
, chunk
.len
);
275 this->buf
.len
+= chunk
.len
+ sizeof(u_int16_t
);;
278 /** traffic_selector_t */
283 traffic_selector_t
*ts
;
286 ts
= va_arg(args
, traffic_selector_t
*);
287 data
= chunk_cata("cc", ts
->get_from_address(ts
),
288 ts
->get_to_address(ts
));
289 check_buf(this, sizeof(ts_encoding_t
) + data
.len
);
290 enc
= (ts_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
291 this->buf
.len
+= sizeof(ts_encoding_t
) + data
.len
;
292 enc
->type
= ts
->get_type(ts
);
293 enc
->protocol
= ts
->get_protocol(ts
);
294 enc
->from_port
= htons(ts
->get_from_port(ts
));
295 enc
->to_port
= htons(ts
->get_to_port(ts
));
296 enc
->dynamic
= ts
->is_dynamic(ts
);
297 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
302 DBG1(DBG_CFG
, "unable to encode, attribute %d unknown", attribute
);
303 this->buf
.len
-= sizeof(u_int8_t
);
311 * Attribute enumerator implementation
314 /** implementes enumerator_t */
316 /** position in message */
318 /** cleanup handler of current element, if any */
319 void (*cleanup
)(void* data
);
320 /** data to pass to cleanup handler */
322 } attribute_enumerator_t
;
324 METHOD(enumerator_t
, attribute_enumerate
, bool,
325 attribute_enumerator_t
*this, ha_message_attribute_t
*attr_out
,
326 ha_message_value_t
*value
)
328 ha_message_attribute_t attr
;
332 this->cleanup(this->cleanup_data
);
333 this->cleanup
= NULL
;
335 if (this->buf
.len
< 1)
339 attr
= this->buf
.ptr
[0];
340 this->buf
= chunk_skip(this->buf
, 1);
345 case HA_IKE_REKEY_ID
:
347 ike_sa_id_encoding_t
*enc
;
349 if (this->buf
.len
< sizeof(ike_sa_id_encoding_t
))
353 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
);
354 value
->ike_sa_id
= ike_sa_id_create(enc
->initiator_spi
,
355 enc
->responder_spi
, enc
->initiator
);
357 this->cleanup
= (void*)value
->ike_sa_id
->destroy
;
358 this->cleanup_data
= value
->ike_sa_id
;
359 this->buf
= chunk_skip(this->buf
, sizeof(ike_sa_id_encoding_t
));
362 /* identification_t* */
365 case HA_REMOTE_EAP_ID
:
367 identification_encoding_t
*enc
;
369 enc
= (identification_encoding_t
*)(this->buf
.ptr
);
370 if (this->buf
.len
< sizeof(identification_encoding_t
) ||
371 this->buf
.len
< sizeof(identification_encoding_t
) + enc
->len
)
375 value
->id
= identification_create_from_encoding(enc
->type
,
376 chunk_create(enc
->encoding
, enc
->len
));
378 this->cleanup
= (void*)value
->id
->destroy
;
379 this->cleanup_data
= value
->id
;
380 this->buf
= chunk_skip(this->buf
,
381 sizeof(identification_encoding_t
) + enc
->len
);
391 host_encoding_t
*enc
;
393 enc
= (host_encoding_t
*)(this->buf
.ptr
);
394 if (this->buf
.len
< sizeof(host_encoding_t
))
398 value
->host
= host_create_from_chunk(enc
->family
,
399 chunk_create(enc
->encoding
,
400 this->buf
.len
- sizeof(host_encoding_t
)),
407 this->cleanup
= (void*)value
->host
->destroy
;
408 this->cleanup_data
= value
->host
;
409 this->buf
= chunk_skip(this->buf
, sizeof(host_encoding_t
) +
410 value
->host
->get_address(value
->host
).len
);
418 len
= strnlen(this->buf
.ptr
, this->buf
.len
);
419 if (len
>= this->buf
.len
)
423 value
->str
= this->buf
.ptr
;
425 this->buf
= chunk_skip(this->buf
, len
+ 1);
433 if (this->buf
.len
< sizeof(u_int8_t
))
437 value
->u8
= *(u_int8_t
*)this->buf
.ptr
;
439 this->buf
= chunk_skip(this->buf
, sizeof(u_int8_t
));
446 case HA_ALG_ENCR_LEN
:
449 case HA_OUTBOUND_CPI
:
453 if (this->buf
.len
< sizeof(u_int16_t
))
457 value
->u16
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
459 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
466 case HA_OUTBOUND_SPI
:
469 if (this->buf
.len
< sizeof(u_int32_t
))
473 value
->u32
= ntohl(*(u_int32_t
*)this->buf
.ptr
);
475 this->buf
= chunk_skip(this->buf
, sizeof(u_int32_t
));
486 if (this->buf
.len
< sizeof(u_int16_t
))
490 len
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
491 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
492 if (this->buf
.len
< len
)
496 value
->chunk
.len
= len
;
497 value
->chunk
.ptr
= this->buf
.ptr
;
499 this->buf
= chunk_skip(this->buf
, len
);
509 enc
= (ts_encoding_t
*)(this->buf
.ptr
);
510 if (this->buf
.len
< sizeof(ts_encoding_t
))
516 case TS_IPV4_ADDR_RANGE
:
518 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
523 case TS_IPV6_ADDR_RANGE
:
525 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
535 host
= host_create_from_chunk(0,
536 chunk_create(enc
->encoding
, addr_len
), 0);
541 value
->ts
= traffic_selector_create_dynamic(enc
->protocol
,
542 ntohs(enc
->from_port
), ntohs(enc
->to_port
));
543 value
->ts
->set_address(value
->ts
, host
);
548 value
->ts
= traffic_selector_create_from_bytes(enc
->protocol
,
549 enc
->type
, chunk_create(enc
->encoding
, addr_len
),
550 ntohs(enc
->from_port
),
551 chunk_create(enc
->encoding
+ addr_len
, addr_len
),
552 ntohs(enc
->to_port
));
559 this->cleanup
= (void*)value
->ts
->destroy
;
560 this->cleanup_data
= value
->ts
;
561 this->buf
= chunk_skip(this->buf
, sizeof(ts_encoding_t
)
572 METHOD(enumerator_t
, enum_destroy
, void,
573 attribute_enumerator_t
*this)
577 this->cleanup(this->cleanup_data
);
582 METHOD(ha_message_t
, create_attribute_enumerator
, enumerator_t
*,
583 private_ha_message_t
*this)
585 attribute_enumerator_t
*e
;
589 .enumerate
= (void*)_attribute_enumerate
,
590 .destroy
= _enum_destroy
,
592 .buf
= chunk_skip(this->buf
, 2),
598 METHOD(ha_message_t
, get_encoding
, chunk_t
,
599 private_ha_message_t
*this)
604 METHOD(ha_message_t
, destroy
, void,
605 private_ha_message_t
*this)
612 static private_ha_message_t
*ha_message_create_generic()
614 private_ha_message_t
*this;
618 .get_type
= _get_type
,
619 .add_attribute
= _add_attribute
,
620 .create_attribute_enumerator
= _create_attribute_enumerator
,
621 .get_encoding
= _get_encoding
,
631 ha_message_t
*ha_message_create(ha_message_type_t type
)
633 private_ha_message_t
*this = ha_message_create_generic();
635 this->allocated
= ALLOCATION_BLOCK
;
636 this->buf
.ptr
= malloc(this->allocated
);
638 this->buf
.ptr
[0] = HA_MESSAGE_VERSION
;
639 this->buf
.ptr
[1] = type
;
641 return &this->public;
647 ha_message_t
*ha_message_parse(chunk_t data
)
649 private_ha_message_t
*this;
653 DBG1(DBG_CFG
, "HA message too short");
656 if (data
.ptr
[0] != HA_MESSAGE_VERSION
)
658 DBG1(DBG_CFG
, "HA message has version %d, expected %d",
659 data
.ptr
[0], HA_MESSAGE_VERSION
);
663 this = ha_message_create_generic();
664 this->buf
= chunk_clone(data
);
665 this->allocated
= this->buf
.len
;
667 return &this->public;