2 * Copyright (C) 2006-2011 Tobias Brunner,
3 * Copyright (C) 2006-2007 Martin Willi
4 * Copyright (C) 2006 Daniel Roethlisberger
5 * Hochschule fuer Technik Rapperswil
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "isakmp_natd.h"
24 #include <sa/ikev1/keymat_v1.h>
25 #include <config/peer_cfg.h>
26 #include <crypto/hashers/hasher.h>
27 #include <encoding/payloads/hash_payload.h>
29 typedef struct private_isakmp_natd_t private_isakmp_natd_t
;
32 * Private members of a ike_natt_t task.
34 struct private_isakmp_natd_t
{
47 * Are we the initiator?
52 * Keymat derivation (from SA)
57 * Did we process any NAT detection payloads for a source address?
62 * Did we process any NAT detection payloads for a destination address?
67 * Have we found a matching source address NAT hash?
72 * Have we found a matching destination address NAT hash?
78 * Build NAT detection hash for a host.
80 static chunk_t
generate_natd_hash(private_isakmp_natd_t
*this,
81 ike_sa_id_t
*ike_sa_id
, host_t
*host
)
84 chunk_t natd_chunk
, natd_hash
;
85 u_int64_t spi_i
, spi_r
;
88 hasher
= this->keymat
->get_hasher(this->keymat
);
91 DBG1(DBG_IKE
, "no hasher available to build NAT-D payload");
95 spi_i
= ike_sa_id
->get_initiator_spi(ike_sa_id
);
96 spi_r
= ike_sa_id
->get_responder_spi(ike_sa_id
);
97 port
= htons(host
->get_port(host
));
99 /* natd_hash = HASH(CKY-I | CKY-R | IP | Port) */
100 natd_chunk
= chunk_cata("cccc", chunk_from_thing(spi_i
),
101 chunk_from_thing(spi_r
), host
->get_address(host
),
102 chunk_from_thing(port
));
103 if (!hasher
->allocate_hash(hasher
, natd_chunk
, &natd_hash
))
105 DBG1(DBG_IKE
, "creating NAT-D payload hash failed");
108 DBG3(DBG_IKE
, "natd_chunk %B", &natd_chunk
);
109 DBG3(DBG_IKE
, "natd_hash %B", &natd_hash
);
115 * Build a faked NAT-D payload to enforce UDP encapsulation.
117 static chunk_t
generate_natd_hash_faked(private_isakmp_natd_t
*this)
123 hasher
= this->keymat
->get_hasher(this->keymat
);
126 DBG1(DBG_IKE
, "no hasher available to build NAT-D payload");
129 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_WEAK
);
131 !rng
->allocate_bytes(rng
, hasher
->get_hash_size(hasher
), &chunk
))
133 DBG1(DBG_IKE
, "unable to get random bytes for NAT-D fake");
142 * Build a NAT-D payload.
144 static hash_payload_t
*build_natd_payload(private_isakmp_natd_t
*this, bool src
,
147 hash_payload_t
*payload
;
151 config
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
152 if (src
&& config
->force_encap(config
))
154 hash
= generate_natd_hash_faked(this);
158 ike_sa_id_t
*ike_sa_id
= this->ike_sa
->get_id(this->ike_sa
);
159 hash
= generate_natd_hash(this, ike_sa_id
, host
);
165 payload
= hash_payload_create(NAT_D_V1
);
166 payload
->set_hash(payload
, hash
);
172 * Add NAT-D payloads to the message.
174 static void add_natd_payloads(private_isakmp_natd_t
*this, message_t
*message
)
176 hash_payload_t
*payload
;
179 /* destination has to be added first */
180 host
= message
->get_destination(message
);
181 payload
= build_natd_payload(this, FALSE
, host
);
184 message
->add_payload(message
, (payload_t
*)payload
);
187 /* source is added second, compared with IKEv2 we always know the source,
188 * as these payloads are added in the second Phase 1 exchange or the
189 * response to the first */
190 host
= message
->get_source(message
);
191 payload
= build_natd_payload(this, TRUE
, host
);
194 message
->add_payload(message
, (payload_t
*)payload
);
199 * Read NAT-D payloads from message and evaluate them.
201 static void process_payloads(private_isakmp_natd_t
*this, message_t
*message
)
203 enumerator_t
*enumerator
;
205 hash_payload_t
*hash_payload
;
206 chunk_t hash
, src_hash
, dst_hash
;
207 ike_sa_id_t
*ike_sa_id
;
211 /* precompute hashes for incoming NAT-D comparison */
212 ike_sa_id
= message
->get_ike_sa_id(message
);
213 me
= message
->get_destination(message
);
214 other
= message
->get_source(message
);
215 dst_hash
= generate_natd_hash(this, ike_sa_id
, me
);
216 src_hash
= generate_natd_hash(this, ike_sa_id
, other
);
218 DBG3(DBG_IKE
, "precalculated src_hash %B", &src_hash
);
219 DBG3(DBG_IKE
, "precalculated dst_hash %B", &dst_hash
);
221 enumerator
= message
->create_payload_enumerator(message
);
222 while (enumerator
->enumerate(enumerator
, &payload
))
224 if (payload
->get_type(payload
) != NAT_D_V1
)
228 hash_payload
= (hash_payload_t
*)payload
;
230 { /* the first NAT-D payload contains the destination hash */
231 this->dst_seen
= TRUE
;
232 hash
= hash_payload
->get_hash(hash_payload
);
233 DBG3(DBG_IKE
, "received dst_hash %B", &hash
);
234 if (chunk_equals(hash
, dst_hash
))
236 this->dst_matched
= TRUE
;
240 /* the other NAT-D payloads contain source hashes */
241 this->src_seen
= TRUE
;
242 if (!this->src_matched
)
244 hash
= hash_payload
->get_hash(hash_payload
);
245 DBG3(DBG_IKE
, "received src_hash %B", &hash
);
246 if (chunk_equals(hash
, src_hash
))
248 this->src_matched
= TRUE
;
252 enumerator
->destroy(enumerator
);
254 chunk_free(&src_hash
);
255 chunk_free(&dst_hash
);
257 if (this->src_seen
&& this->dst_seen
)
259 this->ike_sa
->set_condition(this->ike_sa
, COND_NAT_HERE
,
261 this->ike_sa
->set_condition(this->ike_sa
, COND_NAT_THERE
,
263 config
= this->ike_sa
->get_ike_cfg(this->ike_sa
);
264 if (this->dst_matched
&& this->src_matched
&&
265 config
->force_encap(config
))
267 this->ike_sa
->set_condition(this->ike_sa
, COND_NAT_FAKE
, TRUE
);
272 METHOD(task_t
, build_i
, status_t
,
273 private_isakmp_natd_t
*this, message_t
*message
)
275 status_t result
= NEED_MORE
;
277 switch (message
->get_exchange_type(message
))
280 { /* add NAT-D payloads to the second request, already processed
281 * those by the responder contained in the first response */
286 { /* add NAT-D payloads to the second request, need to process
287 * those by the responder contained in the second response */
288 if (message
->get_payload(message
, SECURITY_ASSOCIATION_V1
))
289 { /* wait for the second exchange */
292 add_natd_payloads(this, message
);
301 METHOD(task_t
, process_i
, status_t
,
302 private_isakmp_natd_t
*this, message_t
*message
)
304 status_t result
= NEED_MORE
;
306 if (!this->ike_sa
->supports_extension(this->ike_sa
, EXT_NATT
))
307 { /* we didn't receive VIDs inidcating support for NAT-T */
311 switch (message
->get_exchange_type(message
))
314 { /* process NAT-D payloads in the second response, added them in the
315 * second request already, so we're done afterwards */
316 if (message
->get_payload(message
, SECURITY_ASSOCIATION_V1
))
317 { /* wait for the second exchange */
324 { /* process NAT-D payloads in the first response, add them in the
325 * following second request */
326 process_payloads(this, message
);
328 if (this->ike_sa
->has_condition(this->ike_sa
, COND_NAT_ANY
))
330 this->ike_sa
->float_ports(this->ike_sa
);
340 METHOD(task_t
, process_r
, status_t
,
341 private_isakmp_natd_t
*this, message_t
*message
)
343 status_t result
= NEED_MORE
;
345 if (!this->ike_sa
->supports_extension(this->ike_sa
, EXT_NATT
))
346 { /* we didn't receive VIDs indicating NAT-T support */
350 switch (message
->get_exchange_type(message
))
353 { /* proccess NAT-D payloads in the second request, already added ours
354 * in the first response */
359 { /* process NAT-D payloads in the second request, need to add ours
360 * to the second response */
361 if (message
->get_payload(message
, SECURITY_ASSOCIATION_V1
))
362 { /* wait for the second exchange */
365 process_payloads(this, message
);
374 METHOD(task_t
, build_r
, status_t
,
375 private_isakmp_natd_t
*this, message_t
*message
)
377 switch (message
->get_exchange_type(message
))
380 { /* add NAT-D payloads to second response, already processed those
381 * contained in the second request */
382 if (message
->get_payload(message
, SECURITY_ASSOCIATION_V1
))
383 { /* wait for the second exchange */
386 add_natd_payloads(this, message
);
390 { /* add NAT-D payloads to the first response, process those contained
391 * in the following second request */
392 add_natd_payloads(this, message
);
401 METHOD(task_t
, get_type
, task_type_t
,
402 private_isakmp_natd_t
*this)
404 return TASK_ISAKMP_NATD
;
407 METHOD(task_t
, migrate
, void,
408 private_isakmp_natd_t
*this, ike_sa_t
*ike_sa
)
410 this->ike_sa
= ike_sa
;
411 this->keymat
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
);
412 this->src_seen
= FALSE
;
413 this->dst_seen
= FALSE
;
414 this->src_matched
= FALSE
;
415 this->dst_matched
= FALSE
;
418 METHOD(task_t
, destroy
, void,
419 private_isakmp_natd_t
*this)
425 * Described in header.
427 isakmp_natd_t
*isakmp_natd_create(ike_sa_t
*ike_sa
, bool initiator
)
429 private_isakmp_natd_t
*this;
434 .get_type
= _get_type
,
440 .keymat
= (keymat_v1_t
*)ike_sa
->get_keymat(ike_sa
),
441 .initiator
= initiator
,
446 this->public.task
.build
= _build_i
;
447 this->public.task
.process
= _process_i
;
451 this->public.task
.build
= _build_r
;
452 this->public.task
.process
= _process_r
;
455 return &this->public;