]>
Commit | Line | Data |
---|---|---|
e5e91eec MW |
1 | /* |
2 | * Copyright (C) 2008 Martin Willi | |
1b671669 | 3 | * HSR Hochschule fuer Technik Rapperswil |
e5e91eec MW |
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. | |
e5e91eec MW |
14 | */ |
15 | ||
190edaf5 MW |
16 | #define _GNU_SOURCE |
17 | #include <string.h> | |
e5e91eec MW |
18 | #include <arpa/inet.h> |
19 | ||
d8748966 | 20 | #include "ha_message.h" |
190edaf5 | 21 | |
e5e91eec MW |
22 | #include <daemon.h> |
23 | ||
12ec91ba MW |
24 | #define ALLOCATION_BLOCK 64 |
25 | ||
d8748966 | 26 | typedef struct private_ha_message_t private_ha_message_t; |
e5e91eec MW |
27 | |
28 | /** | |
d8748966 | 29 | * Private data of an ha_message_t object. |
e5e91eec | 30 | */ |
d8748966 | 31 | struct private_ha_message_t { |
e5e91eec MW |
32 | |
33 | /** | |
d8748966 | 34 | * Public ha_message_t interface. |
e5e91eec | 35 | */ |
d8748966 | 36 | ha_message_t public; |
e5e91eec MW |
37 | |
38 | /** | |
12ec91ba | 39 | * Allocated size of buf |
e5e91eec MW |
40 | */ |
41 | size_t allocated; | |
42 | ||
43 | /** | |
44 | * Buffer containing encoded data | |
45 | */ | |
46 | chunk_t buf; | |
47 | }; | |
48 | ||
c8531b7e | 49 | ENUM(ha_message_type_names, HA_IKE_ADD, HA_IKE_IV, |
f2eebed2 MW |
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", | |
c8531b7e | 61 | "IKE_IV", |
f2eebed2 MW |
62 | ); |
63 | ||
12ec91ba MW |
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 { | |
b12c53ce AS |
70 | uint8_t ike_version; |
71 | uint64_t initiator_spi; | |
72 | uint64_t responder_spi; | |
73 | uint8_t initiator; | |
12ec91ba MW |
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 { | |
b12c53ce AS |
82 | uint8_t type; |
83 | uint8_t len; | |
12ec91ba MW |
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 { | |
b12c53ce AS |
93 | uint16_t port; |
94 | uint8_t family; | |
12ec91ba MW |
95 | char encoding[]; |
96 | } __attribute__((packed)); | |
97 | ||
7999be5b MW |
98 | typedef struct ts_encoding_t ts_encoding_t; |
99 | ||
100 | /** | |
101 | * encoding of a traffic_selector_t | |
102 | */ | |
103 | struct ts_encoding_t { | |
b12c53ce AS |
104 | uint8_t type; |
105 | uint8_t protocol; | |
106 | uint16_t from_port; | |
107 | uint16_t to_port; | |
108 | uint8_t dynamic; | |
7999be5b MW |
109 | char encoding[]; |
110 | } __attribute__((packed)); | |
111 | ||
00c1bd06 MW |
112 | METHOD(ha_message_t, get_type, ha_message_type_t, |
113 | private_ha_message_t *this) | |
e5e91eec MW |
114 | { |
115 | return this->buf.ptr[1]; | |
116 | } | |
117 | ||
118 | /** | |
119 | * check for space in buffer, increase if necessary | |
120 | */ | |
d8748966 | 121 | static void check_buf(private_ha_message_t *this, size_t len) |
e5e91eec | 122 | { |
12ec91ba MW |
123 | int increased = 0; |
124 | ||
e5e91eec MW |
125 | while (this->buf.len + len > this->allocated) |
126 | { /* double size */ | |
12ec91ba MW |
127 | this->allocated += ALLOCATION_BLOCK; |
128 | increased++; | |
129 | } | |
130 | if (increased) | |
131 | { | |
e5e91eec MW |
132 | this->buf.ptr = realloc(this->buf.ptr, this->allocated); |
133 | } | |
134 | } | |
135 | ||
00c1bd06 MW |
136 | METHOD(ha_message_t, add_attribute, void, |
137 | private_ha_message_t *this, ha_message_attribute_t attribute, ...) | |
e5e91eec MW |
138 | { |
139 | size_t len; | |
12ec91ba | 140 | va_list args; |
e5e91eec | 141 | |
b12c53ce | 142 | check_buf(this, sizeof(uint8_t)); |
e5e91eec | 143 | this->buf.ptr[this->buf.len] = attribute; |
b12c53ce | 144 | this->buf.len += sizeof(uint8_t); |
e5e91eec | 145 | |
12ec91ba | 146 | va_start(args, attribute); |
e5e91eec MW |
147 | switch (attribute) |
148 | { | |
12ec91ba | 149 | /* ike_sa_id_t* */ |
d8748966 MW |
150 | case HA_IKE_ID: |
151 | case HA_IKE_REKEY_ID: | |
12ec91ba MW |
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); | |
1726795f | 161 | enc->ike_version = id->get_ike_version(id); |
12ec91ba MW |
162 | enc->initiator_spi = id->get_initiator_spi(id); |
163 | enc->responder_spi = id->get_responder_spi(id); | |
e5e91eec | 164 | break; |
12ec91ba MW |
165 | } |
166 | /* identification_t* */ | |
d8748966 MW |
167 | case HA_LOCAL_ID: |
168 | case HA_REMOTE_ID: | |
fa4f71c8 | 169 | case HA_REMOTE_EAP_ID: |
12ec91ba MW |
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); | |
e5e91eec | 183 | break; |
12ec91ba MW |
184 | } |
185 | /* host_t* */ | |
d8748966 MW |
186 | case HA_LOCAL_ADDR: |
187 | case HA_REMOTE_ADDR: | |
188 | case HA_LOCAL_VIP: | |
189 | case HA_REMOTE_VIP: | |
94bbc602 | 190 | case HA_PEER_ADDR: |
12ec91ba MW |
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); | |
e5e91eec | 204 | break; |
12ec91ba MW |
205 | } |
206 | /* char* */ | |
d8748966 | 207 | case HA_CONFIG_NAME: |
12ec91ba MW |
208 | { |
209 | char *str; | |
210 | ||
211 | str = va_arg(args, char*); | |
212 | len = strlen(str) + 1; | |
e5e91eec | 213 | check_buf(this, len); |
12ec91ba | 214 | memcpy(this->buf.ptr + this->buf.len, str, len); |
e5e91eec MW |
215 | this->buf.len += len; |
216 | break; | |
12ec91ba | 217 | } |
b12c53ce | 218 | /* uint8_t */ |
8bcd9bd1 | 219 | case HA_IKE_VERSION: |
3e6736f6 | 220 | case HA_INITIATOR: |
d8748966 MW |
221 | case HA_IPSEC_MODE: |
222 | case HA_IPCOMP: | |
7999be5b | 223 | { |
b12c53ce | 224 | uint8_t val; |
7999be5b | 225 | |
34d240a6 | 226 | val = va_arg(args, u_int); |
7999be5b MW |
227 | check_buf(this, sizeof(val)); |
228 | this->buf.ptr[this->buf.len] = val; | |
229 | this->buf.len += sizeof(val); | |
230 | break; | |
231 | } | |
b12c53ce | 232 | /* uint16_t */ |
f1e90883 | 233 | case HA_ALG_DH: |
d8748966 MW |
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: | |
98788537 | 242 | case HA_ESN: |
eed20c21 | 243 | case HA_AUTH_METHOD: |
765935c8 | 244 | { |
b12c53ce | 245 | uint16_t val; |
765935c8 | 246 | |
34d240a6 | 247 | val = va_arg(args, u_int); |
765935c8 | 248 | check_buf(this, sizeof(val)); |
b12c53ce | 249 | *(uint16_t*)(this->buf.ptr + this->buf.len) = htons(val); |
765935c8 MW |
250 | this->buf.len += sizeof(val); |
251 | break; | |
252 | } | |
b12c53ce | 253 | /** uint32_t */ |
d8748966 MW |
254 | case HA_CONDITIONS: |
255 | case HA_EXTENSIONS: | |
256 | case HA_INBOUND_SPI: | |
257 | case HA_OUTBOUND_SPI: | |
ad2488fc | 258 | case HA_MID: |
12ec91ba | 259 | { |
b12c53ce | 260 | uint32_t val; |
12ec91ba | 261 | |
34d240a6 | 262 | val = va_arg(args, u_int); |
12ec91ba | 263 | check_buf(this, sizeof(val)); |
b12c53ce | 264 | *(uint32_t*)(this->buf.ptr + this->buf.len) = htonl(val); |
12ec91ba MW |
265 | this->buf.len += sizeof(val); |
266 | break; | |
267 | } | |
268 | /** chunk_t */ | |
d8748966 MW |
269 | case HA_NONCE_I: |
270 | case HA_NONCE_R: | |
271 | case HA_SECRET: | |
8bcd9bd1 MW |
272 | case HA_LOCAL_DH: |
273 | case HA_REMOTE_DH: | |
274 | case HA_PSK: | |
c8531b7e | 275 | case HA_IV: |
d8748966 | 276 | case HA_OLD_SKD: |
12ec91ba MW |
277 | { |
278 | chunk_t chunk; | |
279 | ||
280 | chunk = va_arg(args, chunk_t); | |
b12c53ce AS |
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), | |
190edaf5 | 284 | chunk.ptr, chunk.len); |
b12c53ce | 285 | this->buf.len += chunk.len + sizeof(uint16_t);; |
12ec91ba MW |
286 | break; |
287 | } | |
7999be5b | 288 | /** traffic_selector_t */ |
d8748966 MW |
289 | case HA_LOCAL_TS: |
290 | case HA_REMOTE_TS: | |
7999be5b MW |
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 | } | |
e5e91eec | 310 | default: |
12ec91ba | 311 | { |
e5e91eec | 312 | DBG1(DBG_CFG, "unable to encode, attribute %d unknown", attribute); |
b12c53ce | 313 | this->buf.len -= sizeof(uint8_t); |
e5e91eec | 314 | break; |
12ec91ba | 315 | } |
e5e91eec | 316 | } |
12ec91ba | 317 | va_end(args); |
e5e91eec MW |
318 | } |
319 | ||
190edaf5 MW |
320 | /** |
321 | * Attribute enumerator implementation | |
322 | */ | |
323 | typedef struct { | |
89bd016e | 324 | /** implements enumerator_t */ |
190edaf5 MW |
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 | ||
00c1bd06 | 334 | METHOD(enumerator_t, attribute_enumerate, bool, |
95a63bf2 | 335 | attribute_enumerator_t *this, va_list args) |
190edaf5 | 336 | { |
95a63bf2 TB |
337 | ha_message_attribute_t attr, *attr_out; |
338 | ha_message_value_t *value; | |
339 | ||
340 | VA_ARGS_VGET(args, attr_out, value); | |
190edaf5 MW |
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* */ | |
d8748966 MW |
356 | case HA_IKE_ID: |
357 | case HA_IKE_REKEY_ID: | |
190edaf5 MW |
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); | |
1726795f TB |
366 | value->ike_sa_id = ike_sa_id_create(enc->ike_version, |
367 | enc->initiator_spi, enc->responder_spi, | |
368 | enc->initiator); | |
190edaf5 MW |
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* */ | |
d8748966 MW |
376 | case HA_LOCAL_ID: |
377 | case HA_REMOTE_ID: | |
fa4f71c8 | 378 | case HA_REMOTE_EAP_ID: |
190edaf5 MW |
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* */ | |
d8748966 MW |
398 | case HA_LOCAL_ADDR: |
399 | case HA_REMOTE_ADDR: | |
400 | case HA_LOCAL_VIP: | |
401 | case HA_REMOTE_VIP: | |
94bbc602 | 402 | case HA_PEER_ADDR: |
190edaf5 MW |
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* */ | |
d8748966 | 427 | case HA_CONFIG_NAME: |
190edaf5 MW |
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 | } | |
b12c53ce | 441 | /* uint8_t */ |
8bcd9bd1 | 442 | case HA_IKE_VERSION: |
3e6736f6 | 443 | case HA_INITIATOR: |
d8748966 MW |
444 | case HA_IPSEC_MODE: |
445 | case HA_IPCOMP: | |
7999be5b | 446 | { |
b12c53ce | 447 | if (this->buf.len < sizeof(uint8_t)) |
7999be5b MW |
448 | { |
449 | return FALSE; | |
450 | } | |
b12c53ce | 451 | value->u8 = *(uint8_t*)this->buf.ptr; |
7999be5b | 452 | *attr_out = attr; |
b12c53ce | 453 | this->buf = chunk_skip(this->buf, sizeof(uint8_t)); |
7999be5b MW |
454 | return TRUE; |
455 | } | |
b12c53ce | 456 | /** uint16_t */ |
f1e90883 | 457 | case HA_ALG_DH: |
d8748966 MW |
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: | |
98788537 | 466 | case HA_ESN: |
eed20c21 | 467 | case HA_AUTH_METHOD: |
765935c8 | 468 | { |
b12c53ce | 469 | if (this->buf.len < sizeof(uint16_t)) |
765935c8 MW |
470 | { |
471 | return FALSE; | |
472 | } | |
b12c53ce | 473 | value->u16 = ntohs(*(uint16_t*)this->buf.ptr); |
765935c8 | 474 | *attr_out = attr; |
b12c53ce | 475 | this->buf = chunk_skip(this->buf, sizeof(uint16_t)); |
765935c8 MW |
476 | return TRUE; |
477 | } | |
b12c53ce | 478 | /** uint32_t */ |
d8748966 MW |
479 | case HA_CONDITIONS: |
480 | case HA_EXTENSIONS: | |
481 | case HA_INBOUND_SPI: | |
482 | case HA_OUTBOUND_SPI: | |
ad2488fc | 483 | case HA_MID: |
190edaf5 | 484 | { |
b12c53ce | 485 | if (this->buf.len < sizeof(uint32_t)) |
190edaf5 MW |
486 | { |
487 | return FALSE; | |
488 | } | |
b12c53ce | 489 | value->u32 = ntohl(*(uint32_t*)this->buf.ptr); |
190edaf5 | 490 | *attr_out = attr; |
b12c53ce | 491 | this->buf = chunk_skip(this->buf, sizeof(uint32_t)); |
190edaf5 MW |
492 | return TRUE; |
493 | } | |
494 | /** chunk_t */ | |
d8748966 MW |
495 | case HA_NONCE_I: |
496 | case HA_NONCE_R: | |
497 | case HA_SECRET: | |
8bcd9bd1 MW |
498 | case HA_LOCAL_DH: |
499 | case HA_REMOTE_DH: | |
500 | case HA_PSK: | |
c8531b7e | 501 | case HA_IV: |
d8748966 | 502 | case HA_OLD_SKD: |
190edaf5 MW |
503 | { |
504 | size_t len; | |
505 | ||
b12c53ce | 506 | if (this->buf.len < sizeof(uint16_t)) |
190edaf5 MW |
507 | { |
508 | return FALSE; | |
509 | } | |
b12c53ce AS |
510 | len = ntohs(*(uint16_t*)this->buf.ptr); |
511 | this->buf = chunk_skip(this->buf, sizeof(uint16_t)); | |
190edaf5 MW |
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 | } | |
d8748966 MW |
522 | case HA_LOCAL_TS: |
523 | case HA_REMOTE_TS: | |
7999be5b MW |
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 | } | |
190edaf5 MW |
585 | default: |
586 | { | |
587 | return FALSE; | |
588 | } | |
589 | } | |
590 | } | |
591 | ||
00c1bd06 MW |
592 | METHOD(enumerator_t, enum_destroy, void, |
593 | attribute_enumerator_t *this) | |
190edaf5 MW |
594 | { |
595 | if (this->cleanup) | |
596 | { | |
597 | this->cleanup(this->cleanup_data); | |
598 | } | |
599 | free(this); | |
600 | } | |
601 | ||
00c1bd06 MW |
602 | METHOD(ha_message_t, create_attribute_enumerator, enumerator_t*, |
603 | private_ha_message_t *this) | |
e5e91eec | 604 | { |
00c1bd06 | 605 | attribute_enumerator_t *e; |
190edaf5 | 606 | |
00c1bd06 MW |
607 | INIT(e, |
608 | .public = { | |
95a63bf2 TB |
609 | .enumerate = enumerator_enumerate_default, |
610 | .venumerate = _attribute_enumerate, | |
00c1bd06 MW |
611 | .destroy = _enum_destroy, |
612 | }, | |
613 | .buf = chunk_skip(this->buf, 2), | |
614 | ); | |
190edaf5 MW |
615 | |
616 | return &e->public; | |
e5e91eec MW |
617 | } |
618 | ||
00c1bd06 MW |
619 | METHOD(ha_message_t, get_encoding, chunk_t, |
620 | private_ha_message_t *this) | |
e5e91eec MW |
621 | { |
622 | return this->buf; | |
623 | } | |
624 | ||
00c1bd06 MW |
625 | METHOD(ha_message_t, destroy, void, |
626 | private_ha_message_t *this) | |
e5e91eec MW |
627 | { |
628 | free(this->buf.ptr); | |
629 | free(this); | |
630 | } | |
631 | ||
632 | ||
d8748966 | 633 | static private_ha_message_t *ha_message_create_generic() |
e5e91eec | 634 | { |
00c1bd06 | 635 | private_ha_message_t *this; |
e5e91eec | 636 | |
00c1bd06 MW |
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 | ); | |
e5e91eec MW |
646 | return this; |
647 | } | |
648 | ||
649 | /** | |
650 | * See header | |
651 | */ | |
d8748966 | 652 | ha_message_t *ha_message_create(ha_message_type_t type) |
e5e91eec | 653 | { |
d8748966 | 654 | private_ha_message_t *this = ha_message_create_generic(); |
e5e91eec | 655 | |
12ec91ba | 656 | this->allocated = ALLOCATION_BLOCK; |
e5e91eec MW |
657 | this->buf.ptr = malloc(this->allocated); |
658 | this->buf.len = 2; | |
d8748966 | 659 | this->buf.ptr[0] = HA_MESSAGE_VERSION; |
e5e91eec MW |
660 | this->buf.ptr[1] = type; |
661 | ||
662 | return &this->public; | |
663 | } | |
664 | ||
665 | /** | |
666 | * See header | |
667 | */ | |
d8748966 | 668 | ha_message_t *ha_message_parse(chunk_t data) |
e5e91eec | 669 | { |
d8748966 | 670 | private_ha_message_t *this; |
e5e91eec MW |
671 | |
672 | if (data.len < 2) | |
673 | { | |
d8748966 | 674 | DBG1(DBG_CFG, "HA message too short"); |
e5e91eec MW |
675 | return NULL; |
676 | } | |
d8748966 | 677 | if (data.ptr[0] != HA_MESSAGE_VERSION) |
e5e91eec | 678 | { |
d8748966 MW |
679 | DBG1(DBG_CFG, "HA message has version %d, expected %d", |
680 | data.ptr[0], HA_MESSAGE_VERSION); | |
e5e91eec MW |
681 | return NULL; |
682 | } | |
683 | ||
d8748966 | 684 | this = ha_message_create_generic(); |
e5e91eec MW |
685 | this->buf = chunk_clone(data); |
686 | this->allocated = this->buf.len; | |
687 | ||
688 | return &this->public; | |
689 | } | |
690 |