diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 557558c..60817e4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,6 +66,7 @@ set(SOURCES anbox/build/version.h.in anbox/android/intent.cpp + anbox/android/ip_config_builder.cpp anbox/common/fd.cpp anbox/common/fd_sets.h diff --git a/src/anbox/android/ip_config_builder.cpp b/src/anbox/android/ip_config_builder.cpp new file mode 100644 index 0000000..fa10610 --- /dev/null +++ b/src/anbox/android/ip_config_builder.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#include "anbox/android/ip_config_builder.h" + +#include + +#include +#include + +namespace { +constexpr const char *assignment_key{"ipAssignment"}; +constexpr const char *link_address_key{"linkAddress"}; +constexpr const char *gateway_key{"gateway"}; +constexpr const char *dns_key{"dns"}; +constexpr const char *id_key{"id"}; +constexpr const char *eos_key{"eos"}; +constexpr const char *assignment_static{"STATIC"}; +constexpr const char *assignment_dhcp{"DHCP"}; +constexpr const char *assignment_unknown{"UNKNOWN"}; + +namespace aa = anbox::android; +std::string assignment_to_string(const aa::IpConfigBuilder::Assignment &value) { + switch (value) { + case anbox::android::IpConfigBuilder::Assignment::Static: + return assignment_static; + break; + case anbox::android::IpConfigBuilder::Assignment::DHCP: + return assignment_dhcp; + break; + default: + break; + } + return assignment_unknown; +} +} + +namespace anbox { +namespace android { +std::size_t IpConfigBuilder::write(common::BinaryWriter &writer) { + writer.set_byte_order(common::BinaryWriter::Order::Big); + + writer.write_unsigned_long(static_cast(version_)); + + writer.write_string_with_size(assignment_key); + writer.write_string_with_size(assignment_to_string(assignment_)); + + writer.write_string_with_size(link_address_key); + writer.write_string_with_size(link_.address); + writer.write_unsigned_long(link_.prefix_length); + + writer.write_string_with_size(gateway_key); + writer.write_unsigned_long(0); + writer.write_unsigned_long(1); + writer.write_string_with_size(gateway_); + + writer.write_string_with_size(dns_key); + for (const auto &server : dns_servers_) + writer.write_string_with_size(server); + + writer.write_string_with_size(id_key); + writer.write_unsigned_long(id_); + + writer.write_string_with_size(eos_key); + + return writer.bytes_written(); +} + +void IpConfigBuilder::set_version(const Version &version) { + version_ = version; +} + +void IpConfigBuilder::set_assignment(const Assignment &assignment) { + assignment_ = assignment; +} + +void IpConfigBuilder::set_link_address(const std::string &address, uint32_t prefix_length) { + link_.address = address; + link_.prefix_length = prefix_length; +} + +void IpConfigBuilder::set_gateway(const std::string &gateway) { + gateway_ = gateway; +} + +void IpConfigBuilder::set_dns_servers(const std::vector &dns_servers) { + dns_servers_ = dns_servers; +} + +void IpConfigBuilder::set_id(uint32_t id) { + id_ = id; +} +} // namespace android +} // namespace anbox diff --git a/src/anbox/android/ip_config_builder.h b/src/anbox/android/ip_config_builder.h new file mode 100644 index 0000000..6ae0db0 --- /dev/null +++ b/src/anbox/android/ip_config_builder.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2017 Simon Fels + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3, as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + * + */ + +#ifndef ANBOX_ANDROID_IPCONFIGBUILDER_H_ +#define ANBOX_ANDROID_IPCONFIGBUILDER_H_ + +#include "anbox/common/binary_writer.h" + +#include +#include +#include + +namespace anbox { +namespace android { +struct IpConfigBuilder { + enum class Version : std::uint32_t { + Version1 = 1, + Version2 = 2, + }; + + enum class Assignment { + Static, + DHCP, + }; + + std::size_t write(common::BinaryWriter &writer); + + void set_version(const Version &version); + void set_assignment(const Assignment &assignment); + void set_link_address(const std::string &address, std::uint32_t prefix_length); + void set_gateway(const std::string &gateway); + void set_dns_servers(const std::vector &dns_servers); + void set_id(std::uint32_t id); + + private: + Version version_; + Assignment assignment_; + struct { + std::string address; + std::uint32_t prefix_length; + } link_; + std::string gateway_; + std::vector dns_servers_; + std::uint32_t id_; +}; +} // namespace android +} // namespace anbox + +#endif diff --git a/src/anbox/container/lxc_container.cpp b/src/anbox/container/lxc_container.cpp index 3faf842..b8c0cf8 100644 --- a/src/anbox/container/lxc_container.cpp +++ b/src/anbox/container/lxc_container.cpp @@ -15,6 +15,7 @@ * */ +#include "anbox/android/ip_config_builder.h" #include "anbox/container/lxc_container.h" #include "anbox/config.h" #include "anbox/logger.h" @@ -22,6 +23,7 @@ #include #include +#include #include #include @@ -76,6 +78,53 @@ void LxcContainer::setup_id_maps() { max_id - creds_.gid() - 1)); } +void LxcContainer::setup_network() { + if (!fs::exists("/sys/class/net/anbox0")) { + WARNING("Anbox bridge interface 'anbox0' doesn't exist. Network functionality will not be available"); + return; + } + + set_config_item("lxc.network.type", "veth"); + set_config_item("lxc.network.flags", "up"); + set_config_item("lxc.network.link", "anbox0"); + + // Instead of relying on DHCP we will give Android a static IP configuration + // for the virtual ethernet interface LXC creates for us. This will be bridged + // to the host and will allows us to have reliable network connectivity and + // not depend on any other system service. + // + // See http://androidxref.com/7.1.1_r6/xref/frameworks/base/core/java/android/net/IpConfiguration.java + // for more details of the IP configuration format used here. + + android::IpConfigBuilder ip_conf; + ip_conf.set_version(android::IpConfigBuilder::Version::Version2); + ip_conf.set_assignment(android::IpConfigBuilder::Assignment::Static); + ip_conf.set_link_address("192.168.250.2", 24); + ip_conf.set_gateway("192.168.250.1"); + ip_conf.set_dns_servers({"8.8.8.8"}); + ip_conf.set_id(0); + + std::vector buffer(512); + common::BinaryWriter writer(buffer.begin(), buffer.end()); + const auto size = ip_conf.write(writer); + + const auto ip_conf_dir = SystemConfiguration::instance().data_dir() / "data" / "misc" / "ethernet"; + if (!fs::exists(ip_conf_dir)) + fs::create_directories(ip_conf_dir); + + const auto ip_conf_path = ip_conf_dir / "ipconfig.txt"; + if (fs::exists(ip_conf_path)) + fs::remove(ip_conf_path); + + std::ofstream f(ip_conf_path.string(), std::ofstream::binary); + if (f.is_open()) { + f.write(reinterpret_cast(buffer.data()), size); + f.close(); + } else { + ERROR("Failed to write IP configuration. Network functionality will not be available."); + } +} + void LxcContainer::start(const Configuration &configuration) { if (getuid() != 0) BOOST_THROW_EXCEPTION(std::runtime_error("You have to start the container as root")); @@ -131,11 +180,7 @@ void LxcContainer::start(const Configuration &configuration) { const auto log_path = SystemConfiguration::instance().log_dir(); set_config_item("lxc.logfile", utils::string_format("%s/container.log", log_path).c_str()); - if (fs::exists("/sys/class/net/anboxbr0")) { - set_config_item("lxc.network.type", "veth"); - set_config_item("lxc.network.flags", "up"); - set_config_item("lxc.network.link", "anboxbr0"); - } + setup_network(); #if 0 // Android uses namespaces as well so we have to allow nested namespaces for LXC diff --git a/src/anbox/container/lxc_container.h b/src/anbox/container/lxc_container.h index 886a9d4..bc87760 100644 --- a/src/anbox/container/lxc_container.h +++ b/src/anbox/container/lxc_container.h @@ -39,6 +39,7 @@ class LxcContainer : public Container { private: void set_config_item(const std::string &key, const std::string &value); void setup_id_maps(); + void setup_network(); State state_; lxc_container *container_;