]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libcharon/plugins/ha/ha_message.c
Renamed list of additional peer addresses as it now stores all known addresses.
[thirdparty/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 case HA_REMOTE_EAP_ID:
167 {
168 identification_encoding_t *enc;
169 identification_t *id;
170 chunk_t data;
171
172 id = va_arg(args, identification_t*);
173 data = id->get_encoding(id);
174 check_buf(this, sizeof(identification_encoding_t) + data.len);
175 enc = (identification_encoding_t*)(this->buf.ptr + this->buf.len);
176 this->buf.len += sizeof(identification_encoding_t) + data.len;
177 enc->type = id->get_type(id);
178 enc->len = data.len;
179 memcpy(enc->encoding, data.ptr, data.len);
180 break;
181 }
182 /* host_t* */
183 case HA_LOCAL_ADDR:
184 case HA_REMOTE_ADDR:
185 case HA_LOCAL_VIP:
186 case HA_REMOTE_VIP:
187 case HA_PEER_ADDR:
188 {
189 host_encoding_t *enc;
190 host_t *host;
191 chunk_t data;
192
193 host = va_arg(args, host_t*);
194 data = host->get_address(host);
195 check_buf(this, sizeof(host_encoding_t) + data.len);
196 enc = (host_encoding_t*)(this->buf.ptr + this->buf.len);
197 this->buf.len += sizeof(host_encoding_t) + data.len;
198 enc->family = host->get_family(host);
199 enc->port = htons(host->get_port(host));
200 memcpy(enc->encoding, data.ptr, data.len);
201 break;
202 }
203 /* char* */
204 case HA_CONFIG_NAME:
205 {
206 char *str;
207
208 str = va_arg(args, char*);
209 len = strlen(str) + 1;
210 check_buf(this, len);
211 memcpy(this->buf.ptr + this->buf.len, str, len);
212 this->buf.len += len;
213 break;
214 }
215 /* u_int8_t */
216 case HA_INITIATOR:
217 case HA_IPSEC_MODE:
218 case HA_IPCOMP:
219 {
220 u_int8_t val;
221
222 val = va_arg(args, u_int);
223 check_buf(this, sizeof(val));
224 this->buf.ptr[this->buf.len] = val;
225 this->buf.len += sizeof(val);
226 break;
227 }
228 /* u_int16_t */
229 case HA_ALG_PRF:
230 case HA_ALG_OLD_PRF:
231 case HA_ALG_ENCR:
232 case HA_ALG_ENCR_LEN:
233 case HA_ALG_INTEG:
234 case HA_INBOUND_CPI:
235 case HA_OUTBOUND_CPI:
236 case HA_SEGMENT:
237 case HA_ESN:
238 {
239 u_int16_t val;
240
241 val = va_arg(args, u_int);
242 check_buf(this, sizeof(val));
243 *(u_int16_t*)(this->buf.ptr + this->buf.len) = htons(val);
244 this->buf.len += sizeof(val);
245 break;
246 }
247 /** u_int32_t */
248 case HA_CONDITIONS:
249 case HA_EXTENSIONS:
250 case HA_INBOUND_SPI:
251 case HA_OUTBOUND_SPI:
252 case HA_MID:
253 {
254 u_int32_t val;
255
256 val = va_arg(args, u_int);
257 check_buf(this, sizeof(val));
258 *(u_int32_t*)(this->buf.ptr + this->buf.len) = htonl(val);
259 this->buf.len += sizeof(val);
260 break;
261 }
262 /** chunk_t */
263 case HA_NONCE_I:
264 case HA_NONCE_R:
265 case HA_SECRET:
266 case HA_OLD_SKD:
267 {
268 chunk_t chunk;
269
270 chunk = va_arg(args, chunk_t);
271 check_buf(this, chunk.len + sizeof(u_int16_t));
272 *(u_int16_t*)(this->buf.ptr + this->buf.len) = htons(chunk.len);
273 memcpy(this->buf.ptr + this->buf.len + sizeof(u_int16_t),
274 chunk.ptr, chunk.len);
275 this->buf.len += chunk.len + sizeof(u_int16_t);;
276 break;
277 }
278 /** traffic_selector_t */
279 case HA_LOCAL_TS:
280 case HA_REMOTE_TS:
281 {
282 ts_encoding_t *enc;
283 traffic_selector_t *ts;
284 chunk_t data;
285
286 ts = va_arg(args, traffic_selector_t*);
287 data = chunk_cata("cc", ts->get_from_address(ts),
288 ts->get_to_address(ts));
289 check_buf(this, sizeof(ts_encoding_t) + data.len);
290 enc = (ts_encoding_t*)(this->buf.ptr + this->buf.len);
291 this->buf.len += sizeof(ts_encoding_t) + data.len;
292 enc->type = ts->get_type(ts);
293 enc->protocol = ts->get_protocol(ts);
294 enc->from_port = htons(ts->get_from_port(ts));
295 enc->to_port = htons(ts->get_to_port(ts));
296 enc->dynamic = ts->is_dynamic(ts);
297 memcpy(enc->encoding, data.ptr, data.len);
298 break;
299 }
300 default:
301 {
302 DBG1(DBG_CFG, "unable to encode, attribute %d unknown", attribute);
303 this->buf.len -= sizeof(u_int8_t);
304 break;
305 }
306 }
307 va_end(args);
308 }
309
310 /**
311 * Attribute enumerator implementation
312 */
313 typedef struct {
314 /** implementes enumerator_t */
315 enumerator_t public;
316 /** position in message */
317 chunk_t buf;
318 /** cleanup handler of current element, if any */
319 void (*cleanup)(void* data);
320 /** data to pass to cleanup handler */
321 void *cleanup_data;
322 } attribute_enumerator_t;
323
324 METHOD(enumerator_t, attribute_enumerate, bool,
325 attribute_enumerator_t *this, ha_message_attribute_t *attr_out,
326 ha_message_value_t *value)
327 {
328 ha_message_attribute_t attr;
329
330 if (this->cleanup)
331 {
332 this->cleanup(this->cleanup_data);
333 this->cleanup = NULL;
334 }
335 if (this->buf.len < 1)
336 {
337 return FALSE;
338 }
339 attr = this->buf.ptr[0];
340 this->buf = chunk_skip(this->buf, 1);
341 switch (attr)
342 {
343 /* ike_sa_id_t* */
344 case HA_IKE_ID:
345 case HA_IKE_REKEY_ID:
346 {
347 ike_sa_id_encoding_t *enc;
348
349 if (this->buf.len < sizeof(ike_sa_id_encoding_t))
350 {
351 return FALSE;
352 }
353 enc = (ike_sa_id_encoding_t*)(this->buf.ptr);
354 value->ike_sa_id = ike_sa_id_create(enc->initiator_spi,
355 enc->responder_spi, enc->initiator);
356 *attr_out = attr;
357 this->cleanup = (void*)value->ike_sa_id->destroy;
358 this->cleanup_data = value->ike_sa_id;
359 this->buf = chunk_skip(this->buf, sizeof(ike_sa_id_encoding_t));
360 return TRUE;
361 }
362 /* identification_t* */
363 case HA_LOCAL_ID:
364 case HA_REMOTE_ID:
365 case HA_REMOTE_EAP_ID:
366 {
367 identification_encoding_t *enc;
368
369 enc = (identification_encoding_t*)(this->buf.ptr);
370 if (this->buf.len < sizeof(identification_encoding_t) ||
371 this->buf.len < sizeof(identification_encoding_t) + enc->len)
372 {
373 return FALSE;
374 }
375 value->id = identification_create_from_encoding(enc->type,
376 chunk_create(enc->encoding, enc->len));
377 *attr_out = attr;
378 this->cleanup = (void*)value->id->destroy;
379 this->cleanup_data = value->id;
380 this->buf = chunk_skip(this->buf,
381 sizeof(identification_encoding_t) + enc->len);
382 return TRUE;
383 }
384 /* host_t* */
385 case HA_LOCAL_ADDR:
386 case HA_REMOTE_ADDR:
387 case HA_LOCAL_VIP:
388 case HA_REMOTE_VIP:
389 case HA_PEER_ADDR:
390 {
391 host_encoding_t *enc;
392
393 enc = (host_encoding_t*)(this->buf.ptr);
394 if (this->buf.len < sizeof(host_encoding_t))
395 {
396 return FALSE;
397 }
398 value->host = host_create_from_chunk(enc->family,
399 chunk_create(enc->encoding,
400 this->buf.len - sizeof(host_encoding_t)),
401 ntohs(enc->port));
402 if (!value->host)
403 {
404 return FALSE;
405 }
406 *attr_out = attr;
407 this->cleanup = (void*)value->host->destroy;
408 this->cleanup_data = value->host;
409 this->buf = chunk_skip(this->buf, sizeof(host_encoding_t) +
410 value->host->get_address(value->host).len);
411 return TRUE;
412 }
413 /* char* */
414 case HA_CONFIG_NAME:
415 {
416 size_t len;
417
418 len = strnlen(this->buf.ptr, this->buf.len);
419 if (len >= this->buf.len)
420 {
421 return FALSE;
422 }
423 value->str = this->buf.ptr;
424 *attr_out = attr;
425 this->buf = chunk_skip(this->buf, len + 1);
426 return TRUE;
427 }
428 /* u_int8_t */
429 case HA_INITIATOR:
430 case HA_IPSEC_MODE:
431 case HA_IPCOMP:
432 {
433 if (this->buf.len < sizeof(u_int8_t))
434 {
435 return FALSE;
436 }
437 value->u8 = *(u_int8_t*)this->buf.ptr;
438 *attr_out = attr;
439 this->buf = chunk_skip(this->buf, sizeof(u_int8_t));
440 return TRUE;
441 }
442 /** u_int16_t */
443 case HA_ALG_PRF:
444 case HA_ALG_OLD_PRF:
445 case HA_ALG_ENCR:
446 case HA_ALG_ENCR_LEN:
447 case HA_ALG_INTEG:
448 case HA_INBOUND_CPI:
449 case HA_OUTBOUND_CPI:
450 case HA_SEGMENT:
451 case HA_ESN:
452 {
453 if (this->buf.len < sizeof(u_int16_t))
454 {
455 return FALSE;
456 }
457 value->u16 = ntohs(*(u_int16_t*)this->buf.ptr);
458 *attr_out = attr;
459 this->buf = chunk_skip(this->buf, sizeof(u_int16_t));
460 return TRUE;
461 }
462 /** u_int32_t */
463 case HA_CONDITIONS:
464 case HA_EXTENSIONS:
465 case HA_INBOUND_SPI:
466 case HA_OUTBOUND_SPI:
467 case HA_MID:
468 {
469 if (this->buf.len < sizeof(u_int32_t))
470 {
471 return FALSE;
472 }
473 value->u32 = ntohl(*(u_int32_t*)this->buf.ptr);
474 *attr_out = attr;
475 this->buf = chunk_skip(this->buf, sizeof(u_int32_t));
476 return TRUE;
477 }
478 /** chunk_t */
479 case HA_NONCE_I:
480 case HA_NONCE_R:
481 case HA_SECRET:
482 case HA_OLD_SKD:
483 {
484 size_t len;
485
486 if (this->buf.len < sizeof(u_int16_t))
487 {
488 return FALSE;
489 }
490 len = ntohs(*(u_int16_t*)this->buf.ptr);
491 this->buf = chunk_skip(this->buf, sizeof(u_int16_t));
492 if (this->buf.len < len)
493 {
494 return FALSE;
495 }
496 value->chunk.len = len;
497 value->chunk.ptr = this->buf.ptr;
498 *attr_out = attr;
499 this->buf = chunk_skip(this->buf, len);
500 return TRUE;
501 }
502 case HA_LOCAL_TS:
503 case HA_REMOTE_TS:
504 {
505 ts_encoding_t *enc;
506 host_t *host;
507 int addr_len;
508
509 enc = (ts_encoding_t*)(this->buf.ptr);
510 if (this->buf.len < sizeof(ts_encoding_t))
511 {
512 return FALSE;
513 }
514 switch (enc->type)
515 {
516 case TS_IPV4_ADDR_RANGE:
517 addr_len = 4;
518 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
519 {
520 return FALSE;
521 }
522 break;
523 case TS_IPV6_ADDR_RANGE:
524 addr_len = 16;
525 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
526 {
527 return FALSE;
528 }
529 break;
530 default:
531 return FALSE;
532 }
533 if (enc->dynamic)
534 {
535 host = host_create_from_chunk(0,
536 chunk_create(enc->encoding, addr_len), 0);
537 if (!host)
538 {
539 return FALSE;
540 }
541 value->ts = traffic_selector_create_dynamic(enc->protocol,
542 ntohs(enc->from_port), ntohs(enc->to_port));
543 value->ts->set_address(value->ts, host);
544 host->destroy(host);
545 }
546 else
547 {
548 value->ts = traffic_selector_create_from_bytes(enc->protocol,
549 enc->type, chunk_create(enc->encoding, addr_len),
550 ntohs(enc->from_port),
551 chunk_create(enc->encoding + addr_len, addr_len),
552 ntohs(enc->to_port));
553 if (!value->ts)
554 {
555 return FALSE;
556 }
557 }
558 *attr_out = attr;
559 this->cleanup = (void*)value->ts->destroy;
560 this->cleanup_data = value->ts;
561 this->buf = chunk_skip(this->buf, sizeof(ts_encoding_t)
562 + addr_len * 2);
563 return TRUE;
564 }
565 default:
566 {
567 return FALSE;
568 }
569 }
570 }
571
572 METHOD(enumerator_t, enum_destroy, void,
573 attribute_enumerator_t *this)
574 {
575 if (this->cleanup)
576 {
577 this->cleanup(this->cleanup_data);
578 }
579 free(this);
580 }
581
582 METHOD(ha_message_t, create_attribute_enumerator, enumerator_t*,
583 private_ha_message_t *this)
584 {
585 attribute_enumerator_t *e;
586
587 INIT(e,
588 .public = {
589 .enumerate = (void*)_attribute_enumerate,
590 .destroy = _enum_destroy,
591 },
592 .buf = chunk_skip(this->buf, 2),
593 );
594
595 return &e->public;
596 }
597
598 METHOD(ha_message_t, get_encoding, chunk_t,
599 private_ha_message_t *this)
600 {
601 return this->buf;
602 }
603
604 METHOD(ha_message_t, destroy, void,
605 private_ha_message_t *this)
606 {
607 free(this->buf.ptr);
608 free(this);
609 }
610
611
612 static private_ha_message_t *ha_message_create_generic()
613 {
614 private_ha_message_t *this;
615
616 INIT(this,
617 .public = {
618 .get_type = _get_type,
619 .add_attribute = _add_attribute,
620 .create_attribute_enumerator = _create_attribute_enumerator,
621 .get_encoding = _get_encoding,
622 .destroy = _destroy,
623 },
624 );
625 return this;
626 }
627
628 /**
629 * See header
630 */
631 ha_message_t *ha_message_create(ha_message_type_t type)
632 {
633 private_ha_message_t *this = ha_message_create_generic();
634
635 this->allocated = ALLOCATION_BLOCK;
636 this->buf.ptr = malloc(this->allocated);
637 this->buf.len = 2;
638 this->buf.ptr[0] = HA_MESSAGE_VERSION;
639 this->buf.ptr[1] = type;
640
641 return &this->public;
642 }
643
644 /**
645 * See header
646 */
647 ha_message_t *ha_message_parse(chunk_t data)
648 {
649 private_ha_message_t *this;
650
651 if (data.len < 2)
652 {
653 DBG1(DBG_CFG, "HA message too short");
654 return NULL;
655 }
656 if (data.ptr[0] != HA_MESSAGE_VERSION)
657 {
658 DBG1(DBG_CFG, "HA message has version %d, expected %d",
659 data.ptr[0], HA_MESSAGE_VERSION);
660 return NULL;
661 }
662
663 this = ha_message_create_generic();
664 this->buf = chunk_clone(data);
665 this->allocated = this->buf.len;
666
667 return &this->public;
668 }
669