OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / pluto / virtual.c
1 /* FreeS/WAN Virtual IP Management
2  * Copyright (C) 2002 Mathieu Lafon - Arkoon Network Security
3  *
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>.
8  *
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
12  * for more details.
13  *
14  * RCSID $Id: virtual.c,v 1.3 2003-09-29 05:08:44 philipc Exp $
15  */
16
17 #ifdef VIRTUAL_IP
18
19 #include <freeswan.h>
20
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include "constants.h"
25 #include "defs.h"
26 #include "log.h"
27 #include "id.h"
28 #include "x509.h"
29 #include "connections.h"
30 #include "whack.h"
31 #include "virtual.h"
32
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
39
40 struct virtual_t {
41     unsigned short flags;
42     unsigned short n_net;
43     ip_subnet net[0];
44 };
45
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;
48
49 /**
50  * read %v4:x.x.x.x/y or %v6:xxxxxxxxx/yy
51  * or %v4:!x.x.x.x/y if dstko not NULL
52  */
53 static bool
54 _read_subnet(const char *src, size_t len, ip_subnet *dst, ip_subnet *dstko,
55     bool *isok)
56 {
57     bool ok;
58     int af;
59
60     if ((len > 4) && (strncmp(src, "%v4:", 4)==0)) {
61         af = AF_INET;
62     }
63     else if ((len > 4) && (strncmp(src, "%v6:", 4)==0)) {
64         af = AF_INET6;
65     }
66     else {
67         return FALSE;
68     }
69
70     ok = (src[4] == '!') ? FALSE : TRUE;
71     src += ok ? 4 : 5;
72     len -= ok ? 4 : 5;
73
74     if (!len) return FALSE;
75     if ((!ok) && (!dstko)) return FALSE;
76
77     passert ( ((ok)?(dst):(dstko))!=NULL );
78
79     if (ttosubnet(src, len, af, ((ok)?(dst):(dstko)))) {
80         return FALSE;
81     }
82     if (isok) *isok = ok;
83     return TRUE;
84 }
85
86 void
87 init_virtual_ip(const char *private_list)
88 {
89     const char *next, *str=private_list;
90     unsigned short ign = 0, i_ok, i_ko;
91     ip_subnet sub;
92     bool ok;
93
94     /** Count **/
95     private_net_ok_len=0;
96     private_net_ko_len=0;
97     while (str) {
98         next = strchr(str,',');
99         if (!next) next = str + strlen(str);
100         if (_read_subnet(str, next-str, &sub, &sub, &ok)) {
101             if (ok)
102                 private_net_ok_len++;
103             else
104                 private_net_ko_len++;
105         }
106         else {
107             ign++;
108         }
109         str = *next ? next+1 : NULL;
110     }
111
112     if (!ign) {
113         /** Allocate **/
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");
118         }
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");
123         }
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;
132         }
133         else {
134             /** Fill **/
135             str = private_list;
136             i_ok = 0;
137             i_ko = 0;
138             while (str) {
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)) {
143                     if (ok)
144                         i_ok++;
145                     else
146                         i_ko++;
147                 }
148                 str = *next ? next+1 : NULL;
149             }
150         }
151     }
152     else {
153         loglog(RC_LOG_SERIOUS,
154             "%d bad entries in virtual_private - none loaded", ign);
155     }
156 }
157
158 /**
159  * virtual string must be :
160  * {vhost,vnet}:[%method]*
161  *
162  * vhost = accept only a host (/32)
163  * vnet  = accept any network
164  *
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]
172  *
173  * ex: vhost:%no,%dhcp,%priv,%v4:192.168.1.0/24
174  */
175 struct virtual_t
176 *create_virtual(const struct connection *c, const char *string)
177 {
178     unsigned short flags=0, n_net=0, i;
179     const char *str = string, *next, *first_net=NULL;
180     ip_subnet sub;
181     struct virtual_t *v;
182
183     if ((!string) || (string[0]=='\0')) return NULL;
184
185     if ((strlen(string)>=6) && (strncmp(string,"vhost:",6)==0)) {
186         flags |= F_VIRTUAL_HOST;
187         str += 6;
188     }
189     else if ((strlen(string)>=5) && (strncmp(string,"vnet:",5)==0)) {
190         str += 5;
191     }
192     else {
193         goto fail;
194     }
195
196     /**
197      * Parse string : fill flags & count subnets
198      */
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;
204         }
205 #if 0
206         else if ((next-str == 4) && (strncmp(str, "%ike", 4)==0)) {
207             flags |= F_VIRTUAL_IKE_CONFIG;
208         }
209         else if ((next-str == 5) && (strncmp(str, "%dhcp", 5)==0)) {
210             flags |= F_VIRTUAL_DHCP;
211         }
212 #endif
213         else if ((next-str == 5) && (strncmp(str, "%priv", 5)==0)) {
214             flags |= F_VIRTUAL_PRIVATE;
215         }
216         else if ((next-str == 4) && (strncmp(str, "%all", 4)==0)) {
217             flags |= F_VIRTUAL_ALL;
218         }
219         else if (_read_subnet(str, next-str, &sub, NULL, NULL)) {
220             n_net++;
221             if (!first_net) first_net = str;
222         }
223         else {
224             goto fail;
225         }
226         str = *next ? next+1 : NULL;
227     }
228
229     v = (struct virtual_t *)alloc_bytes(
230         sizeof(struct virtual_t) + (n_net*sizeof(ip_subnet)),
231         "virtual description");
232     if (!v) goto fail;
233
234     v->flags = flags;
235     v->n_net = n_net;
236     if (n_net && first_net) {
237         /**
238          * Save subnets in newly allocated struct
239          */
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))
244                 i++;
245             str = *next ? next+1 : NULL;
246         }
247     }
248
249     return v;
250
251 fail:
252     log("invalid virtual string [%s] - "
253         "virtual selection disabled for connection '%s'", string, c->name);
254     return NULL;
255 }
256
257 bool
258 is_virtual_end(const struct end *that)
259 {
260     return ((that->virt)?TRUE:FALSE);
261 }
262
263 bool
264 is_virtual_connection(const struct connection *c)
265 {
266     return ((c->that.virt)?TRUE:FALSE);
267 }
268
269 static bool
270 net_in_list(const ip_subnet *peer_net, const ip_subnet *list,
271     unsigned short len)
272 {
273     unsigned short i;
274     if (!list || !len) return FALSE;
275     for (i=0; i<len; i++) {
276         if (subnetinsubnet(peer_net, &(list[i])))
277             return TRUE;
278     }
279     return FALSE;
280 }
281
282 bool
283 is_virtual_net_allowed(const struct connection *c, const ip_subnet *peer_net,
284         const ip_address *his_addr)
285 {
286     if (!c->that.virt) return FALSE;
287
288     if (c->that.virt->flags & F_VIRTUAL_HOST) {
289         if (!subnetishost(peer_net))
290             return FALSE;
291     }
292
293     if (c->that.virt->flags & F_VIRTUAL_NO) {
294         if (subnetishost(peer_net) &&
295             addrinsubnet(his_addr, peer_net))
296             return TRUE;
297     }
298
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))
302             return TRUE;
303     }
304
305     if (c->that.virt->n_net) {
306         if (net_in_list(peer_net, c->that.virt->net, c->that.virt->n_net))
307             return TRUE;
308     }
309
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");
315         return TRUE;
316     }
317
318     return FALSE;
319 }
320
321 #endif
322