Pass initiator parameter to distinguish between original and exchange initiator
[strongswan.git] / src / libcharon / plugins / ha / ha_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_message.h"
21
22 #include <daemon.h>
23
24 #define ALLOCATION_BLOCK 64
25
26 typedef struct private_ha_message_t private_ha_message_t;
27
28 /**
29 * Private data of an ha_message_t object.
30 */
31 struct private_ha_message_t {
32
33 /**
34 * Public ha_message_t interface.
35 */
36 ha_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 ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC,
50 "IKE_ADD",
51 "IKE_UPDATE",
52 "IKE_MID_INITIATOR",
53 "IKE_MID_RESPONDER",
54 "IKE_DELETE",
55 "CHILD_ADD",
56 "CHILD_DELETE",
57 "SEGMENT_DROP",
58 "SEGMENT_TAKE",
59 "STATUS",
60 "RESYNC",
61 );
62
63 typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t;
64
65 /**
66 * Encoding if an ike_sa_id_t
67 */
68 struct ike_sa_id_encoding_t {
69 u_int64_t initiator_spi;
70 u_int64_t responder_spi;
71 u_int8_t initiator;
72 } __attribute__((packed));
73
74 typedef struct identification_encoding_t identification_encoding_t;
75
76 /**
77 * Encoding of a identification_t
78 */
79 struct identification_encoding_t {
80 u_int8_t type;
81 u_int8_t len;
82 char encoding[];
83 } __attribute__((packed));
84
85 typedef struct host_encoding_t host_encoding_t;
86
87 /**
88 * encoding of a host_t
89 */
90 struct host_encoding_t {
91 u_int16_t port;
92 u_int8_t family;
93 char encoding[];
94 } __attribute__((packed));
95
96 typedef struct ts_encoding_t ts_encoding_t;
97
98 /**
99 * encoding of a traffic_selector_t
100 */
101 struct ts_encoding_t {
102 u_int8_t type;
103 u_int8_t protocol;
104 u_int16_t from_port;
105 u_int16_t to_port;
106 u_int8_t dynamic;
107 char encoding[];
108 } __attribute__((packed));
109
110 METHOD(ha_message_t, get_type, ha_message_type_t,
111 private_ha_message_t *this)
112 {
113 return this->buf.ptr[1];
114 }
115
116 /**
117 * check for space in buffer, increase if necessary
118 */
119 static void check_buf(private_ha_message_t *this, size_t len)
120 {
121 int increased = 0;
122
123 while (this->buf.len + len > this->allocated)
124 { /* double size */
125 this->allocated += ALLOCATION_BLOCK;
126 increased++;
127 }
128 if (increased)
129 {
130 this->buf.ptr = realloc(this->buf.ptr, this->allocated);
131 }
132 }
133
134 METHOD(ha_message_t, add_attribute, void,
135 private_ha_message_t *this, ha_message_attribute_t attribute, ...)
136 {
137 size_t len;
138 va_list args;
139
140 check_buf(this, sizeof(u_int8_t));
141 this->buf.ptr[this->buf.len] = attribute;
142 this->buf.len += sizeof(u_int8_t);
143
144 va_start(args, attribute);
145 switch (attribute)
146 {
147 /* ike_sa_id_t* */
148 case HA_IKE_ID:
149 case HA_IKE_REKEY_ID:
150 {
151 ike_sa_id_encoding_t *enc;
152 ike_sa_id_t *id;
153
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);
161 break;
162 }
163 /* identification_t* */
164 case HA_LOCAL_ID:
165 case HA_REMOTE_ID:
166 {
167 identification_encoding_t *enc;
168 identification_t *id;
169 chunk_t data;
170
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);
177 enc->len = data.len;
178 memcpy(enc->encoding, data.ptr, data.len);
179 break;
180 }
181 /* host_t* */
182 case HA_LOCAL_ADDR:
183 case HA_REMOTE_ADDR:
184 case HA_LOCAL_VIP:
185 case HA_REMOTE_VIP:
186 case HA_ADDITIONAL_ADDR:
187 {
188 host_encoding_t *enc;
189 host_t *host;
190 chunk_t data;
191
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);
200 break;
201 }
202 /* char* */
203 case HA_CONFIG_NAME:
204 {
205 char *str;
206
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;
212 break;
213 }
214 /* u_int8_t */
215 case HA_INITIATOR:
216 case HA_IPSEC_MODE:
217 case HA_IPCOMP:
218 {
219 u_int8_t val;
220
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);
225 break;
226 }
227 /* u_int16_t */
228 case HA_ALG_PRF:
229 case HA_ALG_OLD_PRF:
230 case HA_ALG_ENCR:
231 case HA_ALG_ENCR_LEN:
232 case HA_ALG_INTEG:
233 case HA_INBOUND_CPI:
234 case HA_OUTBOUND_CPI:
235 case HA_SEGMENT:
236 {
237 u_int16_t val;
238
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);
243 break;
244 }
245 /** u_int32_t */
246 case HA_CONDITIONS:
247 case HA_EXTENSIONS:
248 case HA_INBOUND_SPI:
249 case HA_OUTBOUND_SPI:
250 case HA_MID:
251 {
252 u_int32_t val;
253
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);
258 break;
259 }
260 /** chunk_t */
261 case HA_NONCE_I:
262 case HA_NONCE_R:
263 case HA_SECRET:
264 case HA_OLD_SKD:
265 {
266 chunk_t chunk;
267
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);;
274 break;
275 }
276 /** traffic_selector_t */
277 case HA_LOCAL_TS:
278 case HA_REMOTE_TS:
279 {
280 ts_encoding_t *enc;
281 traffic_selector_t *ts;
282 chunk_t data;
283
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);
296 break;
297 }
298 default:
299 {
300 DBG1(DBG_CFG, "unable to encode, attribute %d unknown", attribute);
301 this->buf.len -= sizeof(u_int8_t);
302 break;
303 }
304 }
305 va_end(args);
306 }
307
308 /**
309 * Attribute enumerator implementation
310 */
311 typedef struct {
312 /** implementes enumerator_t */
313 enumerator_t public;
314 /** position in message */
315 chunk_t buf;
316 /** cleanup handler of current element, if any */
317 void (*cleanup)(void* data);
318 /** data to pass to cleanup handler */
319 void *cleanup_data;
320 } attribute_enumerator_t;
321
322 METHOD(enumerator_t, attribute_enumerate, bool,
323 attribute_enumerator_t *this, ha_message_attribute_t *attr_out,
324 ha_message_value_t *value)
325 {
326 ha_message_attribute_t attr;
327
328 if (this->cleanup)
329 {
330 this->cleanup(this->cleanup_data);
331 this->cleanup = NULL;
332 }
333 if (this->buf.len < 1)
334 {
335 return FALSE;
336 }
337 attr = this->buf.ptr[0];
338 this->buf = chunk_skip(this->buf, 1);
339 switch (attr)
340 {
341 /* ike_sa_id_t* */
342 case HA_IKE_ID:
343 case HA_IKE_REKEY_ID:
344 {
345 ike_sa_id_encoding_t *enc;
346
347 if (this->buf.len < sizeof(ike_sa_id_encoding_t))
348 {
349 return FALSE;
350 }
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);
354 *attr_out = attr;
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));
358 return TRUE;
359 }
360 /* identification_t* */
361 case HA_LOCAL_ID:
362 case HA_REMOTE_ID:
363 {
364 identification_encoding_t *enc;
365
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)
369 {
370 return FALSE;
371 }
372 value->id = identification_create_from_encoding(enc->type,
373 chunk_create(enc->encoding, enc->len));
374 *attr_out = attr;
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);
379 return TRUE;
380 }
381 /* host_t* */
382 case HA_LOCAL_ADDR:
383 case HA_REMOTE_ADDR:
384 case HA_LOCAL_VIP:
385 case HA_REMOTE_VIP:
386 case HA_ADDITIONAL_ADDR:
387 {
388 host_encoding_t *enc;
389
390 enc = (host_encoding_t*)(this->buf.ptr);
391 if (this->buf.len < sizeof(host_encoding_t))
392 {
393 return FALSE;
394 }
395 value->host = host_create_from_chunk(enc->family,
396 chunk_create(enc->encoding,
397 this->buf.len - sizeof(host_encoding_t)),
398 ntohs(enc->port));
399 if (!value->host)
400 {
401 return FALSE;
402 }
403 *attr_out = attr;
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);
408 return TRUE;
409 }
410 /* char* */
411 case HA_CONFIG_NAME:
412 {
413 size_t len;
414
415 len = strnlen(this->buf.ptr, this->buf.len);
416 if (len >= this->buf.len)
417 {
418 return FALSE;
419 }
420 value->str = this->buf.ptr;
421 *attr_out = attr;
422 this->buf = chunk_skip(this->buf, len + 1);
423 return TRUE;
424 }
425 /* u_int8_t */
426 case HA_INITIATOR:
427 case HA_IPSEC_MODE:
428 case HA_IPCOMP:
429 {
430 if (this->buf.len < sizeof(u_int8_t))
431 {
432 return FALSE;
433 }
434 value->u8 = *(u_int8_t*)this->buf.ptr;
435 *attr_out = attr;
436 this->buf = chunk_skip(this->buf, sizeof(u_int8_t));
437 return TRUE;
438 }
439 /** u_int16_t */
440 case HA_ALG_PRF:
441 case HA_ALG_OLD_PRF:
442 case HA_ALG_ENCR:
443 case HA_ALG_ENCR_LEN:
444 case HA_ALG_INTEG:
445 case HA_INBOUND_CPI:
446 case HA_OUTBOUND_CPI:
447 case HA_SEGMENT:
448 {
449 if (this->buf.len < sizeof(u_int16_t))
450 {
451 return FALSE;
452 }
453 value->u16 = ntohs(*(u_int16_t*)this->buf.ptr);
454 *attr_out = attr;
455 this->buf = chunk_skip(this->buf, sizeof(u_int16_t));
456 return TRUE;
457 }
458 /** u_int32_t */
459 case HA_CONDITIONS:
460 case HA_EXTENSIONS:
461 case HA_INBOUND_SPI:
462 case HA_OUTBOUND_SPI:
463 case HA_MID:
464 {
465 if (this->buf.len < sizeof(u_int32_t))
466 {
467 return FALSE;
468 }
469 value->u32 = ntohl(*(u_int32_t*)this->buf.ptr);
470 *attr_out = attr;
471 this->buf = chunk_skip(this->buf, sizeof(u_int32_t));
472 return TRUE;
473 }
474 /** chunk_t */
475 case HA_NONCE_I:
476 case HA_NONCE_R:
477 case HA_SECRET:
478 case HA_OLD_SKD:
479 {
480 size_t len;
481
482 if (this->buf.len < sizeof(u_int16_t))
483 {
484 return FALSE;
485 }
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)
489 {
490 return FALSE;
491 }
492 value->chunk.len = len;
493 value->chunk.ptr = this->buf.ptr;
494 *attr_out = attr;
495 this->buf = chunk_skip(this->buf, len);
496 return TRUE;
497 }
498 case HA_LOCAL_TS:
499 case HA_REMOTE_TS:
500 {
501 ts_encoding_t *enc;
502 host_t *host;
503 int addr_len;
504
505 enc = (ts_encoding_t*)(this->buf.ptr);
506 if (this->buf.len < sizeof(ts_encoding_t))
507 {
508 return FALSE;
509 }
510 switch (enc->type)
511 {
512 case TS_IPV4_ADDR_RANGE:
513 addr_len = 4;
514 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
515 {
516 return FALSE;
517 }
518 break;
519 case TS_IPV6_ADDR_RANGE:
520 addr_len = 16;
521 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
522 {
523 return FALSE;
524 }
525 break;
526 default:
527 return FALSE;
528 }
529 if (enc->dynamic)
530 {
531 host = host_create_from_chunk(0,
532 chunk_create(enc->encoding, addr_len), 0);
533 if (!host)
534 {
535 return FALSE;
536 }
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);
540 host->destroy(host);
541 }
542 else
543 {
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));
549 if (!value->ts)
550 {
551 return FALSE;
552 }
553 }
554 *attr_out = attr;
555 this->cleanup = (void*)value->ts->destroy;
556 this->cleanup_data = value->ts;
557 this->buf = chunk_skip(this->buf, sizeof(ts_encoding_t)
558 + addr_len * 2);
559 return TRUE;
560 }
561 default:
562 {
563 return FALSE;
564 }
565 }
566 }
567
568 METHOD(enumerator_t, enum_destroy, void,
569 attribute_enumerator_t *this)
570 {
571 if (this->cleanup)
572 {
573 this->cleanup(this->cleanup_data);
574 }
575 free(this);
576 }
577
578 METHOD(ha_message_t, create_attribute_enumerator, enumerator_t*,
579 private_ha_message_t *this)
580 {
581 attribute_enumerator_t *e;
582
583 INIT(e,
584 .public = {
585 .enumerate = (void*)_attribute_enumerate,
586 .destroy = _enum_destroy,
587 },
588 .buf = chunk_skip(this->buf, 2),
589 );
590
591 return &e->public;
592 }
593
594 METHOD(ha_message_t, get_encoding, chunk_t,
595 private_ha_message_t *this)
596 {
597 return this->buf;
598 }
599
600 METHOD(ha_message_t, destroy, void,
601 private_ha_message_t *this)
602 {
603 free(this->buf.ptr);
604 free(this);
605 }
606
607
608 static private_ha_message_t *ha_message_create_generic()
609 {
610 private_ha_message_t *this;
611
612 INIT(this,
613 .public = {
614 .get_type = _get_type,
615 .add_attribute = _add_attribute,
616 .create_attribute_enumerator = _create_attribute_enumerator,
617 .get_encoding = _get_encoding,
618 .destroy = _destroy,
619 },
620 );
621 return this;
622 }
623
624 /**
625 * See header
626 */
627 ha_message_t *ha_message_create(ha_message_type_t type)
628 {
629 private_ha_message_t *this = ha_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_MESSAGE_VERSION;
635 this->buf.ptr[1] = type;
636
637 return &this->public;
638 }
639
640 /**
641 * See header
642 */
643 ha_message_t *ha_message_parse(chunk_t data)
644 {
645 private_ha_message_t *this;
646
647 if (data.len < 2)
648 {
649 DBG1(DBG_CFG, "HA message too short");
650 return NULL;
651 }
652 if (data.ptr[0] != HA_MESSAGE_VERSION)
653 {
654 DBG1(DBG_CFG, "HA message has version %d, expected %d",
655 data.ptr[0], HA_MESSAGE_VERSION);
656 return NULL;
657 }
658
659 this = ha_message_create_generic();
660 this->buf = chunk_clone(data);
661 this->allocated = this->buf.len;
662
663 return &this->public;
664 }
665