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* */
167 identification_encoding_t
*enc
;
168 identification_t
*id
;
171 id
= va_arg(args
, identification_t
*);
172 data
= id
->get_encoding(id
);
173 check_buf(this, sizeof(identification_encoding_t
) + data
.len
);
174 enc
= (identification_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
175 this->buf
.len
+= sizeof(identification_encoding_t
) + data
.len
;
176 enc
->type
= id
->get_type(id
);
178 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
186 case HA_ADDITIONAL_ADDR
:
188 host_encoding_t
*enc
;
192 host
= va_arg(args
, host_t
*);
193 data
= host
->get_address(host
);
194 check_buf(this, sizeof(host_encoding_t
) + data
.len
);
195 enc
= (host_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
196 this->buf
.len
+= sizeof(host_encoding_t
) + data
.len
;
197 enc
->family
= host
->get_family(host
);
198 enc
->port
= htons(host
->get_port(host
));
199 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
207 str
= va_arg(args
, char*);
208 len
= strlen(str
) + 1;
209 check_buf(this, len
);
210 memcpy(this->buf
.ptr
+ this->buf
.len
, str
, len
);
211 this->buf
.len
+= len
;
221 val
= va_arg(args
, u_int
);
222 check_buf(this, sizeof(val
));
223 this->buf
.ptr
[this->buf
.len
] = val
;
224 this->buf
.len
+= sizeof(val
);
231 case HA_ALG_ENCR_LEN
:
234 case HA_OUTBOUND_CPI
:
239 val
= va_arg(args
, u_int
);
240 check_buf(this, sizeof(val
));
241 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(val
);
242 this->buf
.len
+= sizeof(val
);
249 case HA_OUTBOUND_SPI
:
254 val
= va_arg(args
, u_int
);
255 check_buf(this, sizeof(val
));
256 *(u_int32_t
*)(this->buf
.ptr
+ this->buf
.len
) = htonl(val
);
257 this->buf
.len
+= sizeof(val
);
268 chunk
= va_arg(args
, chunk_t
);
269 check_buf(this, chunk
.len
+ sizeof(u_int16_t
));
270 *(u_int16_t
*)(this->buf
.ptr
+ this->buf
.len
) = htons(chunk
.len
);
271 memcpy(this->buf
.ptr
+ this->buf
.len
+ sizeof(u_int16_t
),
272 chunk
.ptr
, chunk
.len
);
273 this->buf
.len
+= chunk
.len
+ sizeof(u_int16_t
);;
276 /** traffic_selector_t */
281 traffic_selector_t
*ts
;
284 ts
= va_arg(args
, traffic_selector_t
*);
285 data
= chunk_cata("cc", ts
->get_from_address(ts
),
286 ts
->get_to_address(ts
));
287 check_buf(this, sizeof(ts_encoding_t
) + data
.len
);
288 enc
= (ts_encoding_t
*)(this->buf
.ptr
+ this->buf
.len
);
289 this->buf
.len
+= sizeof(ts_encoding_t
) + data
.len
;
290 enc
->type
= ts
->get_type(ts
);
291 enc
->protocol
= ts
->get_protocol(ts
);
292 enc
->from_port
= htons(ts
->get_from_port(ts
));
293 enc
->to_port
= htons(ts
->get_to_port(ts
));
294 enc
->dynamic
= ts
->is_dynamic(ts
);
295 memcpy(enc
->encoding
, data
.ptr
, data
.len
);
300 DBG1(DBG_CFG
, "unable to encode, attribute %d unknown", attribute
);
301 this->buf
.len
-= sizeof(u_int8_t
);
309 * Attribute enumerator implementation
312 /** implementes enumerator_t */
314 /** position in message */
316 /** cleanup handler of current element, if any */
317 void (*cleanup
)(void* data
);
318 /** data to pass to cleanup handler */
320 } attribute_enumerator_t
;
322 METHOD(enumerator_t
, attribute_enumerate
, bool,
323 attribute_enumerator_t
*this, ha_message_attribute_t
*attr_out
,
324 ha_message_value_t
*value
)
326 ha_message_attribute_t attr
;
330 this->cleanup(this->cleanup_data
);
331 this->cleanup
= NULL
;
333 if (this->buf
.len
< 1)
337 attr
= this->buf
.ptr
[0];
338 this->buf
= chunk_skip(this->buf
, 1);
343 case HA_IKE_REKEY_ID
:
345 ike_sa_id_encoding_t
*enc
;
347 if (this->buf
.len
< sizeof(ike_sa_id_encoding_t
))
351 enc
= (ike_sa_id_encoding_t
*)(this->buf
.ptr
);
352 value
->ike_sa_id
= ike_sa_id_create(enc
->initiator_spi
,
353 enc
->responder_spi
, enc
->initiator
);
355 this->cleanup
= (void*)value
->ike_sa_id
->destroy
;
356 this->cleanup_data
= value
->ike_sa_id
;
357 this->buf
= chunk_skip(this->buf
, sizeof(ike_sa_id_encoding_t
));
360 /* identification_t* */
364 identification_encoding_t
*enc
;
366 enc
= (identification_encoding_t
*)(this->buf
.ptr
);
367 if (this->buf
.len
< sizeof(identification_encoding_t
) ||
368 this->buf
.len
< sizeof(identification_encoding_t
) + enc
->len
)
372 value
->id
= identification_create_from_encoding(enc
->type
,
373 chunk_create(enc
->encoding
, enc
->len
));
375 this->cleanup
= (void*)value
->id
->destroy
;
376 this->cleanup_data
= value
->id
;
377 this->buf
= chunk_skip(this->buf
,
378 sizeof(identification_encoding_t
) + enc
->len
);
386 case HA_ADDITIONAL_ADDR
:
388 host_encoding_t
*enc
;
390 enc
= (host_encoding_t
*)(this->buf
.ptr
);
391 if (this->buf
.len
< sizeof(host_encoding_t
))
395 value
->host
= host_create_from_chunk(enc
->family
,
396 chunk_create(enc
->encoding
,
397 this->buf
.len
- sizeof(host_encoding_t
)),
404 this->cleanup
= (void*)value
->host
->destroy
;
405 this->cleanup_data
= value
->host
;
406 this->buf
= chunk_skip(this->buf
, sizeof(host_encoding_t
) +
407 value
->host
->get_address(value
->host
).len
);
415 len
= strnlen(this->buf
.ptr
, this->buf
.len
);
416 if (len
>= this->buf
.len
)
420 value
->str
= this->buf
.ptr
;
422 this->buf
= chunk_skip(this->buf
, len
+ 1);
430 if (this->buf
.len
< sizeof(u_int8_t
))
434 value
->u8
= *(u_int8_t
*)this->buf
.ptr
;
436 this->buf
= chunk_skip(this->buf
, sizeof(u_int8_t
));
443 case HA_ALG_ENCR_LEN
:
446 case HA_OUTBOUND_CPI
:
449 if (this->buf
.len
< sizeof(u_int16_t
))
453 value
->u16
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
455 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
462 case HA_OUTBOUND_SPI
:
465 if (this->buf
.len
< sizeof(u_int32_t
))
469 value
->u32
= ntohl(*(u_int32_t
*)this->buf
.ptr
);
471 this->buf
= chunk_skip(this->buf
, sizeof(u_int32_t
));
482 if (this->buf
.len
< sizeof(u_int16_t
))
486 len
= ntohs(*(u_int16_t
*)this->buf
.ptr
);
487 this->buf
= chunk_skip(this->buf
, sizeof(u_int16_t
));
488 if (this->buf
.len
< len
)
492 value
->chunk
.len
= len
;
493 value
->chunk
.ptr
= this->buf
.ptr
;
495 this->buf
= chunk_skip(this->buf
, len
);
505 enc
= (ts_encoding_t
*)(this->buf
.ptr
);
506 if (this->buf
.len
< sizeof(ts_encoding_t
))
512 case TS_IPV4_ADDR_RANGE
:
514 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
519 case TS_IPV6_ADDR_RANGE
:
521 if (this->buf
.len
< sizeof(ts_encoding_t
) + 2 * addr_len
)
531 host
= host_create_from_chunk(0,
532 chunk_create(enc
->encoding
, addr_len
), 0);
537 value
->ts
= traffic_selector_create_dynamic(enc
->protocol
,
538 ntohs(enc
->from_port
), ntohs(enc
->to_port
));
539 value
->ts
->set_address(value
->ts
, host
);
544 value
->ts
= traffic_selector_create_from_bytes(enc
->protocol
,
545 enc
->type
, chunk_create(enc
->encoding
, addr_len
),
546 ntohs(enc
->from_port
),
547 chunk_create(enc
->encoding
+ addr_len
, addr_len
),
548 ntohs(enc
->to_port
));
555 this->cleanup
= (void*)value
->ts
->destroy
;
556 this->cleanup_data
= value
->ts
;
557 this->buf
= chunk_skip(this->buf
, sizeof(ts_encoding_t
)
568 METHOD(enumerator_t
, enum_destroy
, void,
569 attribute_enumerator_t
*this)
573 this->cleanup(this->cleanup_data
);
578 METHOD(ha_message_t
, create_attribute_enumerator
, enumerator_t
*,
579 private_ha_message_t
*this)
581 attribute_enumerator_t
*e
;
585 .enumerate
= (void*)_attribute_enumerate
,
586 .destroy
= _enum_destroy
,
588 .buf
= chunk_skip(this->buf
, 2),
594 METHOD(ha_message_t
, get_encoding
, chunk_t
,
595 private_ha_message_t
*this)
600 METHOD(ha_message_t
, destroy
, void,
601 private_ha_message_t
*this)
608 static private_ha_message_t
*ha_message_create_generic()
610 private_ha_message_t
*this;
614 .get_type
= _get_type
,
615 .add_attribute
= _add_attribute
,
616 .create_attribute_enumerator
= _create_attribute_enumerator
,
617 .get_encoding
= _get_encoding
,
627 ha_message_t
*ha_message_create(ha_message_type_t type
)
629 private_ha_message_t
*this = ha_message_create_generic();
631 this->allocated
= ALLOCATION_BLOCK
;
632 this->buf
.ptr
= malloc(this->allocated
);
634 this->buf
.ptr
[0] = HA_MESSAGE_VERSION
;
635 this->buf
.ptr
[1] = type
;
637 return &this->public;
643 ha_message_t
*ha_message_parse(chunk_t data
)
645 private_ha_message_t
*this;
649 DBG1(DBG_CFG
, "HA message too short");
652 if (data
.ptr
[0] != HA_MESSAGE_VERSION
)
654 DBG1(DBG_CFG
, "HA message has version %d, expected %d",
655 data
.ptr
[0], HA_MESSAGE_VERSION
);
659 this = ha_message_create_generic();
660 this->buf
= chunk_clone(data
);
661 this->allocated
= this->buf
.len
;
663 return &this->public;