1/*	$KAME: sainfo.c,v 1.16 2003/06/27 07:32:39 sakane Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include "config.h"
33
34#include <sys/param.h>
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <sys/queue.h>
38
39#include <netinet/in.h>
40#include <netinet/in.h>
41#ifdef HAVE_NETINET6_IPSEC
42#  include <netinet6/ipsec.h>
43#else
44#  include <netinet/ipsec.h>
45#endif
46
47#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <errno.h>
51
52#include "var.h"
53#include "misc.h"
54#include "vmbuf.h"
55#include "plog.h"
56#include "sockmisc.h"
57#include "debug.h"
58
59#include "localconf.h"
60#include "isakmp_var.h"
61#include "isakmp.h"
62#include "ipsec_doi.h"
63#include "oakley.h"
64#include "handler.h"
65#include "algorithm.h"
66#include "sainfo.h"
67#include "gcmalloc.h"
68
69static LIST_HEAD(_sitree, sainfo) sitree;
70
71/* %%%
72 * modules for ipsec sa info
73 */
74/*
75 * return matching entry.
76 * no matching entry found and if there is anonymous entry, return it.
77 * else return NULL.
78 * XXX by each data type, should be changed to compare the buffer.
79 * First pass is for sainfo from a specified peer, second for others.
80 */
81struct sainfo *
82getsainfo(const vchar_t *src, const vchar_t *dst, const vchar_t *peer, int use_nat_addr)
83{
84	struct sainfo *s = NULL;
85	struct sainfo *anonymous = NULL;
86	int pass = 1;
87
88	if (use_nat_addr && lcconf->ext_nat_id == NULL)
89		return NULL;
90
91	if (peer == NULL)
92		pass = 2;
93    again:
94	LIST_FOREACH(s, &sitree, chain) {
95		if (s->id_i != NULL) {
96			if (pass == 2)
97				continue;
98			if (memcmp(peer->v, s->id_i->v, s->id_i->l) != 0)
99				continue;
100		} else if (pass == 1)
101			continue;
102		if (s->idsrc == NULL) {
103			anonymous = s;
104			continue;
105		}
106
107		/* anonymous ? */
108		if (src == NULL) {
109			if (anonymous != NULL)
110				break;
111			continue;
112		}
113
114        // TODO: handle wildcard port numbers in the id
115        if (memcmp(src->v, s->idsrc->v, s->idsrc->l) == 0) {
116			if (use_nat_addr) {
117				if (memcmp(lcconf->ext_nat_id->v, s->iddst->v, s->iddst->l) == 0) {
118					plogdump(ASL_LEVEL_DEBUG, lcconf->ext_nat_id->v, lcconf->ext_nat_id->l, "matched external nat address.\n");
119					return s;
120				}
121			} else if (memcmp(dst->v, s->iddst->v, s->iddst->l) == 0)
122				return s;
123		}
124	}
125
126	if (anonymous) {
127		plog(ASL_LEVEL_DEBUG,
128			"anonymous sainfo selected.\n");
129	} else if (pass == 1) {
130		pass = 2;
131		goto again;
132	}
133
134	return anonymous;
135}
136
137/*
138 * return matching entry.
139 * no matching entry found and if there is anonymous entry, return it.
140 * else return NULL.
141 * XXX by each data type, should be changed to compare the buffer.
142 */
143struct sainfo *
144getsainfo_by_dst_id(const vchar_t *dst, const vchar_t *peer)
145{
146	struct sainfo *s = NULL;
147	struct sainfo *anonymous = NULL;
148
149	plog(ASL_LEVEL_DEBUG, "getsainfo_by_dst_id - dst id:\n");
150	if (dst != NULL)
151		plogdump(ASL_LEVEL_DEBUG, dst->v, dst->l, "getsainfo_by_dst_id - dst id:\n");
152	else
153		return NULL;
154
155	LIST_FOREACH(s, &sitree, chain) {
156		if (s->idsrc != NULL) {
157			plogdump(ASL_LEVEL_DEBUG, s->idsrc->v, s->idsrc->l, "getsainfo_by_dst_id - sainfo id - src:\n");
158			plogdump(ASL_LEVEL_DEBUG, s->iddst->v, s->iddst->l, "getsainfo_by_dst_id - sainfo id - dst:\n");
159		} else {
160			plog(ASL_LEVEL_DEBUG, "getsainfo_by_dst_id - sainfo id = anonymous\n");
161		}
162		if (s->id_i != NULL) {
163			plogdump(ASL_LEVEL_DEBUG, s->id_i->v, s->id_i->l, "getsainfo_by_dst_id - sainfo id_i:\n");
164			if (peer == NULL)
165				continue;
166			if (memcmp(peer->v, s->id_i->v, s->id_i->l) != 0)
167				continue;
168		}
169		if (s->idsrc == NULL) {
170			anonymous = s;
171			continue;
172		}
173
174		if (memcmp(dst->v, s->iddst->v, s->iddst->l) == 0)
175			return s;
176	}
177
178	if (anonymous) {
179		plog(ASL_LEVEL_DEBUG,
180			 "anonymous sainfo selected.\n");
181	}
182
183	return anonymous;
184}
185
186
187struct sainfo *
188create_sainfo()
189{
190	struct sainfo *new;
191
192	new = racoon_calloc(1, sizeof(*new));
193	if (new == NULL)
194		return NULL;
195
196	new->lifetime = IPSECDOI_ATTR_SA_LD_SEC_DEFAULT;
197	new->lifebyte = IPSECDOI_ATTR_SA_LD_KB_MAX;
198	new->refcount = 1;
199    new->in_list = 0;
200
201	return new;
202}
203
204
205void
206delsainfo(struct sainfo *si)
207{
208	int i;
209
210	for (i = 0; i < MAXALGCLASS; i++)
211		delsainfoalg(si->algs[i]);
212
213	if (si->idsrc)
214		vfree(si->idsrc);
215	if (si->iddst)
216		vfree(si->iddst);
217
218#ifdef ENABLE_HYBRID
219	if (si->group)
220		vfree(si->group);
221#endif
222
223	racoon_free(si);
224}
225
226void
227inssainfo(struct sainfo *new)
228{
229	LIST_INSERT_HEAD(&sitree, new, chain);
230    new->in_list = 1;
231}
232
233void
234remsainfo(struct sainfo *si)
235{
236    if (si->in_list) {
237        LIST_REMOVE(si, chain);
238        si->in_list = 0;
239    }
240}
241
242// remove sainfos from linked list
243// if not used - delete it
244void
245flushsainfo()
246{
247	struct sainfo *s, *next;
248
249	LIST_FOREACH_SAFE(s, &sitree, chain, next) {
250		if (s->dynamic == 0) {
251            remsainfo(s);
252            if (--(s->refcount) <= 0)
253                delsainfo(s);
254		}
255	}
256}
257
258// remove sainfos from linked list
259// if not used - delete it
260void
261flushsainfo_dynamic(u_int32_t addr)
262{
263	struct sainfo *s, *next;
264
265	LIST_FOREACH_SAFE(s, &sitree, chain, next) {
266		if (s->dynamic == addr) {
267            remsainfo(s);
268            if (--(s->refcount) <= 0)
269                delsainfo(s);
270		}
271	}
272}
273
274void
275retain_sainfo(struct sainfo *si)
276{
277	(si->refcount)++;
278}
279
280void
281release_sainfo(struct sainfo *si)
282{
283	if (--(si->refcount) <= 0) {
284        remsainfo(si);
285        delsainfo(si);
286    }
287}
288
289void
290initsainfo()
291{
292	LIST_INIT(&sitree);
293}
294
295struct sainfoalg *
296newsainfoalg()
297{
298	struct sainfoalg *new;
299
300	new = racoon_calloc(1, sizeof(*new));
301	if (new == NULL)
302		return NULL;
303
304	return new;
305}
306
307void
308delsainfoalg(struct sainfoalg *alg)
309{
310	struct sainfoalg *a, *next;
311
312	for (a = alg; a; a = next) {
313		next = a->next;
314		racoon_free(a);
315	}
316}
317
318void
319inssainfoalg(struct sainfoalg **head, struct sainfoalg *new)
320{
321	struct sainfoalg *a;
322
323	for (a = *head; a && a->next; a = a->next)
324		;
325	if (a)
326		a->next = new;
327	else
328		*head = new;
329}
330
331
332
333const char *
334sainfo2str(const struct sainfo *si)
335{
336    char *idsrc_str;
337    char *iddst_str;
338    char *idi_str;
339	static char buf[256];
340
341	if (si->idsrc == NULL)
342		snprintf(buf, sizeof(buf), "anonymous");
343	else {
344        idsrc_str = ipsecdoi_id2str(si->idsrc);
345        if (idsrc_str) {
346            snprintf(buf, sizeof(buf), "%s", idsrc_str);
347            racoon_free(idsrc_str);
348        }
349        iddst_str = ipsecdoi_id2str(si->iddst);
350        if (iddst_str) {
351            snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
352                     " %s", iddst_str);
353            racoon_free(iddst_str);
354        }
355	}
356
357	if (si->id_i != NULL) {
358        idi_str = ipsecdoi_id2str(si->id_i);
359        if (idi_str) {
360            snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
361                     " from %s", idi_str);
362            racoon_free(idi_str);
363        }
364    }
365
366	return buf;
367}
368