ee3aa245cb83948385fc2df24ef77cafb2ba75cb
[strongswan.git] / src / charon / plugins / ha_sync / ha_sync_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 * $Id$
16 */
17
18 #include "ha_sync_message.h"
19
20 #include <arpa/inet.h>
21
22 #include <daemon.h>
23
24 #define ALLOCATION_BLOCK 64
25
26 typedef struct private_ha_sync_message_t private_ha_sync_message_t;
27
28 /**
29 * Private data of an ha_sync_message_t object.
30 */
31 struct private_ha_sync_message_t {
32
33 /**
34 * Public ha_sync_message_t interface.
35 */
36 ha_sync_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 /**
83 * Implementation of ha_sync_message_t.get_type
84 */
85 static ha_sync_message_type_t get_type(private_ha_sync_message_t *this)
86 {
87 return this->buf.ptr[1];
88 }
89
90 /**
91 * check for space in buffer, increase if necessary
92 */
93 static void check_buf(private_ha_sync_message_t *this, size_t len)
94 {
95 int increased = 0;
96
97 while (this->buf.len + len > this->allocated)
98 { /* double size */
99 this->allocated += ALLOCATION_BLOCK;
100 increased++;
101 }
102 if (increased)
103 {
104 this->buf.ptr = realloc(this->buf.ptr, this->allocated);
105 }
106 }
107
108 /**
109 * Implementation of ha_sync_message_t.add_attribute
110 */
111 static void add_attribute(private_ha_sync_message_t *this,
112 ha_sync_message_attribute_t attribute, ...)
113 {
114 size_t len;
115 va_list args;
116
117 check_buf(this, sizeof(u_int8_t));
118 this->buf.ptr[this->buf.len] = attribute;
119 this->buf.len += sizeof(u_int8_t);
120
121 va_start(args, attribute);
122 switch (attribute)
123 {
124 /* ike_sa_id_t* */
125 case HA_SYNC_IKE_ID:
126 case HA_SYNC_IKE_REKEY_ID:
127 {
128 ike_sa_id_encoding_t *enc;
129 ike_sa_id_t *id;
130
131 id = va_arg(args, ike_sa_id_t*);
132 check_buf(this, sizeof(ike_sa_id_encoding_t));
133 enc = (ike_sa_id_encoding_t*)(this->buf.ptr + this->buf.len);
134 this->buf.len += sizeof(ike_sa_id_encoding_t);
135 enc->initiator = id->is_initiator(id);
136 enc->initiator_spi = id->get_initiator_spi(id);
137 enc->responder_spi = id->get_responder_spi(id);
138 break;
139 }
140 /* identification_t* */
141 case HA_SYNC_LOCAL_ID:
142 case HA_SYNC_REMOTE_ID:
143 case HA_SYNC_EAP_ID:
144 {
145 identification_encoding_t *enc;
146 identification_t *id;
147 chunk_t data;
148
149 id = va_arg(args, identification_t*);
150 data = id->get_encoding(id);
151 check_buf(this, sizeof(identification_encoding_t) + data.len);
152 enc = (identification_encoding_t*)(this->buf.ptr + this->buf.len);
153 this->buf.len += sizeof(identification_encoding_t) + data.len;
154 enc->type = id->get_type(id);
155 enc->len = data.len;
156 memcpy(enc->encoding, data.ptr, data.len);
157 break;
158 }
159 /* host_t* */
160 case HA_SYNC_LOCAL_ADDR:
161 case HA_SYNC_REMOTE_ADDR:
162 case HA_SYNC_LOCAL_VIP:
163 case HA_SYNC_REMOTE_VIP:
164 case HA_SYNC_ADDITIONAL_ADDR:
165 {
166 host_encoding_t *enc;
167 host_t *host;
168 chunk_t data;
169
170 host = va_arg(args, host_t*);
171 data = host->get_address(host);
172 check_buf(this, sizeof(host_encoding_t) + data.len);
173 enc = (host_encoding_t*)(this->buf.ptr + this->buf.len);
174 this->buf.len += sizeof(host_encoding_t) + data.len;
175 enc->family = host->get_family(host);
176 enc->port = htons(host->get_port(host));
177 memcpy(enc->encoding, data.ptr, data.len);
178 break;
179 }
180 /* char* */
181 case HA_SYNC_CONFIG_NAME:
182 {
183 char *str;
184
185 str = va_arg(args, char*);
186 len = strlen(str) + 1;
187 check_buf(this, len);
188 memcpy(this->buf.ptr + this->buf.len, str, len);
189 this->buf.len += len;
190 break;
191 }
192 /** u_int32_t */
193 case HA_SYNC_CONDITIONS:
194 case HA_SYNC_EXTENSIONS:
195 {
196 u_int32_t val;
197
198 val = va_arg(args, u_int32_t);
199 check_buf(this, sizeof(val));
200 this->buf.ptr[this->buf.len] = htonl(val);
201 this->buf.len += sizeof(val);
202 break;
203 }
204 /** chunk_t */
205 case HA_SYNC_NONCE_I:
206 case HA_SYNC_NONCE_R:
207 case HA_SYNC_SECRET:
208 {
209 chunk_t chunk;
210
211 chunk = va_arg(args, chunk_t);
212 check_buf(this, chunk.len);
213 memcpy(this->buf.ptr + this->buf.len, chunk.ptr, chunk.len);
214 this->buf.len += chunk.len;
215 break;
216 }
217 default:
218 {
219 DBG1(DBG_CFG, "unable to encode, attribute %d unknown", attribute);
220 this->buf.len -= sizeof(u_int8_t);
221 break;
222 }
223 }
224 va_end(args);
225 }
226
227 /**
228 * Implementation of ha_sync_message_t.create_attribute_enumerator
229 */
230 static enumerator_t* create_attribute_enumerator(private_ha_sync_message_t *this)
231 {
232 return enumerator_create_empty();
233 }
234
235 /**
236 * Implementation of ha_sync_message_t.get_encoding
237 */
238 static chunk_t get_encoding(private_ha_sync_message_t *this)
239 {
240 return this->buf;
241 }
242
243 /**
244 * Implementation of ha_sync_message_t.destroy.
245 */
246 static void destroy(private_ha_sync_message_t *this)
247 {
248 free(this->buf.ptr);
249 free(this);
250 }
251
252
253 static private_ha_sync_message_t *ha_sync_message_create_generic()
254 {
255 private_ha_sync_message_t *this = malloc_thing(private_ha_sync_message_t);
256
257 this->public.get_type = (ha_sync_message_type_t(*)(ha_sync_message_t*))get_type;
258 this->public.add_attribute = (void(*)(ha_sync_message_t*, ha_sync_message_attribute_t attribute, ...))add_attribute;
259 this->public.create_attribute_enumerator = (enumerator_t*(*)(ha_sync_message_t*))create_attribute_enumerator;
260 this->public.get_encoding = (chunk_t(*)(ha_sync_message_t*))get_encoding;
261 this->public.destroy = (void(*)(ha_sync_message_t*))destroy;
262
263 return this;
264 }
265
266 /**
267 * See header
268 */
269 ha_sync_message_t *ha_sync_message_create(ha_sync_message_type_t type)
270 {
271 private_ha_sync_message_t *this = ha_sync_message_create_generic();
272
273 this->allocated = ALLOCATION_BLOCK;
274 this->buf.ptr = malloc(this->allocated);
275 this->buf.len = 2;
276 this->buf.ptr[0] = HA_SYNC_MESSAGE_VERSION;
277 this->buf.ptr[1] = type;
278
279 return &this->public;
280 }
281
282 /**
283 * See header
284 */
285 ha_sync_message_t *ha_sync_message_parse(chunk_t data)
286 {
287 private_ha_sync_message_t *this;
288
289 if (data.len < 2)
290 {
291 DBG1(DBG_CFG, "HA sync message too short");
292 return NULL;
293 }
294 if (data.ptr[0] != HA_SYNC_MESSAGE_VERSION)
295 {
296 DBG1(DBG_CFG, "HA sync message has version %d, expected %d",
297 data.ptr[0], HA_SYNC_MESSAGE_VERSION);
298 return NULL;
299 }
300
301 this = ha_sync_message_create_generic();
302 this->buf = chunk_clone(data);
303 this->allocated = this->buf.len;
304
305 return &this->public;
306 }
307