Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b009e1a7 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 7490197 from cbd90515 to tm-release

Change-Id: I378588a6e0ae27cf6c1f8e9f84b3e4e91bc8abd3
parents 4aba8040 cbd90515
Loading
Loading
Loading
Loading
+44 −27
Original line number Diff line number Diff line
@@ -53,7 +53,6 @@ const MAX_INCOMING_BUFFER_SIZE_WHOLE: u64 = 10000000;
const MAX_INCOMING_BUFFER_SIZE_EACH: u64 = 1000000;
const MAX_CONCURRENT_STREAM_SIZE: u64 = 100;
const MAX_DATAGRAM_SIZE: usize = 1350;
const MAX_DATAGRAM_SIZE_U64: u64 = 1350;
const DOH_PORT: u16 = 443;
const QUICHE_IDLE_TIMEOUT_MS: u64 = 180000;
const SYSTEM_CERT_PATH: &str = "/system/etc/security/cacerts";
@@ -78,19 +77,19 @@ pub struct DohDispatcher {
    join_handle: task::JoinHandle<Result<()>>,
}

fn make_doh_udp_socket(ip_addr: &str, mark: u32) -> Result<std::net::UdpSocket> {
    let sock_addr = SocketAddr::new(IpAddr::from_str(&ip_addr)?, DOH_PORT);
    let bind_addr = match sock_addr {
fn make_doh_udp_socket(ip_addr: &str, mark: u32) -> Result<(SocketAddr, std::net::UdpSocket)> {
    let peer_addr = SocketAddr::new(IpAddr::from_str(&ip_addr)?, DOH_PORT);
    let bind_addr = match peer_addr {
        std::net::SocketAddr::V4(_) => "0.0.0.0:0",
        std::net::SocketAddr::V6(_) => "[::]:0",
    };
    let udp_sk = std::net::UdpSocket::bind(bind_addr)?;
    udp_sk.set_nonblocking(true)?;
    mark_socket(udp_sk.as_raw_fd(), mark)?;
    udp_sk.connect(sock_addr)?;
    udp_sk.connect(peer_addr)?;

    debug!("connecting to {:} from {:}", sock_addr, udp_sk.local_addr()?);
    Ok(udp_sk)
    debug!("connecting to {:} from {:}", peer_addr, udp_sk.local_addr()?);
    Ok((peer_addr, udp_sk))
}

// DoH dispatcher
@@ -102,13 +101,14 @@ impl DohDispatcher {
        cert_path: Option<&str>,
    ) -> Result<Box<DohDispatcher>> {
        // Setup socket
        let udp_sk = make_doh_udp_socket(&ip_addr, mark)?;
        DohDispatcher::new_with_socket(url, ip_addr, mark, cert_path, udp_sk)
        let (peer_addr, udp_sk) = make_doh_udp_socket(&ip_addr, mark)?;
        DohDispatcher::new_with_socket(url, ip_addr, peer_addr, mark, cert_path, udp_sk)
    }

    fn new_with_socket(
        url: &str,
        ip_addr: &str,
        peer_addr: SocketAddr,
        mark: u32,
        cert_path: Option<&str>,
        udp_sk: std::net::UdpSocket,
@@ -128,8 +128,15 @@ impl DohDispatcher {
            "Creating a doh handler task: url={}, ip_addr={}, mark={:#x}, scid {:x?}",
            url, ip_addr, mark, &scid
        );
        let join_handle =
            RUNTIME_STATIC.spawn(doh_handler(url, udp_sk, config, h3_config, scid, cmd_receiver));
        let join_handle = RUNTIME_STATIC.spawn(doh_handler(
            url,
            peer_addr,
            udp_sk,
            config,
            h3_config,
            scid,
            cmd_receiver,
        ));
        Ok(Box::new(DohDispatcher { query_sender: cmd_sender, join_handle }))
    }

@@ -145,6 +152,7 @@ impl DohDispatcher {

async fn doh_handler(
    url: url::Url,
    peer_addr: SocketAddr,
    udp_sk: std::net::UdpSocket,
    mut config: quiche::Config,
    h3_config: h3::Config,
@@ -153,8 +161,10 @@ async fn doh_handler(
) -> Result<()> {
    debug!("doh_handler: url={:?}", url);

    let connid = quiche::ConnectionId::from_ref(&scid);
    let sk = UdpSocket::from_std(udp_sk)?;
    let mut conn = quiche::connect(url.domain(), &scid, &mut config)?;
    let mut conn = quiche::connect(url.domain(), &connid, peer_addr, &mut config)?;
    let recv_info = quiche::RecvInfo { from: peer_addr };
    let mut quic_conn_start = std::time::Instant::now();
    let mut h3_conn: Option<h3::Connection> = None;
    let mut is_idle = false;
@@ -170,7 +180,7 @@ async fn doh_handler(
                debug!("recv {:?} ", size);
                match size {
                    Ok(size) => {
                        let processed = match conn.recv(&mut buf[..size]) {
                        let processed = match conn.recv(&mut buf[..size], recv_info) {
                            Ok(l) => l,
                            Err(e) => {
                                error!("quic recv failed: {:?}", e);
@@ -207,7 +217,7 @@ async fn doh_handler(
            // If there is any pending query, resume the quic connection.
            if !pending_cmds.is_empty() {
                info!("still some pending queries but connection is not avaiable, resume it");
                conn = quiche::connect(url.domain(), &scid, &mut config)?;
                conn = quiche::connect(url.domain(), &connid, peer_addr, &mut config)?;
                quic_conn_start = std::time::Instant::now();
                h3_conn = None;
                is_idle = false;
@@ -264,15 +274,15 @@ fn send_dns_query(
    path.push_str("?dns=");
    path.push_str(std::str::from_utf8(&query)?);
    let _req = vec![
        quiche::h3::Header::new(":method", "GET"),
        quiche::h3::Header::new(":scheme", "https"),
        quiche::h3::Header::new(b":method", b"GET"),
        quiche::h3::Header::new(b":scheme", b"https"),
        quiche::h3::Header::new(
            ":authority",
            url.host_str().ok_or_else(|| anyhow!("failed to get host"))?,
            b":authority",
            url.host_str().ok_or_else(|| anyhow!("failed to get host"))?.as_bytes(),
        ),
        quiche::h3::Header::new(":path", &path),
        quiche::h3::Header::new("user-agent", "quiche"),
        quiche::h3::Header::new("accept", "application/dns-message"),
        quiche::h3::Header::new(b":path", path.as_bytes()),
        quiche::h3::Header::new(b"user-agent", b"quiche"),
        quiche::h3::Header::new(b"accept", b"application/dns-message"),
        // TODO: is content-length required?
    ];

@@ -334,7 +344,7 @@ async fn recv_query(
async fn flush_tx(sk: &UdpSocket, conn: &mut quiche::Connection) -> Result<()> {
    let mut out = [0; MAX_DATAGRAM_SIZE];
    loop {
        let write = match conn.send(&mut out) {
        let (write, _) = match conn.send(&mut out) {
            Ok(v) => v,
            Err(quiche::Error::Done) => {
                debug!("done writing");
@@ -358,7 +368,7 @@ fn create_quiche_config(cert_path: Option<&str>) -> Result<quiche::Config> {
    config.load_verify_locations_from_directory(cert_path.unwrap_or(SYSTEM_CERT_PATH))?;
    // Some of these configs are necessary, or the server can't respond the HTTP/3 request.
    config.set_max_idle_timeout(QUICHE_IDLE_TIMEOUT_MS);
    config.set_max_udp_payload_size(MAX_DATAGRAM_SIZE_U64);
    config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
    config.set_initial_max_data(MAX_INCOMING_BUFFER_SIZE_WHOLE);
    config.set_initial_max_stream_data_bidi_local(MAX_INCOMING_BUFFER_SIZE_EACH);
    config.set_initial_max_stream_data_bidi_remote(MAX_INCOMING_BUFFER_SIZE_EACH);
@@ -516,7 +526,7 @@ mod tests {
            assert!(super::make_doh_udp_socket(ip, 0).is_err(), "udp socket should not be created");
        }
        // Make a socket connecting to loopback with a test mark.
        let sk = super::make_doh_udp_socket(LOOPBACK_ADDR, TEST_MARK).unwrap();
        let (_, sk) = super::make_doh_udp_socket(LOOPBACK_ADDR, TEST_MARK).unwrap();
        // Check if the socket is connected to loopback.
        assert_eq!(
            sk.peer_addr().unwrap(),
@@ -568,9 +578,16 @@ mod tests {
    const SAMPLE_QUERY: &str = "q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB";
    #[test]
    fn close_doh() {
        let udp_sk = super::make_doh_udp_socket(LOOPBACK_ADDR, TEST_MARK).unwrap();
        let doh =
            DohDispatcher::new_with_socket(GOOGLE_DNS_URL, GOOGLE_DNS_IP, 0, None, udp_sk).unwrap();
        let (peer_socket, udp_sk) = super::make_doh_udp_socket(LOOPBACK_ADDR, TEST_MARK).unwrap();
        let doh = DohDispatcher::new_with_socket(
            GOOGLE_DNS_URL,
            GOOGLE_DNS_IP,
            peer_socket,
            0,
            None,
            udp_sk,
        )
        .unwrap();
        let (resp_tx, resp_rx) = oneshot::channel();
        let cmd = Command::DohQuery { query: SAMPLE_QUERY.as_bytes().to_vec(), resp: resp_tx };
        assert!(doh.query(cmd).is_ok(), "Send query failed");
+26 −19
Original line number Diff line number Diff line
@@ -18,9 +18,6 @@

#include "dns_responder_client_ndk.h"

#include <android-base/logging.h>
#include <android-base/stringprintf.h>

#include <android/binder_manager.h>
#include "NetdClient.h"

@@ -34,7 +31,6 @@ static const char* ANDROID_DNS_MODE = "ANDROID_DNS_MODE";
using aidl::android::net::IDnsResolver;
using aidl::android::net::INetd;
using aidl::android::net::ResolverParamsParcel;
using android::base::StringPrintf;
using android::net::ResolverStats;

void DnsResponderClient::SetupMappings(unsigned numHosts, const std::vector<std::string>& domains,
@@ -122,20 +118,6 @@ bool DnsResponderClient::GetResolverInfo(aidl::android::net::IDnsResolver* dnsRe
    return ResolverStats::decodeAll(stats32, stats);
}

bool DnsResponderClient::isRemoteVersionSupported(
        aidl::android::net::IDnsResolver* dnsResolverService, int requiredVersion) {
    int remoteVersion = 0;
    if (!dnsResolverService->getInterfaceVersion(&remoteVersion).isOk()) {
        LOG(FATAL) << "Can't get 'dnsresolver' remote version";
    }
    if (remoteVersion < requiredVersion) {
        LOG(WARNING) << StringPrintf("Remote version: %d < Required version: %d", remoteVersion,
                                     requiredVersion);
        return false;
    }
    return true;
}

bool DnsResponderClient::SetResolversForNetwork(const std::vector<std::string>& servers,
                                                const std::vector<std::string>& domains,
                                                const std::vector<int>& params) {
@@ -191,7 +173,19 @@ void DnsResponderClient::SetupDNSServers(unsigned numServers, const std::vector<
int DnsResponderClient::SetupOemNetwork() {
    mNetdSrv->networkDestroy(TEST_NETID);
    mDnsResolvSrv->destroyNetworkCache(TEST_NETID);
    auto ret = mNetdSrv->networkCreatePhysical(TEST_NETID, INetd::PERMISSION_NONE);

    ::ndk::ScopedAStatus ret;
    if (DnsResponderClient::isRemoteVersionSupported(mNetdSrv, 6)) {
        const auto& config = DnsResponderClient::makeNativeNetworkConfig(
                TEST_NETID, NativeNetworkType::PHYSICAL, INetd::PERMISSION_NONE, /*secure=*/false);
        ret = mNetdSrv->networkCreate(config);
    } else {
        // Only for presubmit tests that run mainline module (and its tests) on R or earlier images.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        ret = mNetdSrv->networkCreatePhysical(TEST_NETID, INetd::PERMISSION_NONE);
#pragma clang diagnostic pop
    }
    if (!ret.isOk()) {
        fprintf(stderr, "Creating physical network %d failed, %s\n", TEST_NETID, ret.getMessage());
        return -1;
@@ -238,3 +232,16 @@ void DnsResponderClient::SetUp() {
void DnsResponderClient::TearDown() {
    TearDownOemNetwork(mOemNetId);
}

NativeNetworkConfig DnsResponderClient::makeNativeNetworkConfig(int netId,
                                                                NativeNetworkType networkType,
                                                                int permission, bool secure) {
    NativeNetworkConfig config = {};
    config.netId = netId;
    config.networkType = networkType;
    config.permission = permission;
    config.secure = secure;
    // The vpnType doesn't matter in AOSP. Just pick a well defined one from INetd.
    config.vpnType = NativeVpnType::PLATFORM;
    return config;
}
+24 −2
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@
#include <string>
#include <vector>

#include <android-base/logging.h>
#include <android-base/stringprintf.h>

#include <aidl/android/net/IDnsResolver.h>
#include <aidl/android/net/INetd.h>
#include "ResolverStats.h"  // TODO: stop depending on this internal header
@@ -28,6 +31,11 @@
#include "dns_tls_certificate.h"
#include "params.h"

using aidl::android::net::NativeNetworkConfig;
using aidl::android::net::NativeNetworkType;
using aidl::android::net::NativeVpnType;
using android::base::StringPrintf;

inline const std::vector<std::string> kDefaultServers = {"127.0.0.3"};
inline const std::vector<std::string> kDefaultSearchDomains = {"example.com"};
inline const std::vector<int> kDefaultParams = {
@@ -85,8 +93,22 @@ class DnsResponderClient {

    bool SetResolversFromParcel(const aidl::android::net::ResolverParamsParcel& resolverParams);

    static bool isRemoteVersionSupported(aidl::android::net::IDnsResolver* dnsResolverService,
                                         int enabledVersion);
    template <class T>
    static bool isRemoteVersionSupported(T remoteService, int requiredVersion) {
        int remoteVersion = 0;
        if (!remoteService->getInterfaceVersion(&remoteVersion).isOk()) {
            LOG(FATAL) << "Can't get remote version";
        }
        if (remoteVersion < requiredVersion) {
            LOG(WARNING) << StringPrintf("Remote version: %d < Required version: %d", remoteVersion,
                                         requiredVersion);
            return false;
        }
        return true;
    };

    static NativeNetworkConfig makeNativeNetworkConfig(int netId, NativeNetworkType networkType,
                                                       int permission, bool secure);

    static bool GetResolverInfo(aidl::android::net::IDnsResolver* dnsResolverService,
                                unsigned netId, std::vector<std::string>* servers,
+38 −4
Original line number Diff line number Diff line
@@ -4145,7 +4145,17 @@ void expectDnsNetIdIsDefaultNetwork(INetd* netdService) {
}

void expectDnsNetIdWithVpn(INetd* netdService, unsigned vpnNetId, unsigned expectedNetId) {
    if (DnsResponderClient::isRemoteVersionSupported(netdService, 6)) {
        const auto& config = DnsResponderClient::makeNativeNetworkConfig(
                vpnNetId, NativeNetworkType::VIRTUAL, INetd::PERMISSION_NONE, /*secure=*/false);
        EXPECT_TRUE(netdService->networkCreate(config).isOk());
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        EXPECT_TRUE(netdService->networkCreateVpn(vpnNetId, false /* secure */).isOk());
#pragma clang diagnostic pop
    }

    uid_t uid = getuid();
    // Add uid to VPN
    EXPECT_TRUE(netdService->networkAddUidRanges(vpnNetId, {makeUidRangeParcel(uid, uid)}).isOk());
@@ -6033,8 +6043,20 @@ class ResolverMultinetworkTest : public ResolverTest {

      protected:
        Result<void> createNetwork() const override {
            if (auto r = mNetdSrv->networkCreatePhysical(mNetId, INetd::PERMISSION_NONE);
                !r.isOk()) {
            ::ndk::ScopedAStatus r;
            if (DnsResponderClient::isRemoteVersionSupported(mNetdSrv, 6)) {
                const auto& config = DnsResponderClient::makeNativeNetworkConfig(
                        mNetId, NativeNetworkType::PHYSICAL, INetd::PERMISSION_NONE,
                        /*secure=*/false);
                r = mNetdSrv->networkCreate(config);
            } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                r = mNetdSrv->networkCreatePhysical(mNetId, INetd::PERMISSION_NONE);
#pragma clang diagnostic pop
            }

            if (!r.isOk()) {
                return Error() << r.getMessage();
            }
            return {};
@@ -6079,7 +6101,19 @@ class ResolverMultinetworkTest : public ResolverTest {

      protected:
        Result<void> createNetwork() const override {
            if (auto r = mNetdSrv->networkCreateVpn(mNetId, mIsSecure); !r.isOk()) {
            ::ndk::ScopedAStatus r;
            if (DnsResponderClient::isRemoteVersionSupported(mNetdSrv, 6)) {
                const auto& config = DnsResponderClient::makeNativeNetworkConfig(
                        mNetId, NativeNetworkType::VIRTUAL, INetd::PERMISSION_NONE, mIsSecure);
                r = mNetdSrv->networkCreate(config);
            } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
                r = mNetdSrv->networkCreateVpn(mNetId, mIsSecure);
#pragma clang diagnostic pop
            }

            if (!r.isOk()) {
                return Error() << r.getMessage();
            }
            return {};