1 /* FreeS/WAN Virtual IP Management
2 * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * RCSID $Id: virtual.c,v 1.3 2003-09-29 05:08:44 philipc Exp $
24 #include "constants.h"
29 #include "connections.h"
33 #define F_VIRTUAL_NO 1
34 #define F_VIRTUAL_DHCP 2
35 #define F_VIRTUAL_IKE_CONFIG 4
36 #define F_VIRTUAL_PRIVATE 8
37 #define F_VIRTUAL_ALL 16
38 #define F_VIRTUAL_HOST 32
46 static ip_subnet *private_net_ok=NULL, *private_net_ko=NULL;
47 static unsigned short private_net_ok_len=0, private_net_ko_len=0;
50 * read %v4:x.x.x.x/y or %v6:xxxxxxxxx/yy
51 * or %v4:!x.x.x.x/y if dstko not NULL
54 _read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko,
60 if ((len > 4) && (strncmp(src, "%v4:", 4)==0)) {
63 else if ((len > 4) && (strncmp(src, "%v6:", 4)==0)) {
70 ok = (src[4] == '!') ? FALSE : TRUE;
74 if (!len) return FALSE;
75 if ((!ok) && (!dstko)) return FALSE;
77 passert ( ((ok)?(dst):(dstko))!=NULL );
79 if (ttosubnet(src, len, af, ((ok)?(dst):(dstko)))) {
87 init_virtual_ip(const char *private_list)
89 const char *next, *str=private_list;
90 unsigned short ign = 0, i_ok, i_ko;
98 next = strchr(str,',');
99 if (!next) next = str + strlen(str);
100 if (_read_subnet(str, next-str, &sub, &sub, &ok)) {
102 private_net_ok_len++;
104 private_net_ko_len++;
109 str = *next ? next+1 : NULL;
114 if (private_net_ok_len) {
115 private_net_ok = (ip_subnet *)alloc_bytes(
116 (private_net_ok_len*sizeof(ip_subnet)),
117 "private_net_ok subnets");
119 if (private_net_ko_len) {
120 private_net_ko = (ip_subnet *)alloc_bytes(
121 (private_net_ko_len*sizeof(ip_subnet)),
122 "private_net_ko subnets");
124 if ((private_net_ok_len && !private_net_ok) ||
125 (private_net_ko_len && !private_net_ko)) {
126 loglog(RC_LOG_SERIOUS,
127 "can't alloc in init_virtual_ip");
128 pfreeany(private_net_ok);
129 private_net_ok = NULL;
130 pfreeany(private_net_ko);
131 private_net_ko = NULL;
139 next = strchr(str,',');
140 if (!next) next = str + strlen(str);
141 if (_read_subnet(str, next-str,
142 &(private_net_ok[i_ok]), &(private_net_ko[i_ko]), &ok)) {
148 str = *next ? next+1 : NULL;
153 loglog(RC_LOG_SERIOUS,
154 "%d bad entries in virtual_private - none loaded", ign);
159 * virtual string must be :
160 * {vhost,vnet}:[%method]*
162 * vhost = accept only a host (/32)
163 * vnet = accept any network
165 * %no = no virtual IP (accept public IP)
166 * %dhcp = accept DHCP SA (0.0.0.0/0) of affected IP [not implemented]
167 * %ike = accept affected IKE Config Mode IP [not implemented]
168 * %priv = accept system-wide private net list
169 * %v4:x = accept ipv4 in list 'x'
170 * %v6:x = accept ipv6 in list 'x'
171 * %all = accept all ips [only for testing]
173 * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24
176 *create_virtual(const struct connection *c, const char *string)
178 unsigned short flags=0, n_net=0, i;
179 const char *str = string, *next, *first_net=NULL;
183 if ((!string) || (string[0]=='\0')) return NULL;
185 if ((strlen(string)>=6) && (strncmp(string,"vhost:",6)==0)) {
186 flags |= F_VIRTUAL_HOST;
189 else if ((strlen(string)>=5) && (strncmp(string,"vnet:",5)==0)) {
197 * Parse string : fill flags & count subnets
199 while ((str) && (*str)) {
200 next = strchr(str,',');
201 if (!next) next = str + strlen(str);
202 if ((next-str == 3) && (strncmp(str, "%no", 3)==0)) {
203 flags |= F_VIRTUAL_NO;
206 else if ((next-str == 4) && (strncmp(str, "%ike", 4)==0)) {
207 flags |= F_VIRTUAL_IKE_CONFIG;
209 else if ((next-str == 5) && (strncmp(str, "%dhcp", 5)==0)) {
210 flags |= F_VIRTUAL_DHCP;
213 else if ((next-str == 5) && (strncmp(str, "%priv", 5)==0)) {
214 flags |= F_VIRTUAL_PRIVATE;
216 else if ((next-str == 4) && (strncmp(str, "%all", 4)==0)) {
217 flags |= F_VIRTUAL_ALL;
219 else if (_read_subnet(str, next-str, &sub, NULL, NULL)) {
221 if (!first_net) first_net = str;
226 str = *next ? next+1 : NULL;
229 v = (struct virtual_t *)alloc_bytes(
230 sizeof(struct virtual_t) + (n_net*sizeof(ip_subnet)),
231 "virtual description");
236 if (n_net && first_net) {
238 * Save subnets in newly allocated struct
240 for (str=first_net, i=0; (str) && (*str); ) {
241 next = strchr(str,',');
242 if (!next) next = str + strlen(str);
243 if (_read_subnet(str, next-str, &(v->net[i]), NULL, NULL))
245 str = *next ? next+1 : NULL;
252 log("invalid virtual string [%s] - "
253 "virtual selection disabled for connection '%s'", string, c->name);
258 is_virtual_end(const struct end *that)
260 return ((that->virt)?TRUE:FALSE);
264 is_virtual_connection(const struct connection *c)
266 return ((c->that.virt)?TRUE:FALSE);
270 net_in_list(const ip_subnet *peer_net, const ip_subnet *list,
274 if (!list || !len) return FALSE;
275 for (i=0; i<len; i++) {
276 if (subnetinsubnet(peer_net, &(list[i])))
283 is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net,
284 const ip_address *his_addr)
286 if (!c->that.virt) return FALSE;
288 if (c->that.virt->flags & F_VIRTUAL_HOST) {
289 if (!subnetishost(peer_net))
293 if (c->that.virt->flags & F_VIRTUAL_NO) {
294 if (subnetishost(peer_net) &&
295 addrinsubnet(his_addr, peer_net))
299 if (c->that.virt->flags & F_VIRTUAL_PRIVATE) {
300 if (net_in_list(peer_net, private_net_ok, private_net_ok_len) &&
301 !net_in_list(peer_net, private_net_ko, private_net_ko_len))
305 if (c->that.virt->n_net) {
306 if (net_in_list(peer_net, c->that.virt->net, c->that.virt->n_net))
310 if (c->that.virt->flags & F_VIRTUAL_ALL) {
311 /** %all must only be used for testing - log it **/
312 loglog(RC_LOG_SERIOUS, "Warning - "
313 "v%s:%%all must only be used for testing",
314 (c->that.virt->flags & F_VIRTUAL_HOST) ? "host" : "net");