7e1d77e6f9dc9e57e065d0457743ae9200eebc85
[platform/upstream/connman.git] / vpn / vpn-ipconfig.c
1 /*
2  *
3  *  ConnMan VPN daemon
4  *
5  *  Copyright (C) 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 #include <errno.h>
27 #include <stdio.h>
28 #include <net/if.h>
29 #include <net/if_arp.h>
30 #include <linux/if_link.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stdint.h>
34 #include <arpa/inet.h>
35
36 #ifndef IFF_LOWER_UP
37 #define IFF_LOWER_UP    0x10000
38 #endif
39
40 #include <gdbus.h>
41
42 #include "../src/connman.h"
43
44 #include "vpn.h"
45
46 struct vpn_ipconfig {
47         int refcount;
48         int index;
49         int family;
50         connman_bool_t enabled;
51         struct connman_ipaddress *address;
52         struct connman_ipaddress *system;
53 };
54
55 struct vpn_ipdevice {
56         int index;
57         char *ifname;
58         unsigned short type;
59         unsigned int flags;
60         char *address;
61         uint16_t mtu;
62
63         GSList *address_list;
64         char *ipv4_gateway;
65         char *ipv6_gateway;
66
67         char *pac;
68 };
69
70 static GHashTable *ipdevice_hash = NULL;
71
72 unsigned char __vpn_ipconfig_netmask_prefix_len(const char *netmask)
73 {
74         unsigned char bits;
75         in_addr_t mask;
76         in_addr_t host;
77
78         if (netmask == NULL)
79                 return 32;
80
81         mask = inet_network(netmask);
82         host = ~mask;
83
84         /* a valid netmask must be 2^n - 1 */
85         if ((host & (host + 1)) != 0)
86                 return -1;
87
88         bits = 0;
89         for (; mask; mask <<= 1)
90                 ++bits;
91
92         return bits;
93 }
94
95 const char *__vpn_ipconfig_get_peer(struct vpn_ipconfig *ipconfig)
96 {
97         if (ipconfig->address == NULL)
98                 return NULL;
99
100         return ipconfig->address->peer;
101 }
102
103 unsigned short __vpn_ipconfig_get_type_from_index(int index)
104 {
105         struct vpn_ipdevice *ipdevice;
106
107         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
108         if (ipdevice == NULL)
109                 return ARPHRD_VOID;
110
111         return ipdevice->type;
112 }
113
114 unsigned int __vpn_ipconfig_get_flags_from_index(int index)
115 {
116         struct vpn_ipdevice *ipdevice;
117
118         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
119         if (ipdevice == NULL)
120                 return 0;
121
122         return ipdevice->flags;
123 }
124
125 void __vpn_ipconfig_foreach(void (*function) (int index,
126                                         void *user_data), void *user_data)
127 {
128         GList *list, *keys;
129
130         keys = g_hash_table_get_keys(ipdevice_hash);
131         if (keys == NULL)
132                 return;
133
134         for (list = g_list_first(keys); list; list = g_list_next(list)) {
135                 int index = GPOINTER_TO_INT(list->data);
136
137                 function(index, user_data);
138         }
139
140         g_list_free(keys);
141 }
142
143 void __vpn_ipconfig_set_local(struct vpn_ipconfig *ipconfig,
144                                                         const char *address)
145 {
146         if (ipconfig->address == NULL)
147                 return;
148
149         g_free(ipconfig->address->local);
150         ipconfig->address->local = g_strdup(address);
151 }
152
153 const char *__vpn_ipconfig_get_local(struct vpn_ipconfig *ipconfig)
154 {
155         if (ipconfig->address == NULL)
156                 return NULL;
157
158         return ipconfig->address->local;
159 }
160
161 void __vpn_ipconfig_set_peer(struct vpn_ipconfig *ipconfig,
162                                                         const char *address)
163 {
164         if (ipconfig->address == NULL)
165                 return;
166
167         g_free(ipconfig->address->peer);
168         ipconfig->address->peer = g_strdup(address);
169 }
170
171 void __vpn_ipconfig_set_broadcast(struct vpn_ipconfig *ipconfig,
172                                         const char *broadcast)
173 {
174         if (ipconfig->address == NULL)
175                 return;
176
177         g_free(ipconfig->address->broadcast);
178         ipconfig->address->broadcast = g_strdup(broadcast);
179 }
180
181 void __vpn_ipconfig_set_gateway(struct vpn_ipconfig *ipconfig,
182                                                         const char *gateway)
183 {
184         DBG("");
185
186         if (ipconfig->address == NULL)
187                 return;
188         g_free(ipconfig->address->gateway);
189         ipconfig->address->gateway = g_strdup(gateway);
190 }
191
192 const char *
193 __vpn_ipconfig_get_gateway(struct vpn_ipconfig *ipconfig)
194 {
195         if (ipconfig->address == NULL)
196                 return NULL;
197
198         return ipconfig->address->gateway;
199 }
200
201 void __vpn_ipconfig_set_prefixlen(struct vpn_ipconfig *ipconfig,
202                                         unsigned char prefixlen)
203 {
204         if (ipconfig->address == NULL)
205                 return;
206
207         ipconfig->address->prefixlen = prefixlen;
208 }
209
210 unsigned char
211 __vpn_ipconfig_get_prefixlen(struct vpn_ipconfig *ipconfig)
212 {
213         if (ipconfig->address == NULL)
214                 return 0;
215
216         return ipconfig->address->prefixlen;
217 }
218
219 int __vpn_ipconfig_address_add(struct vpn_ipconfig *ipconfig, int family)
220 {
221         DBG("ipconfig %p family %d", ipconfig, family);
222
223         if (ipconfig == NULL)
224                 return -EINVAL;
225
226         if (family == AF_INET)
227                 return connman_inet_set_address(ipconfig->index,
228                                                 ipconfig->address);
229         else if (family == AF_INET6)
230                 return connman_inet_set_ipv6_address(ipconfig->index,
231                                                         ipconfig->address);
232
233         return 0;
234 }
235
236 int __vpn_ipconfig_gateway_add(struct vpn_ipconfig *ipconfig, int family)
237 {
238         DBG("ipconfig %p family %d", ipconfig, family);
239
240         if (ipconfig == NULL || ipconfig->address == NULL)
241                 return -EINVAL;
242
243         DBG("family %d gw %s peer %s", family,
244                 ipconfig->address->gateway, ipconfig->address->peer);
245
246         if (family == AF_INET)
247                 connman_inet_add_host_route(ipconfig->index,
248                                         ipconfig->address->gateway,
249                                         ipconfig->address->peer);
250         else if (family == AF_INET6)
251                 connman_inet_add_ipv6_host_route(ipconfig->index,
252                                                 ipconfig->address->gateway,
253                                                 ipconfig->address->peer);
254         else
255                 return -EINVAL;
256
257         return 0;
258 }
259
260 void __vpn_ipconfig_unref_debug(struct vpn_ipconfig *ipconfig,
261                                 const char *file, int line, const char *caller)
262 {
263         if (ipconfig == NULL)
264                 return;
265
266         DBG("%p ref %d by %s:%d:%s()", ipconfig, ipconfig->refcount - 1,
267                 file, line, caller);
268
269         if (__sync_fetch_and_sub(&ipconfig->refcount, 1) != 1)
270                 return;
271
272         connman_ipaddress_free(ipconfig->system);
273         connman_ipaddress_free(ipconfig->address);
274         g_free(ipconfig);
275 }
276
277 static struct vpn_ipconfig *create_ipv6config(int index)
278 {
279         struct vpn_ipconfig *ipv6config;
280
281         DBG("index %d", index);
282
283         ipv6config = g_try_new0(struct vpn_ipconfig, 1);
284         if (ipv6config == NULL)
285                 return NULL;
286
287         ipv6config->refcount = 1;
288
289         ipv6config->index = index;
290         ipv6config->enabled = FALSE;
291         ipv6config->family = AF_INET6;
292
293         ipv6config->address = connman_ipaddress_alloc(AF_INET6);
294         if (ipv6config->address == NULL) {
295                 g_free(ipv6config);
296                 return NULL;
297         }
298
299         ipv6config->system = connman_ipaddress_alloc(AF_INET6);
300
301         DBG("ipconfig %p", ipv6config);
302
303         return ipv6config;
304 }
305
306 struct vpn_ipconfig *__vpn_ipconfig_create(int index, int family)
307 {
308         struct vpn_ipconfig *ipconfig;
309
310         if (family == AF_INET6)
311                 return create_ipv6config(index);
312
313         DBG("index %d", index);
314
315         ipconfig = g_try_new0(struct vpn_ipconfig, 1);
316         if (ipconfig == NULL)
317                 return NULL;
318
319         ipconfig->refcount = 1;
320
321         ipconfig->index = index;
322         ipconfig->enabled = FALSE;
323         ipconfig->family = family;
324
325         ipconfig->address = connman_ipaddress_alloc(AF_INET);
326         if (ipconfig->address == NULL) {
327                 g_free(ipconfig);
328                 return NULL;
329         }
330
331         ipconfig->system = connman_ipaddress_alloc(AF_INET);
332
333         DBG("ipconfig %p", ipconfig);
334
335         return ipconfig;
336 }
337
338 void __vpn_ipconfig_set_index(struct vpn_ipconfig *ipconfig, int index)
339 {
340         ipconfig->index = index;
341 }
342
343 static const char *type2str(unsigned short type)
344 {
345         switch (type) {
346         case ARPHRD_ETHER:
347                 return "ETHER";
348         case ARPHRD_LOOPBACK:
349                 return "LOOPBACK";
350         case ARPHRD_PPP:
351                 return "PPP";
352         case ARPHRD_NONE:
353                 return "NONE";
354         case ARPHRD_VOID:
355                 return "VOID";
356         }
357
358         return "";
359 }
360
361 void __vpn_ipconfig_newlink(int index, unsigned short type,
362                                 unsigned int flags,
363                                 const char *address,
364                                 unsigned short mtu,
365                                 struct rtnl_link_stats *stats)
366 {
367         struct vpn_ipdevice *ipdevice;
368         GString *str;
369
370         if (type == ARPHRD_LOOPBACK)
371                 return;
372
373         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
374         if (ipdevice != NULL)
375                 goto update;
376
377         ipdevice = g_try_new0(struct vpn_ipdevice, 1);
378         if (ipdevice == NULL)
379                 return;
380
381         ipdevice->index = index;
382         ipdevice->ifname = connman_inet_ifname(index);
383         ipdevice->type = type;
384
385         ipdevice->address = g_strdup(address);
386
387         g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
388
389         connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
390                                                 index, type, type2str(type));
391
392 update:
393         ipdevice->mtu = mtu;
394
395         if (flags == ipdevice->flags)
396                 return;
397
398         ipdevice->flags = flags;
399
400         str = g_string_new(NULL);
401         if (str == NULL)
402                 return;
403
404         if (flags & IFF_UP)
405                 g_string_append(str, "UP");
406         else
407                 g_string_append(str, "DOWN");
408
409         if (flags & IFF_RUNNING)
410                 g_string_append(str, ",RUNNING");
411
412         if (flags & IFF_LOWER_UP)
413                 g_string_append(str, ",LOWER_UP");
414
415         connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
416                                                         flags, str->str);
417
418         g_string_free(str, TRUE);
419 }
420
421 void __vpn_ipconfig_dellink(int index, struct rtnl_link_stats *stats)
422 {
423         struct vpn_ipdevice *ipdevice;
424
425         DBG("index %d", index);
426
427         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
428         if (ipdevice == NULL)
429                 return;
430
431         g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
432 }
433
434 static void free_ipdevice(gpointer data)
435 {
436         struct vpn_ipdevice *ipdevice = data;
437
438         connman_info("%s {remove} index %d", ipdevice->ifname,
439                                                         ipdevice->index);
440
441         g_free(ipdevice->ipv4_gateway);
442         g_free(ipdevice->ipv6_gateway);
443         g_free(ipdevice->pac);
444
445         g_free(ipdevice->address);
446
447         g_free(ipdevice->ifname);
448         g_free(ipdevice);
449 }
450
451 int __vpn_ipconfig_init(void)
452 {
453         DBG("");
454
455         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
456                                                         NULL, free_ipdevice);
457
458         return 0;
459 }
460
461 void __vpn_ipconfig_cleanup(void)
462 {
463         DBG("");
464
465         g_hash_table_destroy(ipdevice_hash);
466         ipdevice_hash = NULL;
467 }