shill: vpn: Parse openvpn IP configuration options.
The options are pushed to shill over DBus through the .Task.notify service
method.
BUG=chromium-os:27056
TEST=unit tests
Change-Id: I98d7d49c275f49daba5a6dbe0af0878bf82038a6
Reviewed-on: https://gerrit.chromium.org/gerrit/17219
Tested-by: Darin Petkov <petkov@chromium.org>
Reviewed-by: mukesh agrawal <quiche@chromium.org>
Commit-Ready: Darin Petkov <petkov@chromium.org>
diff --git a/openvpn_driver.cc b/openvpn_driver.cc
index e90ef20..69a6d33 100644
--- a/openvpn_driver.cc
+++ b/openvpn_driver.cc
@@ -4,13 +4,19 @@
#include "shill/openvpn_driver.h"
+#include <arpa/inet.h>
+
#include <base/logging.h>
+#include <base/string_number_conversions.h>
+#include <base/string_util.h>
#include <chromeos/dbus/service_constants.h>
#include "shill/device_info.h"
+#include "shill/dhcp_config.h"
#include "shill/error.h"
#include "shill/rpc_task.h"
+using std::map;
using std::string;
using std::vector;
@@ -18,7 +24,16 @@
namespace {
const char kOpenVPNScript[] = "/usr/lib/flimflam/scripts/openvpn-script";
-} // namespace {}
+const char kOpenVPNForeignOptionPrefix[] = "foreign_option_";
+const char kOpenVPNIfconfigBroadcast[] = "ifconfig_broadcast";
+const char kOpenVPNIfconfigLocal[] = "ifconfig_local";
+const char kOpenVPNIfconfigNetmask[] = "ifconfig_netmask";
+const char kOpenVPNIfconfigRemote[] = "ifconfig_remote";
+const char kOpenVPNRouteOptionPrefix[] = "route_";
+const char kOpenVPNRouteVPNGateway[] = "route_vpn_gateway";
+const char kOpenVPNTrustedIP[] = "trusted_ip";
+const char kOpenVPNTunMTU[] = "tun_mtu";
+} // namespace
OpenVPNDriver::OpenVPNDriver(ControlInterface *control,
DeviceInfo *device_info,
@@ -43,6 +58,93 @@
return true;
}
+bool OpenVPNDriver::Notify(const string &reason,
+ const map<string, string> &dict) {
+ VLOG(2) << __func__ << "(" << reason << ")";
+ if (reason != "up") {
+ return false;
+ }
+ IPConfig::Properties properties;
+ ParseIPConfiguration(dict, &properties);
+ // TODO(petkov): Apply the properties to a VPNDevice's IPConfig.
+ return true;
+}
+
+// static
+void OpenVPNDriver::ParseIPConfiguration(
+ const map<string, string> &configuration,
+ IPConfig::Properties *properties) {
+ ForeignOptions foreign_options;
+ string trusted_ip;
+ properties->address_family = IPAddress::kFamilyIPv4;
+ for (map<string, string>::const_iterator it = configuration.begin();
+ it != configuration.end(); ++it) {
+ const string &key = it->first;
+ const string &value = it->second;
+ VLOG(2) << "Processing: " << key << " -> " << value;
+ if (LowerCaseEqualsASCII(key, kOpenVPNIfconfigLocal)) {
+ properties->address = value;
+ } else if (LowerCaseEqualsASCII(key, kOpenVPNIfconfigBroadcast)) {
+ properties->broadcast_address = value;
+ } else if (LowerCaseEqualsASCII(key, kOpenVPNIfconfigNetmask)) {
+ properties->subnet_cidr =
+ IPAddress::GetPrefixLengthFromMask(properties->address_family, value);
+ } else if (LowerCaseEqualsASCII(key, kOpenVPNIfconfigRemote)) {
+ properties->peer_address = value;
+ } else if (LowerCaseEqualsASCII(key, kOpenVPNRouteVPNGateway)) {
+ properties->gateway = value;
+ } else if (LowerCaseEqualsASCII(key, kOpenVPNTrustedIP)) {
+ trusted_ip = value;
+ } else if (LowerCaseEqualsASCII(key, kOpenVPNTunMTU)) {
+ int mtu = 0;
+ if (base::StringToInt(value, &mtu) && mtu >= DHCPConfig::kMinMTU) {
+ properties->mtu = mtu;
+ } else {
+ LOG(ERROR) << "MTU " << value << " ignored.";
+ }
+ } else if (StartsWithASCII(key, kOpenVPNForeignOptionPrefix, false)) {
+ const string suffix = key.substr(strlen(kOpenVPNForeignOptionPrefix));
+ int order = 0;
+ if (base::StringToInt(suffix, &order)) {
+ foreign_options[order] = value;
+ } else {
+ LOG(ERROR) << "Ignored unexpected foreign option suffix: " << suffix;
+ }
+ } else if (StartsWithASCII(key, kOpenVPNRouteOptionPrefix, false)) {
+ // TODO(petkov): Process the route.
+ } else {
+ VLOG(2) << "Key ignored.";
+ }
+ }
+ // TODO(petkov): If gateway and trusted_ip, pin a host route to VPN server.
+ ParseForeignOptions(foreign_options, properties);
+}
+
+// static
+void OpenVPNDriver::ParseForeignOptions(const ForeignOptions &options,
+ IPConfig::Properties *properties) {
+ for (ForeignOptions::const_iterator it = options.begin();
+ it != options.end(); ++it) {
+ ParseForeignOption(it->second, properties);
+ }
+}
+
+// static
+void OpenVPNDriver::ParseForeignOption(const string &option,
+ IPConfig::Properties *properties) {
+ VLOG(2) << __func__ << "(" << option << ")";
+ vector<string> tokens;
+ if (Tokenize(option, " ", &tokens) != 3 ||
+ !LowerCaseEqualsASCII(tokens[0], "dhcp-option")) {
+ return;
+ }
+ if (LowerCaseEqualsASCII(tokens[1], "domain")) {
+ properties->domain_search.push_back(tokens[2]);
+ } else if (LowerCaseEqualsASCII(tokens[1], "dns")) {
+ properties->dns_servers.push_back(tokens[2]);
+ }
+}
+
void OpenVPNDriver::Connect(Error *error) {
// TODO(petkov): Allocate rpc_task_.
error->Populate(Error::kNotSupported);