4 * @brief Implementation of the ike_natd task.
9 * Copyright (C) 2006-2007 Martin Willi
10 * Copyright (C) 2006 Tobias Brunner, Daniel Roethlisberger
11 * Hochschule fuer Technik Rapperswil
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>.
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
29 #include <crypto/hashers/hasher.h>
30 #include <encoding/payloads/notify_payload.h>
33 typedef struct private_ike_natd_t private_ike_natd_t
;
36 * Private members of a ike_natd_t task.
38 struct private_ike_natd_t
{
41 * Public methods and task_t interface.
51 * Are we the initiator?
56 * Hasher used to build NAT detection hashes
61 * Did we process any NAT detection notifys for a source address?
66 * Did we process any NAT detection notifys for a destination address?
71 * Have we found a matching source address NAT hash?
76 * Have we found a matching destination address NAT hash?
83 * Build NAT detection hash for a host
85 static chunk_t
generate_natd_hash(private_ike_natd_t
*this,
86 ike_sa_id_t
*ike_sa_id
, host_t
*host
)
88 chunk_t natd_chunk
, spi_i_chunk
, spi_r_chunk
, addr_chunk
, port_chunk
;
90 u_int64_t spi_i
, spi_r
;
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
);
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
);
111 chunk_free(&natd_chunk
);
116 * Build a NAT detection notify payload.
118 static notify_payload_t
*build_natd_payload(private_ike_natd_t
*this,
119 notify_type_t type
, host_t
*host
)
122 notify_payload_t
*notify
;
123 ike_sa_id_t
*ike_sa_id
;
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
);
136 * read notifys from message and evaluate them
138 static void process_payloads(private_ike_natd_t
*this, message_t
*message
)
140 iterator_t
*iterator
;
142 notify_payload_t
*notify
;
143 chunk_t hash
, src_hash
, dst_hash
;
144 ike_sa_id_t
*ike_sa_id
;
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
);
154 DBG3(DBG_IKE
, "precalculated src_hash %B", &src_hash
);
155 DBG3(DBG_IKE
, "precalculated dst_hash %B", &dst_hash
);
157 iterator
= message
->get_payload_iterator(message
);
158 while (iterator
->iterate(iterator
, (void**)&payload
))
160 if (payload
->get_type(payload
) != NOTIFY
)
164 notify
= (notify_payload_t
*)payload
;
165 switch (notify
->get_notify_type(notify
))
167 case NAT_DETECTION_DESTINATION_IP
:
169 this->dst_seen
= TRUE
;
170 if (!this->dst_matched
)
172 hash
= notify
->get_notification_data(notify
);
173 DBG3(DBG_IKE
, "received dst_hash %B", &hash
);
174 if (chunk_equals(hash
, dst_hash
))
176 this->dst_matched
= TRUE
;
181 case NAT_DETECTION_SOURCE_IP
:
183 this->src_seen
= TRUE
;
184 if (!this->src_matched
)
186 hash
= notify
->get_notification_data(notify
);
187 DBG3(DBG_IKE
, "received src_hash %B", &hash
);
188 if (chunk_equals(hash
, src_hash
))
190 this->src_matched
= TRUE
;
199 iterator
->destroy(iterator
);
201 chunk_free(&src_hash
);
202 chunk_free(&dst_hash
);
204 if (this->src_seen
&& this->dst_seen
)
206 if (!this->dst_matched
)
208 this->ike_sa
->enable_natt(this->ike_sa
, TRUE
);
210 if (!this->src_matched
)
212 this->ike_sa
->enable_natt(this->ike_sa
, FALSE
);
218 * Implementation of task_t.process for initiator
220 static status_t
process_i(private_ike_natd_t
*this, message_t
*message
)
222 process_payloads(this, message
);
224 if (this->ike_sa
->is_natt_enabled(this->ike_sa
))
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
);
238 * Implementation of task_t.process for initiator
240 static status_t
build_i(private_ike_natd_t
*this, message_t
*message
)
242 notify_payload_t
*notify
;
243 iterator_t
*iterator
;
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
))
250 iterator
= charon
->kernel_interface
->create_address_iterator(
251 charon
->kernel_interface
);
252 while (iterator
->iterate(iterator
, (void**)&host
))
254 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, host
);
255 message
->add_payload(message
, (payload_t
*)notify
);
257 iterator
->destroy(iterator
);
261 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, host
);
262 message
->add_payload(message
, (payload_t
*)notify
);
265 host
= this->ike_sa
->get_other_host(this->ike_sa
);
266 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, host
);
267 message
->add_payload(message
, (payload_t
*)notify
);
273 * Implementation of task_t.build for responder
275 static status_t
build_r(private_ike_natd_t
*this, message_t
*message
)
277 notify_payload_t
*notify
;
280 /* only add notifies on successfull responses. */
281 if (message
->get_payload(message
, SECURITY_ASSOCIATION
) == NULL
)
286 if (this->src_seen
&& this->dst_seen
)
288 /* initiator seems to support NAT detection, add response */
289 me
= this->ike_sa
->get_my_host(this->ike_sa
);
290 notify
= build_natd_payload(this, NAT_DETECTION_SOURCE_IP
, me
);
291 message
->add_payload(message
, (payload_t
*)notify
);
293 other
= this->ike_sa
->get_other_host(this->ike_sa
);
294 notify
= build_natd_payload(this, NAT_DETECTION_DESTINATION_IP
, other
);
295 message
->add_payload(message
, (payload_t
*)notify
);
301 * Implementation of task_t.process for responder
303 static status_t
process_r(private_ike_natd_t
*this, message_t
*message
)
305 process_payloads(this, message
);
311 * Implementation of task_t.get_type
313 static task_type_t
get_type(private_ike_natd_t
*this)
319 * Implementation of task_t.migrate
321 static void migrate(private_ike_natd_t
*this, ike_sa_t
*ike_sa
)
323 this->ike_sa
= ike_sa
;
324 this->src_seen
= FALSE
;
325 this->dst_seen
= FALSE
;
326 this->src_matched
= FALSE
;
327 this->dst_matched
= FALSE
;
331 * Implementation of task_t.destroy
333 static void destroy(private_ike_natd_t
*this)
335 this->hasher
->destroy(this->hasher
);
340 * Described in header.
342 ike_natd_t
*ike_natd_create(ike_sa_t
*ike_sa
, bool initiator
)
344 private_ike_natd_t
*this = malloc_thing(private_ike_natd_t
);
346 this->public.task
.get_type
= (task_type_t(*)(task_t
*))get_type
;
347 this->public.task
.migrate
= (void(*)(task_t
*,ike_sa_t
*))migrate
;
348 this->public.task
.destroy
= (void(*)(task_t
*))destroy
;
352 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_i
;
353 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_i
;
357 this->public.task
.build
= (status_t(*)(task_t
*,message_t
*))build_r
;
358 this->public.task
.process
= (status_t(*)(task_t
*,message_t
*))process_r
;
361 this->ike_sa
= ike_sa
;
362 this->initiator
= initiator
;
363 this->hasher
= hasher_create(HASH_SHA1
);
364 this->src_seen
= FALSE
;
365 this->dst_seen
= FALSE
;
366 this->src_matched
= FALSE
;
367 this->dst_matched
= FALSE
;
369 return &this->public;