From 6520320fc6461ec8672527bcdc02c3cdf2b52c30 Mon Sep 17 00:00:00 2001 From: bin liu Date: Thu, 10 Sep 2020 22:38:01 +0800 Subject: [PATCH] agent: setup DNS for guest This PR is a porting of https://github.com/kata-containers/agent/pull/625 Fixes: #689 Signed-off-by: bin liu --- src/agent/src/network.rs | 122 +++++++++++++++++++++++++++++++++++++++ src/agent/src/rpc.rs | 22 +++++++ 2 files changed, 144 insertions(+) diff --git a/src/agent/src/network.rs b/src/agent/src/network.rs index a42d2198bb..01a088dac9 100644 --- a/src/agent/src/network.rs +++ b/src/agent/src/network.rs @@ -3,8 +3,17 @@ // SPDX-License-Identifier: Apache-2.0 // +use anyhow::{anyhow, Context, Result}; +use nix::mount::{self, MntFlags, MsFlags}; use protocols::types::{Interface, Route}; +use slog::Logger; use std::collections::HashMap; +use std::fs; + +use crate::Sandbox; + +const KATA_GUEST_SANDBOX_DNS_FILE: &str = "/run/kata-containers/sandbox/resolv.conf"; +const GUEST_DNS_FILE: &str = "/etc/resolv.conf"; // Network fully describes a sandbox network with its interfaces, routes and dns // related information. @@ -28,3 +37,116 @@ impl Network { self.dns.push(dns); } } + +pub fn setup_guest_dns(logger: Logger, dns_list: Vec) -> Result<()> { + do_setup_guest_dns( + logger, + dns_list, + KATA_GUEST_SANDBOX_DNS_FILE, + GUEST_DNS_FILE, + ) +} + +fn do_setup_guest_dns(logger: Logger, dns_list: Vec, src: &str, dst: &str) -> Result<()> { + let logger = logger.new(o!( "subsystem" => "network")); + + if dns_list.len() == 0 { + info!( + logger, + "Did not set sandbox DNS as DNS not received as part of request." + ); + return Ok(()); + } + + let attr = fs::metadata(dst); + if attr.is_err() { + // not exists or other errors that we could not use it anymore. + return Ok(()); + } + + if attr.unwrap().is_dir() { + return Err(anyhow!("{} is a directory", GUEST_DNS_FILE)); + } + + // write DNS to file + let content = dns_list + .iter() + .map(|x| x.trim()) + .collect::>() + .join("\n"); + fs::write(src, &content)?; + + // bind mount to /etc/resolv.conf + mount::mount(Some(src), dst, Some("bind"), MsFlags::MS_BIND, None::<&str>) + .map_err(|err| anyhow!(err).context("failed to setup guest DNS"))?; + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::skip_if_not_root; + use nix::mount; + use std::fs::File; + use std::io::Write; + use tempfile::tempdir; + + #[test] + fn test_setup_guest_dns() { + skip_if_not_root!(); + + let drain = slog::Discard; + let logger = slog::Logger::root(drain, o!()); + + // create temp for /run/kata-containers/sandbox/resolv.conf + let src_dir = tempdir().expect("failed to create tmpdir"); + let tmp = src_dir.path().join("resolv.conf"); + let src_filename = tmp.to_str().expect("failed to get resolv file filename"); + + // create temp for /etc/resolv.conf + let dst_dir = tempdir().expect("failed to create tmpdir"); + let tmp = dst_dir.path().join("resolv.conf"); + let dst_filename = tmp.to_str().expect("failed to get resolv file filename"); + { + let _file = File::create(dst_filename).unwrap(); + } + + // test DNS + let dns = vec![ + "nameserver 1.2.3.4".to_string(), + "nameserver 5.6.7.8".to_string(), + ]; + + // write to /run/kata-containers/sandbox/resolv.conf + let mut src_file = + File::create(src_filename).expect(&format!("failed to create file {:?}", src_filename)); + let content = dns.join("\n"); + src_file + .write_all(content.as_bytes()) + .expect(&format!("failed to write file contents")); + + // call do_setup_guest_dns + let result = do_setup_guest_dns(logger, dns.clone(), src_filename, dst_filename); + + assert_eq!( + true, + result.is_ok(), + "result should be ok, but {:?}", + result + ); + + // get content of /etc/resolv.conf + let content = fs::read_to_string(dst_filename); + assert_eq!(true, content.is_ok()); + let content = content.unwrap(); + + let expected_DNS: Vec<&str> = content.split('\n').collect(); + + // assert the data are the same as /run/kata-containers/sandbox/resolv.conf + assert_eq!(dns, expected_DNS); + + // umount /etc/resolv.conf + let _ = mount::umount(dst_filename); + } +} diff --git a/src/agent/src/rpc.rs b/src/agent/src/rpc.rs index 4e801e166c..85f0ebb30e 100644 --- a/src/agent/src/rpc.rs +++ b/src/agent/src/rpc.rs @@ -37,6 +37,8 @@ use crate::linux_abi::*; use crate::metrics::get_metrics; use crate::mount::{add_storages, remove_mounts, BareMount, STORAGEHANDLERLIST}; use crate::namespace::{NSTYPEIPC, NSTYPEPID, NSTYPEUTS}; +use crate::network::setup_guest_dns; +use crate::network::Network; use crate::random; use crate::sandbox::Sandbox; use crate::version::{AGENT_VERSION, API_VERSION}; @@ -1066,6 +1068,7 @@ impl protocols::agent_ttrpc::AgentService for agentService { ) -> ttrpc::Result { Ok(Empty::new()) } + fn create_sandbox( &self, _ctx: &ttrpc::TtrpcContext, @@ -1131,8 +1134,27 @@ impl protocols::agent_ttrpc::AgentService for agentService { } }; + match setup_guest_dns(sl!(), req.dns.to_vec()) { + Ok(dns_list) => { + let sandbox = self.sandbox.clone(); + let mut s = sandbox.lock().unwrap(); + let _ = req + .dns + .to_vec() + .iter() + .map(|dns| s.network.set_dns(dns.to_string())); + } + Err(e) => { + return Err(ttrpc::Error::RpcStatus(ttrpc::get_status( + ttrpc::Code::INTERNAL, + e.to_string(), + ))) + } + }; + Ok(Empty::new()) } + fn destroy_sandbox( &self, _ctx: &ttrpc::TtrpcContext,