nm-openconnect-service-openconnect-helper.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
  2. /* NetworkManager -- Network link manager
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. *
  18. * Copyright © 2008 - 2010 Intel Corporation.
  19. *
  20. * Based on nm-vpnc-service-vpnc-helper.c:
  21. * Copyright © 2005 - 2010 Red Hat, Inc.
  22. * Copyright © 2007 - 2008 Novell, Inc.
  23. */
  24. #include <glib.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <sys/socket.h>
  29. #include <netinet/in.h>
  30. #include <arpa/inet.h>
  31. #include <errno.h>
  32. #include <dbus/dbus.h>
  33. #include <dbus/dbus-glib-lowlevel.h>
  34. #include <dbus/dbus-glib.h>
  35. #include <NetworkManager.h>
  36. #include <nm-vpn-plugin-utils.h>
  37. #include "nm-openconnect-service.h"
  38. #include "nm-utils.h"
  39. /* These are here because nm-dbus-glib-types.h isn't exported */
  40. #define DBUS_TYPE_G_ARRAY_OF_UINT (dbus_g_type_get_collection ("GArray", G_TYPE_UINT))
  41. #define DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_ARRAY_OF_UINT))
  42. #define DBUS_TYPE_G_MAP_OF_VARIANT (dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE))
  43. #define DBUS_TYPE_G_IP6_ROUTE (dbus_g_type_get_struct ("GValueArray", DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, G_TYPE_INVALID))
  44. #define DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_IP6_ROUTE))
  45. static void
  46. helper_failed (DBusGConnection *connection, const char *reason)
  47. {
  48. DBusGProxy *proxy;
  49. GError *err = NULL;
  50. g_warning ("nm-nopenconnect-service-openconnect-helper did not receive a valid %s from openconnect", reason);
  51. proxy = dbus_g_proxy_new_for_name (connection,
  52. NM_DBUS_SERVICE_OPENCONNECT,
  53. NM_VPN_DBUS_PLUGIN_PATH,
  54. NM_VPN_DBUS_PLUGIN_INTERFACE);
  55. dbus_g_proxy_call (proxy, "SetFailure", &err,
  56. G_TYPE_STRING, reason,
  57. G_TYPE_INVALID,
  58. G_TYPE_INVALID);
  59. if (err) {
  60. g_warning ("Could not send failure information: %s", err->message);
  61. g_error_free (err);
  62. }
  63. g_object_unref (proxy);
  64. exit (1);
  65. }
  66. static void
  67. send_config (DBusGConnection *connection, GHashTable *config,
  68. GHashTable *ip4config, GHashTable *ip6config)
  69. {
  70. DBusGProxy *proxy;
  71. GError *err = NULL;
  72. proxy = dbus_g_proxy_new_for_name (connection,
  73. NM_DBUS_SERVICE_OPENCONNECT,
  74. NM_VPN_DBUS_PLUGIN_PATH,
  75. NM_VPN_DBUS_PLUGIN_INTERFACE);
  76. if (!dbus_g_proxy_call (proxy, "SetConfig", &err,
  77. DBUS_TYPE_G_MAP_OF_VARIANT,
  78. config,
  79. G_TYPE_INVALID,
  80. G_TYPE_INVALID))
  81. goto done;
  82. if (ip4config) {
  83. if (!dbus_g_proxy_call (proxy, "SetIp4Config", &err,
  84. DBUS_TYPE_G_MAP_OF_VARIANT,
  85. ip4config,
  86. G_TYPE_INVALID,
  87. G_TYPE_INVALID))
  88. goto done;
  89. }
  90. if (ip6config) {
  91. if (!dbus_g_proxy_call (proxy, "SetIp6Config", &err,
  92. DBUS_TYPE_G_MAP_OF_VARIANT,
  93. ip6config,
  94. G_TYPE_INVALID,
  95. G_TYPE_INVALID))
  96. goto done;
  97. }
  98. done:
  99. if (err) {
  100. g_warning ("Could not send configuration information: %s", err->message);
  101. g_error_free (err);
  102. }
  103. g_object_unref (proxy);
  104. }
  105. static GValue *
  106. str_to_gvalue (const char *str, gboolean try_convert)
  107. {
  108. GValue *val;
  109. /* Empty */
  110. if (!str || strlen (str) < 1)
  111. return NULL;
  112. if (!g_utf8_validate (str, -1, NULL)) {
  113. if (try_convert && !(str = g_convert (str, -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL)))
  114. str = g_convert (str, -1, "C", "UTF-8", NULL, NULL, NULL);
  115. if (!str)
  116. /* Invalid */
  117. return NULL;
  118. }
  119. val = g_slice_new0 (GValue);
  120. g_value_init (val, G_TYPE_STRING);
  121. g_value_set_string (val, str);
  122. return val;
  123. }
  124. static GValue *
  125. uint_to_gvalue (guint32 num)
  126. {
  127. GValue *val;
  128. if (num == 0)
  129. return NULL;
  130. val = g_slice_new0 (GValue);
  131. g_value_init (val, G_TYPE_UINT);
  132. g_value_set_uint (val, num);
  133. return val;
  134. }
  135. static GValue *
  136. bool_to_gvalue (gboolean b)
  137. {
  138. GValue *val;
  139. val = g_slice_new0 (GValue);
  140. g_value_init (val, G_TYPE_BOOLEAN);
  141. g_value_set_boolean (val, b);
  142. return val;
  143. }
  144. static GValue *
  145. addr4_to_gvalue (const char *str)
  146. {
  147. struct in_addr temp_addr;
  148. /* Empty */
  149. if (!str || strlen (str) < 1)
  150. return NULL;
  151. if (inet_pton (AF_INET, str, &temp_addr) <= 0)
  152. return NULL;
  153. return uint_to_gvalue (temp_addr.s_addr);
  154. }
  155. static GValue *
  156. addr4_list_to_gvalue (const char *str)
  157. {
  158. GValue *val;
  159. char **split;
  160. int i;
  161. GArray *array;
  162. /* Empty */
  163. if (!str || strlen (str) < 1)
  164. return NULL;
  165. split = g_strsplit (str, " ", -1);
  166. if (g_strv_length (split) == 0)
  167. return NULL;
  168. array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), g_strv_length (split));
  169. for (i = 0; split[i]; i++) {
  170. struct in_addr addr;
  171. if (inet_pton (AF_INET, split[i], &addr) > 0) {
  172. g_array_append_val (array, addr.s_addr);
  173. } else {
  174. g_strfreev (split);
  175. g_array_free (array, TRUE);
  176. return NULL;
  177. }
  178. }
  179. g_strfreev (split);
  180. val = g_slice_new0 (GValue);
  181. g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
  182. g_value_set_boxed (val, array);
  183. return val;
  184. }
  185. static GValue *
  186. addr6_to_gvalue (const char *str)
  187. {
  188. struct in6_addr temp_addr;
  189. GValue *val;
  190. GByteArray *ba;
  191. /* Empty */
  192. if (!str || strlen (str) < 1)
  193. return NULL;
  194. if (inet_pton (AF_INET6, str, &temp_addr) <= 0)
  195. return NULL;
  196. val = g_slice_new0 (GValue);
  197. g_value_init (val, DBUS_TYPE_G_UCHAR_ARRAY);
  198. ba = g_byte_array_new ();
  199. g_byte_array_append (ba, (guint8 *) &temp_addr, sizeof (temp_addr));
  200. g_value_take_boxed (val, ba);
  201. return val;
  202. }
  203. static GValue *
  204. addr6_list_to_gvalue (const char *str)
  205. {
  206. GValue *val;
  207. char **split;
  208. int i;
  209. GPtrArray *array;
  210. GByteArray *ba;
  211. /* Empty */
  212. if (!str || strlen (str) < 1)
  213. return NULL;
  214. split = g_strsplit (str, " ", -1);
  215. if (g_strv_length (split) == 0)
  216. return NULL;
  217. array = g_ptr_array_new_full (g_strv_length (split),
  218. (GDestroyNotify) g_byte_array_unref);
  219. for (i = 0; split[i]; i++) {
  220. struct in6_addr addr;
  221. if (inet_pton (AF_INET6, split[i], &addr) > 0) {
  222. ba = g_byte_array_new ();
  223. g_byte_array_append (ba, (guint8 *) &addr, sizeof (addr));
  224. g_ptr_array_add (array, ba);
  225. } else {
  226. g_strfreev (split);
  227. g_ptr_array_free (array, TRUE);
  228. return NULL;
  229. }
  230. }
  231. g_strfreev (split);
  232. val = g_slice_new0 (GValue);
  233. g_value_init (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT);
  234. g_value_set_boxed (val, array);
  235. return val;
  236. }
  237. #define BUFLEN 256
  238. static GValue *
  239. split_dns_list_to_gvalue (const char *str)
  240. {
  241. GValue *val;
  242. char **split;
  243. if (!str || strlen (str) < 1)
  244. return NULL;
  245. split = g_strsplit (str, ",", -1);
  246. if (g_strv_length (split) == 0)
  247. return NULL;
  248. val = g_slice_new0 (GValue);
  249. g_value_init (val, G_TYPE_STRV);
  250. g_value_take_boxed (val, split);
  251. return val;
  252. }
  253. static GValue *
  254. get_ip4_routes (void)
  255. {
  256. GValue *value = NULL;
  257. GPtrArray *routes;
  258. char *tmp;
  259. int num;
  260. int i;
  261. tmp = getenv ("CISCO_SPLIT_INC");
  262. if (!tmp || strlen (tmp) < 1)
  263. return NULL;
  264. num = atoi (tmp);
  265. if (!num)
  266. return NULL;
  267. routes = g_ptr_array_new ();
  268. for (i = 0; i < num; i++) {
  269. GArray *array;
  270. char buf[BUFLEN];
  271. struct in_addr network;
  272. guint32 next_hop = 0; /* no next hop */
  273. guint32 prefix, metric = 0;
  274. snprintf (buf, BUFLEN, "CISCO_SPLIT_INC_%d_ADDR", i);
  275. tmp = getenv (buf);
  276. if (!tmp || inet_pton (AF_INET, tmp, &network) <= 0) {
  277. g_warning ("Ignoring invalid static route address '%s'", tmp ? tmp : "NULL");
  278. continue;
  279. }
  280. snprintf (buf, BUFLEN, "CISCO_SPLIT_INC_%d_MASKLEN", i);
  281. tmp = getenv (buf);
  282. if (tmp) {
  283. long int tmp_prefix;
  284. errno = 0;
  285. tmp_prefix = strtol (tmp, NULL, 10);
  286. if (errno || tmp_prefix <= 0 || tmp_prefix > 32) {
  287. g_warning ("Ignoring invalid static route prefix '%s'", tmp ? tmp : "NULL");
  288. continue;
  289. }
  290. prefix = (guint32) tmp_prefix;
  291. } else {
  292. struct in_addr netmask;
  293. snprintf (buf, BUFLEN, "CISCO_SPLIT_INC_%d_MASK", i);
  294. tmp = getenv (buf);
  295. if (!tmp || inet_pton (AF_INET, tmp, &netmask) <= 0) {
  296. g_warning ("Ignoring invalid static route netmask '%s'", tmp ? tmp : "NULL");
  297. continue;
  298. }
  299. prefix = nm_utils_ip4_netmask_to_prefix (netmask.s_addr);
  300. }
  301. array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 4);
  302. g_array_append_val (array, network.s_addr);
  303. g_array_append_val (array, prefix);
  304. g_array_append_val (array, next_hop);
  305. g_array_append_val (array, metric);
  306. g_ptr_array_add (routes, array);
  307. }
  308. if (routes->len > 0) {
  309. value = g_new0 (GValue, 1);
  310. g_value_init (value, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT);
  311. g_value_take_boxed (value, routes);
  312. } else
  313. g_ptr_array_free (routes, TRUE);
  314. return value;
  315. }
  316. static GValue *
  317. get_ip6_routes (void)
  318. {
  319. GValue *value = NULL;
  320. GSList *routes;
  321. char *tmp;
  322. int num;
  323. int i;
  324. tmp = getenv ("CISCO_IPV6_SPLIT_INC");
  325. if (!tmp || strlen (tmp) < 1)
  326. return NULL;
  327. num = atoi (tmp);
  328. if (!num)
  329. return NULL;
  330. routes = NULL;
  331. for (i = 0; i < num; i++) {
  332. NMIP6Route *route;
  333. char buf[BUFLEN];
  334. struct in6_addr network;
  335. guint32 prefix;
  336. snprintf (buf, BUFLEN, "CISCO_IPV6_SPLIT_INC_%d_ADDR", i);
  337. tmp = getenv (buf);
  338. if (!tmp || inet_pton (AF_INET6, tmp, &network) <= 0) {
  339. g_warning ("Ignoring invalid static route address '%s'", tmp ? tmp : "NULL");
  340. continue;
  341. }
  342. snprintf (buf, BUFLEN, "CISCO_IPV6_SPLIT_INC_%d_MASKLEN", i);
  343. tmp = getenv (buf);
  344. if (tmp) {
  345. long int tmp_prefix;
  346. errno = 0;
  347. tmp_prefix = strtol (tmp, NULL, 10);
  348. if (errno || tmp_prefix <= 0 || tmp_prefix > 128) {
  349. g_warning ("Ignoring invalid static route prefix '%s'", tmp ? tmp : "NULL");
  350. continue;
  351. }
  352. prefix = (guint32) tmp_prefix;
  353. } else {
  354. g_warning ("Ignoring static route %d with no prefix length", i);
  355. continue;
  356. }
  357. route = nm_ip6_route_new ();
  358. nm_ip6_route_set_dest (route, &network);
  359. nm_ip6_route_set_prefix (route, prefix);
  360. routes = g_slist_append (routes, route);
  361. }
  362. if (routes) {
  363. GSList *iter;
  364. value = g_slice_new0 (GValue);
  365. g_value_init (value, DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE);
  366. nm_utils_ip6_routes_to_gvalue (routes, value);
  367. for (iter = routes; iter; iter = iter->next)
  368. nm_ip6_route_unref (iter->data);
  369. g_slist_free (routes);
  370. }
  371. return value;
  372. }
  373. /*
  374. * Environment variables passed back from 'openconnect':
  375. *
  376. * VPNGATEWAY -- vpn gateway address (always present)
  377. * TUNDEV -- tunnel device (always present)
  378. * INTERNAL_IP4_ADDRESS -- address (always present)
  379. * INTERNAL_IP4_NETMASK -- netmask (often unset)
  380. * INTERNAL_IP4_DNS -- list of dns serverss
  381. * INTERNAL_IP4_NBNS -- list of wins servers
  382. * CISCO_DEF_DOMAIN -- default domain name
  383. * CISCO_BANNER -- banner from server
  384. *
  385. */
  386. int
  387. main (int argc, char *argv[])
  388. {
  389. DBusGConnection *connection;
  390. char *tmp;
  391. GHashTable *config, *ip4config, *ip6config;
  392. GValue *val;
  393. GError *err = NULL;
  394. struct in_addr temp_addr;
  395. #if !GLIB_CHECK_VERSION (2, 35, 0)
  396. g_type_init ();
  397. #endif
  398. /* openconnect gives us a "reason" code. If we are given one,
  399. * don't proceed unless its "connect".
  400. */
  401. tmp = getenv ("reason");
  402. if (tmp && strcmp (tmp, "connect") != 0)
  403. exit (0);
  404. connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
  405. if (!connection) {
  406. g_warning ("Could not get the system bus: %s", err->message);
  407. exit (1);
  408. }
  409. config = g_hash_table_new (g_str_hash, g_str_equal);
  410. ip4config = g_hash_table_new (g_str_hash, g_str_equal);
  411. ip6config = g_hash_table_new (g_str_hash, g_str_equal);
  412. /* Gateway */
  413. val = addr4_to_gvalue (getenv ("VPNGATEWAY"));
  414. if (!val)
  415. val = addr6_to_gvalue (getenv ("VPNGATEWAY"));
  416. if (val)
  417. g_hash_table_insert (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, val);
  418. else
  419. helper_failed (connection, "VPN Gateway");
  420. /* Tunnel device */
  421. val = str_to_gvalue (getenv ("TUNDEV"), FALSE);
  422. if (val)
  423. g_hash_table_insert (config, NM_VPN_PLUGIN_CONFIG_TUNDEV, val);
  424. else
  425. helper_failed (connection, "Tunnel Device");
  426. /* Banner */
  427. val = str_to_gvalue (getenv ("CISCO_BANNER"), TRUE);
  428. if (val)
  429. g_hash_table_insert (config, NM_VPN_PLUGIN_CONFIG_BANNER, val);
  430. /* Default domain */
  431. val = str_to_gvalue (getenv ("CISCO_DEF_DOMAIN"), TRUE);
  432. if (val)
  433. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN, val);
  434. /* MTU */
  435. tmp = getenv ("INTERNAL_IP4_MTU");
  436. if (tmp && strlen (tmp)) {
  437. long int mtu;
  438. errno = 0;
  439. mtu = strtol (tmp, NULL, 10);
  440. if (errno || mtu < 0 || mtu > 20000) {
  441. g_warning ("Ignoring invalid tunnel MTU '%s'", tmp);
  442. } else {
  443. val = uint_to_gvalue ((guint32) mtu);
  444. g_hash_table_insert (config, NM_VPN_PLUGIN_CONFIG_MTU, val);
  445. }
  446. }
  447. /* IPv4 address */
  448. val = addr4_to_gvalue (getenv ("INTERNAL_IP4_ADDRESS"));
  449. if (val)
  450. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val);
  451. else
  452. helper_failed (connection, "IP4 Address");
  453. /* IPv4 PTP address; for openconnect PTP address == internal IPv4 address */
  454. val = addr4_to_gvalue (getenv ("INTERNAL_IP4_ADDRESS"));
  455. if (val)
  456. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_PTP, val);
  457. else
  458. helper_failed (connection, "IP4 PTP Address");
  459. /* IPv4 Netmask */
  460. tmp = getenv ("INTERNAL_IP4_NETMASK");
  461. if (tmp && inet_pton (AF_INET, tmp, &temp_addr) > 0) {
  462. val = uint_to_gvalue (nm_utils_ip4_netmask_to_prefix (temp_addr.s_addr));
  463. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val);
  464. }
  465. /* DNS */
  466. val = addr4_list_to_gvalue (getenv ("INTERNAL_IP4_DNS"));
  467. if (val)
  468. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val);
  469. /* WINS servers */
  470. val = addr4_list_to_gvalue (getenv ("INTERNAL_IP4_NBNS"));
  471. if (val)
  472. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val);
  473. /* Split DNS domains */
  474. val = split_dns_list_to_gvalue (getenv ("CISCO_SPLIT_DNS"));
  475. if (val)
  476. g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS, val);
  477. /* Routes */
  478. val = get_ip4_routes ();
  479. if (val) {
  480. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, val);
  481. /* If routes-to-include were provided, that means no default route */
  482. g_hash_table_insert (ip4config, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
  483. bool_to_gvalue (TRUE));
  484. }
  485. /* IPv6 address */
  486. tmp = getenv ("INTERNAL_IP6_ADDRESS");
  487. if (tmp && strlen (tmp)) {
  488. val = addr6_to_gvalue (tmp);
  489. if (val)
  490. g_hash_table_insert (ip6config, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS, val);
  491. else
  492. helper_failed (connection, "IP6 Address");
  493. }
  494. /* IPv6 PTP address; for openconnect PTP address == internal IPv6 address */
  495. tmp = getenv ("INTERNAL_IP6_ADDRESS");
  496. if (tmp && strlen (tmp)) {
  497. val = addr6_to_gvalue (tmp);
  498. if (val)
  499. g_hash_table_insert (ip6config, NM_VPN_PLUGIN_IP6_CONFIG_PTP, val);
  500. else
  501. helper_failed (connection, "IP6 PTP Address");
  502. }
  503. /* IPv6 Netmask */
  504. tmp = getenv ("INTERNAL_IP6_NETMASK");
  505. if (tmp)
  506. tmp = strchr (tmp, '/');
  507. if (tmp) {
  508. val = uint_to_gvalue (strtol (tmp + 1, NULL, 10));
  509. g_hash_table_insert (ip6config, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX, val);
  510. }
  511. /* DNS */
  512. val = addr6_list_to_gvalue (getenv ("INTERNAL_IP6_DNS"));
  513. if (val)
  514. g_hash_table_insert (ip6config, NM_VPN_PLUGIN_IP6_CONFIG_DNS, val);
  515. /* Routes */
  516. val = get_ip6_routes ();
  517. if (val) {
  518. g_hash_table_insert (ip6config, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, val);
  519. /* If routes-to-include were provided, that means no default route */
  520. g_hash_table_insert (ip6config, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
  521. bool_to_gvalue (TRUE));
  522. }
  523. if (g_hash_table_size (ip4config)) {
  524. g_hash_table_insert (config, NM_VPN_PLUGIN_CONFIG_HAS_IP4,
  525. bool_to_gvalue (TRUE));
  526. } else {
  527. g_hash_table_destroy (ip4config);
  528. ip4config = NULL;
  529. }
  530. if (g_hash_table_size (ip6config)) {
  531. g_hash_table_insert (config, NM_VPN_PLUGIN_CONFIG_HAS_IP6,
  532. bool_to_gvalue (TRUE));
  533. } else {
  534. g_hash_table_destroy (ip6config);
  535. ip6config = NULL;
  536. }
  537. /* Send the config info to nm-openconnect-service */
  538. send_config (connection, config, ip4config, ip6config);
  539. exit (0);
  540. }