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