xref: /openbsd-src/sbin/isakmpd/nat_traversal.c (revision 6ee513e5aba73254713aefffb1d985e0a57a9b85)
1*6ee513e5Sjca /*	$OpenBSD: nat_traversal.c,v 1.25 2017/12/05 20:31:45 jca Exp $	*/
2cd6bf844Sho 
3cd6bf844Sho /*
4cd6bf844Sho  * Copyright (c) 2004 H�kan Olsson.  All rights reserved.
5cd6bf844Sho  *
6cd6bf844Sho  * Redistribution and use in source and binary forms, with or without
7cd6bf844Sho  * modification, are permitted provided that the following conditions
8cd6bf844Sho  * are met:
9cd6bf844Sho  * 1. Redistributions of source code must retain the above copyright
10cd6bf844Sho  *    notice, this list of conditions and the following disclaimer.
11cd6bf844Sho  * 2. Redistributions in binary form must reproduce the above copyright
12cd6bf844Sho  *    notice, this list of conditions and the following disclaimer in the
13cd6bf844Sho  *    documentation and/or other materials provided with the distribution.
14cd6bf844Sho  *
15cd6bf844Sho  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16cd6bf844Sho  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17cd6bf844Sho  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18cd6bf844Sho  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19cd6bf844Sho  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20cd6bf844Sho  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21cd6bf844Sho  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22cd6bf844Sho  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23cd6bf844Sho  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24cd6bf844Sho  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25cd6bf844Sho  */
26cd6bf844Sho 
27cd6bf844Sho #include <sys/types.h>
28cd6bf844Sho #include <stdlib.h>
299c491683Shshoexer #include <string.h>
30cd6bf844Sho 
31adfd2491Sho #include "conf.h"
32cd6bf844Sho #include "exchange.h"
33cd6bf844Sho #include "hash.h"
34cd6bf844Sho #include "ipsec.h"
35cd6bf844Sho #include "isakmp_fld.h"
36cd6bf844Sho #include "isakmp_num.h"
37cd6bf844Sho #include "ipsec_num.h"
38cd6bf844Sho #include "log.h"
39cd6bf844Sho #include "message.h"
40cd6bf844Sho #include "nat_traversal.h"
41cd6bf844Sho #include "prf.h"
42cd6bf844Sho #include "sa.h"
43adfd2491Sho #include "timer.h"
44cd6bf844Sho #include "transport.h"
45cd6bf844Sho #include "util.h"
46adfd2491Sho #include "virtual.h"
47cd6bf844Sho 
48bfb67d4dScloder int	disable_nat_t = 0;
49bfb67d4dScloder 
50cd6bf844Sho /*
519f8f63b2Sho  * NAT-T capability of the other peer is determined by a particular vendor
529f8f63b2Sho  * ID sent in the first message. This vendor ID string is supposed to be a
539f8f63b2Sho  * MD5 hash of "RFC 3947".
54cd6bf844Sho  *
55cd6bf844Sho  * These seem to be the "well" known variants of this string in use by
56cd6bf844Sho  * products today.
577498162fShshoexer  *
587498162fShshoexer  * Note that the VID specified in draft 2 is ambiguous: It was
597498162fShshoexer  * accidentally calculated from the string "draft-ietf-ipsec-nat-t-ike-02\n"
607498162fShshoexer  * although the string was documented without the trailing '\n'. The authors
617498162fShshoexer  * suggested afterwards to use the string with the trailing '\n'.
62cd6bf844Sho  */
63875f57d0Shshoexer 
64875f57d0Shshoexer static struct nat_t_cap isakmp_nat_t_cap[] = {
65875f57d0Shshoexer 	{ VID_DRAFT_V2_N, EXCHANGE_FLAG_NAT_T_DRAFT,
66875f57d0Shshoexer 	  "draft-ietf-ipsec-nat-t-ike-02\n", NULL, 0 },
67875f57d0Shshoexer 	{ VID_DRAFT_V3, EXCHANGE_FLAG_NAT_T_DRAFT,
68875f57d0Shshoexer 	  "draft-ietf-ipsec-nat-t-ike-03", NULL, 0 },
69875f57d0Shshoexer 	{ VID_RFC3947, EXCHANGE_FLAG_NAT_T_RFC,
70875f57d0Shshoexer 	  "RFC 3947", NULL, 0 },
71cd6bf844Sho };
72cd6bf844Sho 
73875f57d0Shshoexer #define NUMNATTCAP	(sizeof isakmp_nat_t_cap / sizeof isakmp_nat_t_cap[0])
74875f57d0Shshoexer 
75adfd2491Sho /* In seconds. Recommended in draft-ietf-ipsec-udp-encaps-09.  */
76adfd2491Sho #define NAT_T_KEEPALIVE_INTERVAL	20
77adfd2491Sho 
78cd6bf844Sho static int	nat_t_setup_hashes(void);
79875f57d0Shshoexer static int	nat_t_add_vendor_payload(struct message *, struct nat_t_cap *);
80cd6bf844Sho static int	nat_t_add_nat_d(struct message *, struct sockaddr *);
81cd6bf844Sho static int	nat_t_match_nat_d_payload(struct message *, struct sockaddr *);
82cd6bf844Sho 
83cd6bf844Sho void
nat_t_init(void)84cd6bf844Sho nat_t_init(void)
85cd6bf844Sho {
86875f57d0Shshoexer 	nat_t_setup_hashes();
87cd6bf844Sho }
88cd6bf844Sho 
89cd6bf844Sho /* Generate the NAT-T capability marker hashes. Executed only once.  */
90cd6bf844Sho static int
nat_t_setup_hashes(void)91cd6bf844Sho nat_t_setup_hashes(void)
92cd6bf844Sho {
93cd6bf844Sho 	struct hash *hash;
94875f57d0Shshoexer 	int n = NUMNATTCAP;
95cd6bf844Sho 	int i;
96cd6bf844Sho 
97cd6bf844Sho 	/* The draft says to use MD5.  */
98cd6bf844Sho 	hash = hash_get(HASH_MD5);
99cd6bf844Sho 	if (!hash) {
100cd6bf844Sho 		/* Should never happen.  */
101cd6bf844Sho 		log_print("nat_t_setup_hashes: "
102cd6bf844Sho 		    "could not find MD5 hash structure!");
103cd6bf844Sho 		return -1;
104cd6bf844Sho 	}
105cd6bf844Sho 
106875f57d0Shshoexer 	/* Populate isakmp_nat_t_cap with hashes.  */
107cd6bf844Sho 	for (i = 0; i < n; i++) {
108875f57d0Shshoexer 		isakmp_nat_t_cap[i].hashsize = hash->hashsize;
1095ae94ef8Sderaadt 		isakmp_nat_t_cap[i].hash = malloc(hash->hashsize);
110875f57d0Shshoexer 		if (!isakmp_nat_t_cap[i].hash) {
111cd6bf844Sho 			log_error("nat_t_setup_hashes: malloc (%lu) failed",
112875f57d0Shshoexer 			    (unsigned long)hash->hashsize);
113cd6bf844Sho 			goto errout;
114cd6bf844Sho 		}
115cd6bf844Sho 
116cd6bf844Sho 		hash->Init(hash->ctx);
117cd6bf844Sho 		hash->Update(hash->ctx,
118875f57d0Shshoexer 		    (unsigned char *)isakmp_nat_t_cap[i].text,
119875f57d0Shshoexer 		    strlen(isakmp_nat_t_cap[i].text));
120875f57d0Shshoexer 		hash->Final(isakmp_nat_t_cap[i].hash, hash->ctx);
121cd6bf844Sho 
122cd6bf844Sho 		LOG_DBG((LOG_EXCHANGE, 50, "nat_t_setup_hashes: "
123875f57d0Shshoexer 		    "MD5(\"%s\") (%lu bytes)", isakmp_nat_t_cap[i].text,
124875f57d0Shshoexer 		    (unsigned long)hash->hashsize));
125cd6bf844Sho 		LOG_DBG_BUF((LOG_EXCHANGE, 50, "nat_t_setup_hashes",
126875f57d0Shshoexer 		    isakmp_nat_t_cap[i].hash, hash->hashsize));
127cd6bf844Sho 	}
128cd6bf844Sho 
129cd6bf844Sho 	return 0;
130cd6bf844Sho 
131cd6bf844Sho errout:
132cd6bf844Sho 	for (i = 0; i < n; i++)
133875f57d0Shshoexer 		free(isakmp_nat_t_cap[i].hash);
134cd6bf844Sho 	return -1;
135cd6bf844Sho }
136cd6bf844Sho 
137cd6bf844Sho /* Add one NAT-T VENDOR payload.  */
138cd6bf844Sho static int
nat_t_add_vendor_payload(struct message * msg,struct nat_t_cap * cap)139875f57d0Shshoexer nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap)
140cd6bf844Sho {
141875f57d0Shshoexer 	size_t	  buflen = cap->hashsize + ISAKMP_GEN_SZ;
142cd6bf844Sho 	u_int8_t *buf;
143cd6bf844Sho 
144bfb67d4dScloder 	if (disable_nat_t)
145bfb67d4dScloder 		return 0;
146bfb67d4dScloder 
147cd6bf844Sho 	buf = malloc(buflen);
148cd6bf844Sho 	if (!buf) {
149cd6bf844Sho 		log_error("nat_t_add_vendor_payload: malloc (%lu) failed",
150cd6bf844Sho 		    (unsigned long)buflen);
151cd6bf844Sho 		return -1;
152cd6bf844Sho 	}
153cd6bf844Sho 
154cd6bf844Sho 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
155875f57d0Shshoexer 	memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize);
156cd6bf844Sho 	if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
157cd6bf844Sho 		free(buf);
158cd6bf844Sho 		return -1;
159cd6bf844Sho 	}
160cd6bf844Sho 	return 0;
161cd6bf844Sho }
162cd6bf844Sho 
163cd6bf844Sho /* Add the NAT-T capability markers (VENDOR payloads).  */
164cd6bf844Sho int
nat_t_add_vendor_payloads(struct message * msg)165cd6bf844Sho nat_t_add_vendor_payloads(struct message *msg)
166cd6bf844Sho {
167875f57d0Shshoexer 	int i;
168cd6bf844Sho 
169bfb67d4dScloder 	if (disable_nat_t)
170bfb67d4dScloder 		return 0;
171bfb67d4dScloder 
172875f57d0Shshoexer 	for (i = 0; i < NUMNATTCAP; i++)
173875f57d0Shshoexer 		if (nat_t_add_vendor_payload(msg, &isakmp_nat_t_cap[i]))
174cd6bf844Sho 			return -1;
175cd6bf844Sho 	return 0;
176cd6bf844Sho }
177cd6bf844Sho 
178cd6bf844Sho /*
179cd6bf844Sho  * Check an incoming message for NAT-T capability markers.
180cd6bf844Sho  */
181cd6bf844Sho void
nat_t_check_vendor_payload(struct message * msg,struct payload * p)182cd6bf844Sho nat_t_check_vendor_payload(struct message *msg, struct payload *p)
183cd6bf844Sho {
184cd6bf844Sho 	u_int8_t *pbuf = p->p;
185cd6bf844Sho 	size_t	  vlen;
186875f57d0Shshoexer 	int	  i;
187cd6bf844Sho 
188bfb67d4dScloder 	if (disable_nat_t)
189bfb67d4dScloder 		return;
190bfb67d4dScloder 
191cd6bf844Sho 	vlen = GET_ISAKMP_GEN_LENGTH(pbuf) - ISAKMP_GEN_SZ;
192875f57d0Shshoexer 
193875f57d0Shshoexer 	for (i = 0; i < NUMNATTCAP; i++) {
194875f57d0Shshoexer 		if (vlen != isakmp_nat_t_cap[i].hashsize) {
195875f57d0Shshoexer 			continue;
196cd6bf844Sho 		}
197875f57d0Shshoexer 		if (memcmp(isakmp_nat_t_cap[i].hash, pbuf + ISAKMP_GEN_SZ,
198cd6bf844Sho 		    vlen) == 0) {
199cd6bf844Sho 			/* This peer is NAT-T capable.  */
200cd6bf844Sho 			msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_CAP_PEER;
201875f57d0Shshoexer 			msg->exchange->flags |= isakmp_nat_t_cap[i].flags;
202cd6bf844Sho 			LOG_DBG((LOG_EXCHANGE, 10,
203cd6bf844Sho 			    "nat_t_check_vendor_payload: "
204cd6bf844Sho 			    "NAT-T capable peer detected"));
205cd6bf844Sho 			p->flags |= PL_MARK;
206cd6bf844Sho 		}
207cd6bf844Sho 	}
208cd6bf844Sho 
209875f57d0Shshoexer 	return;
210875f57d0Shshoexer }
211875f57d0Shshoexer 
212cd6bf844Sho /* Generate the NAT-D payload hash : HASH(CKY-I | CKY-R | IP | Port).  */
213cd6bf844Sho static u_int8_t *
nat_t_generate_nat_d_hash(struct message * msg,struct sockaddr * sa,size_t * hashlen)214cd6bf844Sho nat_t_generate_nat_d_hash(struct message *msg, struct sockaddr *sa,
215cd6bf844Sho     size_t *hashlen)
216cd6bf844Sho {
217cd6bf844Sho 	struct ipsec_exch *ie = (struct ipsec_exch *)msg->exchange->data;
218cd6bf844Sho 	struct hash	 *hash;
219cd6bf844Sho 	u_int8_t	 *res;
220cd6bf844Sho 	in_port_t	  port;
221cd6bf844Sho 
222cd6bf844Sho 	hash = hash_get(ie->hash->type);
223cd6bf844Sho 	if (hash == NULL) {
224cd6bf844Sho 		log_print ("nat_t_generate_nat_d_hash: no hash");
225cd6bf844Sho 		return NULL;
226cd6bf844Sho 	}
227cd6bf844Sho 
22835dfcbf4Shshoexer 	*hashlen = hash->hashsize;
229cd6bf844Sho 
230c52ea152Sderaadt 	res = malloc(*hashlen);
231cd6bf844Sho 	if (!res) {
232cd6bf844Sho 		log_print("nat_t_generate_nat_d_hash: malloc (%lu) failed",
233cd6bf844Sho 		    (unsigned long)*hashlen);
234cd6bf844Sho 		*hashlen = 0;
235cd6bf844Sho 		return NULL;
236cd6bf844Sho 	}
237cd6bf844Sho 
238cd6bf844Sho 	port = sockaddr_port(sa);
2390dc10397Shshoexer 	bzero(res, *hashlen);
240cd6bf844Sho 
24135dfcbf4Shshoexer 	hash->Init(hash->ctx);
24235dfcbf4Shshoexer 	hash->Update(hash->ctx, msg->exchange->cookies,
24335dfcbf4Shshoexer 	    sizeof msg->exchange->cookies);
24435dfcbf4Shshoexer 	hash->Update(hash->ctx, sockaddr_addrdata(sa), sockaddr_addrlen(sa));
24535dfcbf4Shshoexer 	hash->Update(hash->ctx, (unsigned char *)&port, sizeof port);
24635dfcbf4Shshoexer 	hash->Final(res, hash->ctx);
247cd6bf844Sho 	return res;
248cd6bf844Sho }
249cd6bf844Sho 
250cd6bf844Sho /* Add a NAT-D payload to our message.  */
251cd6bf844Sho static int
nat_t_add_nat_d(struct message * msg,struct sockaddr * sa)252cd6bf844Sho nat_t_add_nat_d(struct message *msg, struct sockaddr *sa)
253cd6bf844Sho {
254875f57d0Shshoexer 	int	  ret;
255cd6bf844Sho 	u_int8_t *hbuf, *buf;
256cd6bf844Sho 	size_t	  hbuflen, buflen;
257cd6bf844Sho 
258cd6bf844Sho 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
259cd6bf844Sho 	if (!hbuf) {
260cd6bf844Sho 		log_print("nat_t_add_nat_d: NAT-D hash gen failed");
261cd6bf844Sho 		return -1;
262cd6bf844Sho 	}
263cd6bf844Sho 
264cd6bf844Sho 	buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen;
265cd6bf844Sho 	buf = malloc(buflen);
266cd6bf844Sho 	if (!buf) {
267cd6bf844Sho 		log_error("nat_t_add_nat_d: malloc (%lu) failed",
268cd6bf844Sho 		    (unsigned long)buflen);
269cd6bf844Sho 		free(hbuf);
270cd6bf844Sho 		return -1;
271cd6bf844Sho 	}
272cd6bf844Sho 
273cd6bf844Sho 	SET_ISAKMP_GEN_LENGTH(buf, buflen);
274cd6bf844Sho 	memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen);
275cd6bf844Sho 	free(hbuf);
276cd6bf844Sho 
277875f57d0Shshoexer 	if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC)
278875f57d0Shshoexer 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf,
279875f57d0Shshoexer 		    buflen, 1);
280875f57d0Shshoexer 	else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT)
281875f57d0Shshoexer 		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT,
282875f57d0Shshoexer 		    buf, buflen, 1);
283875f57d0Shshoexer 	else
284875f57d0Shshoexer 		ret = -1;
285875f57d0Shshoexer 
286875f57d0Shshoexer 	if (ret) {
287cd6bf844Sho 		free(buf);
288cd6bf844Sho 		return -1;
289cd6bf844Sho 	}
290cd6bf844Sho 	return 0;
291cd6bf844Sho }
292cd6bf844Sho 
293cd6bf844Sho /* We add two NAT-D payloads, one each for src and dst.  */
294cd6bf844Sho int
nat_t_exchange_add_nat_d(struct message * msg)295cd6bf844Sho nat_t_exchange_add_nat_d(struct message *msg)
296cd6bf844Sho {
297cd6bf844Sho 	struct sockaddr *sa;
298cd6bf844Sho 
29935dfcbf4Shshoexer 	/* Remote address first. */
30035dfcbf4Shshoexer 	msg->transport->vtbl->get_dst(msg->transport, &sa);
301cd6bf844Sho 	if (nat_t_add_nat_d(msg, sa))
302cd6bf844Sho 		return -1;
303cd6bf844Sho 
30435dfcbf4Shshoexer 	msg->transport->vtbl->get_src(msg->transport, &sa);
305cd6bf844Sho 	if (nat_t_add_nat_d(msg, sa))
306cd6bf844Sho 		return -1;
307cd6bf844Sho 	return 0;
308cd6bf844Sho }
309cd6bf844Sho 
310cd6bf844Sho /* Generate and match a NAT-D hash against the NAT-D payload (pl.) data.  */
311cd6bf844Sho static int
nat_t_match_nat_d_payload(struct message * msg,struct sockaddr * sa)312cd6bf844Sho nat_t_match_nat_d_payload(struct message *msg, struct sockaddr *sa)
313cd6bf844Sho {
314cd6bf844Sho 	struct payload *p;
315cd6bf844Sho 	u_int8_t *hbuf;
316cd6bf844Sho 	size_t	 hbuflen;
317cd6bf844Sho 	int	 found = 0;
318cd6bf844Sho 
3193ca9511cSho 	/*
3203ca9511cSho 	 * If there are no NAT-D payloads in the message, return "found"
3213ca9511cSho 	 * as this will avoid NAT-T (see nat_t_exchange_check_nat_d()).
3223ca9511cSho 	 */
323b14af008Shshoexer 	if ((p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT)) == NULL &&
324b14af008Shshoexer 	    (p = payload_first(msg, ISAKMP_PAYLOAD_NAT_D)) == NULL)
3253ca9511cSho 		return 1;
3263ca9511cSho 
327cd6bf844Sho 	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
328cd6bf844Sho 	if (!hbuf)
329cd6bf844Sho 		return 0;
330cd6bf844Sho 
331b71022a1Smarkus 	for (; p; p = TAILQ_NEXT(p, link)) {
332cd6bf844Sho 		if (GET_ISAKMP_GEN_LENGTH (p->p) !=
333cd6bf844Sho 		    hbuflen + ISAKMP_NAT_D_DATA_OFF)
334cd6bf844Sho 			continue;
335cd6bf844Sho 
336cd6bf844Sho 		if (memcmp(p->p + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen) == 0) {
337cd6bf844Sho 			found++;
338cd6bf844Sho 			break;
339cd6bf844Sho 		}
340cd6bf844Sho 	}
341cd6bf844Sho 	free(hbuf);
342cd6bf844Sho 	return found;
343cd6bf844Sho }
344cd6bf844Sho 
345cd6bf844Sho /*
346cd6bf844Sho  * Check if we need to activate NAT-T, and if we need to send keepalive
347cd6bf844Sho  * messages to the other side, i.e if we are a nat:ed peer.
348cd6bf844Sho  */
349cd6bf844Sho int
nat_t_exchange_check_nat_d(struct message * msg)350cd6bf844Sho nat_t_exchange_check_nat_d(struct message *msg)
351cd6bf844Sho {
352cd6bf844Sho 	struct sockaddr *sa;
353cd6bf844Sho 	int	 outgoing_path_is_clear, incoming_path_is_clear;
354cd6bf844Sho 
355cd6bf844Sho 	/* Assume trouble, i.e NAT-boxes in our path.  */
356cd6bf844Sho 	outgoing_path_is_clear = incoming_path_is_clear = 0;
357cd6bf844Sho 
358cd6bf844Sho 	msg->transport->vtbl->get_src(msg->transport, &sa);
359cd6bf844Sho 	if (nat_t_match_nat_d_payload(msg, sa))
360cd6bf844Sho 		outgoing_path_is_clear = 1;
361cd6bf844Sho 
362cd6bf844Sho 	msg->transport->vtbl->get_dst(msg->transport, &sa);
363cd6bf844Sho 	if (nat_t_match_nat_d_payload(msg, sa))
364cd6bf844Sho 		incoming_path_is_clear = 1;
365cd6bf844Sho 
366cd6bf844Sho 	if (outgoing_path_is_clear && incoming_path_is_clear) {
367cd6bf844Sho 		LOG_DBG((LOG_EXCHANGE, 40, "nat_t_exchange_check_nat_d: "
368cd6bf844Sho 		    "no NAT"));
369cd6bf844Sho 		return 0; /* No NAT-T required.  */
370cd6bf844Sho 	}
371cd6bf844Sho 
372cd6bf844Sho 	/* NAT-T handling required.  */
373cd6bf844Sho 	msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_ENABLE;
374cd6bf844Sho 
375cd6bf844Sho 	if (!outgoing_path_is_clear) {
376cd6bf844Sho 		msg->exchange->flags |= EXCHANGE_FLAG_NAT_T_KEEPALIVE;
377cd6bf844Sho 		LOG_DBG((LOG_EXCHANGE, 10, "nat_t_exchange_check_nat_d: "
378cd6bf844Sho 		    "NAT detected, we're behind it"));
379cd6bf844Sho 	} else
380cd6bf844Sho 		LOG_DBG ((LOG_EXCHANGE, 10,
381cd6bf844Sho 		    "nat_t_exchange_check_nat_d: NAT detected"));
382cd6bf844Sho 	return 1;
383cd6bf844Sho }
384adfd2491Sho 
385adfd2491Sho static void
nat_t_send_keepalive(void * v_arg)386adfd2491Sho nat_t_send_keepalive(void *v_arg)
387adfd2491Sho {
388adfd2491Sho 	struct sa *sa = (struct sa *)v_arg;
389adfd2491Sho 	struct transport *t;
390*6ee513e5Sjca 	struct timespec now;
391adfd2491Sho 	int interval;
392adfd2491Sho 
393adfd2491Sho 	/* Send the keepalive message.  */
394adfd2491Sho 	t = ((struct virtual_transport *)sa->transport)->encap;
395adfd2491Sho 	t->vtbl->send_message(NULL, t);
396adfd2491Sho 
397adfd2491Sho 	/* Set new timer.  */
398adfd2491Sho 	interval = conf_get_num("General", "NAT-T-Keepalive", 0);
399adfd2491Sho 	if (interval < 1)
400adfd2491Sho 		interval = NAT_T_KEEPALIVE_INTERVAL;
401*6ee513e5Sjca 	clock_gettime(CLOCK_MONOTONIC, &now);
402adfd2491Sho 	now.tv_sec += interval;
403adfd2491Sho 
404adfd2491Sho 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
405adfd2491Sho 	    nat_t_send_keepalive, v_arg, &now);
406adfd2491Sho 	if (!sa->nat_t_keepalive)
407adfd2491Sho 		log_print("nat_t_send_keepalive: "
408adfd2491Sho 		    "timer_add_event() failed, will send no more keepalives");
409adfd2491Sho }
410adfd2491Sho 
411adfd2491Sho void
nat_t_setup_keepalive(struct sa * sa)412adfd2491Sho nat_t_setup_keepalive(struct sa *sa)
413adfd2491Sho {
414adfd2491Sho 	struct sockaddr *src;
415*6ee513e5Sjca 	struct timespec now;
416adfd2491Sho 
417dec6ea27Sho 	if (sa->initiator)
418adfd2491Sho 		sa->transport->vtbl->get_src(sa->transport, &src);
419dec6ea27Sho 	else
420dec6ea27Sho 		sa->transport->vtbl->get_dst(sa->transport, &src);
421dec6ea27Sho 
422adfd2491Sho 	if (!virtual_listen_lookup(src))
423adfd2491Sho 		return;
424adfd2491Sho 
425*6ee513e5Sjca 	clock_gettime(CLOCK_MONOTONIC, &now);
426adfd2491Sho 	now.tv_sec += NAT_T_KEEPALIVE_INTERVAL;
427adfd2491Sho 
428adfd2491Sho 	sa->nat_t_keepalive = timer_add_event("nat_t_send_keepalive",
429adfd2491Sho 	    nat_t_send_keepalive, sa, &now);
430adfd2491Sho 	if (!sa->nat_t_keepalive)
431adfd2491Sho 		log_print("nat_t_setup_keepalive: "
432adfd2491Sho 		    "timer_add_event() failed, will not send keepalives");
433dec6ea27Sho 
434dec6ea27Sho 	LOG_DBG((LOG_TRANSPORT, 50, "nat_t_setup_keepalive: "
435dec6ea27Sho 	    "added event for phase 1 SA %p", sa));
436adfd2491Sho }
437