📄 virtual.c
字号:
/* Openswan Virtual IP Management * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security * Copyright (C) 2004 Xelerance Corporation * * 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: virtual.c,v 1.5 2004/05/08 11:05:38 ken Exp $ */#ifdef VIRTUAL_IP#include <openswan.h>#include <stdlib.h>#include <string.h>#include <sys/queue.h>#include "constants.h"#include "oswlog.h"#include "defs.h"#include "log.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"#include "whack.h"#include "virtual.h"#define F_VIRTUAL_NO 1#define F_VIRTUAL_DHCP 2#define F_VIRTUAL_IKE_CONFIG 4#define F_VIRTUAL_PRIVATE 8#define F_VIRTUAL_ALL 16#define F_VIRTUAL_HOST 32struct virtual_t { unsigned short flags; unsigned short n_net; ip_subnet net[0];};static ip_subnet *private_net_ok=NULL, *private_net_ko=NULL;static unsigned short private_net_ok_len=0, private_net_ko_len=0;/** Read a subnet (IPv4/IPv6) * read %v4:x.x.x.x/y or %v6:xxxxxxxxx/yy * or %v4:!x.x.x.x/y if dstko not NULL * * @param src String in format (see above) * @param len Length of src string * @param dst IP Subnet Destination * @param dstko IP Subnet * @param isok Boolean * @return bool If the format string is valid. */static bool_read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko, bool *isok){ bool ok; int af; if ((len > 4) && (strncmp(src, "%v4:", 4)==0)) { af = AF_INET; } else if ((len > 4) && (strncmp(src, "%v6:", 4)==0)) { af = AF_INET6; } else { return FALSE; } ok = (src[4] == '!') ? FALSE : TRUE; src += ok ? 4 : 5; len -= ok ? 4 : 5; if (!len) return FALSE; if ((!ok) && (!dstko)) return FALSE; passert ( ((ok)?(dst):(dstko))!=NULL ); if (ttosubnet(src, len, af, ((ok)?(dst):(dstko)))) { return FALSE; } if (isok) *isok = ok; return TRUE;}/** Initialize Virtual IP Support * * @param private_list String (contents of virtual_private= from ipsec.conf) */voidinit_virtual_ip(const char *private_list){ const char *next, *str=private_list; unsigned short ign = 0, i_ok, i_ko; ip_subnet sub; bool ok; /** Count **/ private_net_ok_len=0; private_net_ko_len=0; while (str) { next = strchr(str,','); if (!next) next = str + strlen(str); if (_read_subnet(str, next-str, &sub, &sub, &ok)) { if (ok) private_net_ok_len++; else private_net_ko_len++; } else { ign++; } str = *next ? next+1 : NULL; } if (!ign) { /** Allocate **/ if (private_net_ok_len) { private_net_ok = (ip_subnet *)alloc_bytes( (private_net_ok_len*sizeof(ip_subnet)), "private_net_ok subnets"); } if (private_net_ko_len) { private_net_ko = (ip_subnet *)alloc_bytes( (private_net_ko_len*sizeof(ip_subnet)), "private_net_ko subnets"); } if ((private_net_ok_len && !private_net_ok) || (private_net_ko_len && !private_net_ko)) { loglog(RC_LOG_SERIOUS, "can't alloc in init_virtual_ip"); pfreeany(private_net_ok); private_net_ok = NULL; pfreeany(private_net_ko); private_net_ko = NULL; } else { /** Fill **/ str = private_list; i_ok = 0; i_ko = 0; while (str) { next = strchr(str,','); if (!next) next = str + strlen(str); if (_read_subnet(str, next-str, &(private_net_ok[i_ok]), &(private_net_ko[i_ko]), &ok)) { if (ok) i_ok++; else i_ko++; } str = *next ? next+1 : NULL; } } } else { loglog(RC_LOG_SERIOUS, "%d bad entries in virtual_private - none loaded", ign); }}/** * virtual string must be : * {vhost,vnet}:[%method]* * * vhost = accept only a host (/32) * vnet = accept any network * * %no = no virtual IP (accept public IP) * %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP [not implemented] * %ike = accept affected IKE Config Mode IP [not implemented] * %priv = accept system-wide private net list * %v4:x = accept ipv4 in list 'x' * %v6:x = accept ipv6 in list 'x' * %all = accept all ips [only for testing] * * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24 * * @param c Connection Struct * @param string (virtual_private= from ipsec.conf) * @return virtual_t */struct virtual_t*create_virtual(const struct connection *c, const char *string){ unsigned short flags=0, n_net=0, i; const char *str = string, *next, *first_net=NULL; ip_subnet sub; struct virtual_t *v; if ((!string) || (string[0]=='\0')) return NULL; if ((strlen(string)>=6) && (strncmp(string,"vhost:",6)==0)) { flags |= F_VIRTUAL_HOST; str += 6; } else if ((strlen(string)>=5) && (strncmp(string,"vnet:",5)==0)) { str += 5; } else { goto fail; } /** * Parse string : fill flags & count subnets */ while ((str) && (*str)) { next = strchr(str,','); if (!next) next = str + strlen(str); if ((next-str == 3) && (strncmp(str, "%no", 3)==0)) { flags |= F_VIRTUAL_NO; }#if 0 else if ((next-str == 4) && (strncmp(str, "%ike", 4)==0)) { flags |= F_VIRTUAL_IKE_CONFIG; } else if ((next-str == 5) && (strncmp(str, "%dhcp", 5)==0)) { flags |= F_VIRTUAL_DHCP; }#endif else if ((next-str == 5) && (strncmp(str, "%priv", 5)==0)) { flags |= F_VIRTUAL_PRIVATE; } else if ((next-str == 4) && (strncmp(str, "%all", 4)==0)) { flags |= F_VIRTUAL_ALL; } else if (_read_subnet(str, next-str, &sub, NULL, NULL)) { n_net++; if (!first_net) first_net = str; } else { goto fail; } str = *next ? next+1 : NULL; } v = (struct virtual_t *)alloc_bytes( sizeof(struct virtual_t) + (n_net*sizeof(ip_subnet)), "virtual description"); if (!v) goto fail; v->flags = flags; v->n_net = n_net; if (n_net && first_net) { /** * Save subnets in newly allocated struct */ for (str=first_net, i=0; (str) && (*str); ) { next = strchr(str,','); if (!next) next = str + strlen(str); if (_read_subnet(str, next-str, &(v->net[i]), NULL, NULL)) i++; str = *next ? next+1 : NULL; } } return v;fail: openswan_log("invalid virtual string [%s] - " "virtual selection disabled for connection '%s'", string, c->name); return NULL;}/** is_virtual_end - Do we have a virtual IP on the other end? * * @param that end structure * @return bool True if we do */boolis_virtual_end(const struct end *that){ return ((that->virt)?TRUE:FALSE);}/** Does this connection have a virtual IP ? * * @param c Active Connection struct * @return bool True if we do */boolis_virtual_connection(const struct connection *c){ return ((c->spd.that.virt)?TRUE:FALSE);}/** net_in_list - Check if a subnet is in a list * * @param peer_net IP Subnet to check * @param list IP Subnet list to search within * @param len # of subnets in list * @return bool True if peer_net is in list */static boolnet_in_list(const ip_subnet *peer_net, const ip_subnet *list, unsigned short len){ unsigned short i; if (!list || !len) return FALSE; for (i=0; i<len; i++) { if (subnetinsubnet(peer_net, &(list[i]))) return TRUE; } return FALSE;}/** is_virtual_net_allowed - Check if the virtual network the client proposes * is acceptable to us * * @param c Connection structure (active) * @param peer_net IP Subnet the peer proposes * @param his_addr Peers IP Address * @return bool True if allowed */boolis_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net, const ip_address *his_addr){ if (!c->spd.that.virt) return FALSE; if (c->spd.that.virt->flags & F_VIRTUAL_HOST) { if (!subnetishost(peer_net)) return FALSE; } if (c->spd.that.virt->flags & F_VIRTUAL_NO) { if (subnetishost(peer_net) && addrinsubnet(his_addr, peer_net)) return TRUE; } if (c->spd.that.virt->flags & F_VIRTUAL_PRIVATE) { if (net_in_list(peer_net, private_net_ok, private_net_ok_len) && !net_in_list(peer_net, private_net_ko, private_net_ko_len)) return TRUE; } if (c->spd.that.virt->n_net) { if (net_in_list(peer_net, c->spd.that.virt->net, c->spd.that.virt->n_net)) return TRUE; } if (c->spd.that.virt->flags & F_VIRTUAL_ALL) { /** %all must only be used for testing - log it **/ loglog(RC_LOG_SERIOUS, "Warning - " "v%s:%%all must only be used for testing", (c->spd.that.virt->flags & F_VIRTUAL_HOST) ? "host" : "net"); return TRUE; } return FALSE;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -