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
20 #include <arpa/inet.h>
22 #include "ha_sync_message.h"
26 #define ALLOCATION_BLOCK 64
28 typedef struct private_ha_sync_message_t private_ha_sync_message_t
;
31 * Private data of an ha_sync_message_t object.
33 struct private_ha_sync_message_t
{
36 * Public ha_sync_message_t interface.
38 ha_sync_message_t
public;
41 * Allocated size of buf
46 * Buffer containing encoded data
51 typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t
;
54 * Encoding if an ike_sa_id_t
56 struct ike_sa_id_encoding_t
{
57 u_int64_t initiator_spi
;
58 u_int64_t responder_spi
;
60 } __attribute__((packed
));
62 typedef struct identification_encoding_t identification_encoding_t
;
65 * Encoding of a identification_t
67 struct identification_encoding_t
{
71 } __attribute__((packed
));
73 typedef struct host_encoding_t host_encoding_t
;
76 * encoding of a host_t
78 struct host_encoding_t
{
82 } __attribute__((packed
));
84 typedef struct ts_encoding_t ts_encoding_t
;
87 * encoding of a traffic_selector_t
89 struct ts_encoding_t
{
96 } __attribute__((packed
));
99 * Implementation of ha_sync_message_t.get_type
101 static ha_sync_message_type_t
get_type(private_ha_sync_message_t
*this)
103 return this->buf
.ptr
[1];
107 * check for space in buffer, increase if necessary
109 static void check_buf(private_ha_sync_message_t
*this, size_t len
)
113 while (this->buf
.len
+ len
> this->allocated
)
115 this->allocated
+= ALLOCATION_BLOCK
;
120 this->buf
.ptr
= realloc(this->buf
.ptr
, this->allocated
);
125 * Implementation of ha_sync_message_t.add_attribute
127 static void add_attribute(private_ha_sync_message_t
*this,
128 ha_sync_message_attribute_t attribute
, ...)
133 check_buf(this, sizeof(u_int8_t
));
134 this->buf
.ptr
[this->buf
.len
] = attribute
;
135 this->buf
.len
+= sizeof(u_int8_t
);
137 va_start(args
, attribute
);
142 case HA_SYNC_IKE_REKEY_ID
:
144 ike_sa_id_encoding_t
*enc
;
147 id
= va_arg(args
, ike_sa_id_t
*);
148 check_buf(this, sizeof(ike_sa_id_encoding_t
));
149 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
150 this->buf
.len
+= sizeof(ike_sa_id_encoding_t
);
151 enc
->initiator
= id
->is_initiator(id
);
152 enc
->initiator_spi
= id
->get_initiator_spi(id
);
153 enc
->responder_spi
= id
->get_responder_spi(id
);
156 /* identification_t* */
157 case HA_SYNC_LOCAL_ID
:
158 case HA_SYNC_REMOTE_ID
:
161 identification_encoding_t
*enc
;
162 identification_t
*id
;
165 id
= va_arg(args
, identification_t
*);
166 data
= id
->get_encoding(id
);
167 check_buf(this, sizeof(identification_encoding_t
) + data
.len
);
168 enc
= (identification_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
169 this->buf
.len
+= sizeof(identification_encoding_t
) + data
.len
;
170 enc
->type
= id
->get_type(id
);
172 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
176 case HA_SYNC_LOCAL_ADDR
:
177 case HA_SYNC_REMOTE_ADDR
:
178 case HA_SYNC_LOCAL_VIP
:
179 case HA_SYNC_REMOTE_VIP
:
180 case HA_SYNC_ADDITIONAL_ADDR
:
182 host_encoding_t
*enc
;
186 host
= va_arg(args
, host_t
*);
187 data
= host
->get_address(host
);
188 check_buf(this, sizeof(host_encoding_t
) + data
.len
);
189 enc
= (host_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
190 this->buf
.len
+= sizeof(host_encoding_t
) + data
.len
;
191 enc
->family
= host
->get_family(host
);
192 enc
->port
= htons(host
->get_port(host
));
193 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
197 case HA_SYNC_CONFIG_NAME
:
201 str
= va_arg(args
, char*);
202 len
= strlen(str
) + 1;
203 check_buf(this, len
);
204 memcpy(this->buf
.ptr
+ this->buf
.len
, str
, len
);
205 this->buf
.len
+= len
;
209 case HA_SYNC_IPSEC_MODE
:
214 val
= (u_int8_t
)va_arg(args
, u_int32_t
);
215 check_buf(this, sizeof(val
));
216 this->buf
.ptr
[this->buf
.len
] = val
;
217 this->buf
.len
+= sizeof(val
);
221 case HA_SYNC_ALG_PRF
:
222 case HA_SYNC_ALG_OLD_PRF
:
223 case HA_SYNC_ALG_ENCR
:
224 case HA_SYNC_ALG_ENCR_LEN
:
225 case HA_SYNC_ALG_INTEG
:
226 case HA_SYNC_INBOUND_CPI
:
227 case HA_SYNC_OUTBOUND_CPI
:
231 val
= (u_int16_t
)va_arg(args
, u_int32_t
);
232 check_buf(this, sizeof(val
));
233 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(val
);
234 this->buf
.len
+= sizeof(val
);
238 case HA_SYNC_CONDITIONS
:
239 case HA_SYNC_EXTENSIONS
:
240 case HA_SYNC_INBOUND_SPI
:
241 case HA_SYNC_OUTBOUND_SPI
:
245 val
= va_arg(args
, u_int32_t
);
246 check_buf(this, sizeof(val
));
247 *(u_int32_t
*)(this->buf
.ptr
+ this->buf
.len
) = htonl(val
);
248 this->buf
.len
+= sizeof(val
);
252 case HA_SYNC_NONCE_I
:
253 case HA_SYNC_NONCE_R
:
255 case HA_SYNC_OLD_SKD
:
259 chunk
= va_arg(args
, chunk_t
);
260 check_buf(this, chunk
.len
+ sizeof(u_int16_t
));
261 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(chunk
.len
);
262 memcpy(this->buf
.ptr
+ this->buf
.len
+ sizeof(u_int16_t
),
263 chunk
.ptr
, chunk
.len
);
264 this->buf
.len
+= chunk
.len
+ sizeof(u_int16_t
);;
267 /** traffic_selector_t */
268 case HA_SYNC_LOCAL_TS
:
269 case HA_SYNC_REMOTE_TS
:
272 traffic_selector_t
*ts
;
275 ts
= va_arg(args
, traffic_selector_t
*);
276 data
= chunk_cata("cc", ts
->get_from_address(ts
),
277 ts
->get_to_address(ts
));
278 check_buf(this, sizeof(ts_encoding_t
) + data
.len
);
279 enc
= (ts_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
280 this->buf
.len
+= sizeof(ts_encoding_t
) + data
.len
;
281 enc
->type
= ts
->get_type(ts
);
282 enc
->protocol
= ts
->get_protocol(ts
);
283 enc
->from_port
= htons(ts
->get_from_port(ts
));
284 enc
->to_port
= htons(ts
->get_to_port(ts
));
285 enc
->dynamic
= ts
->is_dynamic(ts
);
286 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
291 DBG1(DBG_CFG
, "unable to encode, attribute %d unknown", attribute
);
292 this->buf
.len
-= sizeof(u_int8_t
);
300 * Attribute enumerator implementation
303 /** implementes enumerator_t */
305 /** position in message */
307 /** cleanup handler of current element, if any */
308 void (*cleanup
)(void* data
);
309 /** data to pass to cleanup handler */
311 } attribute_enumerator_t
;
314 * Implementation of create_attribute_enumerator().enumerate
316 static bool attribute_enumerate(attribute_enumerator_t
*this,
317 ha_sync_message_attribute_t
*attr_out
,
318 ha_sync_message_value_t
*value
)
320 ha_sync_message_attribute_t attr
;
324 this->cleanup(this->cleanup_data
);
325 this->cleanup
= NULL
;
327 if (this->buf
.len
< 1)
331 attr
= this->buf
.ptr
[0];
332 this->buf
= chunk_skip(this->buf
, 1);
337 case HA_SYNC_IKE_REKEY_ID
:
339 ike_sa_id_encoding_t
*enc
;
341 if (this->buf
.len
< sizeof(ike_sa_id_encoding_t
))
345 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
);
346 value
->ike_sa_id
= ike_sa_id_create(enc
->initiator_spi
,
347 enc
->responder_spi
, enc
->initiator
);
349 this->cleanup
= (void*)value
->ike_sa_id
->destroy
;
350 this->cleanup_data
= value
->ike_sa_id
;
351 this->buf
= chunk_skip(this->buf
, sizeof(ike_sa_id_encoding_t
));
354 /* identification_t* */
355 case HA_SYNC_LOCAL_ID
:
356 case HA_SYNC_REMOTE_ID
:
359 identification_encoding_t
*enc
;
361 enc
= (identification_encoding_t
*)(this->buf
.ptr
);
362 if (this->buf
.len
< sizeof(identification_encoding_t
) ||
363 this->buf
.len
< sizeof(identification_encoding_t
) + enc
->len
)
367 value
->id
= identification_create_from_encoding(enc
->type
,
368 chunk_create(enc
->encoding
, enc
->len
));
370 this->cleanup
= (void*)value
->id
->destroy
;
371 this->cleanup_data
= value
->id
;
372 this->buf
= chunk_skip(this->buf
,
373 sizeof(identification_encoding_t
) + enc
->len
);
377 case HA_SYNC_LOCAL_ADDR
:
378 case HA_SYNC_REMOTE_ADDR
:
379 case HA_SYNC_LOCAL_VIP
:
380 case HA_SYNC_REMOTE_VIP
:
381 case HA_SYNC_ADDITIONAL_ADDR
:
383 host_encoding_t
*enc
;
385 enc
= (host_encoding_t
*)(this->buf
.ptr
);
386 if (this->buf
.len
< sizeof(host_encoding_t
))
390 value
->host
= host_create_from_chunk(enc
->family
,
391 chunk_create(enc
->encoding
,
392 this->buf
.len
- sizeof(host_encoding_t
)),
399 this->cleanup
= (void*)value
->host
->destroy
;
400 this->cleanup_data
= value
->host
;
401 this->buf
= chunk_skip(this->buf
, sizeof(host_encoding_t
) +
402 value
->host
->get_address(value
->host
).len
);
406 case HA_SYNC_CONFIG_NAME
:
410 len
= strnlen(this->buf
.ptr
, this->buf
.len
);
411 if (len
>= this->buf
.len
)
415 value
->str
= this->buf
.ptr
;
417 this->buf
= chunk_skip(this->buf
, len
+ 1);
421 case HA_SYNC_IPSEC_MODE
:
424 if (this->buf
.len
< sizeof(u_int8_t
))
428 value
->u8
= *(u_int8_t
*)this->buf
.ptr
;
430 this->buf
= chunk_skip(this->buf
, sizeof(u_int8_t
));
434 case HA_SYNC_ALG_PRF
:
435 case HA_SYNC_ALG_OLD_PRF
:
436 case HA_SYNC_ALG_ENCR
:
437 case HA_SYNC_ALG_ENCR_LEN
:
438 case HA_SYNC_ALG_INTEG
:
439 case HA_SYNC_INBOUND_CPI
:
440 case HA_SYNC_OUTBOUND_CPI
:
442 if (this->buf
.len
< sizeof(u_int16_t
))
446 value
->u16
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
448 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
452 case HA_SYNC_CONDITIONS
:
453 case HA_SYNC_EXTENSIONS
:
454 case HA_SYNC_INBOUND_SPI
:
455 case HA_SYNC_OUTBOUND_SPI
:
457 if (this->buf
.len
< sizeof(u_int32_t
))
461 value
->u32
= ntohl(*(u_int32_t
*)this->buf
.ptr
);
463 this->buf
= chunk_skip(this->buf
, sizeof(u_int32_t
));
467 case HA_SYNC_NONCE_I
:
468 case HA_SYNC_NONCE_R
:
470 case HA_SYNC_OLD_SKD
:
474 if (this->buf
.len
< sizeof(u_int16_t
))
478 len
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
479 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
480 if (this->buf
.len
< len
)
484 value
->chunk
.len
= len
;
485 value
->chunk
.ptr
= this->buf
.ptr
;
487 this->buf
= chunk_skip(this->buf
, len
);
490 case HA_SYNC_LOCAL_TS
:
491 case HA_SYNC_REMOTE_TS
:
497 enc
= (ts_encoding_t
*)(this->buf
.ptr
);
498 if (this->buf
.len
< sizeof(ts_encoding_t
))
504 case TS_IPV4_ADDR_RANGE
:
506 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
511 case TS_IPV6_ADDR_RANGE
:
513 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
523 host
= host_create_from_chunk(0,
524 chunk_create(enc
->encoding
, addr_len
), 0);
529 value
->ts
= traffic_selector_create_dynamic(enc
->protocol
,
530 ntohs(enc
->from_port
), ntohs(enc
->to_port
));
531 value
->ts
->set_address(value
->ts
, host
);
536 value
->ts
= traffic_selector_create_from_bytes(enc
->protocol
,
537 enc
->type
, chunk_create(enc
->encoding
, addr_len
),
538 ntohs(enc
->from_port
),
539 chunk_create(enc
->encoding
+ addr_len
, addr_len
),
540 ntohs(enc
->to_port
));
547 this->cleanup
= (void*)value
->ts
->destroy
;
548 this->cleanup_data
= value
->ts
;
549 this->buf
= chunk_skip(this->buf
, sizeof(ts_encoding_t
)
561 * Implementation of create_attribute_enumerator().destroy
563 static void enum_destroy(attribute_enumerator_t
*this)
567 this->cleanup(this->cleanup_data
);
573 * Implementation of ha_sync_message_t.create_attribute_enumerator
575 static enumerator_t
* create_attribute_enumerator(private_ha_sync_message_t
*this)
577 attribute_enumerator_t
*e
= malloc_thing(attribute_enumerator_t
);
579 e
->public.enumerate
= (void*)attribute_enumerate
;
580 e
->public.destroy
= (void*)enum_destroy
;
582 e
->buf
= chunk_skip(this->buf
, 2);
584 e
->cleanup_data
= NULL
;
590 * Implementation of ha_sync_message_t.get_encoding
592 static chunk_t
get_encoding(private_ha_sync_message_t
*this)
598 * Implementation of ha_sync_message_t.destroy.
600 static void destroy(private_ha_sync_message_t
*this)
607 static private_ha_sync_message_t
*ha_sync_message_create_generic()
609 private_ha_sync_message_t
*this = malloc_thing(private_ha_sync_message_t
);
611 this->public.get_type
= (ha_sync_message_type_t(*)(ha_sync_message_t
*))get_type
;
612 this->public.add_attribute
= (void(*)(ha_sync_message_t
*, ha_sync_message_attribute_t attribute
, ...))add_attribute
;
613 this->public.create_attribute_enumerator
= (enumerator_t
*(*)(ha_sync_message_t
*))create_attribute_enumerator
;
614 this->public.get_encoding
= (chunk_t(*)(ha_sync_message_t
*))get_encoding
;
615 this->public.destroy
= (void(*)(ha_sync_message_t
*))destroy
;
623 ha_sync_message_t
*ha_sync_message_create(ha_sync_message_type_t type
)
625 private_ha_sync_message_t
*this = ha_sync_message_create_generic();
627 this->allocated
= ALLOCATION_BLOCK
;
628 this->buf
.ptr
= malloc(this->allocated
);
630 this->buf
.ptr
[0] = HA_SYNC_MESSAGE_VERSION
;
631 this->buf
.ptr
[1] = type
;
633 return &this->public;
639 ha_sync_message_t
*ha_sync_message_parse(chunk_t data
)
641 private_ha_sync_message_t
*this;
645 DBG1(DBG_CFG
, "HA sync message too short");
648 if (data
.ptr
[0] != HA_SYNC_MESSAGE_VERSION
)
650 DBG1(DBG_CFG
, "HA sync message has version %d, expected %d",
651 data
.ptr
[0], HA_SYNC_MESSAGE_VERSION
);
655 this = ha_sync_message_create_generic();
656 this->buf
= chunk_clone(data
);
657 this->allocated
= this->buf
.len
;
659 return &this->public;