Add the vpn service
[platform/core/connectivity/net-config.git] / src / vpnsvc.c
1 /*
2  * Network Configuration - VPN Service Module
3  *
4  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <gio/gunixfdlist.h>
24
25 #include "vpnsvc.h"
26 #include "vpnsvc-internal.h"
27 #include "netdbus.h"
28 #include "log.h"
29
30 static Vpnsvc *vpnsvc = NULL;
31
32 /*********************
33  * Handler Functions *
34  ********************/
35 gboolean handle_vpn_init(Vpnsvc *object,
36                                                                 GDBusMethodInvocation *invocation,
37                                                                 const gchar *arg_iface_name,
38                                                                 guint arg_iface_name_len)
39 {
40         DBG("handle_vpn_init");
41
42         int result = VPNSVC_ERROR_NONE;
43
44         vpnsvc_tun_s handle_s;
45         GDBusMessage *msg;
46         GUnixFDList *fd_list;
47         int fd_list_length;
48         const int *fds;
49
50         DBG("vpn_init, %s, %u\n", arg_iface_name, arg_iface_name_len);
51
52         msg = g_dbus_method_invocation_get_message(invocation);
53         fd_list = g_dbus_message_get_unix_fd_list(msg);
54         fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
55
56         if (fd_list_length <= 0)
57                 DBG("D-Bus Message doesn't contain any fd!");
58
59         DBG("fd:%d\n", *fds);
60
61         result = vpn_service_init(arg_iface_name, arg_iface_name_len, *fds, &handle_s);
62
63         DBG("handle_s.fd : %d, handle_s.index : %d, handle_s.name : %s",
64                         handle_s.fd, handle_s.index, handle_s.name);
65
66         vpnsvc_complete_vpn_init(object, invocation, result, handle_s.index, handle_s.name);
67
68         return TRUE;
69 }
70
71 gboolean handle_vpn_deinit(Vpnsvc *object,
72                                                                         GDBusMethodInvocation *invocation,
73                                                                         const gchar *arg_dev_name)
74 {
75         DBG("handle_vpn_deinit");
76
77         int result = VPNSVC_ERROR_NONE;
78
79         DBG("vpn_deinit, %s\n", arg_dev_name);
80
81         result = vpn_service_deinit(arg_dev_name);
82
83         vpnsvc_complete_vpn_deinit(object, invocation, result);
84
85         return TRUE;
86 }
87
88 gboolean handle_vpn_protect(Vpnsvc *object,
89                                                                         GDBusMethodInvocation *invocation,
90                                                                         const gchar *arg_dev_name)
91 {
92         DBG("handle_vpn_protect");
93
94         int result = VPNSVC_ERROR_NONE;
95
96         int socket;
97         GDBusMessage *msg;
98         GUnixFDList *fd_list;
99         int fd_list_length;
100         const int *fds;
101
102         msg = g_dbus_method_invocation_get_message(invocation);
103         fd_list = g_dbus_message_get_unix_fd_list(msg);
104         fds = g_unix_fd_list_peek_fds(fd_list, &fd_list_length);
105         if (fd_list_length <= 0)
106                 DBG("D-Bus Message doesn't contain any fd!");
107
108         socket = *fds;
109         DBG("vpn_protect, %d, %s\n", socket, arg_dev_name);
110
111         result = vpn_service_protect(socket, arg_dev_name);
112
113         vpnsvc_complete_vpn_protect(object, invocation, result);
114
115         return TRUE;
116 }
117
118 gboolean handle_vpn_up(Vpnsvc *object,
119                                                                 GDBusMethodInvocation *invocation,
120                                                                 gint arg_iface_index,
121                                                                 const gchar *arg_local_ip,
122                                                                 const gchar *arg_remote_ip,
123                                                                 GVariant *arg_routes,
124                                                                 guint arg_nr_routes,
125                                                                 GVariant *arg_dns_servers,
126                                                                 guint arg_nr_dns,
127                                                                 const gchar *arg_dns_suffix,
128                                                                 guint arg_mtu)
129 {
130         DBG("handle_vpn_up");
131
132         int result = VPNSVC_ERROR_NONE;
133
134         char *routes[arg_nr_routes];
135         int prefix[arg_nr_routes];
136         char **dns_servers = NULL;
137
138         unsigned int i = 0;
139         size_t total_dns_string_cnt = 0;
140         gchar* temp_dns_server;
141         GVariantIter iter;
142
143         gchar* route_dest;
144         gint route_prefix;
145
146         DBG("iface_index : %d", arg_iface_index);
147         DBG("local ip : %s", arg_local_ip);
148         DBG("remote ip : %s", arg_remote_ip);
149         DBG("dns_suffix : %s", arg_dns_suffix);
150         DBG("mtu : %u", arg_mtu);
151         DBG("arg_routes: %p", arg_routes);
152         DBG("nr_routes : %u", arg_nr_routes);
153         DBG("arg_dns_servers: %p", arg_dns_servers);
154         DBG("nr_dns : %u", arg_nr_dns);
155
156         /* arg_routes check */
157         if (arg_nr_routes > 0) {
158                 if (arg_routes != NULL) {
159                         GVariant *dict = g_variant_get_variant(arg_routes);
160                         g_variant_iter_init(&iter, dict);
161                         i = 0;
162                         while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
163                                 int temp_dest_str_len = strlen(route_dest);
164                                 routes[i] = g_try_malloc0((sizeof(char) * temp_dest_str_len)+1);
165                                 strncpy(routes[i], route_dest, temp_dest_str_len);
166                                 routes[i][temp_dest_str_len] = '\0';
167                                 prefix[i] = route_prefix;
168                                 DBG("routes[%d] = %s \t", i, (routes[i] == NULL) ? "" : routes[i]);
169                                 DBG("prefix[%d] = %d ", i, prefix[i]);
170                                 i++;
171                         }
172                 }
173         }
174
175
176         /* arg_nr_dns check */
177         if (arg_nr_dns > 0) {
178                 if (arg_dns_servers != NULL) {
179                         GVariant *array = g_variant_get_variant(arg_dns_servers);
180                         dns_servers = (char **)g_try_malloc0(arg_nr_dns*sizeof(char *));
181                         if (dns_servers == NULL) {
182                                 ERR("malloc failed.");
183                                 result = VPNSVC_ERROR_OUT_OF_MEMORY;
184                                 goto done;
185                         }
186                         g_variant_iter_init(&iter, array);
187                         i = 0;
188                         while (g_variant_iter_loop(&iter, "s", &temp_dns_server)) {
189                                 int temp_dns_str_len = strlen(temp_dns_server);
190                                 dns_servers[i] = (char *)g_try_malloc0((temp_dns_str_len + 1) * sizeof(char));
191                                 strncpy(dns_servers[i], temp_dns_server, strlen(temp_dns_server));
192                                 dns_servers[i][temp_dns_str_len] = '\0';
193                                 total_dns_string_cnt += temp_dns_str_len;
194                                 DBG("dns_servers[%d] : %s", i, (dns_servers[i] == NULL) ? "" : dns_servers[i]);
195                                 i++;
196                         }
197                 }
198         }
199
200         result = vpn_service_up(arg_iface_index, arg_local_ip, arg_remote_ip,
201                         routes, prefix, arg_nr_routes, dns_servers, arg_nr_dns,
202                         total_dns_string_cnt, arg_dns_suffix, arg_mtu);
203 done:
204         /* free pointers */
205         for (i = 0; i < arg_nr_routes; i++) {
206                 if (routes[i])
207                         g_free(routes[i]);
208         }
209
210         if (dns_servers) {
211                 for (i = 0; i < arg_nr_dns; i++) {
212                         if (dns_servers[i])
213                                 g_free(dns_servers[i]);
214                 }
215                 g_free(dns_servers);
216         }
217
218         vpnsvc_complete_vpn_up(object, invocation, result);
219
220         return TRUE;
221 }
222
223 gboolean handle_vpn_down(Vpnsvc *object,
224                                                                         GDBusMethodInvocation *invocation,
225                                                                         gint arg_iface_index)
226 {
227         DBG("handle_vpn_down");
228
229         int result = VPNSVC_ERROR_NONE;
230
231         DBG("vpn_down, %d\n", arg_iface_index);
232
233         result = vpn_service_down(arg_iface_index);
234
235         vpnsvc_complete_vpn_down(object, invocation, result);
236
237         return TRUE;
238 }
239
240 gboolean handle_vpn_block_networks(Vpnsvc *object,
241                                                                                         GDBusMethodInvocation *invocation,
242                                                                                         GVariant *arg_nets_vpn,
243                                                                                         guint arg_nr_nets_vpn,
244                                                                                         GVariant *arg_nets_orig,
245                                                                                         guint arg_nr_nets_orig)
246 {
247         DBG("handle_vpn_block_networks");
248
249         int result = VPNSVC_ERROR_NONE;
250
251         char *nets_vpn[arg_nr_nets_vpn];
252         int prefix_vpn[arg_nr_nets_vpn];
253
254         char *nets_orig[arg_nr_nets_vpn];
255         int prefix_orig[arg_nr_nets_vpn];
256
257         int i = 0;
258         GVariantIter iter;
259         gchar* route_dest;
260         gint route_prefix;
261
262         DBG("vpn_block_networks");
263
264         /* arg_nets_vpn check */
265         if (arg_nr_nets_vpn > 0) {
266                 if (arg_nets_vpn != NULL) {
267                         GVariant *dict_nets_vpn = g_variant_get_variant(arg_nets_vpn);
268                         g_variant_iter_init(&iter, dict_nets_vpn);
269                         i = 0;
270                         while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
271                                 int tmp_route_len = strlen(route_dest);
272                                 nets_vpn[i] = g_try_malloc0(sizeof(char) * tmp_route_len + 1);
273                                 strncpy(nets_vpn[i], route_dest, tmp_route_len);
274                                 nets_vpn[i][tmp_route_len] = '\0';
275                                 prefix_vpn[i] = route_prefix;
276                                 DBG("nets_vpn[%d] = %s \t", i, (nets_vpn[i] == NULL) ? "" : nets_vpn[i]);
277                                 DBG("prefix_vpn[%d] = %d ", i, prefix_vpn[i]);
278                                 i++;
279                         }
280                 }
281         }
282
283         /* arg_nets_orig check */
284         if (arg_nr_nets_orig > 0) {
285                 if (arg_nets_orig != NULL) {
286                         GVariant *dict_nets_orig = g_variant_get_variant(arg_nets_orig);
287                         g_variant_iter_init(&iter, dict_nets_orig);
288                         i = 0;
289                         while (g_variant_iter_loop(&iter, "{si}", &route_dest, &route_prefix)) {
290                                 int tmp_route_len = strlen(route_dest);
291                                 nets_orig[i] = g_try_malloc0(sizeof(char) * tmp_route_len + 1);
292                                 strncpy(nets_orig[i], route_dest, tmp_route_len);
293                                 nets_orig[i][tmp_route_len] = '\0';
294                                 prefix_orig[i] = route_prefix;
295                                 DBG("nets_orig[%d] = %s \t", i, (nets_orig[i] == NULL) ? "" : nets_orig[i]);
296                                 DBG("prefix_orig[%d] = %d ", i, prefix_orig[i]);
297                                 i++;
298                         }
299                 }
300         }
301
302         /* call function */
303         result = vpn_service_block_networks(nets_vpn, prefix_vpn, arg_nr_nets_vpn, nets_orig, prefix_orig, arg_nr_nets_orig);
304
305         for (i = 0; i < arg_nr_nets_vpn; ++i) {
306                 g_free(nets_orig[i]);
307                 g_free(nets_vpn[i]);
308         }
309
310         vpnsvc_complete_vpn_block_networks(object, invocation, result);
311
312         return TRUE;
313 }
314
315 gboolean handle_vpn_unblock_networks(Vpnsvc *object,
316                                                                                         GDBusMethodInvocation *invocation)
317 {
318         DBG("handle_vpn_unblock_networks");
319
320         int result = VPNSVC_ERROR_NONE;
321
322         DBG("vpn_unblock_networks");
323
324         result = vpn_service_unblock_networks();
325
326         vpnsvc_complete_vpn_unblock_networks(object, invocation, result);
327
328         return TRUE;
329 }
330
331 /*****************************
332  * Initializations Functions *
333  ****************************/
334 Vpnsvc *get_vpnsvc_object(void)
335 {
336         return vpnsvc;
337 }
338
339 void vpnsvc_create_and_init(void)
340 {
341         DBG("Create vpn object.");
342         GDBusInterfaceSkeleton *interface_vpn = NULL;
343         GDBusConnection *connection = NULL;
344         GDBusObjectManagerServer *server = netdbus_get_vpn_manager();
345         if (server == NULL)
346                 return;
347
348         connection = netdbus_get_connection();
349         g_dbus_object_manager_server_set_connection(server, connection);
350
351         /* Interface */
352         vpnsvc = vpnsvc_skeleton_new();
353         interface_vpn = G_DBUS_INTERFACE_SKELETON(vpnsvc);
354
355         /* VPN Service */
356         g_signal_connect(vpnsvc, "handle-vpn-init",
357                         G_CALLBACK(handle_vpn_init), NULL);
358         g_signal_connect(vpnsvc, "handle-vpn-deinit",
359                         G_CALLBACK(handle_vpn_deinit), NULL);
360         g_signal_connect(vpnsvc, "handle-vpn-protect",
361                         G_CALLBACK(handle_vpn_protect), NULL);
362         g_signal_connect(vpnsvc, "handle-vpn-up",
363                         G_CALLBACK(handle_vpn_up), NULL);
364         g_signal_connect(vpnsvc, "handle-vpn-down",
365                         G_CALLBACK(handle_vpn_down), NULL);
366         g_signal_connect(vpnsvc, "handle-vpn-block-networks",
367                         G_CALLBACK(handle_vpn_block_networks), NULL);
368         g_signal_connect(vpnsvc, "handle-vpn-unblock-networks",
369                         G_CALLBACK(handle_vpn_unblock_networks), NULL);
370
371         if (!g_dbus_interface_skeleton_export(interface_vpn, connection,
372                         NETCONFIG_VPNSVC_PATH, NULL)) {
373                 ERR("Export NETCONFIG_VPNSVC_PATH for vpn failed");
374         }
375
376         return;
377 }
378
379 void vpnsvc_destroy_deinit(void)
380 {
381         DBG("Deinit vpn object.");
382
383         if (vpnsvc)
384                 g_object_unref(vpnsvc);
385 }
386