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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use std::net::{Ipv4Addr, Ipv6Addr, AddrParseError};
use std::str::{from_utf8, Utf8Error};
use {Config, Network};
quick_error!{
#[derive(Debug)]
pub enum ParseError {
InvalidUtf8(line: usize, err: Utf8Error) {
display("bad unicode at line {}: {}", line, err)
cause(err)
}
InvalidValue(line: usize) {
display("directive at line {} is improperly formatted \
or contains invalid value", line)
}
InvalidOptionValue(line: usize) {
display("directive options at line {} contains invalid \
value of some option", line)
}
InvalidIp(line: usize, err: AddrParseError) {
display("directive at line {} contains invalid IP: {}", line, err)
}
ExtraData(line: usize) {
display("extra data at the end of the line {}", line)
}
}
}
fn ip_v4_netw(val: &str) -> Result<Network, AddrParseError> {
let mut pair = val.splitn(2, '/');
let ip = try!(pair.next().unwrap().parse());
if let Some(msk) = pair.next() {
Ok(Network::V4(ip, try!(msk.parse())))
} else {
Ok(Network::V4(ip, Ipv4Addr::new(255, 255, 255, 255)))
}
}
fn ip_v6_netw(val: &str) -> Result<Network, AddrParseError> {
let mut pair = val.splitn(2, '/');
let ip = try!(pair.next().unwrap().parse());
if let Some(msk) = pair.next() {
Ok(Network::V6(ip, try!(msk.parse())))
} else {
Ok(Network::V6(ip, Ipv6Addr::new(65535, 65535, 65535, 65535,
65535, 65535, 65535, 65535)))
}
}
pub fn parse(bytes: &[u8]) -> Result<Config, ParseError> {
use self::ParseError::*;
let mut cfg = Config::new();
'lines: for (lineno, line) in bytes.split(|&x| x == b'\n').enumerate() {
for &c in line.iter() {
if c != b'\t' && c != b' ' {
if c == b';' || c == b'#' {
continue 'lines;
} else {
break;
}
}
}
let mut words = try!(from_utf8(line)
.map_err(|e| InvalidUtf8(lineno, e)))
.split_whitespace();
let keyword = match words.next() { Some(x) => x, None => continue };
match keyword {
"nameserver" => {
let srv = try!(words.next().and_then(|x| x.parse().ok())
.ok_or(InvalidValue(lineno)));
cfg.nameservers.push(srv);
if words.next().is_some() {
return Err(ExtraData(lineno));
}
}
"domain" => {
let dom = try!(words.next().and_then(|x| x.parse().ok())
.ok_or(InvalidValue(lineno)));
cfg.search.clear();
cfg.search.push(dom);
if words.next().is_some() {
return Err(ExtraData(lineno));
}
}
"search" => {
cfg.search.clear();
cfg.search.extend(words.map(|x| x.to_string()));
}
"sortlist" => {
cfg.sortlist.clear();
for pair in words {
let netw = try!(ip_v4_netw(pair)
.or_else(|_| ip_v6_netw(pair))
.map_err(|e| InvalidIp(lineno, e)));
cfg.sortlist.push(netw);
}
}
"options" => {
for pair in words {
let mut iter = pair.splitn(2, ':');
let key = iter.next().unwrap();
let value = iter.next();
if iter.next().is_some() {
return Err(ExtraData(lineno));
}
match (key, value) {
("debug", _) => cfg.debug = true,
("ndots", Some(x)) => cfg.ndots = try!(x.parse()
.map_err(|_| InvalidOptionValue(lineno))),
("timeout", Some(x)) => cfg.timeout = try!(x.parse()
.map_err(|_| InvalidOptionValue(lineno))),
("attempts", Some(x)) => cfg.attempts = try!(x.parse()
.map_err(|_| InvalidOptionValue(lineno))),
("rotate", _) => cfg.rotate = true,
("no-check-names", _) => cfg.no_check_names = true,
("inet6", _) => cfg.inet6 = true,
("ip6-bytestring", _) => cfg.ip6_bytestring = true,
("ip6-dotint", _) => cfg.ip6_dotint = true,
("no-ip6-dotint", _) => cfg.ip6_dotint = false,
("edns0", _) => cfg.edns0 = true,
("single-request", _) => cfg.single_request = true,
("single-request-reopen", _)
=> cfg.single_request_reopen = true,
("no-tld-query", _) => cfg.no_tld_query = true,
("use-vc", _) => cfg.use_vc = true,
_ => {}
}
}
}
_ => {}
}
}
Ok(cfg)
}