9b8369355c89560932ac7b03d5c10dc6e53e1385
[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 if (!this->dst_matched)
207 {
208 this->ike_sa->enable_natt(this->ike_sa, TRUE);
209 }
210 if (!this->src_matched)
211 {
212 this->ike_sa->enable_natt(this->ike_sa, FALSE);
213 }
214 }
215 }
216
217 /**
218 * Implementation of task_t.process for initiator
219 */
220 static status_t process_i(private_ike_natd_t *this, message_t *message)
221 {
222 process_payloads(this, message);
223
224 if (this->ike_sa->is_natt_enabled(this->ike_sa))
225 {
226 host_t *me, *other;
227
228 me = this->ike_sa->get_my_host(this->ike_sa);
229 me->set_port(me, IKEV2_NATT_PORT);
230 other = this->ike_sa->get_other_host(this->ike_sa);
231 other->set_port(other, IKEV2_NATT_PORT);
232 }
233
234 return SUCCESS;
235 }
236
237 /**
238 * Implementation of task_t.process for initiator
239 */
240 static status_t build_i(private_ike_natd_t *this, message_t *message)
241 {
242 notify_payload_t *notify;
243 linked_list_t *list;
244 host_t *host;
245
246 /* include one notify if our address is defined, all addresses otherwise */
247 host = this->ike_sa->get_my_host(this->ike_sa);
248 if (host->is_anyaddr(host))
249 {
250 /* TODO: we could get the src address from netlink!? */
251 list = charon->kernel_interface->create_address_list(charon->kernel_interface);
252 while (list->remove_first(list, (void**)&host) == SUCCESS)
253 {
254 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
255 host->destroy(host);
256 message->add_payload(message, (payload_t*)notify);
257 }
258 list->destroy(list);
259 }
260 else
261 {
262 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, host);
263 message->add_payload(message, (payload_t*)notify);
264 }
265
266 host = this->ike_sa->get_other_host(this->ike_sa);
267 notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, host);
268 message->add_payload(message, (payload_t*)notify);
269
270 return NEED_MORE;
271 }
272
273 /**
274 * Implementation of task_t.build for responder
275 */
276 static status_t build_r(private_ike_natd_t *this, message_t *message)
277 {
278 notify_payload_t *notify;
279 host_t *me, *other;
280
281 /* only add notifies on successfull responses. */
282 if (message->get_payload(message, SECURITY_ASSOCIATION))
283 {
284 return NEED_MORE;
285 }
286
287 if (this->src_seen && this->dst_seen)
288 {
289 /* initiator seems to support NAT detection, add response */
290 me = this->ike_sa->get_my_host(this->ike_sa);
291 notify = build_natd_payload(this, NAT_DETECTION_SOURCE_IP, me);
292 message->add_payload(message, (payload_t*)notify);
293
294 other = this->ike_sa->get_other_host(this->ike_sa);
295 notify = build_natd_payload(this, NAT_DETECTION_DESTINATION_IP, other);
296 message->add_payload(message, (payload_t*)notify);
297 }
298 return SUCCESS;
299 }
300
301 /**
302 * Implementation of task_t.process for responder
303 */
304 static status_t process_r(private_ike_natd_t *this, message_t *message)
305 {
306 process_payloads(this, message);
307
308 return NEED_MORE;
309 }
310
311 /**
312 * Implementation of task_t.get_type
313 */
314 static task_type_t get_type(private_ike_natd_t *this)
315 {
316 return IKE_NATD;
317 }
318
319 /**
320 * Implementation of task_t.migrate
321 */
322 static void migrate(private_ike_natd_t *this, ike_sa_t *ike_sa)
323 {
324 this->ike_sa = ike_sa;
325 this->src_seen = FALSE;
326 this->dst_seen = FALSE;
327 this->src_matched = FALSE;
328 this->dst_matched = FALSE;
329 }
330
331 /**
332 * Implementation of task_t.destroy
333 */
334 static void destroy(private_ike_natd_t *this)
335 {
336 this->hasher->destroy(this->hasher);
337 free(this);
338 }
339
340 /*
341 * Described in header.
342 */
343 ike_natd_t *ike_natd_create(ike_sa_t *ike_sa, bool initiator)
344 {
345 private_ike_natd_t *this = malloc_thing(private_ike_natd_t);
346
347 this->public.task.get_type = (task_type_t(*)(task_t*))get_type;
348 this->public.task.migrate = (void(*)(task_t*,ike_sa_t*))migrate;
349 this->public.task.destroy = (void(*)(task_t*))destroy;
350
351 if (initiator)
352 {
353 this->public.task.build = (status_t(*)(task_t*,message_t*))build_i;
354 this->public.task.process = (status_t(*)(task_t*,message_t*))process_i;
355 }
356 else
357 {
358 this->public.task.build = (status_t(*)(task_t*,message_t*))build_r;
359 this->public.task.process = (status_t(*)(task_t*,message_t*))process_r;
360 }
361
362 this->ike_sa = ike_sa;
363 this->initiator = initiator;
364 this->hasher = hasher_create(HASH_SHA1);
365 this->src_seen = FALSE;
366 this->dst_seen = FALSE;
367 this->src_matched = FALSE;
368 this->dst_matched = FALSE;
369
370 return &this->public;
371 }