3cf0a10118fe5a5e43503e45fb1ddbb49e665f94
[strongswan.git] / src / charon / plugins / ha_sync / ha_sync_message.c
1 /*
2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
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>.
9 *
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
13 * for more details.
14 *
15 * $Id$
16 */
17
18 #define _GNU_SOURCE
19 #include <string.h>
20 #include <arpa/inet.h>
21
22 #include "ha_sync_message.h"
23
24 #include <daemon.h>
25
26 #define ALLOCATION_BLOCK 64
27
28 typedef struct private_ha_sync_message_t private_ha_sync_message_t;
29
30 /**
31 * Private data of an ha_sync_message_t object.
32 */
33 struct private_ha_sync_message_t {
34
35 /**
36 * Public ha_sync_message_t interface.
37 */
38 ha_sync_message_t public;
39
40 /**
41 * Allocated size of buf
42 */
43 size_t allocated;
44
45 /**
46 * Buffer containing encoded data
47 */
48 chunk_t buf;
49 };
50
51 typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
52
53 /**
54 * Encoding if an ike_sa_id_t
55 */
56 struct ike_sa_id_encoding_t {
57 u_int64_t initiator_spi;
58 u_int64_t responder_spi;
59 u_int8_t initiator;
60 } __attribute__((packed));
61
62 typedef struct identification_encoding_t identification_encoding_t;
63
64 /**
65 * Encoding of a identification_t
66 */
67 struct identification_encoding_t {
68 u_int8_t type;
69 u_int8_t len;
70 char encoding[];
71 } __attribute__((packed));
72
73 typedef struct host_encoding_t host_encoding_t;
74
75 /**
76 * encoding of a host_t
77 */
78 struct host_encoding_t {
79 u_int16_t port;
80 u_int8_t family;
81 char encoding[];
82 } __attribute__((packed));
83
84 typedef struct ts_encoding_t ts_encoding_t;
85
86 /**
87 * encoding of a traffic_selector_t
88 */
89 struct ts_encoding_t {
90 u_int8_t type;
91 u_int8_t protocol;
92 u_int16_t from_port;
93 u_int16_t to_port;
94 u_int8_t dynamic;
95 char encoding[];
96 } __attribute__((packed));
97
98 /**
99 * Implementation of ha_sync_message_t.get_type
100 */
101 static ha_sync_message_type_t get_type(private_ha_sync_message_t *this)
102 {
103 return this->buf.ptr[1];
104 }
105
106 /**
107 * check for space in buffer, increase if necessary
108 */
109 static void check_buf(private_ha_sync_message_t *this, size_t len)
110 {
111 int increased = 0;
112
113 while (this->buf.len + len > this->allocated)
114 { /* double size */
115 this->allocated += ALLOCATION_BLOCK;
116 increased++;
117 }
118 if (increased)
119 {
120 this->buf.ptr = realloc(this->buf.ptr, this->allocated);
121 }
122 }
123
124 /**
125 * Implementation of ha_sync_message_t.add_attribute
126 */
127 static void add_attribute(private_ha_sync_message_t *this,
128 ha_sync_message_attribute_t attribute, ...)
129 {
130 size_t len;
131 va_list args;
132
133 check_buf(this, sizeof(u_int8_t));
134 this->buf.ptr[this->buf.len] = attribute;
135 this->buf.len += sizeof(u_int8_t);
136
137 va_start(args, attribute);
138 switch (attribute)
139 {
140 /* ike_sa_id_t* */
141 case HA_SYNC_IKE_ID:
142 case HA_SYNC_IKE_REKEY_ID:
143 {
144 ike_sa_id_encoding_t *enc;
145 ike_sa_id_t *id;
146
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);
154 break;
155 }
156 /* identification_t* */
157 case HA_SYNC_LOCAL_ID:
158 case HA_SYNC_REMOTE_ID:
159 case HA_SYNC_EAP_ID:
160 {
161 identification_encoding_t *enc;
162 identification_t *id;
163 chunk_t data;
164
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);
171 enc->len = data.len;
172 memcpy(enc->encoding, data.ptr, data.len);
173 break;
174 }
175 /* host_t* */
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:
181 {
182 host_encoding_t *enc;
183 host_t *host;
184 chunk_t data;
185
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);
194 break;
195 }
196 /* char* */
197 case HA_SYNC_CONFIG_NAME:
198 {
199 char *str;
200
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;
206 break;
207 }
208 /* u_int8_t */
209 case HA_SYNC_IPSEC_MODE:
210 case HA_SYNC_IPCOMP:
211 {
212 u_int8_t val;
213
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);
218 break;
219 }
220 /* u_int16_t */
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:
228 {
229 u_int16_t val;
230
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);
235 break;
236 }
237 /** u_int32_t */
238 case HA_SYNC_CONDITIONS:
239 case HA_SYNC_EXTENSIONS:
240 case HA_SYNC_INBOUND_SPI:
241 case HA_SYNC_OUTBOUND_SPI:
242 {
243 u_int32_t val;
244
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);
249 break;
250 }
251 /** chunk_t */
252 case HA_SYNC_NONCE_I:
253 case HA_SYNC_NONCE_R:
254 case HA_SYNC_SECRET:
255 case HA_SYNC_OLD_SKD:
256 {
257 chunk_t chunk;
258
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);;
265 break;
266 }
267 /** traffic_selector_t */
268 case HA_SYNC_LOCAL_TS:
269 case HA_SYNC_REMOTE_TS:
270 {
271 ts_encoding_t *enc;
272 traffic_selector_t *ts;
273 chunk_t data;
274
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);
287 break;
288 }
289 default:
290 {
291 DBG1(DBG_CFG, "unable to encode, attribute %d unknown", attribute);
292 this->buf.len -= sizeof(u_int8_t);
293 break;
294 }
295 }
296 va_end(args);
297 }
298
299 /**
300 * Attribute enumerator implementation
301 */
302 typedef struct {
303 /** implementes enumerator_t */
304 enumerator_t public;
305 /** position in message */
306 chunk_t buf;
307 /** cleanup handler of current element, if any */
308 void (*cleanup)(void* data);
309 /** data to pass to cleanup handler */
310 void *cleanup_data;
311 } attribute_enumerator_t;
312
313 /**
314 * Implementation of create_attribute_enumerator().enumerate
315 */
316 static bool attribute_enumerate(attribute_enumerator_t *this,
317 ha_sync_message_attribute_t *attr_out,
318 ha_sync_message_value_t *value)
319 {
320 ha_sync_message_attribute_t attr;
321
322 if (this->cleanup)
323 {
324 this->cleanup(this->cleanup_data);
325 this->cleanup = NULL;
326 }
327 if (this->buf.len < 1)
328 {
329 return FALSE;
330 }
331 attr = this->buf.ptr[0];
332 this->buf = chunk_skip(this->buf, 1);
333 switch (attr)
334 {
335 /* ike_sa_id_t* */
336 case HA_SYNC_IKE_ID:
337 case HA_SYNC_IKE_REKEY_ID:
338 {
339 ike_sa_id_encoding_t *enc;
340
341 if (this->buf.len < sizeof(ike_sa_id_encoding_t))
342 {
343 return FALSE;
344 }
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);
348 *attr_out = attr;
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));
352 return TRUE;
353 }
354 /* identification_t* */
355 case HA_SYNC_LOCAL_ID:
356 case HA_SYNC_REMOTE_ID:
357 case HA_SYNC_EAP_ID:
358 {
359 identification_encoding_t *enc;
360
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)
364 {
365 return FALSE;
366 }
367 value->id = identification_create_from_encoding(enc->type,
368 chunk_create(enc->encoding, enc->len));
369 *attr_out = attr;
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);
374 return TRUE;
375 }
376 /* host_t* */
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:
382 {
383 host_encoding_t *enc;
384
385 enc = (host_encoding_t*)(this->buf.ptr);
386 if (this->buf.len < sizeof(host_encoding_t))
387 {
388 return FALSE;
389 }
390 value->host = host_create_from_chunk(enc->family,
391 chunk_create(enc->encoding,
392 this->buf.len - sizeof(host_encoding_t)),
393 ntohs(enc->port));
394 if (!value->host)
395 {
396 return FALSE;
397 }
398 *attr_out = attr;
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);
403 return TRUE;
404 }
405 /* char* */
406 case HA_SYNC_CONFIG_NAME:
407 {
408 size_t len;
409
410 len = strnlen(this->buf.ptr, this->buf.len);
411 if (len >= this->buf.len)
412 {
413 return FALSE;
414 }
415 value->str = this->buf.ptr;
416 *attr_out = attr;
417 this->buf = chunk_skip(this->buf, len + 1);
418 return TRUE;
419 }
420 /* u_int8_t */
421 case HA_SYNC_IPSEC_MODE:
422 case HA_SYNC_IPCOMP:
423 {
424 if (this->buf.len < sizeof(u_int8_t))
425 {
426 return FALSE;
427 }
428 value->u8 = *(u_int8_t*)this->buf.ptr;
429 *attr_out = attr;
430 this->buf = chunk_skip(this->buf, sizeof(u_int8_t));
431 return TRUE;
432 }
433 /** u_int16_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:
441 {
442 if (this->buf.len < sizeof(u_int16_t))
443 {
444 return FALSE;
445 }
446 value->u16 = ntohs(*(u_int16_t*)this->buf.ptr);
447 *attr_out = attr;
448 this->buf = chunk_skip(this->buf, sizeof(u_int16_t));
449 return TRUE;
450 }
451 /** u_int32_t */
452 case HA_SYNC_CONDITIONS:
453 case HA_SYNC_EXTENSIONS:
454 case HA_SYNC_INBOUND_SPI:
455 case HA_SYNC_OUTBOUND_SPI:
456 {
457 if (this->buf.len < sizeof(u_int32_t))
458 {
459 return FALSE;
460 }
461 value->u32 = ntohl(*(u_int32_t*)this->buf.ptr);
462 *attr_out = attr;
463 this->buf = chunk_skip(this->buf, sizeof(u_int32_t));
464 return TRUE;
465 }
466 /** chunk_t */
467 case HA_SYNC_NONCE_I:
468 case HA_SYNC_NONCE_R:
469 case HA_SYNC_SECRET:
470 case HA_SYNC_OLD_SKD:
471 {
472 size_t len;
473
474 if (this->buf.len < sizeof(u_int16_t))
475 {
476 return FALSE;
477 }
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)
481 {
482 return FALSE;
483 }
484 value->chunk.len = len;
485 value->chunk.ptr = this->buf.ptr;
486 *attr_out = attr;
487 this->buf = chunk_skip(this->buf, len);
488 return TRUE;
489 }
490 case HA_SYNC_LOCAL_TS:
491 case HA_SYNC_REMOTE_TS:
492 {
493 ts_encoding_t *enc;
494 host_t *host;
495 int addr_len;
496
497 enc = (ts_encoding_t*)(this->buf.ptr);
498 if (this->buf.len < sizeof(ts_encoding_t))
499 {
500 return FALSE;
501 }
502 switch (enc->type)
503 {
504 case TS_IPV4_ADDR_RANGE:
505 addr_len = 4;
506 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
507 {
508 return FALSE;
509 }
510 break;
511 case TS_IPV6_ADDR_RANGE:
512 addr_len = 16;
513 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
514 {
515 return FALSE;
516 }
517 break;
518 default:
519 return FALSE;
520 }
521 if (enc->dynamic)
522 {
523 host = host_create_from_chunk(0,
524 chunk_create(enc->encoding, addr_len), 0);
525 if (!host)
526 {
527 return FALSE;
528 }
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);
532 host->destroy(host);
533 }
534 else
535 {
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));
541 if (!value->ts)
542 {
543 return FALSE;
544 }
545 }
546 *attr_out = attr;
547 this->cleanup = (void*)value->ts->destroy;
548 this->cleanup_data = value->ts;
549 this->buf = chunk_skip(this->buf, sizeof(ts_encoding_t)
550 + addr_len * 2);
551 return TRUE;
552 }
553 default:
554 {
555 return FALSE;
556 }
557 }
558 }
559
560 /**
561 * Implementation of create_attribute_enumerator().destroy
562 */
563 static void enum_destroy(attribute_enumerator_t *this)
564 {
565 if (this->cleanup)
566 {
567 this->cleanup(this->cleanup_data);
568 }
569 free(this);
570 }
571
572 /**
573 * Implementation of ha_sync_message_t.create_attribute_enumerator
574 */
575 static enumerator_t* create_attribute_enumerator(private_ha_sync_message_t *this)
576 {
577 attribute_enumerator_t *e = malloc_thing(attribute_enumerator_t);
578
579 e->public.enumerate = (void*)attribute_enumerate;
580 e->public.destroy = (void*)enum_destroy;
581
582 e->buf = chunk_skip(this->buf, 2);
583 e->cleanup = NULL;
584 e->cleanup_data = NULL;
585
586 return &e->public;
587 }
588
589 /**
590 * Implementation of ha_sync_message_t.get_encoding
591 */
592 static chunk_t get_encoding(private_ha_sync_message_t *this)
593 {
594 return this->buf;
595 }
596
597 /**
598 * Implementation of ha_sync_message_t.destroy.
599 */
600 static void destroy(private_ha_sync_message_t *this)
601 {
602 free(this->buf.ptr);
603 free(this);
604 }
605
606
607 static private_ha_sync_message_t *ha_sync_message_create_generic()
608 {
609 private_ha_sync_message_t *this = malloc_thing(private_ha_sync_message_t);
610
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;
616
617 return this;
618 }
619
620 /**
621 * See header
622 */
623 ha_sync_message_t *ha_sync_message_create(ha_sync_message_type_t type)
624 {
625 private_ha_sync_message_t *this = ha_sync_message_create_generic();
626
627 this->allocated = ALLOCATION_BLOCK;
628 this->buf.ptr = malloc(this->allocated);
629 this->buf.len = 2;
630 this->buf.ptr[0] = HA_SYNC_MESSAGE_VERSION;
631 this->buf.ptr[1] = type;
632
633 return &this->public;
634 }
635
636 /**
637 * See header
638 */
639 ha_sync_message_t *ha_sync_message_parse(chunk_t data)
640 {
641 private_ha_sync_message_t *this;
642
643 if (data.len < 2)
644 {
645 DBG1(DBG_CFG, "HA sync message too short");
646 return NULL;
647 }
648 if (data.ptr[0] != HA_SYNC_MESSAGE_VERSION)
649 {
650 DBG1(DBG_CFG, "HA sync message has version %d, expected %d",
651 data.ptr[0], HA_SYNC_MESSAGE_VERSION);
652 return NULL;
653 }
654
655 this = ha_sync_message_create_generic();
656 this->buf = chunk_clone(data);
657 this->allocated = this->buf.len;
658
659 return &this->public;
660 }
661