69bf43a7b15b86062771292bcb3f7f82afec61d3
[strongswan.git] / src / libcharon / encoding / payloads / endpoint_notify.c
1 /*
2 * Copyright (C) 2007 Tobias Brunner
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 #include "endpoint_notify.h"
17
18 #include <math.h>
19
20 #include <daemon.h>
21
22 typedef struct private_endpoint_notify_t private_endpoint_notify_t;
23
24 /**
25 * Private data of an notify_payload_t object.
26 */
27 struct private_endpoint_notify_t {
28 /**
29 * Public endpoint_notify_t interface.
30 */
31 endpoint_notify_t public;
32
33 /**
34 * Priority
35 */
36 u_int32_t priority;
37
38 /**
39 * Family
40 */
41 me_endpoint_family_t family;
42
43 /**
44 * Endpoint type
45 */
46 me_endpoint_type_t type;
47
48 /**
49 * Endpoint
50 */
51 host_t *endpoint;
52
53 /**
54 * Base (used for server reflexive endpoints)
55 */
56 host_t *base;
57 };
58
59 /* Notification data:
60 1 2 3
61 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
62 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 ! Priority !
64 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65 ! Family ! Type ! Port !
66 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 ! IP Address (variable) !
68 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69 */
70
71 ENUM(me_endpoint_type_names, HOST, RELAYED,
72 "HOST",
73 "PEER_REFLEXIVE",
74 "SERVER_REFLEXIVE",
75 "RELAYED"
76 );
77
78 /**
79 * Helper functions to parse integer values
80 */
81 static status_t parse_uint8(u_int8_t **cur, u_int8_t *top, u_int8_t *val)
82 {
83 if (*cur + sizeof(u_int8_t) > top)
84 {
85 return FAILED;
86 }
87 *val = *(u_int8_t*)*cur;
88 *cur += sizeof(u_int8_t);
89 return SUCCESS;
90 }
91
92 static status_t parse_uint16(u_int8_t **cur, u_int8_t *top, u_int16_t *val)
93 {
94 if (*cur + sizeof(u_int16_t) > top)
95 {
96 return FAILED;
97 }
98 *val = ntohs(*(u_int16_t*)*cur);
99 *cur += sizeof(u_int16_t);
100 return SUCCESS;
101 }
102
103 static status_t parse_uint32(u_int8_t **cur, u_int8_t *top, u_int32_t *val)
104 {
105 if (*cur + sizeof(u_int32_t) > top)
106 {
107 return FAILED;
108 }
109 *val = ntohl(*(u_int32_t*)*cur);
110 *cur += sizeof(u_int32_t);
111 return SUCCESS;
112 }
113
114 /**
115 * Parses the notification data of a ME_ENDPOINT notify
116 */
117 static status_t parse_notification_data(private_endpoint_notify_t *this, chunk_t data)
118 {
119 u_int8_t family, type, addr_family;
120 u_int16_t port;
121 chunk_t addr;
122 u_int8_t *cur = data.ptr;
123 u_int8_t *top = data.ptr + data.len;
124
125 DBG3(DBG_IKE, "me_endpoint_data %B", &data);
126
127 if (parse_uint32(&cur, top, &this->priority) != SUCCESS)
128 {
129 DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid priority");
130 return FAILED;
131 }
132
133 if (parse_uint8(&cur, top, &family) != SUCCESS || family >= MAX_FAMILY)
134 {
135 DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid family");
136 return FAILED;
137 }
138 this->family = (me_endpoint_family_t)family;
139
140 if (parse_uint8(&cur, top, &type) != SUCCESS ||
141 type == NO_TYPE || type >= MAX_TYPE)
142 {
143 DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid type");
144 return FAILED;
145 }
146 this->type = (me_endpoint_type_t)type;
147
148 addr_family = AF_INET;
149 addr.len = 4;
150
151 switch(this->family)
152 {
153 case IPv6:
154 addr_family = AF_INET6;
155 addr.len = 16;
156 /* fall-through */
157 case IPv4:
158 if (parse_uint16(&cur, top, &port) != SUCCESS)
159 {
160 DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid port");
161 return FAILED;
162 }
163
164 if (cur + addr.len > top)
165 {
166 DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid IP address");
167 return FAILED;
168 }
169
170 addr.ptr = cur;
171 this->endpoint = host_create_from_chunk(addr_family, addr, port);
172 break;
173 case NO_FAMILY:
174 default:
175 this->endpoint = NULL;
176 break;
177 }
178 return SUCCESS;
179 }
180
181
182 /**
183 * Generates the notification data of a ME_ENDPOINT notify
184 */
185 static chunk_t build_notification_data(private_endpoint_notify_t *this)
186 {
187 chunk_t prio_chunk, family_chunk, type_chunk, port_chunk, addr_chunk;
188 chunk_t data;
189 u_int32_t prio;
190 u_int16_t port;
191 u_int8_t family, type;
192
193 prio = htonl(this->priority);
194 prio_chunk = chunk_from_thing(prio);
195 family = this->family;
196 family_chunk = chunk_from_thing(family);
197 type = this->type;
198 type_chunk = chunk_from_thing(type);
199
200 if (this->endpoint)
201 {
202 port = htons(this->endpoint->get_port(this->endpoint));
203 addr_chunk = this->endpoint->get_address(this->endpoint);
204 }
205 else
206 {
207 port = 0;
208 addr_chunk = chunk_empty;
209 }
210 port_chunk = chunk_from_thing(port);
211
212 /* data = prio | family | type | port | addr */
213 data = chunk_cat("ccccc", prio_chunk, family_chunk, type_chunk,
214 port_chunk, addr_chunk);
215 DBG3(DBG_IKE, "me_endpoint_data %B", &data);
216 return data;
217 }
218
219 METHOD(endpoint_notify_t, build_notify, notify_payload_t*,
220 private_endpoint_notify_t *this)
221 {
222 chunk_t data;
223 notify_payload_t *notify;
224
225 notify = notify_payload_create();
226 notify->set_notify_type(notify, ME_ENDPOINT);
227 data = build_notification_data(this);
228 notify->set_notification_data(notify, data);
229 chunk_free(&data);
230
231 return notify;
232 }
233
234
235 METHOD(endpoint_notify_t, get_priority, u_int32_t,
236 private_endpoint_notify_t *this)
237 {
238 return this->priority;
239 }
240
241 METHOD(endpoint_notify_t, set_priority, void,
242 private_endpoint_notify_t *this, u_int32_t priority)
243 {
244 this->priority = priority;
245 }
246
247 METHOD(endpoint_notify_t, get_type, me_endpoint_type_t,
248 private_endpoint_notify_t *this)
249 {
250 return this->type;
251 }
252
253 METHOD(endpoint_notify_t, get_family, me_endpoint_family_t,
254 private_endpoint_notify_t *this)
255 {
256 return this->family;
257 }
258
259 METHOD(endpoint_notify_t, get_host, host_t*,
260 private_endpoint_notify_t *this)
261 {
262 return this->endpoint;
263 }
264
265 METHOD(endpoint_notify_t, get_base, host_t*,
266 private_endpoint_notify_t *this)
267 {
268 return (!this->base) ? this->endpoint : this->base;
269 }
270
271 METHOD(endpoint_notify_t, clone_, endpoint_notify_t*,
272 private_endpoint_notify_t *this)
273 {
274 private_endpoint_notify_t *clone;
275
276 clone = (private_endpoint_notify_t*)endpoint_notify_create();
277 clone->priority = this->priority;
278 clone->type = this->type;
279 clone->family = this->family;
280
281 if (this->endpoint)
282 {
283 clone->endpoint = this->endpoint->clone(this->endpoint);
284 }
285
286 if (this->base)
287 {
288 clone->base = this->base->clone(this->base);
289 }
290
291 return &clone->public;
292 }
293
294 METHOD(endpoint_notify_t, destroy, void,
295 private_endpoint_notify_t *this)
296 {
297 DESTROY_IF(this->endpoint);
298 DESTROY_IF(this->base);
299 free(this);
300 }
301
302 /*
303 * Described in header
304 */
305 endpoint_notify_t *endpoint_notify_create()
306 {
307 private_endpoint_notify_t *this;
308
309 INIT(this,
310 .public = {
311 .get_priority = _get_priority,
312 .set_priority = _set_priority,
313 .get_type = _get_type,
314 .get_family = _get_family,
315 .get_host = _get_host,
316 .get_base = _get_base,
317 .build_notify = _build_notify,
318 .clone = _clone_,
319 .destroy = _destroy,
320 },
321 .family = NO_FAMILY,
322 .type = NO_TYPE,
323 );
324
325 return &this->public;
326 }
327
328 /**
329 * Described in header
330 */
331 endpoint_notify_t *endpoint_notify_create_from_host(me_endpoint_type_t type, host_t *host, host_t *base)
332 {
333 private_endpoint_notify_t *this;
334
335 this = (private_endpoint_notify_t*)endpoint_notify_create();
336 this->type = type;
337
338 switch(type)
339 {
340 case HOST:
341 this->priority = pow(2, 16) * ME_PRIO_HOST;
342 break;
343 case PEER_REFLEXIVE:
344 this->priority = pow(2, 16) * ME_PRIO_PEER;
345 break;
346 case SERVER_REFLEXIVE:
347 this->priority = pow(2, 16) * ME_PRIO_SERVER;
348 break;
349 case RELAYED:
350 default:
351 this->priority = pow(2, 16) * ME_PRIO_RELAY;
352 break;
353 }
354
355 /* FIXME: if there is more than one ip address we should vary this priority */
356 this->priority += 65535;
357
358 if (!host)
359 {
360 return &this->public;
361 }
362
363 switch(host->get_family(host))
364 {
365 case AF_INET:
366 this->family = IPv4;
367 break;
368 case AF_INET6:
369 this->family = IPv6;
370 break;
371 default:
372 /* unsupported family type, we do not set the host
373 * (family is set to NO_FAMILY) */
374 return &this->public;
375 }
376
377 this->endpoint = host->clone(host);
378
379 if (base)
380 {
381 this->base = base->clone(base);
382 }
383
384 return &this->public;
385 }
386
387 /**
388 * Described in header
389 */
390 endpoint_notify_t *endpoint_notify_create_from_payload(notify_payload_t *notify)
391 {
392 private_endpoint_notify_t *this;
393 chunk_t data;
394
395 if (notify->get_notify_type(notify) != ME_ENDPOINT)
396 {
397 return NULL;
398 }
399
400 this = (private_endpoint_notify_t*)endpoint_notify_create();
401 data = notify->get_notification_data(notify);
402
403 if (parse_notification_data(this, data) != SUCCESS)
404 {
405 destroy(this);
406 return NULL;
407 }
408 return &this->public;
409 }