From c5f1a2724bfa802d8b2b197c4d159aa9eb63f300 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Wed, 10 May 2017 19:05:33 +0200 Subject: [PATCH 1/8] Implement BinaryWriter class to allow writing binary data --- src/CMakeLists.txt | 1 + src/anbox/common/binary_writer.cpp | 106 +++++++++++++++++++++ src/anbox/common/binary_writer.h | 57 +++++++++++ tests/anbox/common/CMakeLists.txt | 1 + tests/anbox/common/binary_writer_tests.cpp | 100 +++++++++++++++++++ 5 files changed, 265 insertions(+) create mode 100644 src/anbox/common/binary_writer.cpp create mode 100644 src/anbox/common/binary_writer.h create mode 100644 tests/anbox/common/binary_writer_tests.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 43eb183..557558c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -79,6 +79,7 @@ set(SOURCES anbox/common/loop_device.cpp anbox/common/loop_device_allocator.cpp anbox/common/mount_entry.cpp + anbox/common/binary_writer.cpp anbox/testing/gtest_utils.h diff --git a/src/anbox/common/binary_writer.cpp b/src/anbox/common/binary_writer.cpp new file mode 100644 index 0000000..f6d4973 --- /dev/null +++ b/src/anbox/common/binary_writer.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2016 Thomas Voss + * 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/common/binary_writer.h" + +#include +#include + +#include + +namespace { +bool is_little_endian() { + std::uint32_t v = 1; + return (*reinterpret_cast(&v) == 1); +} +} + +namespace anbox { +namespace common { + +BinaryWriter::BinaryWriter(std::vector::iterator begin, + std::vector::iterator end) : + begin_{begin}, current_{begin}, end_{end}, + byte_order_{is_little_endian() ? Order::Little : Order::Big} {} + +void BinaryWriter::set_byte_order(Order order) { + byte_order_ = order; +} + +void BinaryWriter::write_unsigned_short(std::uint16_t value) { + if (current_ + sizeof(value) > end_) + throw std::out_of_range{"Write buffer exhausted"}; + + std::uint16_t v = value; + switch (byte_order_) { + case Order::Big: + v = boost::endian::native_to_big(value); + break; + case Order::Little: + v = boost::endian::native_to_little(value); + break; + default: + break; + } + + *reinterpret_cast(&(*current_)) = v; + current_ += sizeof(v); +} + +void BinaryWriter::write_unsigned_long(std::uint32_t value) { + if (current_ + sizeof(value) > end_) + throw std::out_of_range{"Write buffer exhausted"}; + + std::uint32_t v = value; + switch (byte_order_) { + case Order::Big: + v = boost::endian::native_to_big(value); + break; + case Order::Little: + v = boost::endian::native_to_little(value); + break; + default: + break; + } + + *reinterpret_cast(&(*current_)) = v; + current_ += sizeof(v); +} + +void BinaryWriter::write_string(const char *s, std::size_t size) { + if (current_ + size > end_) + throw std::out_of_range{"Write buffer exhausted"}; + + memcpy(&(*current_), s, size); + current_ += size; +} + +void BinaryWriter::write_string_with_size(const std::string &str) { + write_string_with_size(str.c_str(), str.length()); +} + +void BinaryWriter::write_string_with_size(const char *s, std::size_t size) { + write_unsigned_short(size); + write_string(s, size); +} + +std::size_t BinaryWriter::bytes_written() const { + return current_ - begin_; +} +} // namespace common +} // namespace anbox diff --git a/src/anbox/common/binary_writer.h b/src/anbox/common/binary_writer.h new file mode 100644 index 0000000..f2aeefd --- /dev/null +++ b/src/anbox/common/binary_writer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 Thomas Voss + * 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_COMMON_BINARY_WRITER_H_ +#define ANBOX_COMMON_BINARY_WRITER_H_ + +#include +#include +#include + +namespace anbox { +namespace common { +class BinaryWriter { + public: + enum class Order { + Big, + Little, + }; + + explicit BinaryWriter(std::vector::iterator begin_, + std::vector::iterator end_); + + void set_byte_order(Order order); + + void write_unsigned_short(std::uint16_t value); + void write_unsigned_long(std::uint32_t value); + void write_string(const char *s, std::size_t size); + void write_string_with_size(const std::string &str); + void write_string_with_size(const char *s, std::size_t size); + + std::size_t bytes_written() const; + + private: + std::vector::iterator begin_; + std::vector::iterator current_; + std::vector::iterator end_; + Order byte_order_; +}; +} // namespace common +} // namespace anbox + +#endif diff --git a/tests/anbox/common/CMakeLists.txt b/tests/anbox/common/CMakeLists.txt index 4d04ebe..facd443 100644 --- a/tests/anbox/common/CMakeLists.txt +++ b/tests/anbox/common/CMakeLists.txt @@ -2,3 +2,4 @@ ANBOX_ADD_TEST(message_channel_tests message_channel_tests.cpp) ANBOX_ADD_TEST(small_vector_tests small_vector_tests.cpp) ANBOX_ADD_TEST(type_traits_tests type_traits_tests.cpp) ANBOX_ADD_TEST(scope_ptr_tests scope_ptr_tests.cpp) +ANBOX_ADD_TEST(binary_writer_tests binary_writer_tests.cpp) diff --git a/tests/anbox/common/binary_writer_tests.cpp b/tests/anbox/common/binary_writer_tests.cpp new file mode 100644 index 0000000..4f12a23 --- /dev/null +++ b/tests/anbox/common/binary_writer_tests.cpp @@ -0,0 +1,100 @@ +/* + * 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/common/binary_writer.h" + +#include + +namespace ac = anbox::common; + +using namespace ::testing; + +TEST(BinaryWriter, WritesUnsignedLong) { + std::vector buffer; + buffer.resize(sizeof(std::uint32_t) * 2); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.write_unsigned_long(0x10); + writer.write_unsigned_long(0x3322); + + ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x00, 0x00, 0x22, 0x33, 0x00, 0x00)); +} + +TEST(BinaryWriter, WriteUnsignedLongFailsWithExhaustedError) { + std::vector buffer; + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + EXPECT_THROW(writer.write_unsigned_long(0x11), std::out_of_range); +} + +TEST(BinaryWriter, WriteUnsignedLongWithChangedBinaryOrder) { + std::vector buffer; + buffer.resize(sizeof(std::uint32_t)); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Big); + writer.write_unsigned_long(0x11223344); + + ASSERT_THAT(buffer, ElementsAre(0x11, 0x22, 0x33, 0x44)); + + buffer.clear(); + buffer.resize(sizeof(std::uint32_t)); + + writer = ac::BinaryWriter(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Little); + writer.write_unsigned_long(0x11223344); + + ASSERT_THAT(buffer, ElementsAre(0x44, 0x33, 0x22, 0x11)); +} + +TEST(BinaryWriter, WriteUnsignedShort) { + std::vector buffer; + buffer.resize(sizeof(std::uint16_t) * 2); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.write_unsigned_short(0x10); + writer.write_unsigned_short(0x3322); + + ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x22, 0x33)); +} + +TEST(BinaryWriter, WriteUnsignedShortFailsWithExhaustedError) { + std::vector buffer; + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + EXPECT_THROW(writer.write_unsigned_short(0x11), std::out_of_range); +} + +TEST(BinaryWriter, WriteUnsignedShortWithChangedBinaryOrder) { + std::vector buffer; + buffer.resize(sizeof(std::uint16_t)); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Big); + writer.write_unsigned_short(0x1122); + + ASSERT_THAT(buffer, ElementsAre(0x11, 0x22)); + + buffer.clear(); + buffer.resize(sizeof(std::uint16_t)); + + writer = ac::BinaryWriter(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Little); + writer.write_unsigned_short(0x1122); + + ASSERT_THAT(buffer, ElementsAre(0x22, 0x11)); +} From 5bc93f76fe2df1dd86dd0bc31c42b1c9922669a5 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Wed, 10 May 2017 19:06:12 +0200 Subject: [PATCH 2/8] Create static IP configuration for Android --- src/CMakeLists.txt | 1 + src/anbox/android/ip_config_builder.cpp | 108 ++++++++++++++++++++++++ src/anbox/android/ip_config_builder.h | 63 ++++++++++++++ src/anbox/container/lxc_container.cpp | 55 ++++++++++-- src/anbox/container/lxc_container.h | 1 + 5 files changed, 223 insertions(+), 5 deletions(-) create mode 100644 src/anbox/android/ip_config_builder.cpp create mode 100644 src/anbox/android/ip_config_builder.h 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_; From 54499f0135c85f346debe601772b42d9dfa1d1e9 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Wed, 10 May 2017 19:06:38 +0200 Subject: [PATCH 3/8] Simply bridge implementation to provide just a static configuration --- scripts/anbox-bridge.sh | 95 ++--------------------------------------- 1 file changed, 4 insertions(+), 91 deletions(-) diff --git a/scripts/anbox-bridge.sh b/scripts/anbox-bridge.sh index e6793b5..46f34b7 100755 --- a/scripts/anbox-bridge.sh +++ b/scripts/anbox-bridge.sh @@ -14,34 +14,21 @@ # limitations under the License. # Taken from https://github.com/lxc/lxd-pkg-ubuntu/blob/dpm-xenial/lxd-bridge/lxd-bridge +# but modified for the use within anbox. varrun="/run/anbox" -varlib="/var/lib/anbox" -BRIDGE="anboxbr0" +BRIDGE="anbox0" # IPv4 -IPV4_ADDR="10.0.6.1" +IPV4_ADDR="192.168.250.1" IPV4_NETMASK="255.255.255.0" -IPV4_NETWORK="10.0.6.1/24" -IPV4_DHCP_RANGE="10.0.6.2,10.0.6.254" -IPV4_DHCP_MAX="252" +IPV4_NETWORK="192.168.250.1/24" IPV4_NAT="true" -# IPv6 -IPV6_ADDR="fd9d:e4dc:4e00:9e98::1" -IPV6_MASK="64" -IPV6_NETWORK="fd9d:e4dc:4e00:9e98::1/64" -IPV6_NAT="true" -IPV6_PROXY="false" - use_iptables_lock="-w" iptables -w -L -n > /dev/null 2>&1 || use_iptables_lock="" -HAS_IPV6=false -[ -e "/proc/sys/net/ipv6/conf/default/disable_ipv6" ] && \ - [ "$(cat /proc/sys/net/ipv6/conf/default/disable_ipv6)" = "0" ] && HAS_IPV6=true - _netmask2cidr () { # Assumes there's no "255." after a non-255 byte in the mask local x=${1##*255.} @@ -88,11 +75,6 @@ start() { # set up the anbox network [ ! -d "/sys/class/net/${BRIDGE}" ] && ip link add dev "${BRIDGE}" type bridge - if [ "${HAS_IPV6}" = "true" ]; then - echo 0 > "/proc/sys/net/ipv6/conf/${BRIDGE}/autoconf" || true - echo 0 > "/proc/sys/net/ipv6/conf/${BRIDGE}/accept_dad" || true - fi - # if we are run from systemd on a system with selinux enabled, # the mkdir will create /run/anbox as init_var_run_t which dnsmasq # can't write its pid into, so we restorecon it (to var_run_t) @@ -103,13 +85,6 @@ start() { fi fi - if [ ! -d "${varlib}" ]; then - mkdir -p "${varlib}" - if which restorecon >/dev/null 2>&1; then - restorecon "${varlib}" - fi - fi - ifup "${BRIDGE}" "${IPV4_ADDR}" "${IPV4_NETMASK}" IPV4_ARG="" @@ -118,25 +93,6 @@ start() { if [ "${IPV4_NAT}" = "true" ]; then iptables "${use_iptables_lock}" -t nat -A POSTROUTING -s "${IPV4_NETWORK}" ! -d "${IPV4_NETWORK}" -j MASQUERADE -m comment --comment "managed by anbox-bridge" fi - IPV4_ARG="--listen-address ${IPV4_ADDR} --dhcp-range ${IPV4_DHCP_RANGE} --dhcp-lease-max=${IPV4_DHCP_MAX}" - fi - - IPV6_ARG="" - if [ "${HAS_IPV6}" = "true" ] && [ -n "${IPV6_ADDR}" ] && [ -n "${IPV6_MASK}" ] && [ -n "${IPV6_NETWORK}" ]; then - # IPv6 sysctls don't respect the "all" path... - for interface in /proc/sys/net/ipv6/conf/*; do - echo 2 > "${interface}/accept_ra" - done - - for interface in /proc/sys/net/ipv6/conf/*; do - echo 1 > "${interface}/forwarding" - done - - ip -6 addr add dev "${BRIDGE}" "${IPV6_ADDR}/${IPV6_MASK}" - if [ "${IPV6_NAT}" = "true" ]; then - ip6tables "${use_iptables_lock}" -t nat -A POSTROUTING -s "${IPV6_NETWORK}" ! -d "${IPV6_NETWORK}" -j MASQUERADE -m comment --comment "managed by anbox-bridge" - fi - IPV6_ARG="--dhcp-range=${IPV6_ADDR},ra-stateless,ra-names --listen-address ${IPV6_ADDR}" fi iptables "${use_iptables_lock}" -I INPUT -i "${BRIDGE}" -p udp --dport 67 -j ACCEPT -m comment --comment "managed by anbox-bridge" @@ -147,35 +103,6 @@ start() { iptables "${use_iptables_lock}" -I FORWARD -o "${BRIDGE}" -j ACCEPT -m comment --comment "managed by anbox-bridge" iptables "${use_iptables_lock}" -t mangle -A POSTROUTING -o "${BRIDGE}" -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill -m comment --comment "managed by anbox-bridge" - DOMAIN_ARG="" - if [ -n "${DOMAIN}" ]; then - DOMAIN_ARG="-s ${DOMAIN} -S /${DOMAIN}/" - fi - - CONFILE_ARG="" - if [ -n "${CONFILE}" ]; then - CONFILE_ARG="--conf-file=${CONFILE}" - fi - - # https://lists.linuxcontainers.org/pipermail/lxc-devel/2014-October/010561.html - for DNSMASQ_USER in anbox dnsmasq nobody - do - if getent passwd "${DNSMASQ_USER}" >/dev/null; then - break - fi - done - - if [ -n "${IPV4_ADDR}" ] || [ -n "${IPV6_ADDR}" ]; then - # shellcheck disable=SC2086 - dnsmasq ${CONFILE_ARG} ${DOMAIN_ARG} -u "${DNSMASQ_USER}" --strict-order --bind-interfaces --pid-file="${varrun}/dnsmasq.pid" --dhcp-no-override --except-interface=lo --interface="${BRIDGE}" --dhcp-leasefile="${varlib}/dnsmasq.${BRIDGE}.leases" --dhcp-authoritative ${IPV4_ARG} ${IPV6_ARG} || cleanup - fi - - if [ "${HAS_IPV6}" = "true" ] && [ "${IPV6_PROXY}" = "true" ]; then - PATH="${PATH}:$(dirname "${0}")" anbox-bridge-proxy --addr="[fe80::1%${BRIDGE}]:13128" & - PID=$! - echo "${PID}" > "${varrun}/proxy.pid" - fi - touch "${varrun}/network_up" FAILED=0 } @@ -197,20 +124,6 @@ stop() { iptables ${use_iptables_lock} -t nat -D POSTROUTING -s ${IPV4_NETWORK} ! -d ${IPV4_NETWORK} -j MASQUERADE -m comment --comment "managed by anbox-bridge" fi - if [ "${HAS_IPV6}" = "true" ] && [ -n "${IPV6_NETWORK}" ] && [ "${IPV6_NAT}" = "true" ]; then - ip6tables ${use_iptables_lock} -t nat -D POSTROUTING -s ${IPV6_NETWORK} ! -d ${IPV6_NETWORK} -j MASQUERADE -m comment --comment "managed by anbox-bridge" - fi - - if [ -e "${varrun}/dnsmasq.pid" ]; then - pid=$(cat "${varrun}/dnsmasq.pid" 2>/dev/null) && kill -9 "${pid}" - rm -f "${varrun}/dnsmasq.pid" - fi - - if [ -e "${varrun}/proxy.pid" ]; then - pid=$(cat "${varrun}/proxy.pid" 2>/dev/null) && kill -9 "${pid}" - rm -f "${varrun}/proxy.pid" - fi - # if ${BRIDGE} has attached interfaces, don't destroy the bridge ls /sys/class/net/${BRIDGE}/brif/* > /dev/null 2>&1 || ip link delete "${BRIDGE}" fi From 2fb4067da97453f12bb00d952e4bfa56041f500d Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 11 May 2017 07:07:47 +0200 Subject: [PATCH 4/8] Add more constants for various static configuration items --- src/anbox/android/ip_config_builder.cpp | 10 ++++++++-- src/anbox/container/lxc_container.cpp | 16 ++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/anbox/android/ip_config_builder.cpp b/src/anbox/android/ip_config_builder.cpp index fa10610..4efe4db 100644 --- a/src/anbox/android/ip_config_builder.cpp +++ b/src/anbox/android/ip_config_builder.cpp @@ -33,6 +33,9 @@ constexpr const char *assignment_static{"STATIC"}; constexpr const char *assignment_dhcp{"DHCP"}; constexpr const char *assignment_unknown{"UNKNOWN"}; +constexpr const std::uint32_t is_default_gateway{0}; +constexpr const std::uint32_t gateway_is_present{1}; + namespace aa = anbox::android; std::string assignment_to_string(const aa::IpConfigBuilder::Assignment &value) { switch (value) { @@ -54,6 +57,9 @@ namespace android { std::size_t IpConfigBuilder::write(common::BinaryWriter &writer) { writer.set_byte_order(common::BinaryWriter::Order::Big); + // See http://androidxref.com/7.1.1_r6/xref/frameworks/base/services/core/java/com/android/server/net/IpConfigStore.java + // for more details on the binary file format used here. + writer.write_unsigned_long(static_cast(version_)); writer.write_string_with_size(assignment_key); @@ -64,8 +70,8 @@ std::size_t IpConfigBuilder::write(common::BinaryWriter &writer) { 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_unsigned_long(is_default_gateway); + writer.write_unsigned_long(gateway_is_present); writer.write_string_with_size(gateway_); writer.write_string_with_size(dns_key); diff --git a/src/anbox/container/lxc_container.cpp b/src/anbox/container/lxc_container.cpp index b8c0cf8..ee388a9 100644 --- a/src/anbox/container/lxc_container.cpp +++ b/src/anbox/container/lxc_container.cpp @@ -35,6 +35,13 @@ namespace fs = boost::filesystem; +namespace { +constexpr const char *default_container_ip_address{"192.168.250.2"}; +constexpr const std::uint32_t default_container_ip_prefix_length{24}; +constexpr const char *default_host_ip_address{"192.168.250.1"}; +constexpr const char *default_dns_server{"8.8.8.8"}; +} + namespace anbox { namespace container { LxcContainer::LxcContainer(bool privileged, const network::Credentials &creds) @@ -92,16 +99,13 @@ void LxcContainer::setup_network() { // 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_link_address(default_container_ip_address, default_container_ip_prefix_length); + ip_conf.set_gateway(default_host_ip_address); + ip_conf.set_dns_servers({default_dns_server}); ip_conf.set_id(0); std::vector buffer(512); From e441f3d42b9d281c4dc48075ab319703e507921c Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 11 May 2017 07:42:01 +0200 Subject: [PATCH 5/8] Extend BinaryWriter test cases to cover all necessary things --- tests/anbox/common/binary_writer_tests.cpp | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/anbox/common/binary_writer_tests.cpp b/tests/anbox/common/binary_writer_tests.cpp index 4f12a23..01495a3 100644 --- a/tests/anbox/common/binary_writer_tests.cpp +++ b/tests/anbox/common/binary_writer_tests.cpp @@ -31,6 +31,7 @@ TEST(BinaryWriter, WritesUnsignedLong) { writer.write_unsigned_long(0x10); writer.write_unsigned_long(0x3322); + ASSERT_EQ(writer.bytes_written(), 8); ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x00, 0x00, 0x22, 0x33, 0x00, 0x00)); } @@ -48,6 +49,7 @@ TEST(BinaryWriter, WriteUnsignedLongWithChangedBinaryOrder) { writer.set_byte_order(ac::BinaryWriter::Order::Big); writer.write_unsigned_long(0x11223344); + ASSERT_EQ(writer.bytes_written(), 4); ASSERT_THAT(buffer, ElementsAre(0x11, 0x22, 0x33, 0x44)); buffer.clear(); @@ -58,6 +60,7 @@ TEST(BinaryWriter, WriteUnsignedLongWithChangedBinaryOrder) { writer.set_byte_order(ac::BinaryWriter::Order::Little); writer.write_unsigned_long(0x11223344); + ASSERT_EQ(writer.bytes_written(), 4); ASSERT_THAT(buffer, ElementsAre(0x44, 0x33, 0x22, 0x11)); } @@ -69,6 +72,7 @@ TEST(BinaryWriter, WriteUnsignedShort) { writer.write_unsigned_short(0x10); writer.write_unsigned_short(0x3322); + ASSERT_EQ(writer.bytes_written(), 4); ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x22, 0x33)); } @@ -86,6 +90,7 @@ TEST(BinaryWriter, WriteUnsignedShortWithChangedBinaryOrder) { writer.set_byte_order(ac::BinaryWriter::Order::Big); writer.write_unsigned_short(0x1122); + ASSERT_EQ(writer.bytes_written(), 2); ASSERT_THAT(buffer, ElementsAre(0x11, 0x22)); buffer.clear(); @@ -96,5 +101,30 @@ TEST(BinaryWriter, WriteUnsignedShortWithChangedBinaryOrder) { writer.set_byte_order(ac::BinaryWriter::Order::Little); writer.write_unsigned_short(0x1122); + ASSERT_EQ(writer.bytes_written(), 2); ASSERT_THAT(buffer, ElementsAre(0x22, 0x11)); } + +TEST(BinaryWriter, WriteString) { + std::vector buffer; + buffer.resize(sizeof(std::uint8_t) * 4); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.write_string("test", 4); + + ASSERT_EQ(writer.bytes_written(), 4); + ASSERT_THAT(buffer, ElementsAre(0x74, 0x65, 0x73, 0x74)); +} + +TEST(BinaryWriter, WriteStringWithSize) { + std::vector buffer; + buffer.resize(sizeof(std::uint8_t) * 6); + ac::BinaryWriter writer(buffer.begin(), buffer.end()); + + writer.set_byte_order(ac::BinaryWriter::Order::Big); + + writer.write_string_with_size("test"); + + ASSERT_EQ(writer.bytes_written(), 6); + ASSERT_THAT(buffer, ElementsAre(0x00, 0x04, 0x74, 0x65, 0x73, 0x74)); +} From 7530bf9246f1b1d20001d0bc82c1c25de6e9858c Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 11 May 2017 07:44:10 +0200 Subject: [PATCH 6/8] Use class instead of struct for IpConfigBuilder --- src/anbox/android/ip_config_builder.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/anbox/android/ip_config_builder.h b/src/anbox/android/ip_config_builder.h index 6ae0db0..812da7c 100644 --- a/src/anbox/android/ip_config_builder.h +++ b/src/anbox/android/ip_config_builder.h @@ -26,7 +26,8 @@ namespace anbox { namespace android { -struct IpConfigBuilder { +class IpConfigBuilder { + public: enum class Version : std::uint32_t { Version1 = 1, Version2 = 2, @@ -37,6 +38,8 @@ struct IpConfigBuilder { DHCP, }; + IpConfigBuilder() = default; + std::size_t write(common::BinaryWriter &writer); void set_version(const Version &version); From dd21e8fa1de0d8a200f63c4dc4e393eec5b5d725 Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 11 May 2017 18:03:56 +0200 Subject: [PATCH 7/8] Make never change value static and const --- src/anbox/common/binary_writer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/anbox/common/binary_writer.cpp b/src/anbox/common/binary_writer.cpp index f6d4973..e9f16d9 100644 --- a/src/anbox/common/binary_writer.cpp +++ b/src/anbox/common/binary_writer.cpp @@ -25,8 +25,8 @@ namespace { bool is_little_endian() { - std::uint32_t v = 1; - return (*reinterpret_cast(&v) == 1); + static const std::uint32_t v = 1; + return (*reinterpret_cast(&v) == 1); } } From e73ea080c43948d46f6bccb153da6bea7ec6dc5c Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 11 May 2017 18:06:24 +0200 Subject: [PATCH 8/8] Rename write_unsigned_{long,short} to write_uint{16,32} --- src/anbox/android/ip_config_builder.cpp | 10 +++---- src/anbox/common/binary_writer.cpp | 6 ++-- src/anbox/common/binary_writer.h | 4 +-- tests/anbox/common/binary_writer_tests.cpp | 32 +++++++++++----------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/anbox/android/ip_config_builder.cpp b/src/anbox/android/ip_config_builder.cpp index 4efe4db..8ba13ce 100644 --- a/src/anbox/android/ip_config_builder.cpp +++ b/src/anbox/android/ip_config_builder.cpp @@ -60,18 +60,18 @@ std::size_t IpConfigBuilder::write(common::BinaryWriter &writer) { // See http://androidxref.com/7.1.1_r6/xref/frameworks/base/services/core/java/com/android/server/net/IpConfigStore.java // for more details on the binary file format used here. - writer.write_unsigned_long(static_cast(version_)); + writer.write_uint32(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_uint32(link_.prefix_length); writer.write_string_with_size(gateway_key); - writer.write_unsigned_long(is_default_gateway); - writer.write_unsigned_long(gateway_is_present); + writer.write_uint32(is_default_gateway); + writer.write_uint32(gateway_is_present); writer.write_string_with_size(gateway_); writer.write_string_with_size(dns_key); @@ -79,7 +79,7 @@ std::size_t IpConfigBuilder::write(common::BinaryWriter &writer) { writer.write_string_with_size(server); writer.write_string_with_size(id_key); - writer.write_unsigned_long(id_); + writer.write_uint32(id_); writer.write_string_with_size(eos_key); diff --git a/src/anbox/common/binary_writer.cpp b/src/anbox/common/binary_writer.cpp index e9f16d9..3202199 100644 --- a/src/anbox/common/binary_writer.cpp +++ b/src/anbox/common/binary_writer.cpp @@ -42,7 +42,7 @@ void BinaryWriter::set_byte_order(Order order) { byte_order_ = order; } -void BinaryWriter::write_unsigned_short(std::uint16_t value) { +void BinaryWriter::write_uint16(std::uint16_t value) { if (current_ + sizeof(value) > end_) throw std::out_of_range{"Write buffer exhausted"}; @@ -62,7 +62,7 @@ void BinaryWriter::write_unsigned_short(std::uint16_t value) { current_ += sizeof(v); } -void BinaryWriter::write_unsigned_long(std::uint32_t value) { +void BinaryWriter::write_uint32(std::uint32_t value) { if (current_ + sizeof(value) > end_) throw std::out_of_range{"Write buffer exhausted"}; @@ -95,7 +95,7 @@ void BinaryWriter::write_string_with_size(const std::string &str) { } void BinaryWriter::write_string_with_size(const char *s, std::size_t size) { - write_unsigned_short(size); + write_uint16(size); write_string(s, size); } diff --git a/src/anbox/common/binary_writer.h b/src/anbox/common/binary_writer.h index f2aeefd..23708c6 100644 --- a/src/anbox/common/binary_writer.h +++ b/src/anbox/common/binary_writer.h @@ -37,8 +37,8 @@ class BinaryWriter { void set_byte_order(Order order); - void write_unsigned_short(std::uint16_t value); - void write_unsigned_long(std::uint32_t value); + void write_uint16(std::uint16_t value); + void write_uint32(std::uint32_t value); void write_string(const char *s, std::size_t size); void write_string_with_size(const std::string &str); void write_string_with_size(const char *s, std::size_t size); diff --git a/tests/anbox/common/binary_writer_tests.cpp b/tests/anbox/common/binary_writer_tests.cpp index 01495a3..6bab562 100644 --- a/tests/anbox/common/binary_writer_tests.cpp +++ b/tests/anbox/common/binary_writer_tests.cpp @@ -23,31 +23,31 @@ namespace ac = anbox::common; using namespace ::testing; -TEST(BinaryWriter, WritesUnsignedLong) { +TEST(BinaryWriter, WriteUint32) { std::vector buffer; buffer.resize(sizeof(std::uint32_t) * 2); ac::BinaryWriter writer(buffer.begin(), buffer.end()); - writer.write_unsigned_long(0x10); - writer.write_unsigned_long(0x3322); + writer.write_uint32(0x10); + writer.write_uint32(0x3322); ASSERT_EQ(writer.bytes_written(), 8); ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x00, 0x00, 0x22, 0x33, 0x00, 0x00)); } -TEST(BinaryWriter, WriteUnsignedLongFailsWithExhaustedError) { +TEST(BinaryWriter, WriteUint32FailsWithExhaustedError) { std::vector buffer; ac::BinaryWriter writer(buffer.begin(), buffer.end()); - EXPECT_THROW(writer.write_unsigned_long(0x11), std::out_of_range); + EXPECT_THROW(writer.write_uint32(0x11), std::out_of_range); } -TEST(BinaryWriter, WriteUnsignedLongWithChangedBinaryOrder) { +TEST(BinaryWriter, WriteUint32WithChangedBinaryOrder) { std::vector buffer; buffer.resize(sizeof(std::uint32_t)); ac::BinaryWriter writer(buffer.begin(), buffer.end()); writer.set_byte_order(ac::BinaryWriter::Order::Big); - writer.write_unsigned_long(0x11223344); + writer.write_uint32(0x11223344); ASSERT_EQ(writer.bytes_written(), 4); ASSERT_THAT(buffer, ElementsAre(0x11, 0x22, 0x33, 0x44)); @@ -58,37 +58,37 @@ TEST(BinaryWriter, WriteUnsignedLongWithChangedBinaryOrder) { writer = ac::BinaryWriter(buffer.begin(), buffer.end()); writer.set_byte_order(ac::BinaryWriter::Order::Little); - writer.write_unsigned_long(0x11223344); + writer.write_uint32(0x11223344); ASSERT_EQ(writer.bytes_written(), 4); ASSERT_THAT(buffer, ElementsAre(0x44, 0x33, 0x22, 0x11)); } -TEST(BinaryWriter, WriteUnsignedShort) { +TEST(BinaryWriter, WriteUint16) { std::vector buffer; buffer.resize(sizeof(std::uint16_t) * 2); ac::BinaryWriter writer(buffer.begin(), buffer.end()); - writer.write_unsigned_short(0x10); - writer.write_unsigned_short(0x3322); + writer.write_uint16(0x10); + writer.write_uint16(0x3322); ASSERT_EQ(writer.bytes_written(), 4); ASSERT_THAT(buffer, ElementsAre(0x10, 0x00, 0x22, 0x33)); } -TEST(BinaryWriter, WriteUnsignedShortFailsWithExhaustedError) { +TEST(BinaryWriter, WriteUint16FailsWithExhaustedError) { std::vector buffer; ac::BinaryWriter writer(buffer.begin(), buffer.end()); - EXPECT_THROW(writer.write_unsigned_short(0x11), std::out_of_range); + EXPECT_THROW(writer.write_uint16(0x11), std::out_of_range); } -TEST(BinaryWriter, WriteUnsignedShortWithChangedBinaryOrder) { +TEST(BinaryWriter, WriteUint16WithChangedBinaryOrder) { std::vector buffer; buffer.resize(sizeof(std::uint16_t)); ac::BinaryWriter writer(buffer.begin(), buffer.end()); writer.set_byte_order(ac::BinaryWriter::Order::Big); - writer.write_unsigned_short(0x1122); + writer.write_uint16(0x1122); ASSERT_EQ(writer.bytes_written(), 2); ASSERT_THAT(buffer, ElementsAre(0x11, 0x22)); @@ -99,7 +99,7 @@ TEST(BinaryWriter, WriteUnsignedShortWithChangedBinaryOrder) { writer = ac::BinaryWriter(buffer.begin(), buffer.end()); writer.set_byte_order(ac::BinaryWriter::Order::Little); - writer.write_unsigned_short(0x1122); + writer.write_uint16(0x1122); ASSERT_EQ(writer.bytes_written(), 2); ASSERT_THAT(buffer, ElementsAre(0x22, 0x11));