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