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

📄 pluto_crypt.c

📁 This a good VPN source
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  * Cryptographic helper function. * Copyright (C) 2004 Michael C. Richardson <mcr@xelerance.com> * * 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. * * This code was developed with the support of IXIA communications. * * RCSID $Id: pluto_crypt.c,v 1.12 2004/11/30 02:27:50 mcr Exp $ */#include <stdlib.h>#include <string.h>#include <ctype.h>#include <errno.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <sys/queue.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/types.h>#include <signal.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#include "constants.h"#include "defs.h"#include "packet.h"#include "demux.h"#include "oswlog.h"#include "log.h"#include "state.h"#include "demux.h"#include "rnd.h"#include "pluto_crypt.h"struct pluto_crypto_worker {    int   pcw_helpernum;    pid_t pcw_pid;    int   pcw_pipe;    int   pcw_work;         /* how many items outstanding */    int   pcw_maxbasicwork; /* how many basic things can be queued */    int   pcw_maxcritwork;  /* how many critical things can be queued */    bool  pcw_dead;         /* worker is dead, waiting for reap */    bool  pcw_reaped;       /* worker has been reaped, waiting for dealloc */    struct pluto_crypto_req_cont *pcw_cont;};static struct pluto_crypto_req_cont *backlogqueue;static int                           backlogqueue_len;static void init_crypto_helper(struct pluto_crypto_worker *w, int n);static void cleanup_crypto_helper(struct pluto_crypto_worker *w);static void handle_helper_comm(struct pluto_crypto_worker *w);extern void free_preshared_secrets(void);/* may be NULL if we are to do all the work ourselves */struct pluto_crypto_worker *pc_workers = NULL;int pc_workers_cnt = 0;int pc_worker_num;pcr_req_id pcw_id;/* local in child */int pc_helper_num=-1;void pluto_do_crypto_op(struct pluto_crypto_req *r){    DBG(DBG_CONTROL	, DBG_log("helper %d doing %s op id: %u"		  , pc_helper_num		  , enum_show(&pluto_cryptoop_names, r->pcr_type)		  , r->pcr_id));    /* now we have the entire request in the buffer, process it */    switch(r->pcr_type) {    case pcr_build_kenonce:	calc_ke(r);	calc_nonce(r);	break;    case pcr_build_nonce:	calc_nonce(r);	break;    case pcr_rsa_sign:    case pcr_rsa_check:    case pcr_x509cert_fetch:    case pcr_x509crl_fetch:	break;    }}void pluto_crypto_allocchunk(wire_chunk_t *space			     , wire_chunk_t *new			     , size_t howbig){    /*     * passert for now, since we should be able to figure out what     * the maximum is.     */    passert(space->start + howbig < space->len);    new->start = space->start;    new->len   = howbig;        space->start += howbig;}static void catchhup(int signo UNUSED){    /* socket closed die */    exit(0);}static void catchusr1(int signo UNUSED){    return;}static voidhelper_passert_fail(const char *pred_str		    , const char *file_str		    , unsigned long line_no) NEVER_RETURNS;static voidhelper_passert_fail(const char *pred_str		    , const char *file_str		    , unsigned long line_no){    static bool dying_breath = 0;    /* we will get a possibly unplanned prefix.  Hope it works */    loglog(RC_LOG_SERIOUS, "ASSERTION FAILED at %s:%lu: %s", file_str, line_no, pred_str);    if (!dying_breath)    {	dying_breath = TRUE;    }    chdir("helper");    abort();}void pluto_crypto_helper(int fd, int helpernum){    char reqbuf[PCR_REQ_SIZE];    struct pluto_crypto_req *r;    signal(SIGHUP, catchhup);    signal(SIGUSR1, catchusr1);    pc_worker_num = helpernum;    /* make us lower priority that average */    setpriority(PRIO_PROCESS, 0, 10);    DBG(DBG_CONTROL, DBG_log("helper %d waiting on fd: %d"			      , helpernum, fd));    while(read(fd, reqbuf, sizeof(r->pcr_len)) == sizeof(r->pcr_len)) {	int restlen;	int actlen;	r = (struct pluto_crypto_req *)reqbuf;	restlen = r->pcr_len-sizeof(r->pcr_len);		passert(restlen < (signed)PCR_REQ_SIZE);	/* okay, got a basic size, read the rest of it */	if((actlen= read(fd, reqbuf+sizeof(r->pcr_len), restlen)) != restlen) {	    /* faulty read. die, parent will restart us */	    	    loglog(RC_LOG_SERIOUS, "cryptographic helper(%d) read(%d)=%d failed: %s\n",		   getpid(), restlen, actlen, strerror(errno));	    exit(1);	}	pluto_do_crypto_op(r);	actlen = write(fd, (unsigned char *)r, r->pcr_len);	if((unsigned)actlen != r->pcr_len) {	    loglog(RC_LOG_SERIOUS, "failed to write answer: %d", actlen);	    exit(2);	}    }    /* probably normal EOF */    close(fd);    exit(0);}/* * this function is called with a request to do some cryptographic operations * along with a continuation structure, which will be used to deal with * the response. * * This may fail if there are no helpers that can take any data, in which * case an error is returned.  * */err_t send_crypto_helper_request(struct pluto_crypto_req *r				 , struct pluto_crypto_req_cont *cn){    struct pluto_crypto_worker *w;    int cnt;    /* do it all ourselves? */    if(pc_workers == NULL) {	reset_cur_state();	pluto_do_crypto_op(r);	/* call the continuation */	(*cn->pcrc_func)(cn, r, NULL);	pfree(cn);	pfree(r);	return NULL;    }    /* set up the id */    r->pcr_id = pcw_id++;    cn->pcrc_id = r->pcr_id;    cn->pcrc_pcr = r;    pc_worker_num++;    if(pc_worker_num >= pc_workers_cnt) {	pc_worker_num = 0;    }    cnt = pc_workers_cnt;    /* find an available worker, restarting one if it was found to be dead */    w = &pc_workers[pc_worker_num];    DBG(DBG_CONTROL	, DBG_log("%d: w->pcw_dead: %d w->pcw_work: %d cnt: %d",		  pc_worker_num, w->pcw_dead, w->pcw_work, cnt));        while((w->pcw_dead || (w->pcw_work >= w->pcw_maxbasicwork))	  && --cnt > 0) {		pc_worker_num++;	w = &pc_workers[pc_worker_num];	/* see if there is something to clean up after */	if(w->pcw_dead      == TRUE	   && w->pcw_reaped == TRUE) {	    cleanup_crypto_helper(w);	}	DBG(DBG_CONTROL	    , DBG_log("%d: w->pcw_dead: %d w->pcw_work: %d cnt: %d",		      pc_worker_num, w->pcw_dead, w->pcw_work, cnt));    }    if(cnt == 0 && r->pcr_pcim > pcim_ongoing_crypto) {	cnt = pc_workers_cnt;	while((w->pcw_dead || (w->pcw_work >= w->pcw_maxcritwork))	      && --cnt > 0) {		    pc_worker_num++;	    w = &pc_workers[pc_worker_num];	    /* see if there is something to clean up after */	    if(w->pcw_dead      == TRUE	       && w->pcw_reaped == TRUE) {		cleanup_crypto_helper(w);	    }	    DBG(DBG_CONTROL		, DBG_log("crit %d: w->pcw_dead: %d w->pcw_work: %d cnt: %d",			  pc_worker_num, w->pcw_dead, w->pcw_work, cnt));	}    }    if(cnt == 0 && r->pcr_pcim >= pcim_demand_crypto) {	/* it is very important. Put it all on a queue for later */	cn->pcrc_next = backlogqueue;	backlogqueue  = cn;		backlogqueue_len++;	DBG(DBG_CONTROL	    , DBG_log("critical demand crypto operation queued as item %d"		      , backlogqueue_len));	return NULL;    }    if(cnt == 0) {	/* didn't find any workers */	DBG(DBG_CONTROL	    , DBG_log("failed to find any available worker"));	return "failed to find any available worker";    }    /* w points to a work. Make sure it is live */    if(w->pcw_pid == -1) {	init_crypto_helper(w, pc_worker_num);	if(w->pcw_pid == -1) {	    DBG(DBG_CONTROL		, DBG_log("found only a dead helper, and failed to restart it"));	    return "failed to start a new helper";	}    }    /* link it to the active worker list */    cn->pcrc_next = w->pcw_cont;    w->pcw_cont = cn;    passert(w->pcw_pid != -1);    passert(w->pcw_pipe != -1);    passert(w->pcw_work < w->pcw_maxcritwork);        DBG(DBG_CONTROL	, DBG_log("asking helper %d to do %s op on seq: %u"		  , w->pcw_helpernum		  , enum_show(&pluto_cryptoop_names, r->pcr_type)		  , r->pcr_id));    /* send the request, and then mark the work as having more work */    cnt = write(w->pcw_pipe, r, r->pcr_len);    if(cnt == -1) {	return "failed to write";    }     w->pcw_work++;    return NULL;}/* * send 1 unit of backlog, if any, to indicated worker. */static void crypto_send_backlog(struct pluto_crypto_worker *w){    struct pluto_crypto_req *r;    struct pluto_crypto_req_cont *cn;    if(backlogqueue_len > 0) {	int cnt;	passert(backlogqueue != NULL);		cn = backlogqueue;	backlogqueue = cn->pcrc_next;	backlogqueue_len--;		r = cn->pcrc_pcr;      	DBG(DBG_CONTROL	    , DBG_log("removing backlog item (%d) from queue: %d left"		      , r->pcr_id, backlogqueue_len));	/* w points to a work. Make sure it is live */	if(w->pcw_pid == -1) {	    init_crypto_helper(w, pc_worker_num);	    if(w->pcw_pid == -1) {		DBG(DBG_CONTROL		    , DBG_log("found only a dead helper, and failed to restart it"));		/* XXX invoke callback with failure */		passert(0);		return;	    }	}		/* link it to the active worker list */	cn->pcrc_next = w->pcw_cont;	w->pcw_cont = cn;

⌨️ 快捷键说明

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