Updated HA plugin to new APIs
[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 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_message_t.get_type
98 */
99 static ha_message_type_t get_type(private_ha_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_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_message_t.add_attribute
124 */
125 static void add_attribute(private_ha_message_t *this,
126 ha_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_IKE_ID:
140 case HA_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_LOCAL_ID:
156 case HA_REMOTE_ID:
157 {
158 identification_encoding_t *enc;
159 identification_t *id;
160 chunk_t data;
161
162 id = va_arg(args, identification_t*);
163 data = id->get_encoding(id);
164 check_buf(this, sizeof(identification_encoding_t) + data.len);
165 enc = (identification_encoding_t*)(this->buf.ptr + this->buf.len);
166 this->buf.len += sizeof(identification_encoding_t) + data.len;
167 enc->type = id->get_type(id);
168 enc->len = data.len;
169 memcpy(enc->encoding, data.ptr, data.len);
170 break;
171 }
172 /* host_t* */
173 case HA_LOCAL_ADDR:
174 case HA_REMOTE_ADDR:
175 case HA_LOCAL_VIP:
176 case HA_REMOTE_VIP:
177 case HA_ADDITIONAL_ADDR:
178 {
179 host_encoding_t *enc;
180 host_t *host;
181 chunk_t data;
182
183 host = va_arg(args, host_t*);
184 data = host->get_address(host);
185 check_buf(this, sizeof(host_encoding_t) + data.len);
186 enc = (host_encoding_t*)(this->buf.ptr + this->buf.len);
187 this->buf.len += sizeof(host_encoding_t) + data.len;
188 enc->family = host->get_family(host);
189 enc->port = htons(host->get_port(host));
190 memcpy(enc->encoding, data.ptr, data.len);
191 break;
192 }
193 /* char* */
194 case HA_CONFIG_NAME:
195 {
196 char *str;
197
198 str = va_arg(args, char*);
199 len = strlen(str) + 1;
200 check_buf(this, len);
201 memcpy(this->buf.ptr + this->buf.len, str, len);
202 this->buf.len += len;
203 break;
204 }
205 /* u_int8_t */
206 case HA_IPSEC_MODE:
207 case HA_IPCOMP:
208 {
209 u_int8_t val;
210
211 val = va_arg(args, u_int);
212 check_buf(this, sizeof(val));
213 this->buf.ptr[this->buf.len] = val;
214 this->buf.len += sizeof(val);
215 break;
216 }
217 /* u_int16_t */
218 case HA_ALG_PRF:
219 case HA_ALG_OLD_PRF:
220 case HA_ALG_ENCR:
221 case HA_ALG_ENCR_LEN:
222 case HA_ALG_INTEG:
223 case HA_INBOUND_CPI:
224 case HA_OUTBOUND_CPI:
225 case HA_SEGMENT:
226 {
227 u_int16_t val;
228
229 val = va_arg(args, u_int);
230 check_buf(this, sizeof(val));
231 *(u_int16_t*)(this->buf.ptr + this->buf.len) = htons(val);
232 this->buf.len += sizeof(val);
233 break;
234 }
235 /** u_int32_t */
236 case HA_CONDITIONS:
237 case HA_EXTENSIONS:
238 case HA_INBOUND_SPI:
239 case HA_OUTBOUND_SPI:
240 case HA_INITIATE_MID:
241 case HA_RESPOND_MID:
242 {
243 u_int32_t val;
244
245 val = va_arg(args, u_int);
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_NONCE_I:
253 case HA_NONCE_R:
254 case HA_SECRET:
255 case HA_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_LOCAL_TS:
269 case HA_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_message_attribute_t *attr_out,
318 ha_message_value_t *value)
319 {
320 ha_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_IKE_ID:
337 case HA_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_LOCAL_ID:
356 case HA_REMOTE_ID:
357 {
358 identification_encoding_t *enc;
359
360 enc = (identification_encoding_t*)(this->buf.ptr);
361 if (this->buf.len < sizeof(identification_encoding_t) ||
362 this->buf.len < sizeof(identification_encoding_t) + enc->len)
363 {
364 return FALSE;
365 }
366 value->id = identification_create_from_encoding(enc->type,
367 chunk_create(enc->encoding, enc->len));
368 *attr_out = attr;
369 this->cleanup = (void*)value->id->destroy;
370 this->cleanup_data = value->id;
371 this->buf = chunk_skip(this->buf,
372 sizeof(identification_encoding_t) + enc->len);
373 return TRUE;
374 }
375 /* host_t* */
376 case HA_LOCAL_ADDR:
377 case HA_REMOTE_ADDR:
378 case HA_LOCAL_VIP:
379 case HA_REMOTE_VIP:
380 case HA_ADDITIONAL_ADDR:
381 {
382 host_encoding_t *enc;
383
384 enc = (host_encoding_t*)(this->buf.ptr);
385 if (this->buf.len < sizeof(host_encoding_t))
386 {
387 return FALSE;
388 }
389 value->host = host_create_from_chunk(enc->family,
390 chunk_create(enc->encoding,
391 this->buf.len - sizeof(host_encoding_t)),
392 ntohs(enc->port));
393 if (!value->host)
394 {
395 return FALSE;
396 }
397 *attr_out = attr;
398 this->cleanup = (void*)value->host->destroy;
399 this->cleanup_data = value->host;
400 this->buf = chunk_skip(this->buf, sizeof(host_encoding_t) +
401 value->host->get_address(value->host).len);
402 return TRUE;
403 }
404 /* char* */
405 case HA_CONFIG_NAME:
406 {
407 size_t len;
408
409 len = strnlen(this->buf.ptr, this->buf.len);
410 if (len >= this->buf.len)
411 {
412 return FALSE;
413 }
414 value->str = this->buf.ptr;
415 *attr_out = attr;
416 this->buf = chunk_skip(this->buf, len + 1);
417 return TRUE;
418 }
419 /* u_int8_t */
420 case HA_IPSEC_MODE:
421 case HA_IPCOMP:
422 {
423 if (this->buf.len < sizeof(u_int8_t))
424 {
425 return FALSE;
426 }
427 value->u8 = *(u_int8_t*)this->buf.ptr;
428 *attr_out = attr;
429 this->buf = chunk_skip(this->buf, sizeof(u_int8_t));
430 return TRUE;
431 }
432 /** u_int16_t */
433 case HA_ALG_PRF:
434 case HA_ALG_OLD_PRF:
435 case HA_ALG_ENCR:
436 case HA_ALG_ENCR_LEN:
437 case HA_ALG_INTEG:
438 case HA_INBOUND_CPI:
439 case HA_OUTBOUND_CPI:
440 case HA_SEGMENT:
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_CONDITIONS:
453 case HA_EXTENSIONS:
454 case HA_INBOUND_SPI:
455 case HA_OUTBOUND_SPI:
456 case HA_INITIATE_MID:
457 case HA_RESPOND_MID:
458 {
459 if (this->buf.len < sizeof(u_int32_t))
460 {
461 return FALSE;
462 }
463 value->u32 = ntohl(*(u_int32_t*)this->buf.ptr);
464 *attr_out = attr;
465 this->buf = chunk_skip(this->buf, sizeof(u_int32_t));
466 return TRUE;
467 }
468 /** chunk_t */
469 case HA_NONCE_I:
470 case HA_NONCE_R:
471 case HA_SECRET:
472 case HA_OLD_SKD:
473 {
474 size_t len;
475
476 if (this->buf.len < sizeof(u_int16_t))
477 {
478 return FALSE;
479 }
480 len = ntohs(*(u_int16_t*)this->buf.ptr);
481 this->buf = chunk_skip(this->buf, sizeof(u_int16_t));
482 if (this->buf.len < len)
483 {
484 return FALSE;
485 }
486 value->chunk.len = len;
487 value->chunk.ptr = this->buf.ptr;
488 *attr_out = attr;
489 this->buf = chunk_skip(this->buf, len);
490 return TRUE;
491 }
492 case HA_LOCAL_TS:
493 case HA_REMOTE_TS:
494 {
495 ts_encoding_t *enc;
496 host_t *host;
497 int addr_len;
498
499 enc = (ts_encoding_t*)(this->buf.ptr);
500 if (this->buf.len < sizeof(ts_encoding_t))
501 {
502 return FALSE;
503 }
504 switch (enc->type)
505 {
506 case TS_IPV4_ADDR_RANGE:
507 addr_len = 4;
508 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
509 {
510 return FALSE;
511 }
512 break;
513 case TS_IPV6_ADDR_RANGE:
514 addr_len = 16;
515 if (this->buf.len < sizeof(ts_encoding_t) + 2 * addr_len)
516 {
517 return FALSE;
518 }
519 break;
520 default:
521 return FALSE;
522 }
523 if (enc->dynamic)
524 {
525 host = host_create_from_chunk(0,
526 chunk_create(enc->encoding, addr_len), 0);
527 if (!host)
528 {
529 return FALSE;
530 }
531 value->ts = traffic_selector_create_dynamic(enc->protocol,
532 ntohs(enc->from_port), ntohs(enc->to_port));
533 value->ts->set_address(value->ts, host);
534 host->destroy(host);
535 }
536 else
537 {
538 value->ts = traffic_selector_create_from_bytes(enc->protocol,
539 enc->type, chunk_create(enc->encoding, addr_len),
540 ntohs(enc->from_port),
541 chunk_create(enc->encoding + addr_len, addr_len),
542 ntohs(enc->to_port));
543 if (!value->ts)
544 {
545 return FALSE;
546 }
547 }
548 *attr_out = attr;
549 this->cleanup = (void*)value->ts->destroy;
550 this->cleanup_data = value->ts;
551 this->buf = chunk_skip(this->buf, sizeof(ts_encoding_t)
552 + addr_len * 2);
553 return TRUE;
554 }
555 default:
556 {
557 return FALSE;
558 }
559 }
560 }
561
562 /**
563 * Implementation of create_attribute_enumerator().destroy
564 */
565 static void enum_destroy(attribute_enumerator_t *this)
566 {
567 if (this->cleanup)
568 {
569 this->cleanup(this->cleanup_data);
570 }
571 free(this);
572 }
573
574 /**
575 * Implementation of ha_message_t.create_attribute_enumerator
576 */
577 static enumerator_t* create_attribute_enumerator(private_ha_message_t *this)
578 {
579 attribute_enumerator_t *e = malloc_thing(attribute_enumerator_t);
580
581 e->public.enumerate = (void*)attribute_enumerate;
582 e->public.destroy = (void*)enum_destroy;
583
584 e->buf = chunk_skip(this->buf, 2);
585 e->cleanup = NULL;
586 e->cleanup_data = NULL;
587
588 return &e->public;
589 }
590
591 /**
592 * Implementation of ha_message_t.get_encoding
593 */
594 static chunk_t get_encoding(private_ha_message_t *this)
595 {
596 return this->buf;
597 }
598
599 /**
600 * Implementation of ha_message_t.destroy.
601 */
602 static void destroy(private_ha_message_t *this)
603 {
604 free(this->buf.ptr);
605 free(this);
606 }
607
608
609 static private_ha_message_t *ha_message_create_generic()
610 {
611 private_ha_message_t *this = malloc_thing(private_ha_message_t);
612
613 this->public.get_type = (ha_message_type_t(*)(ha_message_t*))get_type;
614 this->public.add_attribute = (void(*)(ha_message_t*, ha_message_attribute_t attribute, ...))add_attribute;
615 this->public.create_attribute_enumerator = (enumerator_t*(*)(ha_message_t*))create_attribute_enumerator;
616 this->public.get_encoding = (chunk_t(*)(ha_message_t*))get_encoding;
617 this->public.destroy = (void(*)(ha_message_t*))destroy;
618
619 return this;
620 }
621
622 /**
623 * See header
624 */
625 ha_message_t *ha_message_create(ha_message_type_t type)
626 {
627 private_ha_message_t *this = ha_message_create_generic();
628
629 this->allocated = ALLOCATION_BLOCK;
630 this->buf.ptr = malloc(this->allocated);
631 this->buf.len = 2;
632 this->buf.ptr[0] = HA_MESSAGE_VERSION;
633 this->buf.ptr[1] = type;
634
635 return &this->public;
636 }
637
638 /**
639 * See header
640 */
641 ha_message_t *ha_message_parse(chunk_t data)
642 {
643 private_ha_message_t *this;
644
645 if (data.len < 2)
646 {
647 DBG1(DBG_CFG, "HA message too short");
648 return NULL;
649 }
650 if (data.ptr[0] != HA_MESSAGE_VERSION)
651 {
652 DBG1(DBG_CFG, "HA message has version %d, expected %d",
653 data.ptr[0], HA_MESSAGE_VERSION);
654 return NULL;
655 }
656
657 this = ha_message_create_generic();
658 this->buf = chunk_clone(data);
659 this->allocated = this->buf.len;
660
661 return &this->public;
662 }
663