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