📄 timer.c
字号:
/* timer event handling * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2001 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: timer.c,v 1.96 2004/11/30 16:11:04 mcr Exp $ */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <time.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/queue.h>#include <openswan.h>#include "constants.h"#include "defs.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h" /* needs id.h */#include "state.h"#include "packet.h"#include "demux.h" /* needs packet.h */#include "ipsec_doi.h" /* needs demux.h and state.h */#include "kernel.h" /* needs connections.h */#include "server.h"#include "log.h"#include "rnd.h"#include "timer.h"#include "whack.h"#include "dpd.h"#ifdef NAT_TRAVERSAL#include "nat_traversal.h"#endif/* monotonic version of time(3) */time_tnow(void){ static time_t delta = 0 , last_time = 0; time_t n = time((time_t)NULL); passert(n != (time_t)-1); if (last_time > n) { openswan_log("time moved backwards %ld seconds", (long)(last_time - n)); delta += last_time - n; } last_time = n; return n + delta;}/* This file has the event handling routines. Events are * kept as a linked list of event structures. These structures * have information like event type, expiration time and a pointer * to event specific data (for example, to a state structure). */static struct event *evlist = (struct event *) NULL;/* * This routine places an event in the event list. */voidevent_schedule(enum event_type type, time_t tm, struct state *st){ struct event *ev = alloc_thing(struct event, "struct event in event_schedule()"); passert(tm >= 0); ev->ev_type = type; ev->ev_time = tm + now(); ev->ev_state = st; /* If the event is associated with a state, put a backpointer to the * event in the state object, so we can find and delete the event * if we need to (for example, if we receive a reply). */ if (st != NULL) { if(type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) { passert(st->st_dpd_event == NULL); st->st_dpd_event = ev; } else { passert(st->st_event == NULL); st->st_event = ev; } } DBG(DBG_CONTROL, if (st == NULL) DBG_log("inserting event %s, timeout in %lu seconds" , enum_show(&timer_event_names, type), (unsigned long)tm); else DBG_log("inserting event %s, timeout in %lu seconds for #%lu" , enum_show(&timer_event_names, type), (unsigned long)tm , ev->ev_state->st_serialno)); if (evlist == (struct event *) NULL || evlist->ev_time >= ev->ev_time) { ev->ev_next = evlist; evlist = ev; } else { struct event *evt; for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next) if (evt->ev_next->ev_time >= ev->ev_time) break;#ifdef NEVER /* this seems to be overkill */ DBG(DBG_CONTROL, if (evt->ev_state == NULL) DBG_log("event added after event %s" , enum_show(&timer_event_names, evt->ev_type)); else DBG_log("event added after event %s for #%lu" , enum_show(&timer_event_names, evt->ev_type) , evt->ev_state->st_serialno));#endif /* NEVER */ ev->ev_next = evt->ev_next; evt->ev_next = ev; }}/* * Handle the first event on the list. */voidhandle_timer_event(void){ time_t tm; struct event *ev = evlist; int type; struct state *st; struct connection *c; ip_address peer; if (ev == (struct event *) NULL) /* Just paranoid */ { DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called")); return; } type = ev->ev_type; st = ev->ev_state; tm = now(); if (tm < ev->ev_time) { DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %s)" , (unsigned long)tm, (unsigned long)ev->ev_time , enum_show(&timer_event_names, type))); /* This will happen if the most close-to-expire event was * a retransmission or cleanup, and we received a packet * at the same time as the event expired. Due to the processing * order in call_server(), the packet processing will happen first, * and the event will be removed. */ return; } evlist = evlist->ev_next; /* Ok, we'll handle this event */ DBG(DBG_CONTROL, DBG_log("handling event %s" , enum_show(&timer_event_names, type))); if(DBGP(DBG_CONTROL)) { if (evlist != (struct event *) NULL) { DBG_log("event after this is %s in %ld seconds" , enum_show(&timer_event_names, evlist->ev_type) , (long) (evlist->ev_time - tm)); } else { DBG_log("no more events are scheduled"); } } /* for state-associated events, pick up the state pointer * and remove the backpointer from the state object. * We'll eventually either schedule a new event, or delete the state. */ passert(GLOBALS_ARE_RESET()); if (st != NULL) { c = st->st_connection; if( type == EVENT_DPD || type == EVENT_DPD_TIMEOUT) { passert(st->st_dpd_event == ev); st->st_dpd_event = NULL; } else { passert(st->st_event == ev); st->st_event = NULL; } peer = c->spd.that.host_addr; set_cur_state(st); } switch (type) { case EVENT_REINIT_SECRET: passert(st == NULL); DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled")); init_secret(); break;#ifdef KLIPS case EVENT_SHUNT_SCAN: passert(st == NULL); scan_proc_shunts(); break;#endif case EVENT_LOG_DAILY: daily_log_event(); break; case EVENT_RETRANSMIT: /* Time to retransmit, or give up. * * Generally, we'll only try to send the message * MAXIMUM_RETRANSMISSIONS times. Each time we double * our patience. * * As a special case, if this is the first initiating message * of a Main Mode exchange, and we have been directed to try * forever, we'll extend the number of retransmissions to * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these * extended attempts having the same patience. The intention * is to reduce the bother when nobody is home. * * Since IKEv1 is not reliable for the Quick Mode responder, * we'll extend the number of retransmissions as well to * improve the reliability. */ { time_t delay = 0; DBG(DBG_CONTROL, DBG_log( "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu" , ip_str(&peer), c->name, st->st_serialno)); if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS) delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1); else if ((st->st_state == STATE_MAIN_I1 || st->st_state == STATE_AGGR_I1) && c->sa_keying_tries == 0 && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL) delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS; else if (st->st_state == STATE_QUICK_R1 && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_QUICK_R1) delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS; if (delay != 0) { st->st_retransmit++; whack_log(RC_RETRANSMISSION , "%s: retransmission; will wait %lus for response" , enum_name(&state_names, st->st_state) , (unsigned long)delay); send_packet(st, "EVENT_RETRANSMIT"); event_schedule(EVENT_RETRANSMIT, delay, st); } else { /* check if we've tried rekeying enough times. * st->st_try == 0 means that this should be the only try. * c->sa_keying_tries == 0 means that there is no limit. */ unsigned long try = st->st_try; unsigned long try_limit = c->sa_keying_tries; const char *details = ""; switch (st->st_state) { case STATE_MAIN_I3: details = ". Possible authentication failure:" " no acceptable response to our" " first encrypted message"; break; case STATE_MAIN_I1: details = ". No response (or no acceptable response) to our" " first IKE message"; break; case STATE_QUICK_I1: if (c->newest_ipsec_sa == SOS_NOBODY) details = ". No acceptable response to our" " first Quick Mode message:" " perhaps peer likes no proposal";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -