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_sync_message.h"
24 #define ALLOCATION_BLOCK 64
26 typedef struct private_ha_sync_message_t private_ha_sync_message_t
;
29 * Private data of an ha_sync_message_t object.
31 struct private_ha_sync_message_t
{
34 * Public ha_sync_message_t interface.
36 ha_sync_message_t
public;
39 * Allocated size of buf
44 * Buffer containing encoded data
49 typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t
;
52 * Encoding if an ike_sa_id_t
54 struct ike_sa_id_encoding_t
{
55 u_int64_t initiator_spi
;
56 u_int64_t responder_spi
;
58 } __attribute__((packed
));
60 typedef struct identification_encoding_t identification_encoding_t
;
63 * Encoding of a identification_t
65 struct identification_encoding_t
{
69 } __attribute__((packed
));
71 typedef struct host_encoding_t host_encoding_t
;
74 * encoding of a host_t
76 struct host_encoding_t
{
80 } __attribute__((packed
));
82 typedef struct ts_encoding_t ts_encoding_t
;
85 * encoding of a traffic_selector_t
87 struct ts_encoding_t
{
94 } __attribute__((packed
));
97 * Implementation of ha_sync_message_t.get_type
99 static ha_sync_message_type_t
get_type(private_ha_sync_message_t
*this)
101 return this->buf
.ptr
[1];
105 * check for space in buffer, increase if necessary
107 static void check_buf(private_ha_sync_message_t
*this, size_t len
)
111 while (this->buf
.len
+ len
> this->allocated
)
113 this->allocated
+= ALLOCATION_BLOCK
;
118 this->buf
.ptr
= realloc(this->buf
.ptr
, this->allocated
);
123 * Implementation of ha_sync_message_t.add_attribute
125 static void add_attribute(private_ha_sync_message_t
*this,
126 ha_sync_message_attribute_t attribute
, ...)
131 check_buf(this, sizeof(u_int8_t
));
132 this->buf
.ptr
[this->buf
.len
] = attribute
;
133 this->buf
.len
+= sizeof(u_int8_t
);
135 va_start(args
, attribute
);
140 case HA_SYNC_IKE_REKEY_ID
:
142 ike_sa_id_encoding_t
*enc
;
145 id
= va_arg(args
, ike_sa_id_t
*);
146 check_buf(this, sizeof(ike_sa_id_encoding_t
));
147 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
148 this->buf
.len
+= sizeof(ike_sa_id_encoding_t
);
149 enc
->initiator
= id
->is_initiator(id
);
150 enc
->initiator_spi
= id
->get_initiator_spi(id
);
151 enc
->responder_spi
= id
->get_responder_spi(id
);
154 /* identification_t* */
155 case HA_SYNC_LOCAL_ID
:
156 case HA_SYNC_REMOTE_ID
:
159 identification_encoding_t
*enc
;
160 identification_t
*id
;
163 id
= va_arg(args
, identification_t
*);
164 data
= id
->get_encoding(id
);
165 check_buf(this, sizeof(identification_encoding_t
) + data
.len
);
166 enc
= (identification_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
167 this->buf
.len
+= sizeof(identification_encoding_t
) + data
.len
;
168 enc
->type
= id
->get_type(id
);
170 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
174 case HA_SYNC_LOCAL_ADDR
:
175 case HA_SYNC_REMOTE_ADDR
:
176 case HA_SYNC_LOCAL_VIP
:
177 case HA_SYNC_REMOTE_VIP
:
178 case HA_SYNC_ADDITIONAL_ADDR
:
180 host_encoding_t
*enc
;
184 host
= va_arg(args
, host_t
*);
185 data
= host
->get_address(host
);
186 check_buf(this, sizeof(host_encoding_t
) + data
.len
);
187 enc
= (host_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
188 this->buf
.len
+= sizeof(host_encoding_t
) + data
.len
;
189 enc
->family
= host
->get_family(host
);
190 enc
->port
= htons(host
->get_port(host
));
191 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
195 case HA_SYNC_CONFIG_NAME
:
199 str
= va_arg(args
, char*);
200 len
= strlen(str
) + 1;
201 check_buf(this, len
);
202 memcpy(this->buf
.ptr
+ this->buf
.len
, str
, len
);
203 this->buf
.len
+= len
;
207 case HA_SYNC_IPSEC_MODE
:
212 val
= va_arg(args
, u_int
);
213 check_buf(this, sizeof(val
));
214 this->buf
.ptr
[this->buf
.len
] = val
;
215 this->buf
.len
+= sizeof(val
);
219 case HA_SYNC_ALG_PRF
:
220 case HA_SYNC_ALG_OLD_PRF
:
221 case HA_SYNC_ALG_ENCR
:
222 case HA_SYNC_ALG_ENCR_LEN
:
223 case HA_SYNC_ALG_INTEG
:
224 case HA_SYNC_INBOUND_CPI
:
225 case HA_SYNC_OUTBOUND_CPI
:
226 case HA_SYNC_SEGMENT
:
230 val
= va_arg(args
, u_int
);
231 check_buf(this, sizeof(val
));
232 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(val
);
233 this->buf
.len
+= sizeof(val
);
237 case HA_SYNC_CONDITIONS
:
238 case HA_SYNC_EXTENSIONS
:
239 case HA_SYNC_INBOUND_SPI
:
240 case HA_SYNC_OUTBOUND_SPI
:
241 case HA_SYNC_INITIATE_MID
:
242 case HA_SYNC_RESPOND_MID
:
246 val
= va_arg(args
, u_int
);
247 check_buf(this, sizeof(val
));
248 *(u_int32_t
*)(this->buf
.ptr
+ this->buf
.len
) = htonl(val
);
249 this->buf
.len
+= sizeof(val
);
253 case HA_SYNC_NONCE_I
:
254 case HA_SYNC_NONCE_R
:
256 case HA_SYNC_OLD_SKD
:
260 chunk
= va_arg(args
, chunk_t
);
261 check_buf(this, chunk
.len
+ sizeof(u_int16_t
));
262 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(chunk
.len
);
263 memcpy(this->buf
.ptr
+ this->buf
.len
+ sizeof(u_int16_t
),
264 chunk
.ptr
, chunk
.len
);
265 this->buf
.len
+= chunk
.len
+ sizeof(u_int16_t
);;
268 /** traffic_selector_t */
269 case HA_SYNC_LOCAL_TS
:
270 case HA_SYNC_REMOTE_TS
:
273 traffic_selector_t
*ts
;
276 ts
= va_arg(args
, traffic_selector_t
*);
277 data
= chunk_cata("cc", ts
->get_from_address(ts
),
278 ts
->get_to_address(ts
));
279 check_buf(this, sizeof(ts_encoding_t
) + data
.len
);
280 enc
= (ts_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
281 this->buf
.len
+= sizeof(ts_encoding_t
) + data
.len
;
282 enc
->type
= ts
->get_type(ts
);
283 enc
->protocol
= ts
->get_protocol(ts
);
284 enc
->from_port
= htons(ts
->get_from_port(ts
));
285 enc
->to_port
= htons(ts
->get_to_port(ts
));
286 enc
->dynamic
= ts
->is_dynamic(ts
);
287 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
292 DBG1(DBG_CFG
, "unable to encode, attribute %d unknown", attribute
);
293 this->buf
.len
-= sizeof(u_int8_t
);
301 * Attribute enumerator implementation
304 /** implementes enumerator_t */
306 /** position in message */
308 /** cleanup handler of current element, if any */
309 void (*cleanup
)(void* data
);
310 /** data to pass to cleanup handler */
312 } attribute_enumerator_t
;
315 * Implementation of create_attribute_enumerator().enumerate
317 static bool attribute_enumerate(attribute_enumerator_t
*this,
318 ha_sync_message_attribute_t
*attr_out
,
319 ha_sync_message_value_t
*value
)
321 ha_sync_message_attribute_t attr
;
325 this->cleanup(this->cleanup_data
);
326 this->cleanup
= NULL
;
328 if (this->buf
.len
< 1)
332 attr
= this->buf
.ptr
[0];
333 this->buf
= chunk_skip(this->buf
, 1);
338 case HA_SYNC_IKE_REKEY_ID
:
340 ike_sa_id_encoding_t
*enc
;
342 if (this->buf
.len
< sizeof(ike_sa_id_encoding_t
))
346 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
);
347 value
->ike_sa_id
= ike_sa_id_create(enc
->initiator_spi
,
348 enc
->responder_spi
, enc
->initiator
);
350 this->cleanup
= (void*)value
->ike_sa_id
->destroy
;
351 this->cleanup_data
= value
->ike_sa_id
;
352 this->buf
= chunk_skip(this->buf
, sizeof(ike_sa_id_encoding_t
));
355 /* identification_t* */
356 case HA_SYNC_LOCAL_ID
:
357 case HA_SYNC_REMOTE_ID
:
360 identification_encoding_t
*enc
;
362 enc
= (identification_encoding_t
*)(this->buf
.ptr
);
363 if (this->buf
.len
< sizeof(identification_encoding_t
) ||
364 this->buf
.len
< sizeof(identification_encoding_t
) + enc
->len
)
368 value
->id
= identification_create_from_encoding(enc
->type
,
369 chunk_create(enc
->encoding
, enc
->len
));
371 this->cleanup
= (void*)value
->id
->destroy
;
372 this->cleanup_data
= value
->id
;
373 this->buf
= chunk_skip(this->buf
,
374 sizeof(identification_encoding_t
) + enc
->len
);
378 case HA_SYNC_LOCAL_ADDR
:
379 case HA_SYNC_REMOTE_ADDR
:
380 case HA_SYNC_LOCAL_VIP
:
381 case HA_SYNC_REMOTE_VIP
:
382 case HA_SYNC_ADDITIONAL_ADDR
:
384 host_encoding_t
*enc
;
386 enc
= (host_encoding_t
*)(this->buf
.ptr
);
387 if (this->buf
.len
< sizeof(host_encoding_t
))
391 value
->host
= host_create_from_chunk(enc
->family
,
392 chunk_create(enc
->encoding
,
393 this->buf
.len
- sizeof(host_encoding_t
)),
400 this->cleanup
= (void*)value
->host
->destroy
;
401 this->cleanup_data
= value
->host
;
402 this->buf
= chunk_skip(this->buf
, sizeof(host_encoding_t
) +
403 value
->host
->get_address(value
->host
).len
);
407 case HA_SYNC_CONFIG_NAME
:
411 len
= strnlen(this->buf
.ptr
, this->buf
.len
);
412 if (len
>= this->buf
.len
)
416 value
->str
= this->buf
.ptr
;
418 this->buf
= chunk_skip(this->buf
, len
+ 1);
422 case HA_SYNC_IPSEC_MODE
:
425 if (this->buf
.len
< sizeof(u_int8_t
))
429 value
->u8
= *(u_int8_t
*)this->buf
.ptr
;
431 this->buf
= chunk_skip(this->buf
, sizeof(u_int8_t
));
435 case HA_SYNC_ALG_PRF
:
436 case HA_SYNC_ALG_OLD_PRF
:
437 case HA_SYNC_ALG_ENCR
:
438 case HA_SYNC_ALG_ENCR_LEN
:
439 case HA_SYNC_ALG_INTEG
:
440 case HA_SYNC_INBOUND_CPI
:
441 case HA_SYNC_OUTBOUND_CPI
:
442 case HA_SYNC_SEGMENT
:
444 if (this->buf
.len
< sizeof(u_int16_t
))
448 value
->u16
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
450 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
454 case HA_SYNC_CONDITIONS
:
455 case HA_SYNC_EXTENSIONS
:
456 case HA_SYNC_INBOUND_SPI
:
457 case HA_SYNC_OUTBOUND_SPI
:
458 case HA_SYNC_INITIATE_MID
:
459 case HA_SYNC_RESPOND_MID
:
461 if (this->buf
.len
< sizeof(u_int32_t
))
465 value
->u32
= ntohl(*(u_int32_t
*)this->buf
.ptr
);
467 this->buf
= chunk_skip(this->buf
, sizeof(u_int32_t
));
471 case HA_SYNC_NONCE_I
:
472 case HA_SYNC_NONCE_R
:
474 case HA_SYNC_OLD_SKD
:
478 if (this->buf
.len
< sizeof(u_int16_t
))
482 len
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
483 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
484 if (this->buf
.len
< len
)
488 value
->chunk
.len
= len
;
489 value
->chunk
.ptr
= this->buf
.ptr
;
491 this->buf
= chunk_skip(this->buf
, len
);
494 case HA_SYNC_LOCAL_TS
:
495 case HA_SYNC_REMOTE_TS
:
501 enc
= (ts_encoding_t
*)(this->buf
.ptr
);
502 if (this->buf
.len
< sizeof(ts_encoding_t
))
508 case TS_IPV4_ADDR_RANGE
:
510 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
515 case TS_IPV6_ADDR_RANGE
:
517 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
527 host
= host_create_from_chunk(0,
528 chunk_create(enc
->encoding
, addr_len
), 0);
533 value
->ts
= traffic_selector_create_dynamic(enc
->protocol
,
534 ntohs(enc
->from_port
), ntohs(enc
->to_port
));
535 value
->ts
->set_address(value
->ts
, host
);
540 value
->ts
= traffic_selector_create_from_bytes(enc
->protocol
,
541 enc
->type
, chunk_create(enc
->encoding
, addr_len
),
542 ntohs(enc
->from_port
),
543 chunk_create(enc
->encoding
+ addr_len
, addr_len
),
544 ntohs(enc
->to_port
));
551 this->cleanup
= (void*)value
->ts
->destroy
;
552 this->cleanup_data
= value
->ts
;
553 this->buf
= chunk_skip(this->buf
, sizeof(ts_encoding_t
)
565 * Implementation of create_attribute_enumerator().destroy
567 static void enum_destroy(attribute_enumerator_t
*this)
571 this->cleanup(this->cleanup_data
);
577 * Implementation of ha_sync_message_t.create_attribute_enumerator
579 static enumerator_t
* create_attribute_enumerator(private_ha_sync_message_t
*this)
581 attribute_enumerator_t
*e
= malloc_thing(attribute_enumerator_t
);
583 e
->public.enumerate
= (void*)attribute_enumerate
;
584 e
->public.destroy
= (void*)enum_destroy
;
586 e
->buf
= chunk_skip(this->buf
, 2);
588 e
->cleanup_data
= NULL
;
594 * Implementation of ha_sync_message_t.get_encoding
596 static chunk_t
get_encoding(private_ha_sync_message_t
*this)
602 * Implementation of ha_sync_message_t.destroy.
604 static void destroy(private_ha_sync_message_t
*this)
611 static private_ha_sync_message_t
*ha_sync_message_create_generic()
613 private_ha_sync_message_t
*this = malloc_thing(private_ha_sync_message_t
);
615 this->public.get_type
= (ha_sync_message_type_t(*)(ha_sync_message_t
*))get_type
;
616 this->public.add_attribute
= (void(*)(ha_sync_message_t
*, ha_sync_message_attribute_t attribute
, ...))add_attribute
;
617 this->public.create_attribute_enumerator
= (enumerator_t
*(*)(ha_sync_message_t
*))create_attribute_enumerator
;
618 this->public.get_encoding
= (chunk_t(*)(ha_sync_message_t
*))get_encoding
;
619 this->public.destroy
= (void(*)(ha_sync_message_t
*))destroy
;
627 ha_sync_message_t
*ha_sync_message_create(ha_sync_message_type_t type
)
629 private_ha_sync_message_t
*this = ha_sync_message_create_generic();
631 this->allocated
= ALLOCATION_BLOCK
;
632 this->buf
.ptr
= malloc(this->allocated
);
634 this->buf
.ptr
[0] = HA_SYNC_MESSAGE_VERSION
;
635 this->buf
.ptr
[1] = type
;
637 return &this->public;
643 ha_sync_message_t
*ha_sync_message_parse(chunk_t data
)
645 private_ha_sync_message_t
*this;
649 DBG1(DBG_CFG
, "HA sync message too short");
652 if (data
.ptr
[0] != HA_SYNC_MESSAGE_VERSION
)
654 DBG1(DBG_CFG
, "HA sync message has version %d, expected %d",
655 data
.ptr
[0], HA_SYNC_MESSAGE_VERSION
);
659 this = ha_sync_message_create_generic();
660 this->buf
= chunk_clone(data
);
661 this->allocated
= this->buf
.len
;
663 return &this->public;