add new testing harness for DNSSec

This commit is contained in:
Benjamin Fry 2017-09-27 23:36:12 -07:00
parent f12fd8d23f
commit 32d957d625
9 changed files with 305 additions and 22 deletions

View File

@ -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

View File

@ -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

View File

@ -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 {

View 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

View 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:?}

View 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-----

View File

@ -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

View File

@ -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");

View 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));
})
}