static void update_connection (NMDevice *device, NMConnection *connection) { NMDeviceTun *self = NM_DEVICE_TUN (device); NMSettingTun *s_tun = nm_connection_get_setting_tun (connection); NMPlatformTunProperties props; NMSettingTunMode mode; gint64 user, group; char *str; if (!s_tun) { s_tun = (NMSettingTun *) nm_setting_tun_new (); nm_connection_add_setting (connection, (NMSetting *) s_tun); } if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { _LOGW (LOGD_HW, "failed to get TUN interface info while updating connection."); return; } mode = tun_mode_from_string (props.mode); if (mode != nm_setting_tun_get_mode (s_tun)) g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, mode, NULL); user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); if (props.owner != user) { str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL; g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_OWNER, str, NULL); g_free (str); } if (props.group != group) { str = props.group >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.group) : NULL; g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_GROUP, str, NULL); g_free (str); } if ((!props.no_pi) != nm_setting_tun_get_pi (s_tun)) g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, !props.no_pi, NULL); if (props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun)) g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, props.vnet_hdr, NULL); if (props.multi_queue != nm_setting_tun_get_multi_queue (s_tun)) g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, props.multi_queue, NULL); }
int plugin_init (void) { GDBusConnection *bus; GError *error = NULL; const char *bus_name; nm_g_type_init (); g_return_val_if_fail (!gl.proxy, -1); bus_name = getenv ("NM_DBUS_SERVICE_L2TP"); if (!bus_name) bus_name = NM_DBUS_SERVICE_L2TP; gl.log_level = _nm_utils_ascii_str_to_int64 (getenv ("NM_VPN_LOG_LEVEL"), 10, 0, LOG_DEBUG, LOG_NOTICE); gl.log_prefix_token = getenv ("NM_VPN_LOG_PREFIX_TOKEN") ?: "???"; _LOGI ("initializing"); bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (!bus) { _LOGE ("couldn't connect to system bus: %s", error->message); g_error_free (error); return -1; } gl.proxy = g_dbus_proxy_new_sync (bus, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, bus_name, NM_DBUS_PATH_L2TP_PPP, NM_DBUS_INTERFACE_L2TP_PPP, NULL, &error); g_object_unref (bus); if (!gl.proxy) { _LOGE ("couldn't create D-Bus proxy: %s", error->message); g_error_free (error); return -1; } chap_passwd_hook = get_credentials; chap_check_hook = get_chap_check; pap_passwd_hook = get_credentials; pap_check_hook = get_pap_check; #ifdef USE_EAPTLS eaptls_passwd_hook = get_credentials; #endif add_notifier (&phasechange, nm_phasechange, NULL); add_notifier (&ip_up_notifier, nm_ip_up, NULL); add_notifier (&exitnotify, nm_exit_notify, NULL); return 0; }
static void handle_event (GDBusConnection *connection, const char *sender_name, const char *object_path, const char *interface_name, const char *signal_name, GVariant *parameters, gpointer user_data) { NMDhcpListener *self = NM_DHCP_LISTENER (user_data); char *iface = NULL; char *pid_str = NULL; char *reason = NULL; gint pid; gboolean handled = FALSE; GVariant *options; if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) return; g_variant_get (parameters, "(@a{sv})", &options); iface = get_option (options, "interface"); if (iface == NULL) { nm_log_warn (LOGD_DHCP, "DHCP event: didn't have associated interface."); goto out; } pid_str = get_option (options, "pid"); pid = _nm_utils_ascii_str_to_int64 (pid_str, 10, 0, G_MAXINT32, -1); if (pid == -1) { nm_log_warn (LOGD_DHCP, "DHCP event: couldn't convert PID '%s' to an integer", pid_str ? pid_str : "(null)"); goto out; } reason = get_option (options, "reason"); if (reason == NULL) { nm_log_warn (LOGD_DHCP, "(pid %d) DHCP event didn't have a reason", pid); goto out; } g_signal_emit (self, signals[EVENT], 0, iface, pid, options, reason, &handled); if (!handled) { if (g_ascii_strcasecmp (reason, "RELEASE") == 0) { /* Ignore event when the dhcp client gets killed and we receive its last message */ nm_log_dbg (LOGD_DHCP, "(pid %d) unhandled RELEASE DHCP event for interface %s", pid, iface); } else nm_log_warn (LOGD_DHCP, "(pid %d) unhandled DHCP event for interface %s", pid, iface); } out: g_free (iface); g_free (pid_str); g_free (reason); g_variant_unref (options); }
static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); NMSettingTunMode mode; NMSettingTun *s_tun; gint64 user, group; if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) return FALSE; s_tun = nm_connection_get_setting_tun (connection); if (!s_tun) return FALSE; if (nm_device_is_real (device)) { mode = tun_mode_from_string (priv->mode); if (mode != nm_setting_tun_get_mode (s_tun)) return FALSE; user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); if (user != priv->props.owner) return FALSE; if (group != priv->props.group) return FALSE; if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi) return FALSE; if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) return FALSE; if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) return FALSE; } return TRUE; }
static gboolean create_and_realize (NMDevice *device, NMConnection *connection, NMDevice *parent, const NMPlatformLink **out_plink, GError **error) { const char *iface = nm_device_get_iface (device); NMPlatformError plerr; NMSettingTun *s_tun; gint64 user, group; s_tun = nm_connection_get_setting_tun (connection); g_assert (s_tun); user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); plerr = nm_platform_link_tun_add (NM_PLATFORM_GET, iface, nm_setting_tun_get_mode (s_tun) == NM_SETTING_TUN_MODE_TAP, user, group, nm_setting_tun_get_pi (s_tun), nm_setting_tun_get_vnet_hdr (s_tun), nm_setting_tun_get_multi_queue (s_tun), out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create TUN/TAP interface '%s' for '%s': %s", iface, nm_connection_get_id (connection), nm_platform_error_to_string (plerr)); return FALSE; } return TRUE; }
static gboolean create_and_realize (NMDevice *device, NMConnection *connection, NMDevice *parent, const NMPlatformLink **out_plink, GError **error) { const char *iface = nm_device_get_iface (device); NMSettingIPTunnel *s_ip_tunnel; NMPlatformError plerr; NMPlatformLnkGre lnk_gre = { }; NMPlatformLnkSit lnk_sit = { }; NMPlatformLnkIpIp lnk_ipip = { }; NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; const char *str; gint64 val; s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); g_assert (s_ip_tunnel); switch (nm_setting_ip_tunnel_get_mode (s_ip_tunnel)) { case NM_IP_TUNNEL_MODE_GRE: if (parent) lnk_gre.parent_ifindex = nm_device_get_ifindex (parent); str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); if (str) inet_pton (AF_INET, str, &lnk_gre.local); str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); g_assert (str); inet_pton (AF_INET, str, &lnk_gre.remote); lnk_gre.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); lnk_gre.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); lnk_gre.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), 10, 0, G_MAXUINT32, -1); if (val != -1) { lnk_gre.input_key = val; lnk_gre.input_flags = NM_GRE_KEY; } val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel), 10, 0, G_MAXUINT32, -1); if (val != -1) { lnk_gre.output_key = val; lnk_gre.output_flags = NM_GRE_KEY; } plerr = nm_platform_link_gre_add (NM_PLATFORM_GET, iface, &lnk_gre, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create GRE interface '%s' for '%s': %s", iface, nm_connection_get_id (connection), nm_platform_error_to_string (plerr)); return FALSE; } break; case NM_IP_TUNNEL_MODE_SIT: if (parent) lnk_sit.parent_ifindex = nm_device_get_ifindex (parent); str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); if (str) inet_pton (AF_INET, str, &lnk_sit.local); str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); g_assert (str); inet_pton (AF_INET, str, &lnk_sit.remote); lnk_sit.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); lnk_sit.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); lnk_sit.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); plerr = nm_platform_link_sit_add (NM_PLATFORM_GET, iface, &lnk_sit, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create SIT interface '%s' for '%s': %s", iface, nm_connection_get_id (connection), nm_platform_error_to_string (plerr)); return FALSE; } break; case NM_IP_TUNNEL_MODE_IPIP: if (parent) lnk_ipip.parent_ifindex = nm_device_get_ifindex (parent); str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); if (str) inet_pton (AF_INET, str, &lnk_ipip.local); str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); g_assert (str); inet_pton (AF_INET, str, &lnk_ipip.remote); lnk_ipip.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); lnk_ipip.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); lnk_ipip.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); plerr = nm_platform_link_ipip_add (NM_PLATFORM_GET, iface, &lnk_ipip, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create IPIP interface '%s' for '%s': %s", iface, nm_connection_get_id (connection), nm_platform_error_to_string (plerr)); return FALSE; } break; case NM_IP_TUNNEL_MODE_IPIP6: case NM_IP_TUNNEL_MODE_IP6IP6: if (parent) lnk_ip6tnl.parent_ifindex = nm_device_get_ifindex (parent); str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); if (str) inet_pton (AF_INET6, str, &lnk_ip6tnl.local); str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); g_assert (str); inet_pton (AF_INET6, str, &lnk_ip6tnl.remote); lnk_ip6tnl.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); lnk_ip6tnl.tclass = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel); lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel); lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6; plerr = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, iface, &lnk_ip6tnl, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create IPIP interface '%s' for '%s': %s", iface, nm_connection_get_id (connection), nm_platform_error_to_string (plerr)); return FALSE; } break; default: g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create IP tunnel interface '%s' for '%s': mode %d not supported", iface, nm_connection_get_id (connection), (int) nm_setting_ip_tunnel_get_mode (s_ip_tunnel)); return FALSE; } return TRUE; }
int main (int argc, char *argv[]) { NMDBusLibreswanHelper *proxy; GVariantBuilder environment; GError *err = NULL; gchar **env; gchar **p; const char *bus_name = NM_DBUS_SERVICE_LIBRESWAN; char *str = NULL; char **i_env; #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); #endif /* support old command line arguments. The only reason for that is to * support update of the plugin while being connected. */ switch (argc) { case 1: break; case 4: gl.log_level = _nm_utils_ascii_str_to_int64 (argv[1], 10, 0, LOG_DEBUG, 0); gl.log_prefix_token = argv[2]; bus_name = argv[3]; break; case 3: if (strcmp (argv[1], "--bus-name") == 0) { bus_name = argv[2]; break; } /* fallthrough */ default: g_printerr ("Usage: %s <LEVEL> <PREFIX_TOKEN> <BUS_NAME>\n", argv[0]); exit (1); } if (!g_dbus_is_name (bus_name)) { g_printerr ("Not a valid bus name: '%s'\n", bus_name); exit (1); } _LOGD ("command line: %s", (str = g_strjoinv (" ", argv))); g_clear_pointer (&str, g_free); for (i_env = environ; i_env && *i_env; i_env++) _LOGD ("environment: %s", *i_env); proxy = nmdbus_libreswan_helper_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, bus_name, NM_DBUS_PATH_LIBRESWAN_HELPER, NULL, &err); if (!proxy) { _LOGW ("Could not create a D-Bus proxy: %s", err->message); g_error_free (err); exit (1); } g_variant_builder_init (&environment, G_VARIANT_TYPE ("a{ss}")); env = g_listenv (); for (p = env; *p; p++) { if (strncmp ("PLUTO_", *p, 6)) continue; g_variant_builder_add (&environment, "{ss}", *p, g_getenv (*p)); } g_strfreev (env); if (!nmdbus_libreswan_helper_call_callback_sync (proxy, g_variant_builder_end (&environment), NULL, &err)) { _LOGW ("Could not call the plugin: %s", err->message); g_error_free (err); g_object_unref (proxy); exit (1); } g_object_unref (proxy); exit (0); }
static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingIPTunnelPrivate *priv = NM_SETTING_IP_TUNNEL_GET_PRIVATE (setting); int family = AF_UNSPEC; switch (priv->mode) { case NM_IP_TUNNEL_MODE_IPIP: case NM_IP_TUNNEL_MODE_SIT: case NM_IP_TUNNEL_MODE_ISATAP: case NM_IP_TUNNEL_MODE_GRE: case NM_IP_TUNNEL_MODE_VTI: family = AF_INET; break; case NM_IP_TUNNEL_MODE_IP6IP6: case NM_IP_TUNNEL_MODE_IPIP6: case NM_IP_TUNNEL_MODE_IP6GRE: case NM_IP_TUNNEL_MODE_VTI6: family = AF_INET6; break; case NM_IP_TUNNEL_MODE_UNKNOWN: break; } if (family == AF_UNSPEC) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("'%d' is not a valid tunnel mode"), (int) priv->mode); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_MODE); return FALSE; } if ( priv->parent && !nm_utils_iface_valid_name (priv->parent) && !nm_utils_is_uuid (priv->parent)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("'%s' is neither an UUID nor an interface name"), priv->parent); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_PARENT); return FALSE; } if (priv->local && !nm_utils_ipaddr_valid (family, priv->local)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("'%s' is not a valid IPv%c address"), priv->local, family == AF_INET ? '4' : '6'); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_LOCAL); return FALSE; } if (!priv->remote) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("property is missing")); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_REMOTE); return FALSE; } if (!nm_utils_ipaddr_valid (family, priv->remote)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("'%s' is not a valid IPv%c address"), priv->remote, family == AF_INET ? '4' : '6'); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_REMOTE); return FALSE; } if ( (priv->input_key && priv->input_key[0]) || (priv->output_key && priv->output_key[0])) { if ( priv->mode != NM_IP_TUNNEL_MODE_GRE && priv->mode != NM_IP_TUNNEL_MODE_IP6GRE) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("tunnel keys can only be specified for GRE tunnels")); return FALSE; } } if (priv->input_key && priv->input_key[0]) { gint64 val; val = _nm_utils_ascii_str_to_int64 (priv->input_key, 10, 0, G_MAXUINT32, -1); if (val == -1) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("'%s' is not a valid tunnel key"), priv->input_key); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_INPUT_KEY); return FALSE; } } if (priv->output_key && priv->output_key[0]) { gint64 val; val = _nm_utils_ascii_str_to_int64 (priv->output_key, 10, 0, G_MAXUINT32, -1); if (val == -1) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("'%s' is not a valid tunnel key"), priv->output_key); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_OUTPUT_KEY); return FALSE; } } if (!priv->path_mtu_discovery && priv->ttl != 0) { g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, _("a fixed TTL is allowed only when path MTU discovery is enabled")); g_prefix_error (error, "%s.%s: ", NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_IP_TUNNEL_TTL); return FALSE; } return TRUE; }
int main (int argc, char *argv[]) { GDBusProxy *proxy; GVariantBuilder builder, ip4builder, ip6builder; GVariant *ip4config, *ip6config; char *tmp; GVariant *val; int i; GError *err = NULL; GPtrArray *dns4_list, *dns6_list; GPtrArray *nbns_list; GPtrArray *dns_domains; struct in_addr temp_addr; int tapdev = -1; char **iter; int shift = 0; gboolean is_restart; gboolean has_ip4_prefix = FALSE; gboolean has_ip4_address = FALSE; gboolean has_ip6_address = FALSE; gchar *bus_name = NM_DBUS_SERVICE_OPENVPN; #if !GLIB_CHECK_VERSION (2, 35, 0) g_type_init (); #endif for (i = 1; i < argc; i++) { if (!strcmp (argv[i], "--")) { i++; break; } if (nm_streq (argv[i], "--debug")) { if (i + 2 >= argc) { g_printerr ("Missing debug arguments (requires <LEVEL> <PREFIX_TOKEN>)\n"); exit (1); } gl.log_level = _nm_utils_ascii_str_to_int64 (argv[++i], 10, 0, LOG_DEBUG, 0); gl.log_prefix_token = argv[++i]; } else if (!strcmp (argv[i], "--tun")) tapdev = 0; else if (!strcmp (argv[i], "--tap")) tapdev = 1; else if (!strcmp (argv[i], "--bus-name")) { if (++i == argc) { g_printerr ("Missing bus name argument\n"); exit (1); } if (!g_dbus_is_name (argv[i])) { g_printerr ("Invalid bus name\n"); exit (1); } bus_name = argv[i]; } else break; } shift = i - 1; if (_LOGD_enabled ()) { GString *args; args = g_string_new (NULL); for (i = 0; i < argc; i++) { if (i > 0) g_string_append_c (args, ' '); if (shift && 1 + shift == i) g_string_append (args, " "); tmp = g_strescape (argv[i], NULL); g_string_append_printf (args, "\"%s\"", tmp); g_free (tmp); } _LOGD ("command line: %s", args->str); g_string_free (args, TRUE); for (iter = environ; iter && *iter; iter++) _LOGD ("environment: %s", *iter); } /* shift the arguments to the right leaving only those provided by openvpn */ argv[shift] = argv[0]; argv += shift; argc -= shift; is_restart = argc >= 7 && !g_strcmp0 (argv[6], "restart"); proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, bus_name, NM_VPN_DBUS_PLUGIN_PATH, NM_VPN_DBUS_PLUGIN_INTERFACE, NULL, &err); if (!proxy) { _LOGW ("Could not create a D-Bus proxy: %s", err->message); g_error_free (err); exit (1); } g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT); g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT); /* External world-visible VPN gateway */ val = trusted_remote_to_gvariant (); if (val) g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, val); else helper_failed (proxy, "VPN Gateway"); /* Internal VPN subnet gateway */ tmp = getenv ("route_vpn_gateway"); val = addr4_to_gvariant (tmp); if (val) g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, val); else { val = addr6_to_gvariant (tmp); if (val) g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, val); } /* VPN device */ tmp = getenv ("dev"); val = str_to_gvariant (tmp, FALSE); if (val) g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_TUNDEV, val); else helper_failed (proxy, "Tunnel Device"); if (tapdev == -1) tapdev = strncmp (tmp, "tap", 3) == 0; /* IPv4 address */ tmp = getenv ("ifconfig_local"); if (!tmp && is_restart) tmp = argv[4]; if (tmp && strlen (tmp)) { val = addr4_to_gvariant (tmp); if (val) { has_ip4_address = TRUE; g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val); } else helper_failed (proxy, "IP4 Address"); } /* PTP address; for vpnc PTP address == internal IP4 address */ tmp = getenv ("ifconfig_remote"); if (!tmp && is_restart) tmp = argv[5]; val = addr4_to_gvariant (tmp); if (val) { /* Sigh. Openvpn added 'topology' stuff in 2.1 that changes the meaning * of the ifconfig bits without actually telling you what they are * supposed to mean; basically relying on specific 'ifconfig' behavior. */ if (tmp && !strncmp (tmp, "255.", 4)) { guint32 addr; /* probably a netmask, not a PTP address; topology == subnet */ addr = g_variant_get_uint32 (val); g_variant_unref (val); val = g_variant_new_uint32 (nm_utils_ip4_netmask_to_prefix (addr)); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); has_ip4_prefix = TRUE; } else g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PTP, val); } /* Netmask * * Either TAP or TUN modes can have an arbitrary netmask in newer versions * of openvpn, while in older versions only TAP mode would. So accept a * netmask if passed, otherwise default to /32 for TUN devices since they * are usually point-to-point. */ tmp = getenv ("ifconfig_netmask"); if (tmp && inet_pton (AF_INET, tmp, &temp_addr) > 0) { val = g_variant_new_uint32 (nm_utils_ip4_netmask_to_prefix (temp_addr.s_addr)); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); } else if (!tapdev) { if (has_ip4_address && !has_ip4_prefix) { val = g_variant_new_uint32 (32); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); } } else _LOGW ("No IP4 netmask/prefix (missing or invalid 'ifconfig_netmask')"); val = get_ip4_routes (); if (val) g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, val); else if (is_restart) { g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, g_variant_new_boolean (TRUE)); } /* IPv6 address */ tmp = getenv ("ifconfig_ipv6_local"); if (tmp && strlen (tmp)) { val = addr6_to_gvariant (tmp); if (val) { g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS, val); has_ip6_address = TRUE; } else helper_failed (proxy, "IP6 Address"); } /* IPv6 remote address */ tmp = getenv ("ifconfig_ipv6_remote"); if (tmp && strlen (tmp)) { val = addr6_to_gvariant (tmp); if (val) g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PTP, val); else helper_failed (proxy, "IP6 PTP Address"); } /* IPv6 netbits */ tmp = getenv ("ifconfig_ipv6_netbits"); if (tmp && strlen (tmp)) { long int netbits; errno = 0; netbits = strtol (tmp, NULL, 10); if (errno || netbits < 0 || netbits > 128) { _LOGW ("Ignoring invalid prefix '%s'", tmp); } else { val = g_variant_new_uint32 ((guint32) netbits); g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX, val); } } val = get_ip6_routes (); if (val) g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, val); else if (is_restart) { g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, g_variant_new_boolean (TRUE)); } /* DNS and WINS servers */ dns_domains = g_ptr_array_sized_new (3); dns4_list = g_ptr_array_new (); dns6_list = g_ptr_array_new (); nbns_list = g_ptr_array_new (); for (i = 1; i < 256; i++) { char *env_name; env_name = g_strdup_printf ("foreign_option_%d", i); tmp = getenv (env_name); g_free (env_name); if (!tmp || strlen (tmp) < 1) break; if (!g_str_has_prefix (tmp, "dhcp-option ")) continue; tmp += 12; /* strlen ("dhcp-option ") */ if (g_str_has_prefix (tmp, "DNS ")) parse_addr_list (dns4_list, dns6_list, tmp + 4); else if (g_str_has_prefix (tmp, "WINS ")) parse_addr_list (nbns_list, NULL, tmp + 5); else if (g_str_has_prefix (tmp, "DOMAIN ") && is_domain_valid (tmp + 7)) g_ptr_array_add (dns_domains, tmp + 7); } if (dns4_list->len) { val = g_variant_new_array (G_VARIANT_TYPE_UINT32, (GVariant **) dns4_list->pdata, dns4_list->len); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS, val); } if (has_ip6_address && dns6_list->len) { val = g_variant_new_array (G_VARIANT_TYPE ("ay"), (GVariant **) dns6_list->pdata, dns6_list->len); g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS, val); } if (nbns_list->len) { val = g_variant_new_array (G_VARIANT_TYPE_UINT32, (GVariant **) nbns_list->pdata, nbns_list->len); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val); } if (dns_domains->len) { val = g_variant_new_strv ((const gchar **) dns_domains->pdata, dns_domains->len); g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS, val); /* Domains apply to both IPv4 and IPv6 configurations */ if (has_ip6_address) { val = g_variant_new_strv ((const gchar **) dns_domains->pdata, dns_domains->len); g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS, val); } } g_ptr_array_unref (dns4_list); g_ptr_array_unref (dns6_list); g_ptr_array_unref (nbns_list); g_ptr_array_unref (dns_domains); /* Tunnel MTU */ tmp = getenv ("tun_mtu"); if (tmp && strlen (tmp)) { long int mtu; errno = 0; mtu = strtol (tmp, NULL, 10); if (errno || mtu < 0 || mtu > 20000) { _LOGW ("Ignoring invalid tunnel MTU '%s'", tmp); } else { val = g_variant_new_uint32 ((guint32) mtu); g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_MTU, val); } } ip4config = g_variant_builder_end (&ip4builder); if (g_variant_n_children (ip4config)) { val = g_variant_new_boolean (TRUE); g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4, val); } else { g_variant_unref (ip4config); ip4config = NULL; } ip6config = g_variant_builder_end (&ip6builder); if (g_variant_n_children (ip6config)) { val = g_variant_new_boolean (TRUE); g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6, val); } else { g_variant_unref (ip6config); ip6config = NULL; } if (!ip4config && !ip6config) helper_failed (proxy, "IPv4 or IPv6 configuration"); /* Send the config info to nm-openvpn-service */ send_config (proxy, g_variant_builder_end (&builder), ip4config, ip6config); g_object_unref (proxy); return 0; }