further mobike improvements, regarding to NAT-T
[strongswan.git] / src / charon / sa / tasks / ike_natd.c
1 /**
2 * @file ike_natd.c
3 *
4 * @brief Implementation of the ike_natd task.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006-2007 Martin Willi
10 * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
11 * Hochschule fuer Technik Rapperswil
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * for more details.
22 */
23
24 #include "ike_natd.h"
25
26 #include <string.h>
27
28 #include <daemon.h>
29 #include <crypto/hashers/hasher.h>
30 #include <encoding/payloads/notify_payload.h>
31
32
33 typedef struct private_ike_natd_t private_ike_natd_t;
34
35 /**
36 * Private members of a ike_natd_t task.
37 */
38 struct private_ike_natd_t {
39
40 /**
41 * Public methods and task_t interface.
42 */
43 ike_natd_t public;
44
45 /**
46 * Assigned IKE_SA.
47 */
48 ike_sa_t *ike_sa;
49
50 /**
51 * Are we the initiator?
52 */
53 bool initiator;
54
55 /**
56 * Hasher used to build NAT detection hashes
57 */
58 hasher_t *hasher;
59
60 /**
61 * Did we process any NAT detection notifys for a source address?
62 */
63 bool src_seen;
64
65 /**
66 * Did we process any NAT detection notifys for a destination address?
67 */
68 bool dst_seen;
69
70 /**
71 * Have we found a matching source address NAT hash?
72 */
73 bool src_matched;
74
75 /**
76 * Have we found a matching destination address NAT hash?
77 */
78 bool dst_matched;
79 };
80
81
82 /**
83 * Build NAT detection hash for a host
84 */
85 static chunk_t generate_natd_hash(private_ike_natd_t *this,
86 ike_sa_id_t *ike_sa_id, host_t *host)
87 {
88 chunk_t natd_chunk, spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk;
89 chunk_t natd_hash;
90 u_int64_t spi_i, spi_r;
91 u_int16_t port;
92
93 /* prepare all requred chunks */
94 spi_i = ike_sa_id->get_initiator_spi(ike_sa_id);
95 spi_r = ike_sa_id->get_responder_spi(ike_sa_id);
96 spi_i_chunk.ptr = (void*)&spi_i;
97 spi_i_chunk.len = sizeof(spi_i);
98 spi_r_chunk.ptr = (void*)&spi_r;
99 spi_r_chunk.len = sizeof(spi_r);
100 port = htons(host->get_port(host));
101 port_chunk.ptr = (void*)&port;
102 port_chunk.len = sizeof(port);
103 addr_chunk = host->get_address(host);
104
105 /* natd_hash = SHA1( spi_i | spi_r | address | port ) */
106 natd_chunk = chunk_cat("cccc", spi_i_chunk, spi_r_chunk, addr_chunk, port_chunk);
107 this->hasher->allocate_hash(this->hasher, natd_chunk, &natd_hash);
108 DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk);
109 DBG3(DBG_IKE, "natd_hash %B", &natd_hash);
110
111 chunk_free(&natd_chunk);
112 return natd_hash;
113 }
114
115 /**
116 * Build a NAT detection notify payload.
117 */
118 static notify_payload_t *build_natd_payload(private_ike_natd_t *this,
119 notify_type_t type, host_t *host)
120 {
121 chunk_t hash;
122 notify_payload_t *notify;
123 ike_sa_id_t *ike_sa_id;
124
125 ike_sa_id = this->ike_sa->get_id(this->ike_sa);
126 notify = notify_payload_create();
127 notify->set_notify_type(notify, type);
128 hash = generate_natd_hash(this, ike_sa_id, host);
129 notify->set_notification_data(notify, hash);
130 chunk_free(&hash);
131
132 return notify;
133 }
134
135 /**
136 * read notifys from message and evaluate them
137 */
138 static void process_payloads(private_ike_natd_t *this, message_t *message)
139 {
140 iterator_t *iterator;
141 payload_t *payload;
142 notify_payload_t *notify;
143 chunk_t hash, src_hash, dst_hash;
144 ike_sa_id_t *ike_sa_id;
145 host_t *me, *other;
146
147 /* Precompute NAT-D hashes for incoming NAT notify comparison */
148 ike_sa_id = message->get_ike_sa_id(message);
149 me = this->ike_sa->get_my_host(this->ike_sa);
150 other = this->ike_sa->get_other_host(this->ike_sa);
151 dst_hash = generate_natd_hash(this, ike_sa_id, me);
152 src_hash = generate_natd_hash(this, ike_sa_id, other);
153
154 DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash);
155 DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash);
156
157 iterator = message->get_payload_iterator(message);
158 while (iterator->iterate(iterator, (void**)&payload))
159 {
160 if (payload->get_type(payload) != NOTIFY)
161 {
162 continue;
163 }
164 notify = (notify_payload_t*)payload;
165 switch (notify->get_notify_type(notify))
166 {
167 case NAT_DETECTION_DESTINATION_IP:
168 {
169 this->dst_seen = TRUE;
170 if (!this->dst_matched)
171 {
172 hash = notify->get_notification_data(notify);
173 DBG3(DBG_IKE, "received dst_hash %B", &hash);
174 if (chunk_equals(hash, dst_hash))
175 {
176 this->dst_matched = TRUE;
177 }
178 }
179 break;
180 }
181 case NAT_DETECTION_SOURCE_IP:
182 {
183 this->src_seen = TRUE;
184 if (!this->src_matched)
185 {
186 hash = notify->get_notification_data(notify);
187 DBG3(DBG_IKE, "received src_hash %B", &hash);
188 if (chunk_equals(hash, src_hash))
189 {
190 this->src_matched = TRUE;
191 }
192 }
193 break;
194 }
195 default:
196 break;
197 }
198 }
199 iterator->destroy(iterator);
200
201 chunk_free(&src_hash);
202 chunk_free(&dst_hash);
203
204 if (this->src_seen && this->dst_seen)
205 {
206 this->ike_sa->enable_extension(this->ike_sa, EXT_NATT);
207
208 this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE,
209 !this->dst_matched);
210 this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE,
211 !this->src_matched);
212 }
213 }
214
215 /**
216 * Implementation of task_t.process for initiator
217 */
218 static status_t process_i(private_ike_natd_t *this, message_t *message)
219 {
220 process_payloads(this, message);
221
222 /* if peer supports NAT-T, we switch to port 4500 even
223 * if no NAT is detected. MOBIKE requires this. */
224 if (message->get_exchange_type(message) == IKE_SA_INIT &&
225 this->ike_sa->supports_extension(this->ike_sa, EXT_NATT))
226 {
227 host_t *me, *other;
228
229 me = this->ike_sa->get_my_host(this->ike_sa);
230 me->set_port(me, IKEV2_NATT_PORT);
231 other = this->ike_sa->get_other_host(this->ike_sa);
232 other->set_port(other, IKEV2_NATT_PORT);
233 }
234
235 return SUCCESS;
236 }
237
238 /**
239 * Implementation of task_t.process for initiator
240 */
241 static status_t build_i(private_ike_natd_t *this, message_t *message)
242 {
243 notify_payload_t *notify;
244 iterator_t *iterator;
245 host_t *host;
246
247 /* destination is always set */
248 host = this->ike_sa->get_other_host(this->ike_sa);
249 notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
250 message->add_payload(message, (payload_t*)notify);
251
252 /* source may be any, we have 3 possibilities to get our source address:
253 * 1. It is defined in the config => use the one of the IKE_SA
254 * 2. We do a routing lookup in the kernel interface
255 * 3. Include all possbile addresses
256 */
257 host = this->ike_sa->get_my_host(this->ike_sa);
258 if (!host->is_anyaddr(host))
259 { /* 1. */
260 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
261 message->add_payload(message, (payload_t*)notify);
262 }
263 else
264 {
265 host = charon->kernel_interface->get_source_addr(
266 charon->kernel_interface,
267 this->ike_sa->get_other_host(this->ike_sa));
268 if (host)
269 { /* 2. */
270 host->set_port(host, IKEV2_UDP_PORT);
271 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
272 message->add_payload(message, (payload_t*)notify);
273 host->destroy(host);
274 }
275 else
276 { /* 3. */
277 iterator = charon->kernel_interface->create_address_iterator(
278 charon->kernel_interface);
279 while (iterator->iterate(iterator, (void**)&host))
280 {
281 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
282 message->add_payload(message, (payload_t*)notify);
283 }
284 iterator->destroy(iterator);
285 }
286 }
287 return NEED_MORE;
288 }
289
290 /**
291 * Implementation of task_t.build for responder
292 */
293 static status_t build_r(private_ike_natd_t *this, message_t *message)
294 {
295 notify_payload_t *notify;
296 host_t *me, *other;
297
298 /* only add notifies on successfull responses. */
299 if (message->get_exchange_type(message) == IKE_SA_INIT &&
300 message->get_payload(message, SECURITY_ASSOCIATION) == NULL)
301 {
302 return SUCCESS;
303 }
304
305 if (this->src_seen && this->dst_seen)
306 {
307 /* initiator seems to support NAT detection, add response */
308 me = this->ike_sa->get_my_host(this->ike_sa);
309 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
310 message->add_payload(message, (payload_t*)notify);
311
312 other = this->ike_sa->get_other_host(this->ike_sa);
313 notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
314 message->add_payload(message, (payload_t*)notify);
315 }
316 return SUCCESS;
317 }
318
319 /**
320 * Implementation of task_t.process for responder
321 */
322 static status_t process_r(private_ike_natd_t *this, message_t *message)
323 {
324 process_payloads(this, message);
325
326 return NEED_MORE;
327 }
328
329 /**
330 * Implementation of task_t.get_type
331 */
332 static task_type_t get_type(private_ike_natd_t *this)
333 {
334 return IKE_NATD;
335 }
336
337 /**
338 * Implementation of task_t.migrate
339 */
340 static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
341 {
342 this->ike_sa = ike_sa;
343 this->src_seen = FALSE;
344 this->dst_seen = FALSE;
345 this->src_matched = FALSE;
346 this->dst_matched = FALSE;
347 }
348
349 /**
350 * Implementation of task_t.destroy
351 */
352 static void destroy(private_ike_natd_t *this)
353 {
354 this->hasher->destroy(this->hasher);
355 free(this);
356 }
357
358 /*
359 * Described in header.
360 */
361 ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
362 {
363 private_ike_natd_t *this = malloc_thing(private_ike_natd_t);
364
365 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
366 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
367 this->public.task.destroy = (void(*)(task_t*))destroy;
368
369 if (initiator)
370 {
371 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
372 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
373 }
374 else
375 {
376 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
377 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
378 }
379
380 this->ike_sa = ike_sa;
381 this->initiator = initiator;
382 this->hasher = hasher_create(HASH_SHA1);
383 this->src_seen = FALSE;
384 this->dst_seen = FALSE;
385 this->src_matched = FALSE;
386 this->dst_matched = FALSE;
387
388 return &this->public;
389 }