cb5167f0676d6e92e75b9e222ccbe4df60995510
[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 static struct vpn_ipconfig *create_ipv6config(int index)
261 {
262         struct vpn_ipconfig *ipv6config;
263
264         DBG("index %d", index);
265
266         ipv6config = g_try_new0(struct vpn_ipconfig, 1);
267         if (ipv6config == NULL)
268                 return NULL;
269
270         ipv6config->refcount = 1;
271
272         ipv6config->index = index;
273         ipv6config->enabled = FALSE;
274         ipv6config->family = AF_INET6;
275
276         ipv6config->address = connman_ipaddress_alloc(AF_INET6);
277         if (ipv6config->address == NULL) {
278                 g_free(ipv6config);
279                 return NULL;
280         }
281
282         ipv6config->system = connman_ipaddress_alloc(AF_INET6);
283
284         DBG("ipconfig %p", ipv6config);
285
286         return ipv6config;
287 }
288
289 struct vpn_ipconfig *__vpn_ipconfig_create(int index, int family)
290 {
291         struct vpn_ipconfig *ipconfig;
292
293         if (family == AF_INET6)
294                 return create_ipv6config(index);
295
296         DBG("index %d", index);
297
298         ipconfig = g_try_new0(struct vpn_ipconfig, 1);
299         if (ipconfig == NULL)
300                 return NULL;
301
302         ipconfig->refcount = 1;
303
304         ipconfig->index = index;
305         ipconfig->enabled = FALSE;
306         ipconfig->family = family;
307
308         ipconfig->address = connman_ipaddress_alloc(AF_INET);
309         if (ipconfig->address == NULL) {
310                 g_free(ipconfig);
311                 return NULL;
312         }
313
314         ipconfig->system = connman_ipaddress_alloc(AF_INET);
315
316         DBG("ipconfig %p", ipconfig);
317
318         return ipconfig;
319 }
320
321 void __vpn_ipconfig_set_index(struct vpn_ipconfig *ipconfig, int index)
322 {
323         ipconfig->index = index;
324 }
325
326 static const char *type2str(unsigned short type)
327 {
328         switch (type) {
329         case ARPHRD_ETHER:
330                 return "ETHER";
331         case ARPHRD_LOOPBACK:
332                 return "LOOPBACK";
333         case ARPHRD_PPP:
334                 return "PPP";
335         case ARPHRD_NONE:
336                 return "NONE";
337         case ARPHRD_VOID:
338                 return "VOID";
339         }
340
341         return "";
342 }
343
344 void __vpn_ipconfig_newlink(int index, unsigned short type,
345                                 unsigned int flags,
346                                 const char *address,
347                                 unsigned short mtu,
348                                 struct rtnl_link_stats *stats)
349 {
350         struct vpn_ipdevice *ipdevice;
351         GString *str;
352
353         if (type == ARPHRD_LOOPBACK)
354                 return;
355
356         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
357         if (ipdevice != NULL)
358                 goto update;
359
360         ipdevice = g_try_new0(struct vpn_ipdevice, 1);
361         if (ipdevice == NULL)
362                 return;
363
364         ipdevice->index = index;
365         ipdevice->ifname = connman_inet_ifname(index);
366         ipdevice->type = type;
367
368         ipdevice->address = g_strdup(address);
369
370         g_hash_table_insert(ipdevice_hash, GINT_TO_POINTER(index), ipdevice);
371
372         connman_info("%s {create} index %d type %d <%s>", ipdevice->ifname,
373                                                 index, type, type2str(type));
374
375 update:
376         ipdevice->mtu = mtu;
377
378         if (flags == ipdevice->flags)
379                 return;
380
381         ipdevice->flags = flags;
382
383         str = g_string_new(NULL);
384         if (str == NULL)
385                 return;
386
387         if (flags & IFF_UP)
388                 g_string_append(str, "UP");
389         else
390                 g_string_append(str, "DOWN");
391
392         if (flags & IFF_RUNNING)
393                 g_string_append(str, ",RUNNING");
394
395         if (flags & IFF_LOWER_UP)
396                 g_string_append(str, ",LOWER_UP");
397
398         connman_info("%s {update} flags %u <%s>", ipdevice->ifname,
399                                                         flags, str->str);
400
401         g_string_free(str, TRUE);
402 }
403
404 void __vpn_ipconfig_dellink(int index, struct rtnl_link_stats *stats)
405 {
406         struct vpn_ipdevice *ipdevice;
407
408         DBG("index %d", index);
409
410         ipdevice = g_hash_table_lookup(ipdevice_hash, GINT_TO_POINTER(index));
411         if (ipdevice == NULL)
412                 return;
413
414         g_hash_table_remove(ipdevice_hash, GINT_TO_POINTER(index));
415 }
416
417 static void free_ipdevice(gpointer data)
418 {
419         struct vpn_ipdevice *ipdevice = data;
420
421         connman_info("%s {remove} index %d", ipdevice->ifname,
422                                                         ipdevice->index);
423
424         g_free(ipdevice->ipv4_gateway);
425         g_free(ipdevice->ipv6_gateway);
426         g_free(ipdevice->pac);
427
428         g_free(ipdevice->address);
429
430         g_free(ipdevice->ifname);
431         g_free(ipdevice);
432 }
433
434 int __vpn_ipconfig_init(void)
435 {
436         DBG("");
437
438         ipdevice_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
439                                                         NULL, free_ipdevice);
440
441         return 0;
442 }
443
444 void __vpn_ipconfig_cleanup(void)
445 {
446         DBG("");
447
448         g_hash_table_destroy(ipdevice_hash);
449         ipdevice_hash = NULL;
450 }