Skip to content

Commit 0aad36e

Browse files
committed
config: Support hostnames in registrar_ip option
This restores previous behavior where hostnames could be used to set the 'registrar_ip' configuration option. The configuration will try to parse the input configuration string as an IP and in case of failure, try to parse the string as a hostname. Signed-off-by: Anderson Toshiyuki Sasaki <[email protected]>
1 parent d027299 commit 0aad36e

File tree

6 files changed

+136
-14
lines changed

6 files changed

+136
-14
lines changed

keylime-agent/src/config.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use config::{
99
use glob::glob;
1010
use keylime::{
1111
algorithms::{EncryptionAlgorithm, HashAlgorithm, SignAlgorithm},
12+
hostname_parser::parse_hostname,
1213
ip_parser::parse_ip,
1314
list_parser::parse_list,
1415
};
@@ -856,8 +857,12 @@ fn config_translate_keywords(
856857

857858
let ip = parse_ip(config.agent.ip.as_ref())?.to_string();
858859
let contact_ip = parse_ip(config.agent.contact_ip.as_ref())?.to_string();
859-
let registrar_ip =
860-
parse_ip(config.agent.registrar_ip.as_ref())?.to_string();
860+
let registrar_ip = match parse_ip(config.agent.registrar_ip.as_ref()) {
861+
Ok(ip) => ip.to_string(),
862+
Err(_) => {
863+
parse_hostname(config.agent.registrar_ip.as_ref())?.to_string()
864+
}
865+
};
861866

862867
// Validate the configuration
863868

keylime-agent/src/error.rs

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ pub(crate) enum Error {
4747
Io(#[from] std::io::Error),
4848
#[error("Failed to parse IP")]
4949
IpParserError(#[from] keylime::ip_parser::IpParsingError),
50+
#[error("Failed to parse hostname")]
51+
HostnameParserError(
52+
#[from] keylime::hostname_parser::HostnameParsingError,
53+
),
5054
#[error("Text decoding error: {0}")]
5155
Utf8(#[from] std::string::FromUtf8Error),
5256
#[error("Secure Mount error: {0})")]

keylime-agent/src/registrar_agent.rs

+28-12
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,20 @@ pub(crate) async fn do_activate_agent(
8484
) -> crate::error::Result<()> {
8585
let data = Activate { auth_tag };
8686

87-
// Add brackets if the address is IPv6
88-
let parsed_ip = registrar_ip.parse::<IpAddr>()?;
89-
let remote_ip = if parsed_ip.is_ipv6() {
90-
format!("[{registrar_ip}]")
91-
} else {
92-
registrar_ip.to_string()
87+
let remote_ip = match registrar_ip.parse::<IpAddr>() {
88+
Ok(addr) => {
89+
// Add brackets if the address is IPv6
90+
if addr.is_ipv6() {
91+
format!("[{registrar_ip}]")
92+
} else {
93+
registrar_ip.to_string()
94+
}
95+
}
96+
Err(_) => {
97+
// The registrar_ip option can also be a hostname. If it is the case, the hostname was
98+
// already validated during configuration
99+
registrar_ip.to_string()
100+
}
93101
};
94102

95103
#[cfg(test)]
@@ -173,12 +181,20 @@ pub(crate) async fn do_register_agent(
173181
port: Some(port),
174182
};
175183

176-
// Add brackets if the address is IPv6
177-
let parsed_ip = registrar_ip.parse::<IpAddr>()?;
178-
let remote_ip = if parsed_ip.is_ipv6() {
179-
format!("[{registrar_ip}]")
180-
} else {
181-
registrar_ip.to_string()
184+
let remote_ip = match registrar_ip.parse::<IpAddr>() {
185+
Ok(addr) => {
186+
// Add brackets if the address is IPv6
187+
if addr.is_ipv6() {
188+
format!("[{registrar_ip}]")
189+
} else {
190+
registrar_ip.to_string()
191+
}
192+
}
193+
Err(_) => {
194+
// The registrar_ip option can also be a hostname. If it is the case, the hostname was
195+
// already validated during configuration
196+
registrar_ip.to_string()
197+
}
182198
};
183199

184200
#[cfg(test)]

keylime/src/hostname.pest

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
hostname = {SOI ~ label ~ ("." ~ label)* ~ EOI}
2+
label = { ASCII_ALPHANUMERIC+ ~ ("-"+ ~ ASCII_ALPHANUMERIC+)*}

keylime/src/hostname_parser.rs

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright 2024 Keylime Authors
3+
4+
use pest::Parser;
5+
use pest_derive::Parser;
6+
use thiserror::Error;
7+
8+
#[derive(Parser)]
9+
#[grammar = "hostname.pest"]
10+
pub struct HostnameParser;
11+
12+
#[derive(Error, Debug)]
13+
pub enum HostnameParsingError {
14+
#[error("Invalid input {0}")]
15+
InvalidInput(String),
16+
17+
#[error("failed to parse the input {input}")]
18+
ParseError {
19+
input: String,
20+
source: Box<pest::error::Error<Rule>>,
21+
},
22+
}
23+
24+
/// Parses a hostname from a string slice following RFC-1123
25+
///
26+
/// Valid hostnames are formed by labels separated by dots ('.').
27+
///
28+
/// The labels can only contain alphanumeric characters ('a'..'z' | 'A'..'Z' | '0'..'9') and the
29+
/// hyphen ('-'). The labels cannot begin or end with an hyphen.
30+
///
31+
/// # Arguments
32+
///
33+
/// * `hostname` the string to be parsed
34+
///
35+
/// # Returns
36+
///
37+
/// The obtained hostname as a &str if it is a valid hostname
38+
///
39+
/// # Examples
40+
///
41+
/// Valid hostnames:
42+
///
43+
/// * `hostname`
44+
/// * `host-name`
45+
/// * `a.b.c`
46+
/// * `a-b.c-d.e-f`
47+
///
48+
/// Invalid hostnames:
49+
///
50+
/// * `a_b.c`
51+
/// * `a.b-.c`
52+
/// * `a.-b.c`
53+
pub fn parse_hostname(hostname: &str) -> Result<&str, HostnameParsingError> {
54+
let Some(pair) = HostnameParser::parse(Rule::hostname, hostname)
55+
.map_err(|e| HostnameParsingError::ParseError {
56+
input: hostname.to_string(),
57+
source: Box::new(e),
58+
})?
59+
.next()
60+
else {
61+
return Err(HostnameParsingError::InvalidInput(hostname.to_string()));
62+
};
63+
return Ok(pair.as_str());
64+
}
65+
66+
// Unit Testing
67+
#[cfg(test)]
68+
mod tests {
69+
use super::*;
70+
71+
#[test]
72+
fn test_parse_hostname() {
73+
// Sanity: most common case
74+
assert_eq!(parse_hostname("hostname").unwrap(), "hostname"); //#[allow_ci]
75+
assert_eq!(parse_hostname("ab.cd.ef").unwrap(), "ab.cd.ef"); //#[allow_ci]
76+
assert_eq!(parse_hostname("ab-cd-ef").unwrap(), "ab-cd-ef"); //#[allow_ci]
77+
78+
// More advanced cases
79+
assert_eq!(
80+
parse_hostname("hostname-123.test").unwrap(), //#[allow_ci]
81+
"hostname-123.test"
82+
);
83+
assert_eq!(parse_hostname("123-456.789").unwrap(), "123-456.789"); //#[allow_ci]
84+
assert_eq!(parse_hostname("1----9").unwrap(), "1----9"); //#[allow_ci]
85+
86+
// Invalid input
87+
assert!(parse_hostname("-host-na.me").is_err());
88+
assert!(parse_hostname("host-na.me-").is_err());
89+
assert!(parse_hostname(".host-na.me").is_err());
90+
assert!(parse_hostname("host-na.me.").is_err());
91+
assert!(parse_hostname("host_name").is_err());
92+
assert!(parse_hostname("host..name").is_err());
93+
}
94+
}

keylime/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod algorithms;
22
pub mod crypto;
3+
pub mod hostname_parser;
34
pub mod ima;
45
pub mod ip_parser;
56
pub mod list_parser;

0 commit comments

Comments
 (0)