📄 connections.c
字号:
/* information about connections between hosts and clients * Copyright (C) 1998-2002 D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: connections.c,v 1.256.2.7 2005/11/17 01:44:12 mcr Exp $ */#include <string.h>#include <stdio.h>#include <stddef.h>#include <stdlib.h>#include <unistd.h>#include <netinet/in.h>#include <sys/socket.h>#include <sys/stat.h>#include <netinet/in.h>#include <arpa/inet.h>#include <resolv.h>#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */#include <sys/queue.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include "pfkeyv2.h"#include "kameipsec.h"#include "constants.h"#include "defs.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "ac.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h" /* needs id.h */#include "pending.h"#include "foodgroups.h"#include "packet.h"#include "demux.h" /* needs packet.h */#include "state.h"#include "timer.h"#include "ipsec_doi.h" /* needs demux.h and state.h */#include "server.h"#include "kernel.h" /* needs connections.h */#include "log.h"#include "keys.h"#include "secrets.h"#include "adns.h" /* needs <resolv.h> */#include "dnskey.h" /* needs keys.h and adns.h */#include "whack.h"#include "alg_info.h"#include "spdb.h"#include "ike_alg.h"#include "kernel_alg.h"#include "plutoalg.h"#include "xauth.h"#ifdef NAT_TRAVERSAL#include "nat_traversal.h"#endif#ifdef VIRTUAL_IP#include "virtual.h"#endif#ifndef ns_t_txt#define ns_t_txt T_TXT#endif#ifndef ns_t_key#define ns_t_key T_KEY#endifstatic struct connection *connections = NULL;/* struct host_pair: a nexus of information about a pair of hosts. * A host is an IP address, UDP port pair. This is a debatable choice: * - should port be considered (no choice of port in standard)? * - should ID be considered (hard because not always known)? * - should IP address matter on our end (we don't know our end)? * Only oriented connections are registered. * Unoriented connections are kept on the unoriented_connections * linked list (using hp_next). For them, host_pair is NULL. */struct host_pair { struct { ip_address addr; u_int16_t host_port; /* IKE port */ bool host_port_specific; /* if above is interesting */ } me, him; bool initial_connection_sent; struct connection *connections; /* connections with this pair */ struct pending *pending; /* awaiting Keying Channel */ struct host_pair *next;};static struct host_pair *host_pairs = NULL;static struct connection *unoriented_connections = NULL;void host_pair_enqueue_pending(const struct connection *c , struct pending *p , struct pending **pnext){ *pnext = c->host_pair->pending; c->host_pair->pending = p;}struct pending **host_pair_first_pending(const struct connection *c){ if(c->host_pair == NULL) return NULL; return &c->host_pair->pending;} /* check to see that Ids of peers match */boolsame_peer_ids(const struct connection *c, const struct connection *d, const struct id *his_id){ return same_id(&c->spd.this.id, &d->spd.this.id) && same_id(his_id == NULL? &c->spd.that.id : his_id, &d->spd.that.id);}/** returns a host pair based upon addresses. * * find_host_pair is given a pair of addresses, plus UDP ports, and * returns a host_pair entry that covers it. It also moves the relevant * pair description to the beginning of the list, so that it can be * found faster next time. * */static struct host_pair *find_host_pair(const ip_address *myaddr , u_int16_t myport , const ip_address *hisaddr , u_int16_t hisport){ struct host_pair *p, *prev; char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF]; /* default hisaddr to an appropriate any */ if (hisaddr == NULL) hisaddr = aftoinfo(addrtypeof(myaddr))->any; /* * look for a host-pair that has the right set of ports/address. * */ /* * for the purposes of comparison, port 500 and 4500 are identical, * but other ports are not. * So if any port==4500, then set it to 500. */ if(myport == 4500) myport=500; if(hisport== 4500) hisport=500; for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next) { DBG(DBG_CONTROLMORE , DBG_log("find_host_pair: comparing to %s:%d %s:%d\n" , (addrtot(&p->me.addr, 0, b1, sizeof(b1)), b1) , p->me.host_port , (addrtot(&p->him.addr, 0, b2, sizeof(b2)), b2) , p->him.host_port)); if (sameaddr(&p->me.addr, myaddr) && (!p->me.host_port_specific || p->me.host_port == myport) && sameaddr(&p->him.addr, hisaddr) && (!p->him.host_port_specific || p->him.host_port == hisport) ) { if (prev != NULL) { prev->next = p->next; /* remove p from list */ p->next = host_pairs; /* and stick it on front */ host_pairs = p; } break; } } return p;}/* find head of list of connections with this pair of hosts */static struct connection *find_host_pair_connections(const char *func , const ip_address *myaddr, u_int16_t myport , const ip_address *hisaddr, u_int16_t hisport){ char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF]; struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport); DBG(DBG_CONTROLMORE , DBG_log("find_host_pair_conn (%s): %s:%d %s:%d -> hp:%s\n" , func , (addrtot(myaddr, 0, b1, sizeof(b1)), b1) , myport , hisaddr ? (addrtot(hisaddr, 0, b2, sizeof(b2)), b2) : "%any" , hisport , (hp && hp->connections) ? hp->connections->name : "none")); return hp == NULL? NULL : hp->connections;}static voidconnect_to_host_pair(struct connection *c){ if (oriented(*c)) { struct host_pair *hp = find_host_pair(&c->spd.this.host_addr , c->spd.this.host_port , &c->spd.that.host_addr , c->spd.that.host_port); char b1[ADDRTOT_BUF],b2[ADDRTOT_BUF]; DBG(DBG_CONTROLMORE , DBG_log("connect_to_host_pair: %s:%d %s:%d -> hp:%s\n" , (addrtot(&c->spd.this.host_addr, 0, b1,sizeof(b1)), b1) , c->spd.this.host_port , (addrtot(&c->spd.that.host_addr, 0, b2,sizeof(b2)), b2) , c->spd.that.host_port , (hp && hp->connections) ? hp->connections->name : "none")); if (hp == NULL) { /* no suitable host_pair -- build one */ hp = alloc_thing(struct host_pair, "host_pair"); hp->me.addr = c->spd.this.host_addr; hp->him.addr = c->spd.that.host_addr;#ifdef NAT_TRAVERSAL hp->me.host_port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port; hp->him.host_port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port;#else hp->me.host_port = c->spd.this.host_port; hp->him.host_port = c->spd.that.host_port;#endif hp->initial_connection_sent = FALSE; hp->connections = NULL; hp->pending = NULL; hp->next = host_pairs; host_pairs = hp; } c->host_pair = hp; c->hp_next = hp->connections; hp->connections = c; } else { /* since this connection isn't oriented, we place it * in the unoriented_connections list instead. */ c->host_pair = NULL; c->hp_next = unoriented_connections; unoriented_connections = c; }}/* find a connection by name. * If strict, don't accept a CK_INSTANCE. * Move the winner (if any) to the front. * If none is found, and strict, a diagnostic is logged to whack. */struct connection *con_by_name(const char *nm, bool strict){ struct connection *p, *prev; for (prev = NULL, p = connections; ; prev = p, p = p->ac_next) { if (p == NULL) { if (strict) whack_log(RC_UNKNOWN_NAME , "no connection named \"%s\"", nm); break; } if (streq(p->name, nm) && (!strict || p->kind != CK_INSTANCE)) { if (prev != NULL) { prev->ac_next = p->ac_next; /* remove p from list */ p->ac_next = connections; /* and stick it on front */ connections = p; } break; } } return p;}voidrelease_connection(struct connection *c, bool relations){ if (c->kind == CK_INSTANCE) { /* This does everything we need. * Note that we will be called recursively by delete_connection, * but kind will be CK_GOING_AWAY. */ delete_connection(c, relations); } else { flush_pending_by_connection(c); delete_states_by_connection(c, relations); unroute_connection(c); }}/* Delete a connection */#define list_rm(etype, enext, e, ehead) { \ etype **ep; \ for (ep = &(ehead); *ep != (e); ep = &(*ep)->enext) \ passert(*ep != NULL); /* we must not come up empty-handed */ \ *ep = (e)->enext; \ }static voiddelete_end(struct connection *c UNUSED, struct spd_route *sr UNUSED, struct end *e){ free_id_content(&e->id); pfreeany(e->updown); freeanychunk(e->ca);#ifdef SMARTCARD scx_release(e->sc);#endif release_cert(e->cert); free_ietfAttrList(e->groups);}static voiddelete_sr(struct connection *c, struct spd_route *sr){ delete_end(c, sr, &sr->this); delete_end(c, sr, &sr->that);}voiddelete_connection(struct connection *c, bool relations){ struct spd_route *sr; struct connection *old_cur_connection = cur_connection == c? NULL : cur_connection;#ifdef DEBUG lset_t old_cur_debugging = cur_debugging;#endif set_cur_connection(c); /* Must be careful to avoid circularity: * we mark c as going away so it won't get deleted recursively. */ passert(c->kind != CK_GOING_AWAY); if (c->kind == CK_INSTANCE) { openswan_log("deleting connection \"%s\" instance with peer %s {isakmp=#%lu/ipsec=#%lu}" , c->name , ip_str(&c->spd.that.host_addr) , c->newest_isakmp_sa, c->newest_ipsec_sa); c->kind = CK_GOING_AWAY; } else { openswan_log("deleting connection"); } release_connection(c, relations); /* won't delete c */ if (c->kind == CK_GROUP) delete_group(c); /* free up any logging resources */ perpeer_logfree(c); /* find and delete c from connections list */ list_rm(struct connection, ac_next, c, connections); cur_connection = old_cur_connection; /* find and delete c from the host pair list */ if (c->host_pair == NULL) { list_rm(struct connection, hp_next, c, unoriented_connections); } else { struct host_pair *hp = c->host_pair; list_rm(struct connection, hp_next, c, hp->connections); c->host_pair = NULL; /* redundant, but safe */ /* if there are no more connections with this host_pair * and we haven't even made an initial contact, let's delete * this guy in case we were created by an attempted DOS attack. */ if (hp->connections == NULL && !hp->initial_connection_sent) { passert(hp->pending == NULL); /* ??? must deal with this! */ list_rm(struct host_pair, next, hp, host_pairs); pfree(hp); } }#ifdef VIRTUAL_IP if (c->kind != CK_GOING_AWAY) pfreeany(c->spd.that.virt);#endif#ifdef DEBUG set_debugging(old_cur_debugging);#endif pfreeany(c->name); sr = &c->spd; while(sr) { delete_sr(c, sr); sr = sr->next; } free_generalNames(c->requested_ca, TRUE); gw_delref(&c->gw_info);#ifdef KERNEL_ALG alg_info_delref((struct alg_info **)&c->alg_info_esp);#endif#ifdef IKE_ALG alg_info_delref((struct alg_info **)&c->alg_info_ike);#endif pfree(c);}/* Delete connections with the specified name */voiddelete_connections_by_name(const char *name, bool strict){ struct connection *c = con_by_name(name, strict); for (; c != NULL; c = con_by_name(name, FALSE)) delete_connection(c, FALSE);}voiddelete_every_connection(void){ while (connections != NULL) delete_connection(connections, TRUE);}voidrelease_dead_interfaces(void){ struct host_pair *hp; for (hp = host_pairs; hp != NULL; hp = hp->next) { struct connection **pp , *p; for (pp = &hp->connections; (p = *pp) != NULL; ) { if (p->interface->change == IFN_DELETE) { /* this connection's interface is going away */ enum connection_kind k = p->kind; release_connection(p, TRUE); if (k <= CK_PERMANENT) { /* The connection should have survived release: * move it to the unoriented_connections list. */ passert(p == *pp); p->interface = NULL; *pp = p->hp_next; /* advance *pp */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -