-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhints.rs
87 lines (71 loc) · 2.98 KB
/
hints.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//! Hints to the user made before a query is sent, in case the answer that
//! comes back isn’t what they expect.
use std::collections::BTreeSet;
use std::fs::File;
use std::io;
use log::*;
/// The set of hostnames that are configured to point to a specific host in
/// the hosts file on the local machine. This gets queried before a request is
/// made: because the running OS will consult the hosts file before looking up
/// a hostname, but dog will not, it’s possible for dog to output one address
/// while the OS is using another. dog displays a warning when this is the
/// case, to prevent confusion.
#[derive(Default)]
pub struct LocalHosts {
hostnames: BTreeSet<dns::Labels>,
}
impl LocalHosts {
/// Loads the set of hostnames from the hosts file path on Unix.
#[cfg(unix)]
pub fn load() -> io::Result<Self> {
debug!("Reading hints from /etc/hosts");
Self::load_from_file(File::open("/etc/hosts")?)
}
/// Loads the set of hostnames from the hosts file path on Windows.
#[cfg(windows)]
pub fn load() -> io::Result<Self> {
debug!("Reading hints from /etc/hosts equivalent");
Self::load_from_file(File::open("C:\\Windows\\system32\\drivers\\etc\\hosts")?)
}
/// On other machines, load an empty set of hostnames that match nothing.
#[cfg(all(not(windows), not(unix)))]
pub fn load() -> io::Result<Self> {
Ok(Self::default())
}
/// Reads hostnames from the given file and returns them as a `LocalHosts`
/// struct, or an I/O error if one occurs. The file should be in the
/// standard `/etc/hosts` format, with one entry per line, separated by
/// whitespace, where the first field is the address and the remaining
/// fields are hostname aliases, and `#` signifies a comment.
fn load_from_file(file: File) -> io::Result<Self> {
use std::io::{BufRead, BufReader};
if cfg!(test) {
panic!("load_from_file() called from test code");
}
let reader = BufReader::new(file);
let mut hostnames = BTreeSet::new();
for line in reader.lines() {
let mut line = line?;
if let Some(hash_index) = line.find('#') {
line.truncate(hash_index);
}
for hostname in line.split_ascii_whitespace().skip(1) {
match dns::Labels::encode(hostname) {
Ok(hn) => {
hostnames.insert(hn);
}
Err(e) => {
warn!("Failed to encode local host hint {:?}: {}", hostname, e);
}
}
}
}
trace!("{} hostname hints loaded OK.", hostnames.len());
Ok(Self { hostnames })
}
/// Queries this set of hostnames to see if the given name, which is about
/// to be queried for, exists within the file.
pub fn contains(&self, hostname_in_query: &dns::Labels) -> bool {
self.hostnames.contains(hostname_in_query)
}
}