add new testing harness for DNSSec
This commit is contained in:
parent
f12fd8d23f
commit
32d957d625
@ -5,6 +5,12 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Changed
|
||||
|
||||
- now using env_logger instead of raw logger
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- Server was not properly signing zone after fresh start
|
||||
|
@ -135,13 +135,7 @@ impl Authority {
|
||||
}
|
||||
}
|
||||
|
||||
// zone signing was off during load, now sign the zone.
|
||||
// TODO: this is probably unnecesary, see named, load zone section...
|
||||
if self.is_dnssec_enabled {
|
||||
self.sign_zone().map_err(|e| e.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Persist the state of the current zone to the journal, does nothing if there is no associated
|
||||
|
@ -123,6 +123,8 @@ fn parse_file(
|
||||
}
|
||||
|
||||
fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, String> {
|
||||
debug!("loading zone with config: {:#?}", zone_config);
|
||||
|
||||
let zone_name: Name = zone_config.get_zone().expect("bad zone name");
|
||||
let zone_path: PathBuf = zone_dir.to_owned().join(zone_config.get_file());
|
||||
let journal_path: PathBuf = zone_path.with_extension("jrnl");
|
||||
@ -230,6 +232,7 @@ fn load_zone(zone_dir: &Path, zone_config: &ZoneConfig) -> Result<Authority, Str
|
||||
}
|
||||
}
|
||||
|
||||
info!("signing zone: {:?}", zone_config.get_zone());
|
||||
authority.secure_zone().expect("failed to sign zone");
|
||||
}
|
||||
|
||||
@ -315,7 +318,8 @@ pub fn main() {
|
||||
.and_then(|d| d.help(true).version(Some(version().into())).decode())
|
||||
.unwrap_or_else(|e| e.exit());
|
||||
|
||||
// TODO, this should be set after loading config, but it's necessary for initial log lines, no?
|
||||
// FIXME: add env_logger support
|
||||
// TODO: this should be set after loading config, but it's necessary for initial log lines, no?
|
||||
if args.flag_quiet {
|
||||
logger::TrustDnsLogger::enable_logging(LogLevel::Warn);
|
||||
} else if args.flag_debug {
|
||||
|
131
server/tests/named_test_configs/all_supported_dnssec.toml
Normal file
131
server/tests/named_test_configs/all_supported_dnssec.toml
Normal file
@ -0,0 +1,131 @@
|
||||
##
|
||||
## This is an example configuration file for the TRust-DNS named server.
|
||||
##
|
||||
## The format is in TOML: https://github.com/toml-lang/toml which was chosen
|
||||
## as the configuration format for TRust-DNS. While Trust-DNS is inteaded to
|
||||
## be a drop-in replacement for BIND9, it will not support the named.conf files
|
||||
## directly. At some point, there will be a binary tool for converting the
|
||||
## BIND9 configuration files over to TRust-DNS TOML.
|
||||
##
|
||||
## Many of these options are available as both command line options and
|
||||
## configuration options in these files. In that case, the command line option
|
||||
## will take presidence.
|
||||
##
|
||||
## Comments with two hash marks, ##, document the config parameter
|
||||
## Comments with one hash mark, #, is an example line and should be the default
|
||||
##
|
||||
## The root options are similar to the options in 'options { .. }' in named.conf
|
||||
|
||||
## listen_addrs: address on which to listen for incoming connections
|
||||
## this can be a list of ipv4 or ipv6 addresses
|
||||
# listen_addrs_ipv4 = ["0.0.0.0"]
|
||||
# listen_addrs_ipv6 = ["::0"]
|
||||
|
||||
## listen_port: port on which to list, default 53
|
||||
# listen_port = 53
|
||||
|
||||
## tcp_request_timeout: TCP request timeout in seconds. Allows TCP connections
|
||||
## to timeout if there are no requests from a client in the specified amount of
|
||||
## time. This is not a socket level timeout, so trickles of data will not count,
|
||||
## a full request must be received for it to not count against the timeout.
|
||||
## Specifying a timeout of 0 will disable it.
|
||||
# tcp_request_timeout = 5
|
||||
|
||||
## DNS over TLS certificate information.
|
||||
## if create_if_absent is true, a self-signed cert, with an Ellyptic Curve P256 key,
|
||||
## will be created and used,
|
||||
## beside the cert will be a CSR which can be used (if desired) to have a CA sign. Subsequent
|
||||
## to signing, replace the pkcs12 file (with private key embedded) and restart
|
||||
## the server.
|
||||
# tls_cert = { path = "path/to/some.pkcs12", create_if_absent = "false", subject_name = "ns.example.com", password = "if_encrypted" }
|
||||
|
||||
## port on which to listent, default 853 (should not be 53)
|
||||
# tls_listen_port = 853
|
||||
|
||||
## directory: path on the host filesystem to where zone files are stored.
|
||||
# directory = "/var/named"
|
||||
|
||||
## Default zones, these should be present on all nameservers, except in rare
|
||||
## configuration cases
|
||||
[[zones]]
|
||||
zone = "localhost"
|
||||
zone_type = "Master"
|
||||
file = "default/localhost.zone"
|
||||
|
||||
[[zones]]
|
||||
zone = "0.0.127.in-addr.arpa"
|
||||
zone_type = "Master"
|
||||
file = "default/127.0.0.1.zone"
|
||||
|
||||
[[zones]]
|
||||
zone = "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa"
|
||||
zsone_type = "Master"
|
||||
file = "default/ipv6_1.zone"
|
||||
|
||||
[[zones]]
|
||||
zone = "255.in-addr.arpa"
|
||||
zone_type = "Master"
|
||||
file = "default/255.zone"
|
||||
|
||||
[[zones]]
|
||||
zone = "0.in-addr.arpa"
|
||||
zone_type = "Master"
|
||||
file = "default/0.zone"
|
||||
|
||||
[[zones]]
|
||||
## zone: this is the ORIGIN of the zone, aka the base name, '.' is implied on the end
|
||||
zone = "example.com"
|
||||
|
||||
## zone_type: Master, Slave, Hint, Forward
|
||||
zone_type = "Master"
|
||||
|
||||
## file: this is relative to the directory above
|
||||
file = "example.com.zone"
|
||||
|
||||
## if false, updates will not be allowed, default false
|
||||
# allow_update = false
|
||||
|
||||
## if true, looks to see if a chained pem file exists at $file.pem (see
|
||||
## supported_algorithms below).
|
||||
## these keys will also be registered as authorities for update,
|
||||
## meaning that SIG(0) updates can be established by initially using these
|
||||
## keys. the zone will be signed with all specified keys, it may be desirable
|
||||
## to limit this set for performance reasons.
|
||||
enable_dnssec = true
|
||||
|
||||
## set of DNSSEC algorithms to use to sign the zone. enable_dnssec must be true.
|
||||
## these will be lookedup by $file.{key_name}.pem, for backward compatability
|
||||
## with previous versions of TRust-DNS, if enable_dnssec is enabled but
|
||||
## supported_algorithms is not specified, it will default to "RSASHA256" and
|
||||
## look for the $file.pem for the key. To control key length, or other options
|
||||
## keys of the specified formats can be generated in PEM format. Instructions
|
||||
## for custom keys can be found elsewhere.
|
||||
##
|
||||
## supported extensions are 'der', 'pem'. ED25519 keys are only supported
|
||||
## with 'raw', and are the only keys that support 'raw'.
|
||||
##
|
||||
## the currently supported set of supported_algorithms are
|
||||
## ["RSASHA256", "RSASHA512", "ECDSAP256SHA256", "ECDSAP384SHA384", "ED25519"]
|
||||
##
|
||||
## keys are listed in pairs of key_name and algorithm, the search path is the
|
||||
## same directory has the zone $file (this section would be relative to the
|
||||
## example.com zone):
|
||||
[[zones.keys]]
|
||||
key_path = "./tests/named_test_configs/dnssec/rsa_2048.pem"
|
||||
## the password used to encrypt/decrypt the file (must be PEM), blank for none
|
||||
password = "123456"
|
||||
## specify the algorithm
|
||||
algorithm = "RSASHA256"
|
||||
## this key should be used to sign the zone
|
||||
is_zone_signing_key = true
|
||||
## this key is authorized for dynamic update access to the zone via SIG0
|
||||
# is_zone_update_auth = true
|
||||
## create the key if it is not found
|
||||
# create_if_absent = false
|
||||
#
|
||||
# [[zones.keys]]
|
||||
# key = "/path/to/my_ed25519.raw"
|
||||
# algorithm = "ED25519"
|
||||
## for keys that are not zone signing, the pem need only include the pubic_key
|
||||
# is_zone_signing_key = false
|
||||
# is_zone_update_auth = true
|
9
server/tests/named_test_configs/dnssec/gen-keys.sh
Executable file
9
server/tests/named_test_configs/dnssec/gen-keys.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
OPENSSL=/usr/local/opt/openssl/bin/openssl
|
||||
|
||||
RSA_2048=rsa_2048.pem
|
||||
RSA_2048_PUB=rsa_2048_pub.pem
|
||||
|
||||
[ -f ${RSA_2048:?} ] || ${OPENSSL:?} genrsa -des3 -out ${RSA_2048:?} 2048
|
||||
#[ -f ${RSA_2048_PUB:?} ] || ${OPENSSL:?} rsa -in ${RSA_2048:?} -outform PEM -pubout -out ${RSA_2048_PUB:?}
|
30
server/tests/named_test_configs/dnssec/rsa_2048.pem
Normal file
30
server/tests/named_test_configs/dnssec/rsa_2048.pem
Normal file
@ -0,0 +1,30 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: DES-EDE3-CBC,790415AA1C993188
|
||||
|
||||
d0m+WncbmZOe3fkXpBmHFjYCPMZaxZubVHX+s0J+ONX74+Sw4YH4tyPX2kiMcPyB
|
||||
jReZaYyaDG5td5fU7rDdo26YJv0ytBycJJgZ7Vio7baCY/6nIgj9DV3m7/ZlEWPQ
|
||||
8caArZTa7UtRKAXQ7oto9vmoWAtoNWZIfWVE4J8QTqYLebx1Ef9qRYVJVC/jj4qY
|
||||
9lxYEn9aBSWL8s1s0334MqXkXPYKNKMdXr70At02SMWXflobuLoxiK8+SaRkW1uN
|
||||
DJRz+wzqVAVzMEECahNhsqvz4T/vhORGFpACXKxrafVPYiKPIlJxMt9TBSZaficU
|
||||
y0nNEr4gYm7K9kDUbRWt7+2kAWhFcPEfRWGuGj8DvcXM89KksORWwn0ZvHB3K9De
|
||||
nbPKHDAjU8vwzhXFH2n7YCfyDhf6grO+tDpcI9eEYg5R9VzAOmLLru1gLM5P2GPo
|
||||
80Y2L3XX70usbjcL+9VPdBVQrawTWIXNIb9aq/yw1M2kPPX+FpXIK1zLPOovnSBR
|
||||
7bj7d2HOSXy8ZfWCcxefRbSqXjEsOE5cizskquAe7qGKOx4YJYukjqFujaXJCyTi
|
||||
HawyNHKJrmMULpTUR5xFnYldBcyDDqCP+gTDb5v2UZkdewTNgsLZ2Y28ljWBh8f0
|
||||
byN/GXFT9ciArCLaNqKn95IFJSve2zePS85rnucUrpmc3ryMAcnfQ/67eh04X2m4
|
||||
JudWqx56Vj9Empt43XrB9Enmy7XI9b4L9L+KNE+fe/4Vjbm2XyUR2UPSVWZH2GPL
|
||||
gyAipnBpFUTCH5C/d/J1EpHoSjtrezVydM8UjQThJ4hi3RdEVnvecNWFjN8SfV5u
|
||||
LXBVXREkctZXBgrRsAuCaMKaOWahflafEUpE1PtMogBR9rEu6lcHlbGfK2Tk9vuX
|
||||
fHrhIJ+nObyhpWXivBTmOEseW20KrhBKuAc1ci8ziF+1twwa+kFBvCEC19jszjxj
|
||||
1oaXuXg3vibZ27Xt0QYy2UPMr7PFvfA/4zdJE6BiUzDhFP/27AGtLiHGXkllOeAd
|
||||
DgNOWOwQKqNJkripTjeM8e2VNK1+pbm7NZ1Tp9U5pypvHX6yfSXJ9ELkM4L2FEXY
|
||||
WkwYeaGZz8I/N0/y6czipJRcVKnGba6Lfq0bsTPWQk0xHEGGySXU8+1E1Cbt/WAE
|
||||
kf5Nm+yop62pU/5CaZzNYit7GL6GO5beKaAOY25J2qFgCM/iEXzGWr1K4k5YN58i
|
||||
ahUerORL85SAKJA0wzMd2u3AyQzRDb3fydtW4qFgfUSAHOOT+tzWXeG/3mTCz3iU
|
||||
PwRpU/iaHAAOAaEy4pWgU9KCEk6rIfph6DUVR6y5GpQn1RjtsA3YzvQ1xRRdDm0k
|
||||
qRGcYWjQZa3xYXNJskuZILifr2DtkLhhdeisJCK4jdZQbwNJ2eJqMP/zgXxFAPTR
|
||||
+YQVLBNkOQLoug4QeOiZzZ0v6RYW1Pcv1eXU5SWO82mdmAdMNXhcyBUITM+bnLSg
|
||||
wq63fZ7WKTK9jgbj7d9HfHX01lIA0kEjUSsqJ1x36/zSyuexvKGNSeXQuaMpbhVp
|
||||
rV5L+jw1lZCz9Gcsh9LryJzyHmjfN63mB8DHZ33m4Kp0EaOaD8QqYtO7rNV/eRpZ
|
||||
-----END RSA PRIVATE KEY-----
|
@ -37,9 +37,6 @@
|
||||
## port on which to listent, default 853 (should not be 53)
|
||||
# tls_listen_port = 853
|
||||
|
||||
## log_level: Trace, Debug, Info, Warn, Error
|
||||
# log_level = "Info"
|
||||
|
||||
## directory: path on the host filesystem to where zone files are stored.
|
||||
# directory = "/var/named"
|
||||
|
||||
@ -110,7 +107,7 @@ file = "example.com.zone"
|
||||
## example.com zone):
|
||||
# [[zones.keys]]
|
||||
## relative to the zone $file
|
||||
# key = "my_rsa_2048.pem"
|
||||
# key_path = "my_rsa_2048.pem"
|
||||
## the password used to encrypt/decrypt the file (must be PEM), blank for none
|
||||
# password = ""
|
||||
## specify the algorithm
|
||||
@ -121,7 +118,7 @@ file = "example.com.zone"
|
||||
# is_zone_update_auth = true
|
||||
#
|
||||
# [[zones.keys]]
|
||||
# key = "/path/to/my_ed25519.raw"
|
||||
# key_path = "/path/to/my_ed25519.raw"
|
||||
# algorithm = "ED25519"
|
||||
## for keys that are not zone signing, the pem need only include the pubic_key
|
||||
# is_zone_signing_key = false
|
||||
|
@ -38,14 +38,21 @@ where
|
||||
println!("using server src path: {}", server_path);
|
||||
|
||||
let mut named = Command::new(&format!("{}/../target/debug/named", server_path))
|
||||
.stdout(Stdio::piped())
|
||||
//.arg("-d")
|
||||
.arg(&format!("--config={}/tests/named_test_configs/{}", server_path, toml))
|
||||
.arg(&format!("--zonedir={}/tests/named_test_configs", server_path))
|
||||
.arg(&format!("--port={}", test_port))
|
||||
.arg(&format!("--tls-port={}", test_tls_port))
|
||||
.spawn()
|
||||
.expect("failed to start named");
|
||||
.stdout(Stdio::piped())
|
||||
.arg("-d")
|
||||
.arg(&format!(
|
||||
"--config={}/tests/named_test_configs/{}",
|
||||
server_path,
|
||||
toml
|
||||
))
|
||||
.arg(&format!(
|
||||
"--zonedir={}/tests/named_test_configs",
|
||||
server_path
|
||||
))
|
||||
.arg(&format!("--port={}", test_port))
|
||||
.arg(&format!("--tls-port={}", test_tls_port))
|
||||
.spawn()
|
||||
.expect("failed to start named");
|
||||
|
||||
let mut named_out = BufReader::new(mem::replace(&mut named.stdout, None).expect("no stdout"));
|
||||
|
||||
@ -130,7 +137,32 @@ where
|
||||
// This only validates that a query to the server works, it shouldn't be used for more than this.
|
||||
// i.e. more complex checks live with the clients and authorities to validate deeper funcionality
|
||||
#[allow(dead_code)]
|
||||
pub fn query(io_loop: &mut Core, client: &mut BasicClientHandle) -> bool {
|
||||
pub fn query<C: ClientHandle>(io_loop: &mut Core, client: &mut C) -> bool {
|
||||
let name = domain::Name::from_labels(vec!["www", "example", "com"]);
|
||||
|
||||
println!("sending request");
|
||||
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A));
|
||||
println!("got response: {}", response.is_ok());
|
||||
if response.is_err() {
|
||||
return false;
|
||||
}
|
||||
let response = response.unwrap();
|
||||
|
||||
|
||||
let record = &response.answers()[0];
|
||||
|
||||
if let &RData::A(ref address) = record.rdata() {
|
||||
address == &Ipv4Addr::new(127, 0, 0, 1)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// This only validates that a query to the server works, it shouldn't be used for more than this.
|
||||
// i.e. more complex checks live with the clients and authorities to validate deeper funcionality
|
||||
#[allow(dead_code)]
|
||||
pub fn query_all_dnssec<C: ClientHandle>(io_loop: &mut Core, client: &mut C) -> bool {
|
||||
// FIXME: query for all Records and show that they are good.
|
||||
let name = domain::Name::from_labels(vec!["www", "example", "com"]);
|
||||
|
||||
println!("sending request");
|
||||
|
80
server/tests/z_named_test_rsa_dnssec.rs
Normal file
80
server/tests/z_named_test_rsa_dnssec.rs
Normal file
@ -0,0 +1,80 @@
|
||||
extern crate log;
|
||||
extern crate trust_dns;
|
||||
extern crate tokio_core;
|
||||
extern crate openssl;
|
||||
|
||||
mod server_harness;
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::path::Path;
|
||||
use std::io::*;
|
||||
use std::net::*;
|
||||
|
||||
use openssl::x509::X509;
|
||||
|
||||
use tokio_core::reactor::Core;
|
||||
|
||||
use trust_dns::client::*;
|
||||
use trust_dns::tcp::TcpClientStream;
|
||||
use trust_dns::tls::TlsClientStream;
|
||||
use trust_dns::rr::dnssec::*;
|
||||
|
||||
use server_harness::{named_test_harness, query};
|
||||
|
||||
fn trust_anchor(public_key_path: &Path, format: KeyFormat, algorithm: Algorithm) -> TrustAnchor {
|
||||
let mut file = File::open(public_key_path).expect("key not found");
|
||||
let mut buf = Vec::<u8>::new();
|
||||
|
||||
file.read_to_end(&mut buf).expect("could not read key");
|
||||
let key_pair = format.decode_key(&buf, Some("123456"), algorithm).expect(
|
||||
"could not decode key",
|
||||
);
|
||||
|
||||
let public_key = key_pair.to_public_key().unwrap();
|
||||
let mut trust_anchor = TrustAnchor::new();
|
||||
|
||||
trust_anchor.insert_trust_anchor(public_key);
|
||||
trust_anchor
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rsa() {
|
||||
use trust_dns::logger;
|
||||
use log::LogLevel;
|
||||
logger::TrustDnsLogger::enable_logging(LogLevel::Debug);
|
||||
|
||||
let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or(".".to_owned());
|
||||
let server_path = Path::new(&server_path);
|
||||
|
||||
named_test_harness("all_supported_dnssec.toml", |port, _| {
|
||||
let mut io_loop = Core::new().unwrap();
|
||||
let addr: SocketAddr = ("127.0.0.1", port)
|
||||
.to_socket_addrs()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap();
|
||||
let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
|
||||
let client = ClientFuture::new(stream, sender, &io_loop.handle(), None);
|
||||
|
||||
let trust_anchor = trust_anchor(
|
||||
&server_path.join("tests/named_test_configs/dnssec/rsa_2048.pem"),
|
||||
KeyFormat::Pem,
|
||||
Algorithm::RSASHA256,
|
||||
);
|
||||
let mut client = SecureClientHandle::with_trust_anchor(client, trust_anchor);
|
||||
|
||||
assert!(query(&mut io_loop, &mut client));
|
||||
|
||||
// just tests that multiple queries work
|
||||
let addr: SocketAddr = ("127.0.0.1", port)
|
||||
.to_socket_addrs()
|
||||
.unwrap()
|
||||
.next()
|
||||
.unwrap();
|
||||
let (stream, sender) = TcpClientStream::new(addr, &io_loop.handle());
|
||||
let mut client = ClientFuture::new(stream, sender, &io_loop.handle(), None);
|
||||
|
||||
assert!(query(&mut io_loop, &mut client));
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user