vpn: New vpn daemon that handles vpn connections and clients
[platform/upstream/connman.git] / vpn / plugins / vpn.c
1 /*
2  *
3  *  ConnMan VPN daemon
4  *
5  *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <string.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <linux/if_tun.h>
36 #include <net/if.h>
37
38 #include <dbus/dbus.h>
39
40 #include <glib/gprintf.h>
41
42 #include <connman/log.h>
43 #include <connman/rtnl.h>
44 #include <connman/task.h>
45 #include <connman/inet.h>
46
47 #include "../vpn-rtnl.h"
48 #include "../vpn-provider.h"
49
50 #include "vpn.h"
51
52 struct vpn_data {
53         struct vpn_provider *provider;
54         char *if_name;
55         unsigned flags;
56         unsigned int watch;
57         unsigned int state;
58         struct connman_task *task;
59 };
60
61 struct vpn_driver_data {
62         const char *name;
63         const char *program;
64         struct vpn_driver *vpn_driver;
65         struct vpn_provider_driver provider_driver;
66 };
67
68 GHashTable *driver_hash = NULL;
69
70 static int stop_vpn(struct vpn_provider *provider)
71 {
72         struct vpn_data *data = vpn_provider_get_data(provider);
73         struct vpn_driver_data *vpn_driver_data;
74         const char *name;
75         struct ifreq ifr;
76         int fd, err;
77
78         if (data == NULL)
79                 return -EINVAL;
80
81         name = vpn_provider_get_driver_name(provider);
82         if (name == NULL)
83                 return -EINVAL;
84
85         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
86
87         if (vpn_driver_data != NULL && vpn_driver_data->vpn_driver != NULL &&
88                         vpn_driver_data->vpn_driver->flags == VPN_FLAG_NO_TUN)
89                 return 0;
90
91         memset(&ifr, 0, sizeof(ifr));
92         ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
93         sprintf(ifr.ifr_name, "%s", data->if_name);
94
95         fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
96         if (fd < 0) {
97                 err = -errno;
98                 connman_error("Failed to open /dev/net/tun to device %s: %s",
99                               data->if_name, strerror(errno));
100                 return err;
101         }
102
103         if (ioctl(fd, TUNSETIFF, (void *)&ifr)) {
104                 err = -errno;
105                 connman_error("Failed to TUNSETIFF for device %s to it: %s",
106                               data->if_name, strerror(errno));
107                 close(fd);
108                 return err;
109         }
110
111         if (ioctl(fd, TUNSETPERSIST, 0)) {
112                 err = -errno;
113                 connman_error("Failed to set tun device %s nonpersistent: %s",
114                               data->if_name, strerror(errno));
115                 close(fd);
116                 return err;
117         }
118         close(fd);
119         DBG("Killed tun device %s", data->if_name);
120         return 0;
121 }
122
123 void vpn_died(struct connman_task *task, int exit_code, void *user_data)
124 {
125         struct vpn_provider *provider = user_data;
126         struct vpn_data *data = vpn_provider_get_data(provider);
127         int state = VPN_STATE_FAILURE;
128         enum vpn_provider_error ret;
129
130         DBG("provider %p data %p", provider, data);
131
132         if (data == NULL)
133                 goto vpn_exit;
134
135         state = data->state;
136
137         stop_vpn(provider);
138         vpn_provider_set_data(provider, NULL);
139
140         if (data->watch != 0) {
141                 vpn_provider_unref(provider);
142                 vpn_rtnl_remove_watch(data->watch);
143                 data->watch = 0;
144         }
145
146 vpn_exit:
147         if (state != VPN_STATE_READY && state != VPN_STATE_DISCONNECT) {
148                 const char *name;
149                 struct vpn_driver_data *vpn_data = NULL;
150
151                 name = vpn_provider_get_driver_name(provider);
152                 if (name != NULL)
153                         vpn_data = g_hash_table_lookup(driver_hash, name);
154
155                 if (vpn_data != NULL &&
156                                 vpn_data->vpn_driver->error_code != NULL)
157                         ret = vpn_data->vpn_driver->error_code(exit_code);
158                 else
159                         ret = VPN_PROVIDER_ERROR_UNKNOWN;
160
161                 vpn_provider_indicate_error(provider, ret);
162         } else
163                 vpn_provider_set_state(provider, VPN_PROVIDER_STATE_IDLE);
164
165         vpn_provider_set_index(provider, -1);
166
167         if (data != NULL) {
168                 vpn_provider_unref(data->provider);
169                 g_free(data->if_name);
170                 g_free(data);
171         }
172
173         connman_task_destroy(task);
174 }
175
176 int vpn_set_ifname(struct vpn_provider *provider, const char *ifname)
177 {
178         struct vpn_data *data = vpn_provider_get_data(provider);
179         int index;
180
181         if (ifname == NULL || data == NULL)
182                 return  -EIO;
183
184         index = connman_inet_ifindex(ifname);
185         if (index < 0)
186                 return  -EIO;
187
188         if (data->if_name != NULL)
189                 g_free(data->if_name);
190
191         data->if_name = (char *)g_strdup(ifname);
192         vpn_provider_set_index(provider, index);
193
194         return 0;
195 }
196
197 static void vpn_newlink(unsigned flags, unsigned change, void *user_data)
198 {
199         struct vpn_provider *provider = user_data;
200         struct vpn_data *data = vpn_provider_get_data(provider);
201
202         if ((data->flags & IFF_UP) != (flags & IFF_UP)) {
203                 if (flags & IFF_UP) {
204                         data->state = VPN_STATE_READY;
205                         vpn_provider_set_state(provider,
206                                         VPN_PROVIDER_STATE_READY);
207                 }
208         }
209         data->flags = flags;
210 }
211
212 static DBusMessage *vpn_notify(struct connman_task *task,
213                         DBusMessage *msg, void *user_data)
214 {
215         struct vpn_provider *provider = user_data;
216         struct vpn_data *data;
217         struct vpn_driver_data *vpn_driver_data;
218         const char *name;
219         int state, index;
220
221         data = vpn_provider_get_data(provider);
222
223         name = vpn_provider_get_driver_name(provider);
224         if (name == NULL)
225                 return NULL;
226
227         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
228         if (vpn_driver_data == NULL)
229                 return NULL;
230
231         state = vpn_driver_data->vpn_driver->notify(msg, provider);
232         switch (state) {
233         case VPN_STATE_CONNECT:
234         case VPN_STATE_READY:
235                 index = vpn_provider_get_index(provider);
236                 vpn_provider_ref(provider);
237                 data->watch = vpn_rtnl_add_newlink_watch(index,
238                                                      vpn_newlink, provider);
239                 connman_inet_ifup(index);
240                 break;
241
242         case VPN_STATE_UNKNOWN:
243         case VPN_STATE_IDLE:
244         case VPN_STATE_DISCONNECT:
245         case VPN_STATE_FAILURE:
246                 vpn_provider_set_state(provider,
247                                         VPN_PROVIDER_STATE_DISCONNECT);
248                 break;
249
250         case VPN_STATE_AUTH_FAILURE:
251                 vpn_provider_indicate_error(provider,
252                                         VPN_PROVIDER_ERROR_AUTH_FAILED);
253                 break;
254         }
255
256         return NULL;
257 }
258
259 static int vpn_create_tun(struct vpn_provider *provider)
260 {
261         struct vpn_data *data = vpn_provider_get_data(provider);
262         struct ifreq ifr;
263         int i, fd, index;
264         int ret = 0;
265
266         if (data == NULL)
267                 return -EISCONN;
268
269         fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
270         if (fd < 0) {
271                 i = -errno;
272                 connman_error("Failed to open /dev/net/tun: %s",
273                               strerror(errno));
274                 ret = i;
275                 goto exist_err;
276         }
277
278         memset(&ifr, 0, sizeof(ifr));
279         ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
280
281         for (i = 0; i < 256; i++) {
282                 sprintf(ifr.ifr_name, "vpn%d", i);
283
284                 if (!ioctl(fd, TUNSETIFF, (void *)&ifr))
285                         break;
286         }
287
288         if (i == 256) {
289                 connman_error("Failed to find available tun device");
290                 close(fd);
291                 ret = -ENODEV;
292                 goto exist_err;
293         }
294
295         data->if_name = (char *)g_strdup(ifr.ifr_name);
296         if (data->if_name == NULL) {
297                 connman_error("Failed to allocate memory");
298                 close(fd);
299                 ret = -ENOMEM;
300                 goto exist_err;
301         }
302
303         if (ioctl(fd, TUNSETPERSIST, 1)) {
304                 i = -errno;
305                 connman_error("Failed to set tun persistent: %s",
306                               strerror(errno));
307                 close(fd);
308                 ret = i;
309                 goto exist_err;
310         }
311
312         close(fd);
313
314         index = connman_inet_ifindex(data->if_name);
315         if (index < 0) {
316                 connman_error("Failed to get tun ifindex");
317                 stop_vpn(provider);
318                 ret = -EIO;
319                 goto exist_err;
320         }
321         vpn_provider_set_index(provider, index);
322
323         return 0;
324
325 exist_err:
326         return ret;
327 }
328
329 static int vpn_connect(struct vpn_provider *provider)
330 {
331         struct vpn_data *data = vpn_provider_get_data(provider);
332         struct vpn_driver_data *vpn_driver_data;
333         const char *name;
334         int ret = 0;
335
336         if (data != NULL)
337                 return -EISCONN;
338
339         data = g_try_new0(struct vpn_data, 1);
340         if (data == NULL)
341                 return -ENOMEM;
342
343         data->provider = vpn_provider_ref(provider);
344         data->watch = 0;
345         data->flags = 0;
346         data->task = NULL;
347         data->state = VPN_STATE_IDLE;
348
349         vpn_provider_set_data(provider, data);
350
351         name = vpn_provider_get_driver_name(provider);
352         if (name == NULL)
353                 return -EINVAL;
354
355         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
356
357         if (vpn_driver_data == NULL || vpn_driver_data->vpn_driver == NULL) {
358                 ret = -EINVAL;
359                 goto exist_err;
360         }
361
362         if (vpn_driver_data->vpn_driver->flags != VPN_FLAG_NO_TUN) {
363                 ret = vpn_create_tun(provider);
364                 if (ret < 0)
365                         goto exist_err;
366         }
367
368         data->task = connman_task_create(vpn_driver_data->program);
369
370         if (data->task == NULL) {
371                 ret = -ENOMEM;
372                 stop_vpn(provider);
373                 goto exist_err;
374         }
375
376         if (connman_task_set_notify(data->task, "notify",
377                                         vpn_notify, provider)) {
378                 ret = -ENOMEM;
379                 stop_vpn(provider);
380                 connman_task_destroy(data->task);
381                 data->task = NULL;
382                 goto exist_err;
383         }
384
385         ret = vpn_driver_data->vpn_driver->connect(provider, data->task,
386                                                         data->if_name);
387         if (ret < 0) {
388                 stop_vpn(provider);
389                 connman_task_destroy(data->task);
390                 data->task = NULL;
391                 goto exist_err;
392         }
393
394         DBG("%s started with dev %s",
395                 vpn_driver_data->provider_driver.name, data->if_name);
396
397         data->state = VPN_STATE_CONNECT;
398
399         return -EINPROGRESS;
400
401 exist_err:
402         vpn_provider_set_index(provider, -1);
403         vpn_provider_set_data(provider, NULL);
404         vpn_provider_unref(data->provider);
405         g_free(data->if_name);
406         g_free(data);
407
408         return ret;
409 }
410
411 static int vpn_probe(struct vpn_provider *provider)
412 {
413         return 0;
414 }
415
416 static int vpn_disconnect(struct vpn_provider *provider)
417 {
418         struct vpn_data *data = vpn_provider_get_data(provider);
419         struct vpn_driver_data *vpn_driver_data;
420         const char *name;
421
422         DBG("disconnect provider %p:", provider);
423
424         if (data == NULL)
425                 return 0;
426
427         name = vpn_provider_get_driver_name(provider);
428         if (name == NULL)
429                 return 0;
430
431         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
432         if (vpn_driver_data->vpn_driver->disconnect)
433                 vpn_driver_data->vpn_driver->disconnect();
434
435         if (data->watch != 0) {
436                 vpn_provider_unref(provider);
437                 vpn_rtnl_remove_watch(data->watch);
438                 data->watch = 0;
439         }
440
441         data->state = VPN_STATE_DISCONNECT;
442         connman_task_stop(data->task);
443
444         return 0;
445 }
446
447 static int vpn_remove(struct vpn_provider *provider)
448 {
449         struct vpn_data *data;
450
451         data = vpn_provider_get_data(provider);
452         if (data == NULL)
453                 return 0;
454
455         if (data->watch != 0) {
456                 vpn_provider_unref(provider);
457                 vpn_rtnl_remove_watch(data->watch);
458                 data->watch = 0;
459         }
460
461         connman_task_stop(data->task);
462
463         g_usleep(G_USEC_PER_SEC);
464         stop_vpn(provider);
465         return 0;
466 }
467
468 static int vpn_save(struct vpn_provider *provider, GKeyFile *keyfile)
469 {
470         struct vpn_driver_data *vpn_driver_data;
471         const char *name;
472
473         name = vpn_provider_get_driver_name(provider);
474         vpn_driver_data = g_hash_table_lookup(driver_hash, name);
475         if (vpn_driver_data != NULL &&
476                         vpn_driver_data->vpn_driver->save != NULL)
477                 return vpn_driver_data->vpn_driver->save(provider, keyfile);
478
479         return 0;
480 }
481
482 int vpn_register(const char *name, struct vpn_driver *vpn_driver,
483                         const char *program)
484 {
485         struct vpn_driver_data *data;
486
487         data = g_try_new0(struct vpn_driver_data, 1);
488         if (data == NULL)
489                 return -ENOMEM;
490
491         data->name = name;
492         data->program = program;
493
494         data->vpn_driver = vpn_driver;
495
496         data->provider_driver.name = name;
497         data->provider_driver.disconnect = vpn_disconnect;
498         data->provider_driver.connect = vpn_connect;
499         data->provider_driver.probe = vpn_probe;
500         data->provider_driver.remove = vpn_remove;
501         data->provider_driver.save = vpn_save;
502
503         if (driver_hash == NULL)
504                 driver_hash = g_hash_table_new_full(g_str_hash,
505                                                         g_str_equal,
506                                                         NULL, g_free);
507
508         if (driver_hash == NULL) {
509                 connman_error("driver_hash not initialized for %s", name);
510                 g_free(data);
511                 return -ENOMEM;
512         }
513
514         g_hash_table_replace(driver_hash, (char *)name, data);
515
516         vpn_provider_driver_register(&data->provider_driver);
517
518         return 0;
519 }
520
521 void vpn_unregister(const char *name)
522 {
523         struct vpn_driver_data *data;
524
525         data = g_hash_table_lookup(driver_hash, name);
526         if (data == NULL)
527                 return;
528
529         vpn_provider_driver_unregister(&data->provider_driver);
530
531         g_hash_table_remove(driver_hash, name);
532
533         if (g_hash_table_size(driver_hash) == 0)
534                 g_hash_table_destroy(driver_hash);
535 }