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