⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 connections.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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.234 2004/11/30 14:02:52 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 "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 "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 "adns.h"	/* needs <resolv.h> */#include "dnskey.h"	/* needs keys.h and adns.h */#include "whack.h"#include "alg_info.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"#endifstatic void flush_pending_by_connection(struct connection *c);	/* forward */static 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 port;	/* host order */    } 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;/* 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);}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;    /* default hisaddr to an appropriate any */    if (hisaddr == NULL)	hisaddr = aftoinfo(addrtypeof(myaddr))->any;#ifdef NAT_TRAVERSAL    if (nat_traversal_enabled) {	/**	 * port is not relevant in host_pair. with nat_traversal we	 * always use pluto_port (500)	 */	myport = pluto_port;	hisport = pluto_port;    }#endif    for (prev = NULL, p = host_pairs; p != NULL; prev = p, p = p->next)    {	if (sameaddr(&p->me.addr, myaddr) && p->me.port == myport	&& sameaddr(&p->him.addr, hisaddr) && p->him.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 ip_address *myaddr, u_int16_t myport, const ip_address *hisaddr, u_int16_t hisport){    struct host_pair *hp = find_host_pair(myaddr, myport, hisaddr, hisport);#ifdef NAT_TRAVERSAL    if (nat_traversal_enabled && hp && hisaddr) {	struct connection *c;	for (c = hp->connections; c != NULL; c = c->hp_next) {	    if ((c->spd.this.host_port==myport) && (c->spd.that.host_port==hisport))		return c;	}	return NULL;    }#endif    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);	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.port = nat_traversal_enabled ? pluto_port : c->spd.this.host_port;	    hp->him.port = nat_traversal_enabled ? pluto_port : c->spd.that.host_port;#else	    hp->me.port = c->spd.this.host_port; 	    hp->him.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 */		    p->host_pair = NULL;		    p->hp_next = unoriented_connections;		    unoriented_connections = p;		}		else		{		    /* The connection should have vanished,		     * but the previous connection remains.		     */		    passert(p != *pp);		}	    }	    else	    {		pp = &p->hp_next;	/* advance pp */	    }	}    }}/* adjust orientations of connections to reflect newly added interfaces */voidcheck_orientations(void){    /* try to orient all the unoriented connections */    {	struct connection *c = unoriented_connections;	unoriented_connections = NULL;	while (c != NULL)	{	    struct connection *nxt = c->hp_next;	    (void)orient(c);	    connect_to_host_pair(c);	    c = nxt;	}    }    /* Check that no oriented connection has become double-oriented.     * In other words, the far side must not match one of our new interfaces.     */    {	struct iface *i;	for (i = interfaces; i != NULL; i = i->next)	{	    if (i->change == IFN_ADD)	    {		struct host_pair *hp;		for (hp = host_pairs; hp != NULL; hp = hp->next)		{		    if (sameaddr(&hp->him.addr, &i->addr)		    && (!no_klips || hp->him.port == pluto_port))		    {			/* bad news: the whole chain of connections			 * hanging off this host pair has both sides			 * matching an interface.			 * We'll get rid of them, using orient and			 * connect_to_host_pair.  But we'll be lazy			 * and not ditch the host_pair itself (the			 * cost of leaving it is slight and cannot			 * be induced by a foe).			 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -