pending.c
来自「ipsec vpn」· C语言 代码 · 共 337 行
C
337 行
/* 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: pending.c,v 1.5 2005/03/27 20:18:13 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 "pending.h"#include "log.h"#include "state.h"#include "packet.h"#include "demux.h"#include "ikev1_quick.h"#include "timer.h"/* struct pending, the structure representing Quick Mode * negotiations delayed until a Keying Channel has been negotiated. * Essentially, a pending call to quick_outI1. */struct pending { int whack_sock; struct state *isakmp_sa; struct connection *connection; lset_t policy; unsigned long try; so_serial_t replacing; time_t pend_time; struct pending *next;};/* queue a Quick Mode negotiation pending completion of a suitable Main Mode */voidadd_pending(int whack_sock, struct state *isakmp_sa, struct connection *c, lset_t policy, unsigned long try, so_serial_t replacing){ struct pending *p = alloc_thing(struct pending, "struct pending"); DBG(DBG_CONTROL, DBG_log("Queuing pending Quick Mode with %s \"%s\"" , ip_str(&c->spd.that.host_addr) , c->name)); p->whack_sock = whack_sock; p->isakmp_sa = isakmp_sa; p->connection = c; p->policy = policy; p->try = try; p->replacing = replacing; p->pend_time = time(NULL); host_pair_enqueue_pending(c, p, &p->next);}/* Release all the whacks awaiting the completion of this state. * This is accomplished by closing all the whack socket file descriptors. * We go to a lot of trouble to tell each whack, but to not tell it twice. */voidrelease_pending_whacks(struct state *st, err_t story){ struct pending *p, **pp; struct stat stst; if (st->st_whack_sock == NULL_FD || fstat(st->st_whack_sock, &stst) != 0) zero(&stst); /* resulting st_dev/st_ino ought to be distinct */ release_whack(st); pp = host_pair_first_pending(st->st_connection); if(pp == NULL) return; for (p = *pp; p != NULL; p = p->next) { if (p->isakmp_sa == st && p->whack_sock != NULL_FD) { struct stat pst; if (fstat(p->whack_sock, &pst) == 0 && (stst.st_dev != pst.st_dev || stst.st_ino != pst.st_ino)) { passert(whack_log_fd == NULL_FD); whack_log_fd = p->whack_sock; whack_log(RC_COMMENT , "%s for ISAKMP SA, but releasing whack for pending IPSEC SA" , story); whack_log_fd = NULL_FD; } close(p->whack_sock); p->whack_sock = NULL_FD; } }}static voiddelete_pending(struct pending **pp){ struct pending *p = *pp; *pp = p->next; if (p->connection != NULL) connection_discard(p->connection); close_any(p->whack_sock); DBG(DBG_DPD, DBG_log("removing pending policy for \"%s\" {%p}", p->connection ? p->connection->name : "none", p)); pfree(p);}/* * Look for phase2s that were waiting for a phase 1. * * XXX instead of doing this work NOW, we should simply create an event * in zero future time to unpend the state. * YYY but, in fact, quick_mode will enqueue a cryptographic operation * anyway, which will get done "later" anyway, so make it is just fine * as it is. */voidunpend(struct state *st){ struct pending **pp , *p; DBG(DBG_DPD, DBG_log("unpending state #%lu", st->st_serialno)); for (pp = host_pair_first_pending(st->st_connection); (p = *pp) != NULL; ) { if (p->isakmp_sa == st) { DBG(DBG_CONTROL , DBG_log("unqueuing pending Quick Mode with %s \"%s\"" , ip_str(&p->connection->spd.that.host_addr) , p->connection->name)); p->pend_time = time(NULL); (void) quick_outI1(p->whack_sock, st, p->connection, p->policy , p->try, p->replacing); p->whack_sock = NULL_FD; /* ownership transferred */ p->connection = NULL; /* ownership transferred */ delete_pending(pp); } else { pp = &p->next; } }}/* * Look for phase2s that were waiting for a phase 1. If the time that we * have been pending exceeds a DPD timeout that was set, then we call the * dpd_timeout() on this state, which hopefully kills this pending state. */bool pending_check_timeout(struct connection *c){ struct pending **pp, *p; time_t n = time(NULL); bool restart = FALSE; for (pp = host_pair_first_pending(c); (p = *pp) != NULL; ) { DBG(DBG_DPD, DBG_log("checking connection \"%s\" for stuck phase 2s %lu+%lu <= %lu" , c->name , (unsigned long)p->pend_time , (unsigned long)c->dpd_timeout , (unsigned long)n)); if(c->dpd_timeout > 0) { if((p->pend_time + c->dpd_timeout*3) <= n) { restart = TRUE; } } pp = &p->next; } return restart;}/* a Main Mode negotiation has been replaced; update any pending */voidupdate_pending(struct state *os, struct state *ns){ struct pending *p, **pp; pp = host_pair_first_pending(os->st_connection); if(pp == NULL) return; for (p = *pp; p != NULL; p = p->next) { if (p->isakmp_sa == os) p->isakmp_sa = ns; } }/* a Main Mode negotiation has failed; discard any pending */voidflush_pending_by_state(struct state *st){ struct pending **pp , *p; pp = host_pair_first_pending(st->st_connection); if(pp == NULL) return; while((p = *pp) != NULL) { if (p->isakmp_sa == st) { /* we don't have to worry about deref to free'ed * *pp, because delete_pending updates pp to * point to the next element before it frees *pp */ delete_pending(pp); } else pp = &p->next; }}/* a connection has been deleted; discard any related pending */voidflush_pending_by_connection(struct connection *c){ struct pending **pp , *p; pp = host_pair_first_pending(c); if(pp == NULL) return; while((p = *pp) != NULL) { if (p->connection == c) { p->connection = NULL; /* prevent delete_pending from releasing */ delete_pending(pp); } else { pp = &p->next; } }}voidshow_pending_phase2(const struct connection *c, const struct state *st){ struct pending **pp , *p; pp = host_pair_first_pending(c); if(pp == NULL) return; for (p = *pp; p != NULL; p = p->next) { if (p->isakmp_sa == st) { /* connection-name state-number [replacing state-number] */ char cip[CONN_INST_BUF]; fmt_conn_instance(p->connection, cip); whack_log(RC_COMMENT, "#%lu: pending Phase 2 for \"%s\"%s replacing #%lu" , p->isakmp_sa->st_serialno , p->connection->name , cip , p->replacing); } }}bool in_pending_use(struct connection *c){ /* see if it is being used by a pending */ struct pending **pp, *p; pp = host_pair_first_pending(c); if(pp == NULL) return FALSE; for (p = *pp; p != NULL; p = p->next) if (p->connection == c) return TRUE; /* in use, so we're done */ return FALSE;}/* * Local Variables: * c-basic-offset:4 * c-style: pluto * End: */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?