Add special routing handling for VPN support
[platform/upstream/connman.git] / src / connection.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  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 #include <errno.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <arpa/inet.h>
31 #include <net/if.h>
32 #include <net/route.h>
33
34 #include <gdbus.h>
35
36 #include "connman.h"
37
38 struct gateway_data {
39         int index;
40         char *gateway;
41         struct connman_element *element;
42         unsigned int order;
43         gboolean active;
44         /* VPN extra data */
45         gboolean vpn;
46         char *vpn_ip;
47 };
48
49 static GSList *gateway_list = NULL;
50
51 static struct gateway_data *find_gateway(int index, const char *gateway)
52 {
53         GSList *list;
54
55         if (gateway == NULL)
56                 return NULL;
57
58         for (list = gateway_list; list; list = list->next) {
59                 struct gateway_data *data = list->data;
60
61                 if (data->gateway == NULL)
62                         continue;
63
64                 if (data->index == index &&
65                                 g_str_equal(data->gateway, gateway) == TRUE)
66                         return data;
67         }
68
69         return NULL;
70 }
71
72 static int add_vpn_host(struct connman_element *element,
73                         const char *gateway,
74                         const char *host)
75 {
76         struct ifreq ifr;
77         struct rtentry rt;
78         struct sockaddr_in addr;
79         int sk, err;
80
81         DBG("element %p", element);
82
83         sk = socket(PF_INET, SOCK_DGRAM, 0);
84         if (sk < 0)
85                 return -1;
86
87         memset(&ifr, 0, sizeof(ifr));
88         ifr.ifr_ifindex = element->index;
89
90         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
91                 close(sk);
92                 return -1;
93         }
94         DBG("ifname %s", ifr.ifr_name);
95
96         memset(&rt, 0, sizeof(rt));
97         rt.rt_flags = RTF_UP | RTF_HOST | RTF_GATEWAY;
98
99         memset(&addr, 0, sizeof(addr));
100         addr.sin_family = AF_INET;
101         addr.sin_addr.s_addr = inet_addr(host);
102         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
103
104         memset(&addr, 0, sizeof(addr));
105         addr.sin_family = AF_INET;
106         addr.sin_addr.s_addr = inet_addr(gateway);
107         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
108
109         memset(&addr, 0, sizeof(addr));
110         addr.sin_family = AF_INET;
111         addr.sin_addr.s_addr = INADDR_NONE;
112         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
113
114         rt.rt_dev = ifr.ifr_name;
115
116         err = ioctl(sk, SIOCADDRT, &rt);
117         if (err < 0)
118                 connman_error("Setting VPN host failed (%s)",
119                               strerror(errno));
120
121         close(sk);
122
123         return err;
124 }
125
126 static int del_vpn_host(const char *host)
127 {
128         struct rtentry rt;
129         struct sockaddr_in addr;
130         int sk, err;
131
132         sk = socket(PF_INET, SOCK_DGRAM, 0);
133         if (sk < 0)
134                 return -1;
135
136         memset(&rt, 0, sizeof(rt));
137         rt.rt_flags = RTF_UP | RTF_HOST;
138
139         memset(&addr, 0, sizeof(addr));
140         addr.sin_family = AF_INET;
141         addr.sin_addr.s_addr = inet_addr(host);
142         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
143
144         err = ioctl(sk, SIOCDELRT, &rt);
145         if (err < 0)
146                 connman_error("Del vpn route failed (%s)",
147                               strerror(errno));
148
149         close(sk);
150
151         return err;
152 }
153
154 static int set_vpn_route(struct connman_element *element, const char *gateway)
155 {
156         struct ifreq ifr;
157         struct rtentry rt;
158         struct sockaddr_in addr;
159         int sk, err;
160
161         DBG("set_rout1: element %p", element);
162
163         sk = socket(PF_INET, SOCK_DGRAM, 0);
164         if (sk < 0)
165                 return -1;
166
167         memset(&ifr, 0, sizeof(ifr));
168         ifr.ifr_ifindex = element->index;
169
170         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
171                 close(sk);
172                 return -1;
173         }
174
175         DBG("ifname %s", ifr.ifr_name);
176
177         memset(&ifr, 0, sizeof(ifr));
178         ifr.ifr_ifindex = element->index;
179
180         memset(&rt, 0, sizeof(rt));
181         rt.rt_flags = RTF_UP | RTF_GATEWAY;
182
183         memset(&addr, 0, sizeof(addr));
184         addr.sin_family = AF_INET;
185         addr.sin_addr.s_addr = INADDR_ANY;
186         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
187
188         memset(&addr, 0, sizeof(addr));
189         addr.sin_family = AF_INET;
190         addr.sin_addr.s_addr = inet_addr(gateway);
191         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
192
193         memset(&addr, 0, sizeof(addr));
194         addr.sin_family = AF_INET;
195         addr.sin_addr.s_addr = INADDR_ANY;
196         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
197
198         err = ioctl(sk, SIOCADDRT, &rt);
199         if (err < 0)
200                 connman_error("Setting VPN route failed (%s)",
201                                strerror(errno));
202
203         close(sk);
204
205         return err;
206 }
207
208 static int set_route(struct connman_element *element, const char *gateway)
209 {
210         struct ifreq ifr;
211         struct rtentry rt;
212         struct sockaddr_in addr;
213         int sk, err;
214
215         DBG("element %p", element);
216
217         sk = socket(PF_INET, SOCK_DGRAM, 0);
218         if (sk < 0)
219                 return -1;
220
221         memset(&ifr, 0, sizeof(ifr));
222         ifr.ifr_ifindex = element->index;
223
224         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
225                 close(sk);
226                 return -1;
227         }
228         DBG("ifname %s", ifr.ifr_name);
229
230         memset(&rt, 0, sizeof(rt));
231         rt.rt_flags = RTF_UP | RTF_HOST;
232
233         memset(&addr, 0, sizeof(addr));
234         addr.sin_family = AF_INET;
235         addr.sin_addr.s_addr = inet_addr(gateway);
236         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
237
238         memset(&addr, 0, sizeof(addr));
239         addr.sin_family = AF_INET;
240         addr.sin_addr.s_addr = INADDR_ANY;
241         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
242
243         memset(&addr, 0, sizeof(addr));
244         addr.sin_family = AF_INET;
245         addr.sin_addr.s_addr = INADDR_ANY;
246         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
247
248         rt.rt_dev = ifr.ifr_name;
249
250         err = ioctl(sk, SIOCADDRT, &rt);
251         if (err < 0)
252                 connman_error("Setting host gateway route failed (%s)",
253                                                         strerror(errno));
254         memset(&rt, 0, sizeof(rt));
255         rt.rt_flags = RTF_UP | RTF_GATEWAY;
256
257         memset(&addr, 0, sizeof(addr));
258         addr.sin_family = AF_INET;
259         addr.sin_addr.s_addr = INADDR_ANY;
260         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
261
262         memset(&addr, 0, sizeof(addr));
263         addr.sin_family = AF_INET;
264         addr.sin_addr.s_addr = inet_addr(gateway);
265         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
266
267         memset(&addr, 0, sizeof(addr));
268         addr.sin_family = AF_INET;
269         addr.sin_addr.s_addr = INADDR_ANY;
270         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
271
272         err = ioctl(sk, SIOCADDRT, &rt);
273         if (err < 0)
274                 connman_error("Setting default route failed (%s)",
275                                                         strerror(errno));
276
277         close(sk);
278
279         return err;
280 }
281
282 static int del_route(struct connman_element *element, const char *gateway)
283 {
284         struct ifreq ifr;
285         struct rtentry rt;
286         struct sockaddr_in addr;
287         int sk, err;
288
289         DBG("element %p", element);
290
291         sk = socket(PF_INET, SOCK_DGRAM, 0);
292         if (sk < 0)
293                 return -1;
294
295         memset(&ifr, 0, sizeof(ifr));
296         ifr.ifr_ifindex = element->index;
297
298         if (ioctl(sk, SIOCGIFNAME, &ifr) < 0) {
299                 close(sk);
300                 return -1;
301         }
302
303         DBG("ifname %s", ifr.ifr_name);
304
305         memset(&rt, 0, sizeof(rt));
306         rt.rt_flags = RTF_UP | RTF_GATEWAY;
307
308         memset(&addr, 0, sizeof(addr));
309         addr.sin_family = AF_INET;
310         addr.sin_addr.s_addr = INADDR_ANY;
311         memcpy(&rt.rt_dst, &addr, sizeof(rt.rt_dst));
312
313         memset(&addr, 0, sizeof(addr));
314         addr.sin_family = AF_INET;
315         addr.sin_addr.s_addr = inet_addr(gateway);
316         memcpy(&rt.rt_gateway, &addr, sizeof(rt.rt_gateway));
317
318         memset(&addr, 0, sizeof(addr));
319         addr.sin_family = AF_INET;
320         addr.sin_addr.s_addr = INADDR_ANY;
321         memcpy(&rt.rt_genmask, &addr, sizeof(rt.rt_genmask));
322
323         err = ioctl(sk, SIOCDELRT, &rt);
324         if (err < 0)
325                 connman_error("Removing default route failed (%s)",
326                                                         strerror(errno));
327
328         close(sk);
329
330         return err;
331 }
332
333 static int del_route_all(struct gateway_data *data)
334 {
335         int err = 0;
336
337         if (data->vpn) {
338                 del_vpn_host(data->gateway);
339
340                 err = del_route(data->element, data->vpn_ip);
341         } else
342                 err = del_route(data->element, data->gateway);
343
344         return err;
345 }
346
347 static void find_element(struct connman_element *element, gpointer user_data)
348 {
349         struct gateway_data *data = user_data;
350
351         DBG("element %p name %s", element, element->name);
352
353         if (data->element != NULL)
354                 return;
355
356         if (element->index != data->index)
357                 return;
358
359         data->element = element;
360 }
361
362 static struct gateway_data *add_gateway(int index, const char *gateway)
363 {
364         struct gateway_data *data;
365         struct connman_service *service;
366
367         data = g_try_new0(struct gateway_data, 1);
368         if (data == NULL)
369                 return NULL;
370
371         data->index = index;
372         data->gateway = g_strdup(gateway);
373         data->active = FALSE;
374         data->element = NULL;
375         data->vpn_ip = NULL;
376         data->vpn = FALSE;
377
378         __connman_element_foreach(NULL, CONNMAN_ELEMENT_TYPE_CONNECTION,
379                                                         find_element, data);
380
381         service = __connman_element_get_service(data->element);
382         data->order = __connman_service_get_order(service);
383
384         gateway_list = g_slist_append(gateway_list, data);
385
386         return data;
387 }
388
389 static void connection_newgateway(int index, const char *gateway)
390 {
391         struct gateway_data *data;
392
393         DBG("index %d gateway %s", index, gateway);
394
395         data = find_gateway(index, gateway);
396         if (data == NULL)
397                 return;
398
399         data->active = TRUE;
400 }
401
402 static void set_default_gateway(struct gateway_data *data)
403 {
404         struct connman_element *element = data->element;
405         struct connman_service *service = NULL;
406
407         DBG("gateway %s", data->gateway);
408
409         if (data->vpn == TRUE) {
410
411                 set_vpn_route(element, data->vpn_ip);
412                 /* vpn gateway going away no changes in services */
413                 return;
414         }
415         if (set_route(element, data->gateway) < 0)
416                 return;
417
418         service = __connman_element_get_service(element);
419         __connman_service_indicate_default(service);
420 }
421
422 static struct gateway_data *find_default_gateway(void)
423 {
424         struct gateway_data *found = NULL;
425         unsigned int order = 0;
426         GSList *list;
427
428         for (list = gateway_list; list; list = list->next) {
429                 struct gateway_data *data = list->data;
430
431                 if (found == NULL || data->order > order) {
432                         found = data;
433                         order = data->order;
434                 }
435         }
436
437         return found;
438 }
439
440 static void remove_gateway(struct gateway_data *data)
441 {
442         DBG("gateway %s", data->gateway);
443
444         gateway_list = g_slist_remove(gateway_list, data);
445
446         if (data->active == TRUE)
447                 del_route_all(data);
448
449         g_free(data->gateway);
450         g_free(data->vpn_ip);
451         g_free(data);
452 }
453
454 static void connection_delgateway(int index, const char *gateway)
455 {
456         struct gateway_data *data;
457
458         DBG("index %d gateway %s", index, gateway);
459
460         data = find_gateway(index, gateway);
461         if (data != NULL)
462                 data->active = FALSE;
463
464         data = find_default_gateway();
465         if (data != NULL)
466                 set_default_gateway(data);
467 }
468
469 static struct connman_rtnl connection_rtnl = {
470         .name           = "connection",
471         .newgateway     = connection_newgateway,
472         .delgateway     = connection_delgateway,
473 };
474
475 static struct gateway_data *find_active_gateway(void)
476 {
477         GSList *list;
478
479         DBG("");
480
481         for (list = gateway_list; list; list = list->next) {
482                 struct gateway_data *data = list->data;
483                 if (data->active == TRUE)
484                         return data;
485         }
486
487         return NULL;
488 }
489
490 static int connection_probe(struct connman_element *element)
491 {
492         struct connman_service *service = NULL;
493         const char *gateway = NULL;
494         const char *vpn_ip = NULL;
495         struct gateway_data *active_gateway = NULL;
496         struct gateway_data *new_gateway = NULL;
497
498         DBG("element %p name %s", element, element->name);
499
500         if (element->parent == NULL)
501                 return -ENODEV;
502
503         if (element->parent->type != CONNMAN_ELEMENT_TYPE_IPV4)
504                 return -ENODEV;
505
506         connman_element_get_value(element,
507                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
508
509         connman_element_get_value(element,
510                                   CONNMAN_PROPERTY_ID_IPV4_ADDRESS, &vpn_ip);
511
512         DBG("gateway %s", gateway);
513
514         service = __connman_element_get_service(element);
515         __connman_service_indicate_state(service,
516                                         CONNMAN_SERVICE_STATE_READY);
517
518         connman_element_set_enabled(element, TRUE);
519
520         if (gateway == NULL)
521                 return 0;
522
523         active_gateway = find_active_gateway();
524         new_gateway = add_gateway(element->index, gateway);
525
526         if (service == NULL) {
527                 new_gateway->vpn = TRUE;
528                 new_gateway->vpn_ip = g_strdup(vpn_ip);
529                 /* make sure vpn gateway are at higher priority */
530                 new_gateway->order = 10;
531         } else
532                 new_gateway->vpn = FALSE;
533
534         if (active_gateway == NULL) {
535                 set_default_gateway(new_gateway);
536                 return 0;
537         }
538
539         if (new_gateway->vpn == TRUE) {
540                 add_vpn_host(active_gateway->element,
541                              active_gateway->gateway,
542                              new_gateway->gateway);
543
544         }
545
546         if (new_gateway->order >= active_gateway->order) {
547                 del_route_all(active_gateway);
548                 return 0;
549         }
550
551         return 0;
552 }
553
554 static void connection_remove(struct connman_element *element)
555 {
556         struct connman_service *service;
557         const char *gateway = NULL;
558         struct gateway_data *data = NULL;
559         gboolean set_default = FALSE;
560
561         DBG("element %p name %s", element, element->name);
562
563         service = __connman_element_get_service(element);
564         __connman_service_indicate_state(service,
565                                         CONNMAN_SERVICE_STATE_DISCONNECT);
566
567         connman_element_set_enabled(element, FALSE);
568
569         connman_element_get_value(element,
570                                 CONNMAN_PROPERTY_ID_IPV4_GATEWAY, &gateway);
571
572         DBG("gateway %s", gateway);
573
574         if (gateway == NULL)
575                 return;
576
577         data = find_gateway(element->index, gateway);
578         if (data == NULL)
579                 return;
580
581         set_default = data->vpn;
582
583         if (data->vpn == TRUE)
584                 del_vpn_host(data->gateway);
585
586         remove_gateway(data);
587
588         /* with vpn this will be called after the network was deleted,
589          * we need to call set_default here because we will not recieve any
590          * gateway delete notification.
591          */
592         if (set_default) {
593                 data = find_default_gateway();
594                 if (data != NULL)
595                         set_default_gateway(data);
596         }
597 }
598
599 static struct connman_driver connection_driver = {
600         .name           = "connection",
601         .type           = CONNMAN_ELEMENT_TYPE_CONNECTION,
602         .priority       = CONNMAN_DRIVER_PRIORITY_LOW,
603         .probe          = connection_probe,
604         .remove         = connection_remove,
605 };
606
607 int __connman_connection_init(void)
608 {
609         DBG("");
610
611         if (connman_rtnl_register(&connection_rtnl) < 0)
612                 connman_error("Failed to setup RTNL gateway driver");
613
614         return connman_driver_register(&connection_driver);
615 }
616
617 void __connman_connection_cleanup(void)
618 {
619         GSList *list;
620
621         DBG("");
622
623         connman_driver_unregister(&connection_driver);
624
625         connman_rtnl_unregister(&connection_rtnl);
626
627         for (list = gateway_list; list; list = list->next) {
628                 struct gateway_data *data = list->data;
629
630                 DBG("index %d gateway %s", data->index, data->gateway);
631
632                 g_free(data->gateway);
633                 g_free(data);
634                 list->data = NULL;
635         }
636
637         g_slist_free(gateway_list);
638         gateway_list = NULL;
639 }
640
641 static void update_order(void)
642 {
643         GSList *list = NULL;
644
645         for (list = gateway_list; list; list = list->next) {
646                 struct gateway_data *data = list->data;
647                 struct connman_service *service;
648
649                 /* vpn gataway is not attached to a service. */
650                 if (data->vpn)
651                         continue;
652
653                 service = __connman_element_get_service(data->element);
654                 data->order = __connman_service_get_order(service);
655         }
656 }
657
658 gboolean __connman_connection_update_gateway(void)
659 {
660         struct gateway_data *active_gateway, *default_gateway;
661         gboolean updated = FALSE;
662
663         update_order();
664
665         active_gateway = find_active_gateway();
666         default_gateway = find_default_gateway();
667
668         if (active_gateway && active_gateway != default_gateway) {
669                 del_route_all(active_gateway);
670                 updated = TRUE;
671         }
672
673         return updated;
674 }