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

📄 foodgroups.c

📁 This a good VPN source
💻 C
字号:
/* Implement policy groups-style control files (aka "foodgroups") * Copyright (C) 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: foodgroups.c,v 1.20 2004/04/29 03:59:32 mcr Exp $ */#include <unistd.h>#include <string.h>#include <stdio.h>#include <stddef.h>#include <stdlib.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 "foodgroups.h"#include "kernel.h"	/* needs connections.h */#include "lex.h"#include "log.h"#include "whack.h"#include "paths.h"/* Food group config files are found in directory fg_path */static char *fg_path = NULL;static size_t fg_path_space = 0;/* Groups is a list of connections that are policy groups. * The list is updated as group connections are added and deleted. */struct fg_groups {    struct fg_groups *next;    struct connection *connection;};static struct fg_groups *groups = NULL;/* Targets is a list of pairs: subnet and its policy group. * This list is bulk-updated on whack --listen and * incrementally updated when group connections are deleted. * * It is ordered by source subnet, and if those are equal, then target subnet. * A subnet is compared by comparing the network, and if those are equal, * comparing the mask. */struct fg_targets {    struct fg_targets *next;    struct fg_groups *group;    ip_subnet subnet;    char *name;	/* name of instance of group conn */};static struct fg_targets *targets = NULL;struct fg_targets *new_targets;/* ipcmp compares the two ip_address values a and b. * It returns -1, 0, or +1 if a is, respectively, * less than, equal to, or greater than b. */static intipcmp(ip_address *a, ip_address *b){    if (addrtypeof(a) != addrtypeof(b))    {	return addrtypeof(a) < addrtypeof(b)? -1 : 1;    }    else if (sameaddr(a, b))    {	return 0;    }    else    {	const struct sockaddr *sa = sockaddrof(a)	    , *sb = sockaddrof(b);	passert(addrtypeof(a) == AF_INET);	/* not yet implemented IPv6 version :-( */	return (ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr)	    < ntohl(((const struct sockaddr_in *)sb)->sin_addr.s_addr))	    ? -1 : 1;    }}/* subnetcmp compares the two ip_subnet values a and b. * It returns -1, 0, or +1 if a is, respectively, * less than, equal to, or greater than b. */static intsubnetcmp(const ip_subnet *a, const ip_subnet *b){    ip_address neta, maska, netb, maskb;    int r;    networkof(a, &neta);    maskof(a, &maska);    networkof(b, &netb);    maskof(b, &maskb);    r = ipcmp(&neta, &netb);    if (r == 0)	r = ipcmp(&maska, &maskb);    return r;}static voidread_foodgroup(struct fg_groups *g){    const char *fgn = g->connection->name;    const ip_subnet *lsn = &g->connection->spd.this.client;    size_t plen = strlen(ipsec_dir) + sizeof("/policies/") + 1 + strlen(fgn) + 1;    struct file_lex_position flp_space;    if (plen > fg_path_space)    {	pfreeany(fg_path);	fg_path_space = plen + 10;	fg_path = alloc_bytes(fg_path_space, "policy group path");    }    snprintf(fg_path, fg_path_space, "%s/policies/%s", ipsec_dir, fgn);    if (!lexopen(&flp_space, fg_path, TRUE))    {	char cwd[PATH_MAX];	DBG(DBG_CONTROL	    , DBG_log("no group file \"%s\" (pwd:%s)"		      , fg_path		      , getcwd(cwd, sizeof(cwd))));    }    else    {	openswan_log("loading group \"%s\"", fg_path);	for (;;)	{	    switch (flp->bdry)	    {	    case B_none:		{		    /* !!! this test is not sufficient for distinguishing address families.		     * We need a notation to specify that a FQDN is to be resolved to IPv6.		     */		    const struct af_info *afi = strchr(tok, ':') == NULL			? &af_inet4_info: &af_inet6_info;		    ip_subnet sn;		    err_t ugh;		    if (strchr(tok, '/') == NULL)		    {			/* no /, so treat as /32 or V6 equivalent */			ip_address t;			ugh = ttoaddr(tok, 0, afi->af, &t);			if (ugh == NULL)			    ugh = addrtosubnet(&t, &sn);		    }		    else		    {			ugh = ttosubnet(tok, 0, afi->af, &sn);		    }		    if (ugh != NULL)		    {			loglog(RC_LOG_SERIOUS, "\"%s\" line %d: %s \"%s\""			    , flp->filename, flp->lino, ugh, tok);		    }		    else if (afi->af != AF_INET)		    {			loglog(RC_LOG_SERIOUS			    , "\"%s\" line %d: unsupported Address Family \"%s\""			    , flp->filename, flp->lino, tok);		    }		    else		    {			/* Find where new entry ought to go in new_targets. */			struct fg_targets **pp;			int r;			for (pp = &new_targets; ; pp = &(*pp)->next)			{			    if (*pp == NULL)			    {				r = -1;	/* end of list is infinite */				break;			    }			    r = subnetcmp(lsn, &(*pp)->group->connection->spd.this.client);			    if (r == 0)				r = subnetcmp(&sn, &(*pp)->subnet);			    if (r <= 0)				break;			}			if (r == 0)			{			    char source[SUBNETTOT_BUF];			    subnettot(lsn, 0, source, sizeof(source));			    loglog(RC_LOG_SERIOUS				, "\"%s\" line %d: subnet \"%s\", source %s, already \"%s\""				, flp->filename				, flp->lino				, tok				, source				, (*pp)->group->connection->name);			}			else			{			    struct fg_targets *f = alloc_thing(struct fg_targets, "fg_target");			    f->next = *pp;			    f->group = g;			    f->subnet = sn;			    f->name = NULL;			    *pp = f;			}		    }		}		(void)shift();	/* next */		continue;	    case B_record:		flp->bdry = B_none;	/* eat the Record Boundary */		(void)shift();	/* get real first token */		continue;	    case B_file:		break;	/* done */	    }	    break;	/* if we reach here, out of loop */	}	lexclose();    }}static voidfree_targets(void){    while (targets != NULL)    {	struct fg_targets *t = targets;	targets = t->next;	pfreeany(t->name);	pfree(t);    }}voidload_groups(void){    passert(new_targets == NULL);    /* for each group, add config file targets into new_targets */    {	struct fg_groups *g;	for (g = groups; g != NULL; g = g->next)	    if (oriented(*g->connection))		read_foodgroup(g);    }    /* dump new_targets */    DBG(DBG_CONTROL,	{	    struct fg_targets *t;	    for (t = new_targets; t != NULL; t = t->next)	    {		char asource[SUBNETTOT_BUF];		char atarget[SUBNETTOT_BUF];		subnettot(&t->group->connection->spd.this.client		    , 0, asource, sizeof(asource));		subnettot(&t->subnet, 0, atarget, sizeof(atarget));		DBG_log("%s->%s %s"		    , asource, atarget		    , t->group->connection->name);	    }	});    /* determine and deal with differences between targets and new_targets.     * structured like a merge.     */    {	struct fg_targets *op = targets	    , *np = new_targets;	while (op != NULL && np != NULL)	{	    int r = subnetcmp(&op->group->connection->spd.this.client		, &np->group->connection->spd.this.client);	    if (r == 0)		r = subnetcmp(&op->subnet, &np->subnet);	    if (r == 0 && op->group == np->group)	    {		/* unchanged -- steal name & skip over */		np->name = op->name;		op->name = NULL;		op = op->next;		np = np->next;	    }	    else	    {		/* note: following cases overlap! */		if (r <= 0)		{		    remove_group_instance(op->group->connection, op->name);		    op = op->next;		}		if (r >= 0)		{		    np->name = add_group_instance(np->group->connection, &np->subnet);		    np = np->next;		}	    }	}	for (; op != NULL; op = op->next)	    remove_group_instance(op->group->connection, op->name);	for (; np != NULL; np = np->next)	    np->name = add_group_instance(np->group->connection, &np->subnet);	/* update: new_targets replaces targets */	free_targets();	targets = new_targets;	new_targets = NULL;    }}voidadd_group(struct connection *c){    struct fg_groups *g = alloc_thing(struct fg_groups, "policy group");    g->next = groups;    groups = g;    g->connection = c;}static struct fg_groups *find_group(const struct connection *c){    struct fg_groups *g;    for (g = groups; g != NULL && g->connection != c; g = g->next)	;    return g;}voidroute_group(struct connection *c){    /* it makes no sense to route a connection that is ISAKMP-only */    if (!NEVER_NEGOTIATE(c->policy) && !HAS_IPSEC_POLICY(c->policy))    {	loglog(RC_ROUTE, "cannot route an ISAKMP-only group connection");    }    else    {	struct fg_groups *g = find_group(c);	struct fg_targets *t;	passert(g != NULL);	g->connection->policy |= POLICY_GROUTED;	for (t = targets; t != NULL; t = t->next)	{	    if (t->group == g)	    {		struct connection *ci = con_by_name(t->name, FALSE);		if (ci != NULL)		{		    set_cur_connection(ci);		    if (!trap_connection(ci))			whack_log(RC_ROUTE, "could not route");		    set_cur_connection(c);		}	    }	}    }}voidunroute_group(struct connection *c){    struct fg_groups *g = find_group(c);    struct fg_targets *t;    passert(g != NULL);    g->connection->policy &= ~POLICY_GROUTED;    for (t = targets; t != NULL; t = t->next)    {	if (t->group == g)	{	    struct connection *ci = con_by_name(t->name, FALSE);	    if (ci != NULL)	    {		set_cur_connection(ci);		unroute_connection(ci);		set_cur_connection(c);	    }	}    }}voiddelete_group(const struct connection *c){    struct fg_groups *g;    /* find and remove from groups */    {	struct fg_groups **pp;	for (pp = &groups; (g = *pp)->connection != c; pp = &(*pp)->next)	    ;	*pp = g->next;    }    /* find and remove from targets */    {	struct fg_targets **pp;	for (pp = &targets; *pp != NULL; )	{	    struct fg_targets *t = *pp;	    if (t->group == g)	    {		*pp = t->next;		remove_group_instance(t->group->connection, t->name);		pfree(t);		/* pp is ready for next iteration */	    }	    else	    {		pp = &t->next;	    }	}    }    pfree(g);}/* * Local Variables: * c-basic-offset:4 * c-style: pluto * End: */

⌨️ 快捷键说明

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