Return to ha_message.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / ha |
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: