Add parser for hostname and hosts

This commit is contained in:
ClawSeven 2022-03-17 18:21:39 +08:00 committed by Zongmin.Gu
parent 15932a54b6
commit ffdd4d95a4
13 changed files with 178 additions and 63 deletions

20
src/libos/Cargo.lock generated

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "Occlum"
version = "0.27.0"
@ -22,6 +24,7 @@ dependencies = [
"rcore-fs-ramfs",
"rcore-fs-sefs",
"rcore-fs-unionfs",
"regex",
"resolv-conf",
"ringbuf",
"scroll",
@ -518,6 +521,23 @@ dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "regex"
version = "1.3.1"
source = "git+https://github.com/mesalock-linux/regex-sgx#76aef86f9836532d17764523d0fa23bb7d2e31cf"
dependencies = [
"regex-syntax",
"sgx_tstd",
]
[[package]]
name = "regex-syntax"
version = "0.6.12"
source = "git+https://github.com/mesalock-linux/regex-sgx#76aef86f9836532d17764523d0fa23bb7d2e31cf"
dependencies = [
"sgx_tstd",
]
[[package]]
name = "resolv-conf"
version = "0.7.0"

@ -29,6 +29,7 @@ memoffset = "0.6.1"
scroll = { version = "0.10.2", default-features = false }
itertools = { version = "0.10.0", default-features = false, features = ["use_alloc"] }
ctor = "0.1"
regex = { git = "https://github.com/mesalock-linux/regex-sgx", default-features = false, features = ["std", "unicode", "mesalock_sgx"] }
[patch.'https://github.com/apache/teaclave-sgx-sdk.git']
sgx_tstd = { path = "../../deps/rust-sgx-sdk/sgx_tstd" }

@ -29,11 +29,11 @@ typedef struct itimerspec{
struct _timespec it_value;
} itimerspec_t;
// todo: more detailed description
// The host_file_buffer struct includes /etc/resolv.conf, /etc/hosts and /etc/hostname buffer
struct host_file_buffer {
const char* resolv_conf_ptr;
const char* hosts_ptr;
const char* hostname_ptr;
const char* resolv_conf_buf;
const char* hosts_buf;
const char* hostname_buf;
};
#define FD_SETSIZE 1024

@ -98,7 +98,7 @@ pub extern "C" fn occlum_ecall_init(
});
// Parse host file
let resolv_conf_ptr = unsafe { (*file_buffer).resolv_conf_ptr };
let resolv_conf_ptr = unsafe { (*file_buffer).resolv_conf_buf };
match parse_host_file(HostFile::RESOLV_CONF, resolv_conf_ptr) {
Err(e) => {
error!("failed to parse /etc/resolv.conf: {}", e.backtrace());
@ -111,12 +111,13 @@ pub extern "C" fn occlum_ecall_init(
}
}
let hostname_ptr = unsafe { (*file_buffer).hostname_ptr };
let hostname_ptr = unsafe { (*file_buffer).hostname_buf };
match parse_host_file(HostFile::HOSTNAME, hostname_ptr) {
Err(e) => {
error!("failed to parse /etc/hostname: {}", e.backtrace());
}
Ok(hostname_str) => {
misc::init_nodename(&hostname_str);
*HOSTNAME_STR.write().unwrap() = Some(hostname_str);
if let Err(e) = write_host_file(HostFile::HOSTNAME) {
error!("failed to write /etc/hostname: {}", e.backtrace());
@ -124,7 +125,7 @@ pub extern "C" fn occlum_ecall_init(
}
}
let hosts_ptr = unsafe { (*file_buffer).hosts_ptr };
let hosts_ptr = unsafe { (*file_buffer).hosts_buf };
match parse_host_file(HostFile::HOSTS, hosts_ptr) {
Err(e) => {
error!("failed to parse /etc/hosts: {}", e.backtrace());

@ -10,4 +10,4 @@ mod uname;
pub use self::random::{do_getrandom, get_random, RandFlags};
pub use self::rlimit::{do_prlimit, resource_t, rlimit_t, ResourceLimits};
pub use self::sysinfo::{do_sysinfo, sysinfo_t};
pub use self::uname::{do_uname, utsname_t};
pub use self::uname::{do_uname, init_nodename, utsname_t};

@ -1,7 +1,5 @@
use super::*;
use crate::fs::{AccessMode, CreationFlags, FileMode, FsView};
use std::ffi::{CStr, CString};
use std::str;
/// A sample of `struct utsname`
/// ```
/// sysname = Linux
@ -26,7 +24,7 @@ pub struct utsname_t {
pub fn do_uname(name: &mut utsname_t) -> Result<()> {
copy_from_cstr_to_u8_array(&SYSNAME, &mut name.sysname);
obtain_nodename(&mut name.nodename);
copy_from_cstr_to_u8_array(&NODENAME.read().unwrap(), &mut name.nodename);
copy_from_cstr_to_u8_array(&RELEASE, &mut name.release);
copy_from_cstr_to_u8_array(&VERSION, &mut name.version);
copy_from_cstr_to_u8_array(&MACHINE, &mut name.machine);
@ -36,7 +34,7 @@ pub fn do_uname(name: &mut utsname_t) -> Result<()> {
lazy_static! {
static ref SYSNAME: CString = CString::new("Occlum").unwrap();
static ref NODENAME: CString = CString::new("occlum-node").unwrap();
static ref NODENAME: RwLock<CString> = RwLock::new(CString::new("occlum-node").unwrap());
static ref RELEASE: CString = CString::new("0.1").unwrap();
static ref VERSION: CString = CString::new("0.1").unwrap();
static ref MACHINE: CString = CString::new("x86-64").unwrap();
@ -50,31 +48,8 @@ fn copy_from_cstr_to_u8_array(src: &CStr, dst: &mut [u8]) {
dst[len] = 0;
}
fn obtain_nodename(dst: &mut [u8]) {
const HOSTNAME_PATH: &'static str = "/etc/hostname";
let fs_view = FsView::new();
let hostname_file = match fs_view.open_file(
HOSTNAME_PATH,
AccessMode::O_RDONLY as u32,
FileMode::from_bits(0o666).unwrap(),
) {
Ok(file) => file,
Err(e) => {
// If failed to open hostname file, use "occlum-node" nodename.
error!("failed to open /etc/hostname: {}", e.backtrace());
copy_from_cstr_to_u8_array(&NODENAME, dst);
return;
}
};
let mut nodename: [u8; 65] = [0; 65];
hostname_file.read(&mut nodename);
// The \n need to be eliminated.
let nodename_string = str::from_utf8(&nodename).unwrap().replace("\n", "");
let len = nodename_string.len();
dst[..len].copy_from_slice(&nodename_string.into_bytes());
dst[len] = 0;
pub fn init_nodename(nodename_str: &str) {
let nodename_cstr = CString::new(nodename_str).unwrap();
let mut nodename = NODENAME.write().unwrap();
*nodename = nodename_cstr;
}

@ -6,9 +6,9 @@ use std::str;
#[repr(C)]
pub struct host_file_buffer {
pub resolv_conf_ptr: *const c_char,
pub hosts_ptr: *const c_char,
pub hostname_ptr: *const c_char,
pub resolv_conf_buf: *const c_char,
pub hosts_buf: *const c_char,
pub hostname_buf: *const c_char,
}
pub enum HostFile {
@ -57,15 +57,22 @@ pub fn parse_host_file(host_file: HostFile, host_file_ptr: *const c_char) -> Res
let host_file_str = str::from_utf8(host_file_bytes)
.map_err(|_| errno!(EINVAL, "host file contains non UTF-8 characters"))?;
// Parse and inspect host file
match host_file {
HostFile::HOSTS => {
// TODO: Parsing hosts
}
HostFile::HOSTNAME => {
// TODO: Parsing hostname
if let Err(_) = hosts_parser_util::parse_hosts_buffer(host_file_bytes) {
return_errno!(EINVAL, "malformated host /etc/hosts");
}
}
HostFile::HOSTNAME => match hosts_parser_util::parse_hostname_buffer(host_file_bytes) {
Err(_) => {
return_errno!(EINVAL, "malformated host /etc/hostname");
}
Ok(hostname_str) => {
return Ok(hostname_str);
}
},
HostFile::RESOLV_CONF => {
// Parse and inspect host file
if let Err(_) = resolv_conf::Config::parse(host_file_bytes) {
return_errno!(EINVAL, "malformated host /etc/resolv.conf");
}

@ -0,0 +1,103 @@
use super::*;
use regex::Regex;
use std::net::IpAddr;
use std::path::Path;
use std::str;
use std::str::FromStr;
lazy_static! {
// The hostname regex is compliant with RFC1123
static ref HOSTNAME_RE: Regex = Regex::new(r"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$").unwrap();
}
#[derive(Debug, Default, Clone)]
pub struct HostEntry {
ip: String,
hostname: Vec<String>,
}
#[derive(Debug, Default, Clone)]
pub struct Hosts {
pub entries: Vec<HostEntry>,
}
impl FromStr for HostEntry {
type Err = error::Error;
fn from_str(line: &str) -> Result<Self> {
let slice: Vec<String> = line.split_whitespace().map(|s| s.to_string()).collect();
// check IP:
let ip = match slice.first() {
Some(ip) => ip,
None => {
return_errno!(EINVAL, "malformated ip in hosts file");
}
};
let _ip_addr: IpAddr = match ip.parse() {
Ok(ip) => ip,
Err(_) => {
return_errno!(EINVAL, "malformated ip in hosts file");
}
};
let mut hostname: Vec<String> = Vec::new();
for i in slice[1..].to_vec() {
if !HOSTNAME_RE.is_match(&i) {
return_errno!(EINVAL, "malformated hostname in hosts file");
}
hostname.push(i.to_owned());
}
if hostname.is_empty() {
return_errno!(EINVAL, "malformated hostname in hosts file");
}
Ok(HostEntry {
ip: ip.to_string(),
hostname,
})
}
}
pub fn parse_hosts_buffer(bytes: &[u8]) -> Result<Hosts> {
let mut hosts: Hosts = Default::default();
for (_, line) in bytes.split(|&x| x == b'\n').enumerate() {
let line = str::from_utf8(line).unwrap();
let line = line.trim_start();
match line.chars().next() {
// comment
Some('#') => continue,
// empty line
None => continue,
// valid line
Some(_) => {}
}
hosts.entries.push(line.parse()?);
}
Ok(hosts)
}
pub fn parse_hostname_buffer(bytes: &[u8]) -> Result<String> {
let mut hostname: Vec<String> = Vec::new();
for (_, line) in bytes.split(|&x| x == b'\n').enumerate() {
let line = str::from_utf8(line).unwrap();
let line = line.trim_start();
match line.chars().next() {
// comment
Some('#') => continue,
// empty line
None => continue,
// valid line
Some(_) => {}
}
if (!HOSTNAME_RE.is_match(&line)) | (line.len() > 64) {
return_errno!(EINVAL, "malformated hostname in /etc/hostname file");
}
hostname.push(line.to_owned());
}
if hostname.len() != 1 {
return_errno!(EINVAL, "malformated hostname in /etc/hostname file");
}
Ok(hostname[0].clone())
}

@ -2,6 +2,7 @@ use super::*;
pub mod dirty;
pub mod host_file_util;
pub mod hosts_parser_util;
pub mod log;
pub mod mem_util;
pub mod mpx_util;

@ -93,11 +93,10 @@ struct occlum_pal_create_process_args {
int *pid;
};
// todo: more detailed description
struct host_file_buffer {
const char *resolv_conf_ptr;
const char *hosts_ptr;
const char *hostname_ptr;
const char *resolv_conf_buf;
const char *hosts_buf;
const char *hostname_buf;
};
/*
@ -165,6 +164,8 @@ int occlum_pal_kill(int pid, int sig);
*/
int occlum_pal_destroy(void);
void free_host_file_buffer(struct host_file_buffer file_buffer);
#ifdef __cplusplus
}
#endif

@ -108,9 +108,9 @@ int occlum_pal_init(const struct occlum_pal_attr *attr) {
int ecall_ret = 0;
struct host_file_buffer file_buffer = {
.hostname_ptr = pal_load_file("/etc/hostname"),
.hosts_ptr = pal_load_file("/etc/hosts"),
.resolv_conf_ptr = pal_load_file("/etc/resolv.conf"),
.hostname_buf = pal_load_file_to_string("/etc/hostname"),
.hosts_buf = pal_load_file_to_string("/etc/hosts"),
.resolv_conf_buf = pal_load_file_to_string("/etc/resolv.conf"),
};
const struct host_file_buffer *file_buffer_ptr = &file_buffer;
@ -118,12 +118,7 @@ int occlum_pal_init(const struct occlum_pal_attr *attr) {
sgx_status_t ecall_status = occlum_ecall_init(eid, &ecall_ret, attr->log_level,
resolved_path, file_buffer_ptr);
free((void *)file_buffer.hostname_ptr);
file_buffer.hostname_ptr = NULL;
free((void *)file_buffer.hosts_ptr);
file_buffer.hosts_ptr = NULL;
free((void *)file_buffer.resolv_conf_ptr);
file_buffer.resolv_conf_ptr = NULL;
free_host_file_buffer(file_buffer);
if (ecall_status != SGX_SUCCESS) {
const char *sgx_err = pal_get_sgx_error_msg(ecall_status);
@ -285,6 +280,17 @@ int occlum_pal_destroy(void) {
return ret;
}
void free_host_file_buffer(struct host_file_buffer file_buffer) {
free((void *)file_buffer.hostname_buf);
file_buffer.hostname_buf = NULL;
free((void *)file_buffer.hosts_buf);
file_buffer.hosts_buf = NULL;
free((void *)file_buffer.resolv_conf_buf);
file_buffer.resolv_conf_buf = NULL;
}
int pal_get_version(void) __attribute__((weak, alias ("occlum_pal_get_version")));
int pal_init(const struct occlum_pal_attr *attr)\

@ -2,7 +2,7 @@
#include <stdlib.h>
#include "pal_log.h"
char *pal_load_file(const char *filename) {
char *pal_load_file_to_string(const char *filename) {
FILE *fp = fopen(filename, "rb");
if (fp == NULL) {
@ -18,7 +18,7 @@ char *pal_load_file(const char *filename) {
return NULL;
}
fread(file_buffer, 1, fsize, fp);
file_buffer[fsize] = 0;
file_buffer[fsize] = '\0';
fclose(fp);
return file_buffer;
}

@ -1,6 +1,6 @@
#ifndef __PAL_LOAD_FILE_H__
#define __PAL_LOAD_FILE_H__
char *pal_load_file(const char *filename);
char *pal_load_file_to_string(const char *filename);
#endif /* __PAL_LOAD_FILE_H__ */