Bfry/split client server (#68)

* initial split of server

* split client and server crates

* create scripts for running tests across crates

* fix target location in tests

* trying different travis settings for getting kcov working

* fix directory change in kcov setup

* fixing for loop for the kcov tests

* added some env config for config tests

* adding back sudo settings, and additional coveralls merging config

* fix exclude paths

* merging coverage reports

* fixing results kcov paths
This commit is contained in:
Benjamin Fry 2016-11-08 21:28:51 -08:00 committed by GitHub
parent fb23b277b6
commit 2b705dc300
128 changed files with 3873 additions and 2498 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@
# Generated by Cargo
/target/
**/target/

View File

@ -1,3 +1,5 @@
sudo: required
dist: trusty
language: rust
os:
- linux
@ -9,9 +11,7 @@ rust:
matrix:
allow_failure:
- rust: nightly
after_success: |
sudo apt-get install libcurl4-openssl-dev libelf-dev libdw-dev &&
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make &&
sudo make install && cd ../.. &&
kcov --coveralls-id=$TRAVIS_JOB_ID --exclude-pattern=/.cargo target/kcov target/debug/trust_dns-*
script: scripts/run_tests.sh
after_success: scripts/run_kcov.sh
notifications:
webhooks: https://coveralls.io/webhook?repo_token=0fXi81cx3Khi8g0Q0mGqsABePoEdJfMcf

View File

@ -2,6 +2,11 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## unreleased (0.9.0)
### Changed
- Split Server and Client into separate crates, #43
- Moved many integration tests to `tests` from `src`, #52
## 0.8.1
### Fixed
- Fix build on rustc 1.11, #66

24
Cargo.lock generated
View File

@ -1,10 +1,9 @@
[root]
name = "trust-dns"
name = "trust-dns-server"
version = "0.8.1"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"data-encoding 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -18,6 +17,7 @@ dependencies = [
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns 0.8.1",
]
[[package]]
@ -482,6 +482,26 @@ dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "trust-dns"
version = "0.8.1"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"data-encoding 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns-server 0.8.1",
]
[[package]]
name = "user32-sys"
version = "0.2.0"

View File

@ -1,82 +1,2 @@
[package]
name = "trust-dns"
version = "0.8.1"
authors = ["Benjamin Fry <benjaminfry@me.com>"]
# A short blurb about the package. This is not rendered in any format when
# uploaded to crates.io (aka this is not markdown)
description = """
TRust-DNS is a safe and secure DNS server and client with DNSec support.
Eventually this could be a replacement for BIND9. DNSSec on the client side,
with NSEC validation for negative records, is complete. The client and
server both support dynamic DNS with authenticated requests.
"""
# These URLs point to more information about the repository
documentation = "https://docs.rs/trust-dns"
homepage = "http://www.trust-dns.org/index.html"
repository = "https://github.com/bluejekyll/trust-dns"
# This points to a file in the repository (relative to this Cargo.toml). The
# contents of this file are stored and indexed in the registry.
readme = "README.md"
# This is a small list of keywords used to categorize and search for this
# package.
keywords = ["DNS", "BIND", "dig", "named", "dnssec"]
# This is a string description of the license for this package. Currently
# crates.io will validate the license provided against a whitelist of known
# license identifiers from http://spdx.org/licenses/. Multiple licenses can
# be separated with a `/`
license = "MIT/Apache-2.0"
# custom build steps
build = "build.rs"
[features]
[lib]
name = "trust_dns"
path = "src/lib.rs"
[[bin]]
name = "named"
path = "src/named.rs"
[profile.dev]
opt-level = 0 # Controls the --opt-level the compiler builds with
debug = true # Controls whether the compiler passes `-g`
rpath = false # Controls whether the compiler passes `-C rpath`
lto = false # Controls `-C lto` for binaries and staticlibs
debug-assertions = true # Controls whether debug assertions are enabled
codegen-units = 1 # Controls whether the compiler passes `-C codegen-units`
# `codegen-units` is ignored when `lto = true`
# The testing profile, used for `cargo test`
[profile.test]
opt-level = 0
debug = true
rpath = false
lto = false
debug-assertions = true
codegen-units = 1
[dependencies]
backtrace = "^0.2.1"
chrono = "^0.2.21"
data-encoding = "^1.1.2"
docopt = "^0.6.78"
error-chain = "0.1.12"
futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = "^0.5.1"
openssl = "^0.8.3"
rand = "^0.3"
rustc-serialize = "^0.3.18"
rusqlite = "^0.7.3"
time = "^0.1"
tokio-core = "^0.1"
toml = "^0.1"
[workspace]
members = ["client", "server"]

606
client/Cargo.lock generated Normal file
View File

@ -0,0 +1,606 @@
[root]
name = "trust-dns"
version = "0.8.1"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"data-encoding 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns-server 0.8.1",
]
[[package]]
name = "aho-corasick"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "data-encoding"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dbghelp-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "docopt"
version = "0.6.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error-chain"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gdi32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazycell"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libressl-pnacl-sys"
version = "2.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libsqlite3-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "linked-hash-map"
version = "0.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lru-cache"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pkg-config"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pnacl-build-helper"
version = "1.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rusqlite"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libsqlite3-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scoped-tls"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "tempdir"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread-id"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-core"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "trust-dns-server"
version = "0.8.1"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rusqlite 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns 0.8.1",
]
[[package]]
name = "user32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
"checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f"
"checksum backtrace-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ff73785ae8e06bb4a7b09e09f06d7434f9748b86d2f67bdf334b603354497e08"
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
"checksum bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c129aff112dcc562970abb69e2508b40850dd24c274761bb50fb8a0067ba6c27"
"checksum cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de1e760d7b6535af4241fca8bd8adf68e2e7edacc6b29f5d399050c5e48cf88c"
"checksum chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9213f7cd7c27e95c2b57c49f0e69b1ea65b27138da84a170133fd21b07659c00"
"checksum data-encoding 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f13f03d68d1906eb3222536f5756953e30de4dff4417e5d428414fb8edb26723"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)" = "4a7ef30445607f6fc8720f0a0a2c7442284b629cf0d049286860fae23e71c4d9"
"checksum error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faa976b4fd2e4c2b2f3f486874b19e61944d3de3de8b61c9fcf835d583871bcc"
"checksum futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd89497091f8c5d3a65c6b4baf6d2f0731937a7c9217d2f89141b21437a9d96"
"checksum gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "553f11439bdefe755bf366b264820f1da70f3aaf3924e594b886beb9c831bcf5"
"checksum gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0912515a8ff24ba900422ecda800b52f4016a56251922d397c576bf92c690518"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"
"checksum lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce12306c4739d86ee97c23139f3a34ddf0387bbf181bc7929d287025a8c3ef6b"
"checksum libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "044d1360593a78f5c8e5e710beccdc24ab71d1f01bc19a29bcacdba22e8475d8"
"checksum libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "cbc058951ab6a3ef35ca16462d7642c4867e6403520811f28537a4e2f2db3e71"
"checksum libsqlite3-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "663508cb9c1e23363aea1a8b1f7d6340394ebc3bc3a6daebfb9cc99b8feaf2ec"
"checksum linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "83f7ff3baae999fdf921cccf54b61842bb3b26868d50d02dff48052ebec8dd79"
"checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054"
"checksum lru-cache 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "42d50dcb5d9f145df83b1043207e1ac0c37c9c779c4e128ca4655abc3f3cbf8c"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a637d1ca14eacae06296a008fa7ad955347e34efcb5891cfd8ba05491a37907e"
"checksum mio 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "410a1a0ff76f5a226f1e4e3ff1756128e65cd30166e39c3892283e2ac09d5b67"
"checksum miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d5bfc6782530ac8ace97af10a540054a37126b63b0702ddaaa243b73b5745b9a"
"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2"
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
"checksum nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b"
"checksum num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "bde7c03b09e7c6a301ee81f6ddf66d7a28ec305699e3d3b056d2fc56470e3120"
"checksum num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "fb24d9bfb3f222010df27995441ded1e954f8f69cd35021f6bef02ca9552fb92"
"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c"
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
"checksum openssl 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b11754cb6c81bb9e62faaf0eb6d94dde2aab0928c04db5078b74242880f35eb1"
"checksum openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)" = "89c47ee94c352eea9ddaf8e364be7f978a3bb6d66d73176572484238dd5a5c3f"
"checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa"
"checksum pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "61c9231d31aea845007443d62fcbb58bb6949ab9c18081ee1e09920e0cf1118b"
"checksum rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2791d88c6defac799c3f20d74f094ca33b9332612d9aef9078519c82e4fe04a5"
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum rusqlite 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e9b3854687228334d8a579cd2f666ddd7fb46a5f68ac0460da2898394c4679d2"
"checksum rustc-demangle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "662b2795f21ff17df7c4c50c1d955c8b5fa9eaddd1cf1bb32f8de2372ffd989b"
"checksum rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "6159e4e6e559c81bd706afe9c8fd68f547d3e851ce12e76b1de7914bab61691b"
"checksum rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084"
"checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
"checksum semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac"
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
"checksum strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "50c069df92e4b01425a8bf3576d5d417943a6a7272fbabaf5bd80b1aaa76442e"
"checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6"
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
"checksum time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "3c7ec6d62a20df54e07ab3b78b9a3932972f4b7981de295563686849eb3989af"
"checksum tokio-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "659cbae6c954dee37352853816c6a52180e47feb70be73bbfeec6d58c4da4a71"
"checksum toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "0590d72182e50e879c4da3b11c6488dae18fccb1ae0c7a3eda18e16795844796"
"checksum user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ef4711d107b21b410a3a974b1204d9accc8b10dad75d8324b5d755de1617d47"
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"

59
client/Cargo.toml Normal file
View File

@ -0,0 +1,59 @@
[package]
name = "trust-dns"
version = "0.8.1"
authors = ["Benjamin Fry <benjaminfry@me.com>"]
# A short blurb about the package. This is not rendered in any format when
# uploaded to crates.io (aka this is not markdown)
description = """
TRust-DNS is a safe and secure DNS server and client with DNSec support.
Eventually this could be a replacement for BIND9. DNSSec on the client side,
with NSEC validation for negative records, is complete. The client and
server both support dynamic DNS with authenticated requests.
"""
# These URLs point to more information about the repository
documentation = "https://docs.rs/trust-dns"
homepage = "http://www.trust-dns.org/index.html"
repository = "https://github.com/bluejekyll/trust-dns"
# This points to a file in the repository (relative to this Cargo.toml). The
# contents of this file are stored and indexed in the registry.
readme = "README.md"
# This is a small list of keywords used to categorize and search for this
# package.
keywords = ["DNS", "BIND", "dig", "named", "dnssec"]
# This is a string description of the license for this package. Currently
# crates.io will validate the license provided against a whitelist of known
# license identifiers from http://spdx.org/licenses/. Multiple licenses can
# be separated with a `/`
license = "MIT/Apache-2.0"
# custom build steps
build = "build.rs"
[features]
[lib]
name = "trust_dns"
path = "src/lib.rs"
[dependencies]
backtrace = "^0.2.1"
chrono = "^0.2.21"
data-encoding = "^1.1.2"
error-chain = "0.1.12"
futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = "^0.5.1"
openssl = "^0.8.3"
rand = "^0.3"
rustc-serialize = "^0.3.18"
time = "^0.1"
tokio-core = "^0.1"
[dev-dependencies]
trust-dns-server = { version = "*", path = "../server" }

View File

@ -1013,558 +1013,3 @@ impl<C: ClientConnection> Client<C> {
Ok(response)
}
}
#[cfg(test)]
mod test {
use std::net::*;
use chrono::Duration;
use openssl::crypto::rsa::RSA;
use ::authority::Catalog;
use ::authority::authority_tests::{create_example, create_secure_example};
#[allow(deprecated)]
use ::client::{Client, ClientConnection, TestClientConnection};
use ::op::ResponseCode;
use ::rr::{DNSClass, Record, RecordType, domain, RData};
use ::rr::dnssec::{Algorithm, Signer, TrustAnchor};
use ::tcp::TcpClientConnection;
use ::udp::UdpClientConnection;
#[test]
fn test_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let client = Client::new(TestClientConnection::new(&catalog));
test_query(client);
}
#[test]
#[ignore]
fn test_query_udp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_query(client);
}
#[test]
#[ignore]
fn test_query_tcp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_query(client);
}
#[allow(deprecated)]
#[cfg(test)]
fn test_query<C: ClientConnection>(client: Client<C>) {
use std::cmp::Ordering;
let name = domain::Name::with_labels(vec!["WWW".to_string(), "example".to_string(), "com".to_string()]);
let response = client.query(&name, DNSClass::IN, RecordType::A);
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
let response = response.unwrap();
println!("response records: {:?}", response);
assert_eq!(response.get_queries().first().expect("expected query").get_name().cmp_with_case(&name, false), Ordering::Equal);
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
}
#[test]
fn test_secure_query_example_nonet() {
use ::client::client_connection::test::TestClientConnection;
let authority = create_secure_example();
let public_key = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let client = Client::with_trust_anchor(TestClientConnection::new(&catalog), trust_anchor);
test_secure_query_example(client);
}
#[test]
#[ignore]
fn test_secure_query_example_udp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_secure_query_example(client);
}
#[test]
#[ignore]
fn test_secure_query_example_tcp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_secure_query_example(client);
}
#[allow(deprecated)]
#[cfg(test)]
fn test_secure_query_example<C: ClientConnection>(client: Client<C>) {
use log::LogLevel;
use ::logger::TrustDnsLogger;
TrustDnsLogger::enable_logging(LogLevel::Debug);
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
assert!(response.is_ok(), "query for {} failed: {}", name, response.unwrap_err());
let response = response.unwrap();
println!("response records: {:?}", response);
assert!(response.get_edns().expect("edns not here").is_dnssec_ok());
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_udp() {
use ::logger::TrustDnsLogger;
use log::LogLevel;
TrustDnsLogger::enable_logging(LogLevel::Debug);
let c = Client::new(UdpClientConnection::new("8.8.8.8:53".parse().unwrap()).unwrap());
c.secure_query(
&domain::Name::parse("rollernet.us.", None).unwrap(),
DNSClass::IN,
RecordType::DS,
).unwrap();
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp() {
use ::logger::TrustDnsLogger;
use log::LogLevel;
TrustDnsLogger::enable_logging(LogLevel::Debug);
let c = Client::new(TcpClientConnection::new("8.8.8.8:53".parse().unwrap()).unwrap());
c.secure_query(
&domain::Name::parse("rollernet.us.", None).unwrap(),
DNSClass::IN,
RecordType::DS,
).unwrap();
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp_mixed_case() {
use ::logger::TrustDnsLogger;
use log::LogLevel;
TrustDnsLogger::enable_logging(LogLevel::Debug);
let c = Client::new(TcpClientConnection::new("8.8.8.8:53".parse().unwrap()).unwrap());
c.secure_query(
&domain::Name::parse("RollErnet.Us.", None).unwrap(),
DNSClass::IN,
RecordType::DS,
).unwrap();
}
#[test]
fn test_nsec_query_example_nonet() {
use ::client::client_connection::test::TestClientConnection;
let authority = create_secure_example();
let public_key = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let client = Client::with_trust_anchor(TestClientConnection::new(&catalog), trust_anchor);
test_nsec_query_example(client);
}
#[test]
#[ignore]
fn test_nsec_query_example_udp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_nsec_query_example(client);
}
#[test]
#[ignore]
fn test_nsec_query_example_tcp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_nsec_query_example(client);
}
#[allow(deprecated)]
#[cfg(test)]
fn test_nsec_query_example<C: ClientConnection>(client: Client<C>) {
let name = domain::Name::with_labels(vec!["none".to_string(), "example".to_string(), "com".to_string()]);
let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
let response = response.unwrap();
assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
}
#[test]
#[ignore]
fn test_nsec_query_type() {
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
let response = client.secure_query(&name, DNSClass::IN, RecordType::NS);
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
let response = response.unwrap();
// TODO: it would be nice to verify that the NSEC records were validated...
assert_eq!(response.get_response_code(), ResponseCode::NoError);
assert!(response.get_answers().is_empty());
}
// TODO: disabled until I decide what to do with NSEC3 see issue #10
//
// TODO these NSEC3 tests don't work, it seems that the zone is not signed properly.
// #[test]
// #[ignore]
// fn test_nsec3_sdsmt() {
// let addr: SocketAddr = ("75.75.75.75",53).to_socket_addrs().unwrap().next().unwrap();
// let conn = TcpClientConnection::new(addr).unwrap();
// let name = domain::Name::with_labels(vec!["none".to_string(), "sdsmt".to_string(), "edu".to_string()]);
// let client = Client::new(conn);
//
// let response = client.secure_query(&name, DNSClass::IN, RecordType::NS);
// assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
//
// let response = response.unwrap();
// assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
// }
// TODO: disabled until I decide what to do with NSEC3 see issue #10
//
// #[test]
// #[ignore]
// fn test_nsec3_sdsmt_type() {
// let addr: SocketAddr = ("75.75.75.75",53).to_socket_addrs().unwrap().next().unwrap();
// let conn = TcpClientConnection::new(addr).unwrap();
// let name = domain::Name::with_labels(vec!["www".to_string(), "sdsmt".to_string(), "edu".to_string()]);
// let client = Client::new(conn);
//
// let response = client.secure_query(&name, DNSClass::IN, RecordType::NS);
// assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
//
// let response = response.unwrap();
// assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
// }
#[allow(deprecated)]
#[cfg(test)]
fn create_sig0_ready_client<'a>(catalog: &'a mut Catalog) -> (Client<TestClientConnection<'a>>, Signer, domain::Name) {
use chrono::Duration;
use ::rr::rdata::DNSKEY;
let mut authority = create_example();
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
rsa,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_public_key())));
authority.upsert(auth_key, 0);
catalog.upsert(authority.get_origin().clone(), authority);
let client = Client::new(TestClientConnection::new(catalog));
(client, signer, origin)
}
#[test]
fn test_create() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// trying to create again should error
// TODO: it would be cool to make this
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
}
#[test]
fn test_append() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = client.append(record.clone(), origin.clone(), false, &signer).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// show that appending the same thing again is ok, but doesn't add any records
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
}
#[test]
fn test_compare_and_swap() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let current = record;
let mut new = current.clone();
new.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.compare_and_swap(current.clone(), new.clone(), origin.clone(), &signer).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(new.get_name(), new.get_dns_class(), new.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// check the it fails if tried again.
let mut new = new;
new.rdata(RData::A(Ipv4Addr::new(102,12,102,12)));
let result = client.compare_and_swap(current, new.clone(), origin.clone(), &signer).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
let result = client.query(new.get_name(), new.get_dns_class(), new.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
}
#[test]
fn test_delete_by_rdata() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.delete_by_rdata(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_by_rdata(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
}
#[test]
fn test_delete_rrset() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.delete_rrset(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_rrset(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
#[test]
fn test_delete_all() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN, &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rr_type(RecordType::AAAA);
record.rdata(RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN, &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), RecordType::A).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
let result = client.query(record.get_name(), record.get_dns_class(), RecordType::AAAA).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
}

View File

@ -0,0 +1,30 @@
// Copyright (C) 2016 Benjamin Fry <benjaminfry@me.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Trait for client connections
use std::fmt::Debug;
use ::error::*;
/// Trait for client connections
pub trait ClientConnection: Sized+Debug {
/// Sends a serialized message to via this connection, returning the serialized response.
///
/// # Arguments
///
/// * `bytes` - the serialized Message
fn send(&mut self, bytes: Vec<u8>) -> ClientResult<Vec<u8>>;
// TODO: split connect, send and read...
}

View File

@ -777,524 +777,3 @@ pub trait ClientHandle: Clone {
self.send(message)
}
}
#[cfg(test)]
pub mod test {
use std;
use std::fmt;
use std::io;
use std::net::*;
use chrono::Duration;
use futures::{Async, Future, finished, Poll};
use futures::stream::{Fuse, Stream};
use futures::task::park;
use openssl::crypto::rsa::RSA;
use tokio_core::reactor::{Core, Handle};
use tokio_core::channel::{channel, Receiver};
use super::{ClientFuture, BasicClientHandle, ClientHandle, StreamHandle};
use ::error::*;
use ::op::{Message, ResponseCode};
use ::authority::Catalog;
use ::authority::authority_tests::{create_example};
use ::rr::domain;
use ::rr::{DNSClass, RData, Record, RecordType};
use ::rr::dnssec::{Algorithm, Signer};
use ::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
use ::udp::UdpClientStream;
use ::tcp::TcpClientStream;
pub struct TestClientStream {
catalog: Catalog,
outbound_messages: Fuse<Receiver<Vec<u8>>>,
}
impl TestClientStream {
pub fn new(catalog: Catalog, loop_handle: Handle) -> (Box<Future<Item=Self, Error=io::Error>>, StreamHandle) {
let (message_sender, outbound_messages) = channel(&loop_handle).expect("somethings wrong with the event loop");
let stream: Box<Future<Item=TestClientStream, Error=io::Error>> = Box::new(finished(
TestClientStream { catalog: catalog, outbound_messages: outbound_messages.fuse() }
));
(stream, message_sender)
}
}
impl Stream for TestClientStream {
type Item = Vec<u8>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match try!(self.outbound_messages.poll()) {
// already handled above, here to make sure the poll() pops the next message
Async::Ready(Some(bytes)) => {
let mut decoder = BinDecoder::new(&bytes);
let message = Message::read(&mut decoder).expect("could not decode message");
let response = self.catalog.handle_request(&message);
let mut buf = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut buf);
response.emit(&mut encoder).expect("could not encode");
}
Ok(Async::Ready(Some(buf)))
},
// now we get to drop through to the receives...
// TODO: should we also return None if there are no more messages to send?
_ => {
park().unpark();
Ok(Async::NotReady)
},
}
}
}
impl fmt::Debug for TestClientStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestClientStream catalog")
}
}
#[test]
fn test_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_udp_ipv4() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_udp_ipv6() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888",53).to_socket_addrs().unwrap().next().unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_tcp_ipv4() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).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);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_tcp_ipv6() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888",53).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);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[cfg(test)]
fn test_query(client: &BasicClientHandle) -> Box<Future<Item=(), Error=()>> {
use std::net::Ipv4Addr;
use std::cmp::Ordering;
use ::rr::RData;
use log::LogLevel;
use ::logger::TrustDnsLogger;
TrustDnsLogger::enable_logging(LogLevel::Debug);
let name = domain::Name::with_labels(vec!["WWW".to_string(), "example".to_string(), "com".to_string()]);
Box::new(client.query(name.clone(), DNSClass::IN, RecordType::A)
.map(move |response| {
println!("response records: {:?}", response);
assert_eq!(response.get_queries().first().expect("expected query").get_name().cmp_with_case(&name, false), Ordering::Equal);
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
})
.map_err(|e| {
assert!(false, "query failed: {}", e);
})
)
}
// update tests
//
/// create a client with a sig0 section
fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name) {
use chrono::Duration;
use ::rr::rdata::DNSKEY;
let mut authority = create_example();
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
rsa,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_public_key())));
authority.upsert(auth_key, 0);
// setup the catalog
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), Some(signer));
(client, origin)
}
#[test]
fn test_create() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// trying to create again should error
// TODO: it would be cool to make this
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
}
#[test]
fn test_append() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = io_loop.run(client.append(record.clone(), origin.clone(), false)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// show that appending the same thing again is ok, but doesn't add any records
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
}
#[test]
fn test_compare_and_swap() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let current = record;
let mut new = current.clone();
new.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.compare_and_swap(current.clone(), new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// check the it fails if tried again.
let mut new = new;
new.rdata(RData::A(Ipv4Addr::new(102,12,102,12)));
let result = io_loop.run(client.compare_and_swap(current, new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
}
#[test]
fn test_delete_by_rdata() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.delete_by_rdata(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_by_rdata(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
}
#[test]
fn test_delete_rrset() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
#[test]
fn test_delete_all() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rr_type(RecordType::AAAA);
record.rdata(RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), RecordType::A)).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), RecordType::AAAA)).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
// need to do something with the message channel, otherwise the ClientFuture will think there
// is no one listening to messages and shutdown...
#[allow(dead_code)]
pub struct NeverReturnsClientStream {
outbound_messages: Fuse<Receiver<Vec<u8>>>,
}
impl NeverReturnsClientStream {
pub fn new(loop_handle: Handle) -> (Box<Future<Item=Self, Error=io::Error>>, StreamHandle) {
let (message_sender, outbound_messages) = channel(&loop_handle).expect("somethings wrong with the event loop");
let stream: Box<Future<Item=NeverReturnsClientStream, Error=io::Error>> = Box::new(finished(
NeverReturnsClientStream {
outbound_messages: outbound_messages.fuse()
}
));
(stream, message_sender)
}
}
impl Stream for NeverReturnsClientStream {
type Item = Vec<u8>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
// always not ready...
park().unpark();
Ok(Async::NotReady)
}
}
impl fmt::Debug for NeverReturnsClientStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestClientStream catalog")
}
}
#[test]
fn test_timeout_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = NeverReturnsClientStream::new(io_loop.handle());
let client = ClientFuture::with_timeout(stream, sender, io_loop.handle(),
std::time::Duration::from_millis(1), None);
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).unwrap_err().kind() {
()
} else {
assert!(false);
}
// test that we don't have any thing funky with registering new timeouts, etc...
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::AAAA)).unwrap_err().kind() {
()
} else {
assert!(false);
}
}
}

View File

@ -28,12 +28,7 @@ mod secure_client_handle;
#[allow(deprecated)]
pub use self::client::Client;
pub use self::client_connection::ClientConnection;
pub use self::client_future::{ClientFuture, BasicClientHandle, ClientHandle};
pub use self::client_future::{ClientFuture, BasicClientHandle, ClientHandle, StreamHandle};
pub use self::memoize_client_handle::MemoizeClientHandle;
pub use self::retry_client_handle::RetryClientHandle;
pub use self::secure_client_handle::SecureClientHandle;
#[cfg(test)]
pub use self::client_connection::test::TestClientConnection;
#[cfg(test)]
pub use self::client_future::test::TestClientStream;

View File

@ -748,259 +748,3 @@ fn verify_nsec(query: &Query, nsecs: Vec<&Record>) -> bool {
// if we got here, then there are no matching NSEC records, no validation
false
}
#[cfg(test)]
pub mod test {
use std::net::*;
use tokio_core::reactor::Core;
use ::authority::Catalog;
use ::authority::authority_tests::create_secure_example;
use ::client::{BasicClientHandle, ClientFuture, ClientHandle, MemoizeClientHandle, SecureClientHandle, TestClientStream};
use ::op::ResponseCode;
use ::rr::domain;
use ::rr::{DNSClass, RData, RecordType};
use ::rr::dnssec::TrustAnchor;
use ::tcp::TcpClientStream;
use ::udp::UdpClientStream;
#[test]
fn test_secure_query_example_nonet() {
with_nonet(test_secure_query_example);
}
#[test]
#[ignore]
fn test_secure_query_example_udp() {
with_udp(test_secure_query_example);
}
#[test]
#[ignore]
fn test_secure_query_example_tcp() {
with_tcp(test_secure_query_example);
}
#[cfg(test)]
fn test_secure_query_example<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).expect("query failed");
println!("response records: {:?}", response);
assert!(response.get_edns().expect("edns not here").is_dnssec_ok());
assert!(!response.get_answers().is_empty());
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
}
#[test]
fn test_nsec_query_example_nonet() {
with_nonet(test_nsec_query_example);
}
#[test]
#[ignore]
fn test_nsec_query_example_udp() {
with_udp(test_nsec_query_example);
}
#[test]
#[ignore]
fn test_nsec_query_example_tcp() {
with_tcp(test_nsec_query_example);
}
#[cfg(test)]
fn test_nsec_query_example<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::with_labels(vec!["none".to_string(), "example".to_string(), "com".to_string()]);
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
}
// TODO: NSEC response code wrong in Trust-DNS? Issue #53
// #[test]
// fn test_nsec_query_type_nonet() {
// with_nonet(test_nsec_query_type);
// }
#[test]
#[ignore]
fn test_nsec_query_type_udp() {
with_udp(test_nsec_query_type);
}
#[test]
#[ignore]
fn test_nsec_query_type_tcp() {
with_tcp(test_nsec_query_type);
}
#[cfg(test)]
fn test_nsec_query_type<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::NS)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NoError);
assert!(response.get_answers().is_empty());
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_udp() {
with_udp(dnssec_rollernet_td_test);
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp() {
with_udp(dnssec_rollernet_td_test);
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp_mixed_case() {
with_tcp(dnssec_rollernet_td_mixed_case_test);
}
fn dnssec_rollernet_td_test<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::parse("rollernet.us.", None).unwrap();
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::DS)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NoError);
// rollernet doesn't have any DS records...
// would have failed validation
assert!(response.get_answers().is_empty());
}
fn dnssec_rollernet_td_mixed_case_test<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::parse("RollErnet.Us.", None).unwrap();
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::DS)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NoError);
// rollernet doesn't have any DS records...
// would have failed validation
assert!(response.get_answers().is_empty());
}
#[cfg(test)]
fn with_nonet<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<BasicClientHandle>>, Core) {
use log::LogLevel;
use ::logger::TrustDnsLogger;
TrustDnsLogger::enable_logging(LogLevel::Debug);
use std;
let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let succeeded_clone = succeeded.clone();
std::thread::Builder::new().name("thread_killer".to_string()).spawn(move || {
let succeeded = succeeded_clone.clone();
for _ in 0..15 {
std::thread::sleep(std::time::Duration::from_secs(1));
if succeeded.load(std::sync::atomic::Ordering::Relaxed) { return }
}
panic!("timeout");
}).unwrap();
let authority = create_secure_example();
let public_key = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
let client = MemoizeClientHandle::new(client);
let secure_client = SecureClientHandle::with_trust_anchor(client, trust_anchor);
test(secure_client, io_loop);
succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
}
#[cfg(test)]
fn with_udp<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<BasicClientHandle>>, Core) {
use log::LogLevel;
use ::logger::TrustDnsLogger;
TrustDnsLogger::enable_logging(LogLevel::Debug);
use std;
let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let succeeded_clone = succeeded.clone();
std::thread::Builder::new().name("thread_killer".to_string()).spawn(move || {
let succeeded = succeeded_clone.clone();
for _ in 0..15 {
std::thread::sleep(std::time::Duration::from_secs(1));
if succeeded.load(std::sync::atomic::Ordering::Relaxed) { return }
}
panic!("timeout");
}).unwrap();
let io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
let client = MemoizeClientHandle::new(client);
let secure_client = SecureClientHandle::new(client);
test(secure_client, io_loop);
succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
}
#[cfg(test)]
fn with_tcp<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<BasicClientHandle>>, Core) {
use log::LogLevel;
use ::logger::TrustDnsLogger;
TrustDnsLogger::enable_logging(LogLevel::Debug);
use std;
let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let succeeded_clone = succeeded.clone();
std::thread::Builder::new().name("thread_killer".to_string()).spawn(move || {
let succeeded = succeeded_clone.clone();
for _ in 0..15 {
std::thread::sleep(std::time::Duration::from_secs(1));
if succeeded.load(std::sync::atomic::Ordering::Relaxed) { return }
}
panic!("timeout");
}).unwrap();
let io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).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 client = MemoizeClientHandle::new(client);
let secure_client = SecureClientHandle::new(client);
test(secure_client, io_loop);
succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
}
}

View File

@ -21,37 +21,27 @@ mod encode_error;
mod client_error;
mod lexer_error;
mod parse_error;
mod persistence_error;
mod config_error;
pub use self::decode_error::Error as DecodeError;
pub use self::encode_error::Error as EncodeError;
pub use self::client_error::Error as ClientError;
pub use self::lexer_error::Error as LexerError;
pub use self::parse_error::Error as ParseError;
pub use self::persistence_error::Error as PersistenceError;
pub use self::config_error::Error as ConfigError;
pub use self::decode_error::ErrorKind as DecodeErrorKind;
pub use self::encode_error::ErrorKind as EncodeErrorKind;
pub use self::client_error::ErrorKind as ClientErrorKind;
pub use self::lexer_error::ErrorKind as LexerErrorKind;
pub use self::parse_error::ErrorKind as ParseErrorKind;
pub use self::persistence_error::ErrorKind as PersistenceErrorKind;
pub use self::config_error::ErrorKind as ConfigErrorKind;
pub use self::decode_error::ChainErr as DecodeChainErr;
pub use self::encode_error::ChainErr as EncodeChainErr;
pub use self::client_error::ChainErr as ClientChainErr;
pub use self::lexer_error::ChainErr as LexerChainErr;
pub use self::parse_error::ChainErr as ParseChainErr;
pub use self::persistence_error::ChainErr as PersistenceChainErr;
pub use self::config_error::ChainErr as ConfigChainErr;
pub type DecodeResult<T> = Result<T, DecodeError>;
pub type EncodeResult = Result<(), EncodeError>;
pub type ClientResult<T> = Result<T, ClientError>;
pub type LexerResult<T> = Result<T, LexerError>;
pub type ParseResult<T> = Result<T, ParseError>;
pub type PersistenceResult<T> = Result<T, PersistenceError>;
pub type ConfigResult<T> = Result<T, ConfigError>;

View File

@ -36,27 +36,23 @@ extern crate data_encoding;
extern crate mio;
extern crate openssl;
extern crate rand;
extern crate rusqlite;
extern crate rustc_serialize;
extern crate time;
#[macro_use] extern crate tokio_core;
extern crate toml;
pub mod error;
pub mod logger;
pub mod rr;
pub mod authority;
pub mod op;
pub mod udp;
pub mod tcp;
pub mod client;
pub mod server;
pub mod serialize;
pub mod config;
/// this exposes a version function which gives access to the access
include!(concat!(env!("OUT_DIR"), "/version.rs"));
// TODO switch env_logger and remove this
#[test]
fn enable_logging_for_tests() {
use log::LogLevel;

View File

@ -82,6 +82,16 @@ impl Message {
name_servers: Vec::new(), additionals: Vec::new(), sig0: Vec::new(), edns: None }
}
pub fn error_msg(id: u16, op_code: OpCode, response_code: ResponseCode) -> Message {
let mut message: Message = Message::new();
message.message_type(MessageType::Response);
message.id(id);
message.response_code(response_code);
message.op_code(op_code);
message
}
pub fn truncate(&self) -> Self {
let mut truncated: Message = Message::new();
truncated.id(self.get_id());

View File

@ -17,17 +17,19 @@
//! Operations to send with a `Client` or server, e.g. `Query`, `Message`, or `UpdateMessage` can
//! be used to gether to either query or update resource records sets.
pub mod op_code;
pub mod response_code;
pub mod message;
pub mod header;
pub mod query;
mod edns;
pub mod header;
pub mod message;
pub mod op_code;
pub mod query;
pub mod request_handler;
pub mod response_code;
pub use self::message::{Message, UpdateMessage};
pub use self::query::Query;
pub use self::edns::Edns;
pub use self::header::Header;
pub use self::header::MessageType;
pub use self::message::{Message, UpdateMessage};
pub use self::op_code::OpCode;
pub use self::query::Query;
pub use self::request_handler::RequestHandler;
pub use self::response_code::ResponseCode;
pub use self::edns::Edns;

View File

@ -0,0 +1,17 @@
use ::op::Message;
/// Trait for handling incoming requests, and providing a message response.
///
/// *note* this probably belongs in the server crate and may move there in the future.
pub trait RequestHandler {
/// Determine's what needs to happen given the type of request, i.e. Query or Update.
///
/// # Arguments
///
/// * `request` - the requested action to perform.
///
/// # Returns
///
/// The derived response to the the request
fn handle_request(&self, request: &Message) -> Message;
}

View File

@ -16,16 +16,20 @@
//! Resource record related components, e.g. `Name` aka label, `Record`, `RData`, ...
pub mod record_type;
pub mod dns_class;
pub mod resource;
pub mod record_data;
pub mod dnssec;
pub mod domain;
pub mod rdata;
pub mod dnssec;
pub mod record_data;
pub mod record_type;
pub mod resource;
mod rr_key;
mod rr_set;
pub use self::record_type::RecordType;
pub use self::resource::Record;
pub use self::domain::Name;
pub use self::dns_class::DNSClass;
pub use self::record_data::RData;
pub use self::record_type::RecordType;
pub use self::resource::Record;
pub use self::rr_key::RrKey;
pub use self::rr_set::RrSet;

41
client/src/rr/rr_key.rs Normal file
View File

@ -0,0 +1,41 @@
use std::cmp::Ordering;
use ::rr::{Name, RecordType};
/// Accessor key for RRSets in the Authority.
#[derive(Eq, PartialEq, Debug, Hash, Clone)]
pub struct RrKey { pub name: Name, pub record_type: RecordType }
impl RrKey {
/// Creates a new key to access the Authority.
///
/// # Arguments
///
/// * `name` - domain name to lookup.
/// * `record_type` - the `RecordType` to lookup.
///
/// # Return value
///
/// A new key to access the Authorities.
/// TODO: make all cloned params pass by value.
pub fn new(name: &Name, record_type: RecordType) -> RrKey {
RrKey{ name: name.clone(), record_type: record_type }
}
}
impl PartialOrd for RrKey {
fn partial_cmp(&self, other: &RrKey) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RrKey {
fn cmp(&self, other: &Self) -> Ordering {
let order = self.name.cmp(&other.name);
if order == Ordering::Equal {
self.record_type.cmp(&other.record_type)
} else {
order
}
}
}

View File

@ -10,7 +10,7 @@ use ::rr::{Name, Record, RecordType, RData};
/// Set of resource records associated to a name and type
#[derive(Debug, PartialEq)]
pub struct RRSet {
pub struct RrSet {
name: Name,
record_type: RecordType,
ttl: u32,
@ -19,13 +19,13 @@ pub struct RRSet {
serial: u32, // serial number at which this record was modified
}
impl RRSet {
impl RrSet {
/// Creates a new Resource Record Set.
///
/// # Arguments
///
/// * `name` - The label for the `RRSet`
/// * `record_type` - `RecordType` of this `RRSet`, all records in the `RRSet` must be of the
/// * `name` - The label for the `RrSet`
/// * `record_type` - `RecordType` of this `RrSet`, all records in the `RrSet` must be of the
/// specified `RecordType`.
/// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
/// signing for DNSSec after updates.
@ -33,8 +33,9 @@ impl RRSet {
/// # Return value
///
/// The newly created Resource Record Set
pub fn new(name: &Name, record_type: RecordType, serial: u32) -> RRSet {
RRSet{name: name.clone(), record_type: record_type, ttl: 0, records: Vec::new(), rrsigs: Vec::new(), serial: serial}
/// TODO: make all cloned params pass by value
pub fn new(name: &Name, record_type: RecordType, serial: u32) -> RrSet {
RrSet{name: name.clone(), record_type: record_type, ttl: 0, records: Vec::new(), rrsigs: Vec::new(), serial: serial}
}
/// # Return value
@ -54,7 +55,7 @@ impl RRSet {
/// # Return value
///
/// TTL, time-to-live, of the Resource Record Set, this is the maximum length of time that an
/// RRSet should be cached.
/// RrSet should be cached.
pub fn get_ttl(&self) -> u32 {
self.ttl
}
@ -129,7 +130,7 @@ impl RRSet {
///
/// # Arguments
///
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RRSet`.
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RrSet`.
/// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
/// signing for DNSSec after updates. The serial will only be updated if the
/// record was added.
@ -219,7 +220,7 @@ impl RRSet {
///
/// # Arguments
///
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RRSet`. Removes
/// * `record` - `Record` asserts that the `name` and `record_type` match the `RrSet`. Removes
/// any `record` if the record data, `RData`, match.
/// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
/// signing for DNSSec after updates. The serial will only be updated if the
@ -270,13 +271,12 @@ mod test {
use std::net::Ipv4Addr;
use ::rr::*;
use ::rr::rdata::SOA;
use super::RRSet;
#[test]
fn test_insert() {
let name = Name::new().label("www").label("example").label("com");
let record_type = RecordType::A;
let mut rr_set = RRSet::new(&name, record_type, 0);
let mut rr_set = RrSet::new(&name, record_type, 0);
let insert = Record::new().name(name.clone()).ttl(86400).rr_type(record_type).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone();
@ -301,7 +301,7 @@ mod test {
fn test_insert_soa() {
let name = Name::new().label("example").label("com");
let record_type = RecordType::SOA;
let mut rr_set = RRSet::new(&name, record_type, 0);
let mut rr_set = RrSet::new(&name, record_type, 0);
let insert = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone();
let same_serial = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.net.", None).unwrap(), Name::parse("noc.dns.icann.net.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone();
@ -330,7 +330,7 @@ mod test {
let new_cname = Name::new().label("w2").label("example").label("com");
let record_type = RecordType::CNAME;
let mut rr_set = RRSet::new(&name, record_type, 0);
let mut rr_set = RrSet::new(&name, record_type, 0);
let insert = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::CNAME).dns_class(DNSClass::IN).rdata(RData::CNAME(cname.clone()) ).clone();
let new_record = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::CNAME).dns_class(DNSClass::IN).rdata(RData::CNAME(new_cname.clone()) ).clone();
@ -348,7 +348,7 @@ mod test {
fn test_remove() {
let name = Name::new().label("www").label("example").label("com");
let record_type = RecordType::A;
let mut rr_set = RRSet::new(&name, record_type, 0);
let mut rr_set = RrSet::new(&name, record_type, 0);
let insert = Record::new().name(name.clone()).ttl(86400).rr_type(record_type).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone();
let insert1 = Record::new().name(name.clone()).ttl(86400).rr_type(record_type).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,25))).clone();
@ -366,7 +366,7 @@ mod test {
fn test_remove_soa() {
let name = Name::new().label("example").label("com");
let record_type = RecordType::SOA;
let mut rr_set = RRSet::new(&name, record_type, 0);
let mut rr_set = RrSet::new(&name, record_type, 0);
let insert = Record::new().name(name.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone();
@ -379,7 +379,7 @@ mod test {
fn test_remove_ns() {
let name = Name::new().label("example").label("com");
let record_type = RecordType::NS;
let mut rr_set = RRSet::new(&name, record_type, 0);
let mut rr_set = RrSet::new(&name, record_type, 0);
let ns1 = Record::new().name(name.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone();
let ns2 = Record::new().name(name.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone();

View File

@ -14,12 +14,9 @@
* limitations under the License.
*/
use std::collections::BTreeMap;
use std::io::Read;
use std::fs::File;
use ::error::*;
use ::rr::{ Name, RecordType, Record, DNSClass, RData};
use ::authority::{Authority, RrKey, ZoneType, RRSet};
use ::rr::{ Name, RecordType, Record, DNSClass, RData, RrKey, RrSet};
use super::master_lex::{Lexer, Token};
@ -130,21 +127,10 @@ impl Parser {
Parser
}
pub fn parse_file(file: File, origin: Option<Name>, zone_type: ZoneType, allow_update: bool) -> ParseResult<Authority> {
let mut file = file;
let mut buf = String::new();
// TODO, this should really use something to read line by line or some other method to
// keep the usage down. and be a custom lexer...
try!(file.read_to_string(&mut buf));
let lexer = Lexer::new(&buf);
Self::new().parse(lexer, origin, zone_type, allow_update)
}
// TODO: change this function to load into an Authority, using the update_records() method
pub fn parse(&mut self, lexer: Lexer, origin: Option<Name>, zone_type: ZoneType, allow_update: bool) -> ParseResult<Authority> {
pub fn parse(&mut self, lexer: Lexer, origin: Option<Name>) -> ParseResult<(Name, BTreeMap<RrKey, RrSet>)> {
let mut lexer = lexer;
let mut records: BTreeMap<RrKey, RRSet> = BTreeMap::new();
let mut records: BTreeMap<RrKey, RrSet> = BTreeMap::new();
let mut origin: Option<Name> = origin;
let mut current_name: Option<Name> = None;
@ -283,7 +269,7 @@ impl Parser {
match rtype.unwrap() {
RecordType::SOA => {
let mut set = RRSet::new(record.get_name(), record.get_rr_type(), 0);
let mut set = RrSet::new(record.get_name(), record.get_rr_type(), 0);
set.insert(record, 0);
if records.insert(key, set).is_some() {
return Err(ParseErrorKind::Message("SOA is already specified").into());
@ -291,7 +277,7 @@ impl Parser {
},
_ => {
// add a Vec if it's not there, then add the record to the list
let mut set = records.entry(key).or_insert(RRSet::new(record.get_name(), record.get_rr_type(), 0));
let mut set = records.entry(key).or_insert(RrSet::new(record.get_name(), record.get_rr_type(), 0));
set.insert(record, 0);
},
}
@ -306,7 +292,8 @@ impl Parser {
//
// build the Authority and return.
Ok(Authority::new(try!(origin.ok_or(ParseError::from(ParseErrorKind::Message("$ORIGIN was not specified")))), records, zone_type, allow_update))
let origin = try!(origin.ok_or(ParseError::from(ParseErrorKind::Message("$ORIGIN was not specified"))));
Ok((origin, records))
}
/// parses the string following the rules from:

View File

@ -19,6 +19,3 @@ mod master;
pub use self::master::Parser;
pub use self::master_lex::Lexer;
pub use self::master_lex::Token;
#[cfg(test)]
mod txt_tests;

View File

@ -18,9 +18,8 @@ use std::io;
use std::sync::Arc;
use mio::udp::UdpSocket;
use mio::EventSet; // not * b/c don't want confusion with std::net
use mio::EventSet;
use ::authority::Catalog;
use ::op::*;
use ::serialize::binary::*;
@ -42,7 +41,7 @@ impl UdpHandler {
UdpHandler{ state: UdpState::Writing, addr: server_addr, message: request, buffer: bytes}
}
pub fn new_server(socket: &UdpSocket, catalog: Arc<Catalog>) -> Option<Self> {
pub fn new_server<H>(socket: &UdpSocket, catalog: Arc<H>) -> Option<Self> where H: RequestHandler {
//let mut buf: Vec<u8> = Vec::with_capacity(512);
let mut buf: [u8; 4096] = [0u8; 4096];
let recv_result = socket.recv_from(&mut buf);
@ -58,7 +57,7 @@ impl UdpHandler {
let response = match request {
Err(ref decode_error) => {
warn!("unable to decode request from client: {:?}: {}", addr, decode_error);
Catalog::error_msg(0/* id is in the message... */, OpCode::Query/* right default? */, ResponseCode::FormErr)
Message::error_msg(0/* id is in the message... */, OpCode::Query/* right default? */, ResponseCode::FormErr)
},
Ok(ref req) => catalog.handle_request(req), // this is a buf if the unwrap() fails
};
@ -101,7 +100,7 @@ impl UdpHandler {
// otherwise we'll blow the stack, which is ok, there's something horribly wrong in that
// case with the code.
error!("error encoding response to client: {}", encode_error);
Self::serialize_msg(buf, &Catalog::error_msg(response.get_id(), response.get_op_code(), ResponseCode::ServFail))
Self::serialize_msg(buf, &Message::error_msg(response.get_id(), response.get_op_code(), ResponseCode::ServFail))
} else {
buf
}

View File

@ -0,0 +1,461 @@
extern crate chrono;
extern crate futures;
extern crate openssl;
extern crate tokio_core;
extern crate trust_dns;
extern crate trust_dns_server;
use std::fmt;
use std::io;
use std::net::*;
use std::cmp::Ordering;
use chrono::Duration;
use futures::{Async, Future, finished, Poll};
use futures::stream::{Fuse, Stream};
use futures::task::park;
use openssl::crypto::rsa::RSA;
use tokio_core::reactor::{Core, Handle};
use tokio_core::channel::{channel, Receiver};
use trust_dns::client::{ClientFuture, BasicClientHandle, ClientHandle, StreamHandle};
use trust_dns::error::*;
use trust_dns::op::ResponseCode;
use trust_dns::rr::domain;
use trust_dns::rr::{DNSClass, RData, Record, RecordType};
use trust_dns::rr::dnssec::{Algorithm, Signer};
use trust_dns::rr::rdata::*;
use trust_dns::udp::UdpClientStream;
use trust_dns::tcp::TcpClientStream;
use trust_dns_server::authority::Catalog;
use trust_dns_server::authority::authority::{create_example};
mod common;
use common::TestClientStream;
#[test]
fn test_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_udp_ipv4() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_udp_ipv6() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888",53).to_socket_addrs().unwrap().next().unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_tcp_ipv4() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).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);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[test]
#[ignore]
fn test_query_tcp_ipv6() {
use std::net::{SocketAddr, ToSocketAddrs};
use tokio_core::reactor::Core;
let mut io_loop = Core::new().unwrap();
let addr: SocketAddr = ("2001:4860:4860::8888",53).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);
// TODO: timeouts on these requests so that the test doesn't hang
io_loop.run(test_query(&client)).unwrap();
io_loop.run(test_query(&client)).unwrap();
}
#[cfg(test)]
fn test_query(client: &BasicClientHandle) -> Box<Future<Item=(), Error=()>> {
let name = domain::Name::with_labels(vec!["WWW".to_string(), "example".to_string(), "com".to_string()]);
Box::new(client.query(name.clone(), DNSClass::IN, RecordType::A)
.map(move |response| {
println!("response records: {:?}", response);
assert_eq!(response.get_queries().first().expect("expected query").get_name().cmp_with_case(&name, false), Ordering::Equal);
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
})
.map_err(|e| {
assert!(false, "query failed: {}", e);
})
)
}
// update tests
//
/// create a client with a sig0 section
fn create_sig0_ready_client(io_loop: &Core) -> (BasicClientHandle, domain::Name) {
let mut authority = create_example();
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256,
rsa,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_public_key())));
authority.upsert(auth_key, 0);
// setup the catalog
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), Some(signer));
(client, origin)
}
#[test]
fn test_create() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// trying to create again should error
// TODO: it would be cool to make this
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
}
#[test]
fn test_append() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = io_loop.run(client.append(record.clone(), origin.clone(), false)).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// show that appending the same thing again is ok, but doesn't add any records
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
}
#[test]
fn test_compare_and_swap() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let current = record;
let mut new = current.clone();
new.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.compare_and_swap(current.clone(), new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// check the it fails if tried again.
let mut new = new;
new.rdata(RData::A(Ipv4Addr::new(102,12,102,12)));
let result = io_loop.run(client.compare_and_swap(current, new.clone(), origin.clone())).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
let result = io_loop.run(client.query(new.get_name().clone(), new.get_dns_class(), new.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
}
#[test]
fn test_delete_by_rdata() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.delete_by_rdata(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_by_rdata(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
}
#[test]
fn test_delete_rrset() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = io_loop.run(client.append(record.clone(), origin.clone(), true)).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_rrset(record.clone(), origin.clone())).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), record.get_rr_type())).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
#[test]
fn test_delete_all() {
let mut io_loop = Core::new().unwrap();
let (client, origin) = create_sig0_ready_client(&io_loop);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rr_type(RecordType::AAAA);
record.rdata(RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)));
let result = io_loop.run(client.create(record.clone(), origin.clone())).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = io_loop.run(client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN)).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), RecordType::A)).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
let result = io_loop.run(client.query(record.get_name().clone(), record.get_dns_class(), RecordType::AAAA)).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
// need to do something with the message channel, otherwise the ClientFuture will think there
// is no one listening to messages and shutdown...
#[allow(dead_code)]
pub struct NeverReturnsClientStream {
outbound_messages: Fuse<Receiver<Vec<u8>>>,
}
impl NeverReturnsClientStream {
pub fn new(loop_handle: Handle) -> (Box<Future<Item=Self, Error=io::Error>>, StreamHandle) {
let (message_sender, outbound_messages) = channel(&loop_handle).expect("somethings wrong with the event loop");
let stream: Box<Future<Item=NeverReturnsClientStream, Error=io::Error>> = Box::new(finished(
NeverReturnsClientStream {
outbound_messages: outbound_messages.fuse()
}
));
(stream, message_sender)
}
}
impl Stream for NeverReturnsClientStream {
type Item = Vec<u8>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
// always not ready...
park().unpark();
Ok(Async::NotReady)
}
}
impl fmt::Debug for NeverReturnsClientStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestClientStream catalog")
}
}
#[test]
fn test_timeout_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut io_loop = Core::new().unwrap();
let (stream, sender) = NeverReturnsClientStream::new(io_loop.handle());
let client = ClientFuture::with_timeout(stream, sender, io_loop.handle(),
std::time::Duration::from_millis(1), None);
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).unwrap_err().kind() {
()
} else {
assert!(false);
}
// test that we don't have any thing funky with registering new timeouts, etc...
if let &ClientErrorKind::Timeout = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::AAAA)).unwrap_err().kind() {
()
} else {
assert!(false);
}
}

View File

@ -0,0 +1,563 @@
extern crate chrono;
extern crate openssl;
extern crate trust_dns;
extern crate trust_dns_server;
use std::net::*;
use std::fmt;
use chrono::Duration;
use openssl::crypto::rsa::RSA;
#[allow(deprecated)]
use trust_dns::client::{Client, ClientConnection};
use trust_dns::error::*;
use trust_dns::op::*;
use trust_dns::rr::{DNSClass, Record, RecordType, domain, RData};
use trust_dns::rr::dnssec::{Algorithm, Signer, TrustAnchor};
use trust_dns::rr::rdata::*;
use trust_dns::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
use trust_dns::tcp::TcpClientConnection;
use trust_dns::udp::UdpClientConnection;
use trust_dns_server::authority::Catalog;
use trust_dns_server::authority::authority::{create_example, create_secure_example};
pub struct TestClientConnection<'a> {
catalog: &'a Catalog
}
impl<'a> TestClientConnection<'a> {
pub fn new(catalog: &'a Catalog) -> TestClientConnection<'a> {
TestClientConnection { catalog: catalog }
}
}
impl<'a> ClientConnection for TestClientConnection<'a> {
fn send(&mut self, bytes: Vec<u8>) -> ClientResult<Vec<u8>> {
let mut decoder = BinDecoder::new(&bytes);
let message = try!(Message::read(&mut decoder));
let response = self.catalog.handle_request(&message);
let mut buf = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut buf);
try!(response.emit(&mut encoder));
}
Ok(buf)
}
}
impl<'a> fmt::Debug for TestClientConnection<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestClientConnection catalog")
}
}
#[test]
fn test_query_nonet() {
let authority = create_example();
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let client = Client::new(TestClientConnection::new(&catalog));
test_query(client);
}
#[test]
#[ignore]
fn test_query_udp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_query(client);
}
#[test]
#[ignore]
fn test_query_tcp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_query(client);
}
#[allow(deprecated)]
fn test_query<C: ClientConnection>(client: Client<C>) {
use std::cmp::Ordering;
let name = domain::Name::with_labels(vec!["WWW".to_string(), "example".to_string(), "com".to_string()]);
let response = client.query(&name, DNSClass::IN, RecordType::A);
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
let response = response.unwrap();
println!("response records: {:?}", response);
assert_eq!(response.get_queries().first().expect("expected query").get_name().cmp_with_case(&name, false), Ordering::Equal);
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
}
#[test]
fn test_secure_query_example_nonet() {
let authority = create_secure_example();
let public_key = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let client = Client::with_trust_anchor(TestClientConnection::new(&catalog), trust_anchor);
test_secure_query_example(client);
}
#[test]
#[ignore]
fn test_secure_query_example_udp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_secure_query_example(client);
}
#[test]
#[ignore]
fn test_secure_query_example_tcp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_secure_query_example(client);
}
#[allow(deprecated)]
fn test_secure_query_example<C: ClientConnection>(client: Client<C>) {
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
assert!(response.is_ok(), "query for {} failed: {}", name, response.unwrap_err());
let response = response.unwrap();
println!("response records: {:?}", response);
assert!(response.get_edns().expect("edns not here").is_dnssec_ok());
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_udp() {
let c = Client::new(UdpClientConnection::new("8.8.8.8:53".parse().unwrap()).unwrap());
c.secure_query(
&domain::Name::parse("rollernet.us.", None).unwrap(),
DNSClass::IN,
RecordType::DS,
).unwrap();
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp() {
let c = Client::new(TcpClientConnection::new("8.8.8.8:53".parse().unwrap()).unwrap());
c.secure_query(
&domain::Name::parse("rollernet.us.", None).unwrap(),
DNSClass::IN,
RecordType::DS,
).unwrap();
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp_mixed_case() {
let c = Client::new(TcpClientConnection::new("8.8.8.8:53".parse().unwrap()).unwrap());
c.secure_query(
&domain::Name::parse("RollErnet.Us.", None).unwrap(),
DNSClass::IN,
RecordType::DS,
).unwrap();
}
#[test]
fn test_nsec_query_example_nonet() {
let authority = create_secure_example();
let public_key = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let client = Client::with_trust_anchor(TestClientConnection::new(&catalog), trust_anchor);
test_nsec_query_example(client);
}
#[test]
#[ignore]
fn test_nsec_query_example_udp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = UdpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_nsec_query_example(client);
}
#[test]
#[ignore]
fn test_nsec_query_example_tcp() {
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
test_nsec_query_example(client);
}
#[allow(deprecated)]
fn test_nsec_query_example<C: ClientConnection>(client: Client<C>) {
let name = domain::Name::with_labels(vec!["none".to_string(), "example".to_string(), "com".to_string()]);
let response = client.secure_query(&name, DNSClass::IN, RecordType::A);
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
let response = response.unwrap();
assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
}
#[test]
#[ignore]
fn test_nsec_query_type() {
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let conn = TcpClientConnection::new(addr).unwrap();
let client = Client::new(conn);
let response = client.secure_query(&name, DNSClass::IN, RecordType::NS);
assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
let response = response.unwrap();
// TODO: it would be nice to verify that the NSEC records were validated...
assert_eq!(response.get_response_code(), ResponseCode::NoError);
assert!(response.get_answers().is_empty());
}
// TODO: disabled until I decide what to do with NSEC3 see issue #10
//
// TODO these NSEC3 tests don't work, it seems that the zone is not signed properly.
// #[test]
// #[ignore]
// fn test_nsec3_sdsmt() {
// let addr: SocketAddr = ("75.75.75.75",53).to_socket_addrs().unwrap().next().unwrap();
// let conn = TcpClientConnection::new(addr).unwrap();
// let name = domain::Name::with_labels(vec!["none".to_string(), "sdsmt".to_string(), "edu".to_string()]);
// let client = Client::new(conn);
//
// let response = client.secure_query(&name, DNSClass::IN, RecordType::NS);
// assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
//
// let response = response.unwrap();
// assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
// }
// TODO: disabled until I decide what to do with NSEC3 see issue #10
//
// #[test]
// #[ignore]
// fn test_nsec3_sdsmt_type() {
// let addr: SocketAddr = ("75.75.75.75",53).to_socket_addrs().unwrap().next().unwrap();
// let conn = TcpClientConnection::new(addr).unwrap();
// let name = domain::Name::with_labels(vec!["www".to_string(), "sdsmt".to_string(), "edu".to_string()]);
// let client = Client::new(conn);
//
// let response = client.secure_query(&name, DNSClass::IN, RecordType::NS);
// assert!(response.is_ok(), "query failed: {}", response.unwrap_err());
//
// let response = response.unwrap();
// assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
// }
#[allow(deprecated)]
fn create_sig0_ready_client<'a>(catalog: &'a mut Catalog) -> (Client<TestClientConnection<'a>>, Signer, domain::Name) {
let mut authority = create_example();
authority.set_allow_update(true);
let origin = authority.get_origin().clone();
let rsa = RSA::generate(512).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa,
domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
Duration::max_value());
// insert the KEY for the trusted.example.com
let mut auth_key = Record::with(domain::Name::with_labels(vec!["trusted".to_string(), "example".to_string(), "com".to_string()]),
RecordType::KEY,
Duration::minutes(5).num_seconds() as u32);
auth_key.rdata(RData::KEY(DNSKEY::new(false, false, false, signer.get_algorithm(), signer.get_public_key())));
authority.upsert(auth_key, 0);
catalog.upsert(authority.get_origin().clone(), authority);
let client = Client::new(TestClientConnection::new(catalog));
(client, signer, origin)
}
#[test]
fn test_create() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// trying to create again should error
// TODO: it would be cool to make this
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::YXRRSet);
}
#[test]
fn test_append() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
// next append to a non-existent RRset
let result = client.append(record.clone(), origin.clone(), false, &signer).expect("append failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert_eq!(result.get_answers()[0], record);
// will fail if already set and not the same value.
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// show that appending the same thing again is ok, but doesn't add any records
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 2);
}
#[test]
fn test_compare_and_swap() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// create a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let current = record;
let mut new = current.clone();
new.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.compare_and_swap(current.clone(), new.clone(), origin.clone(), &signer).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(new.get_name(), new.get_dns_class(), new.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
// check the it fails if tried again.
let mut new = new;
new.rdata(RData::A(Ipv4Addr::new(102,12,102,12)));
let result = client.compare_and_swap(current, new.clone(), origin.clone(), &signer).expect("compare_and_swap failed");
assert_eq!(result.get_response_code(), ResponseCode::NXRRSet);
let result = client.query(new.get_name(), new.get_dns_class(), new.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(101,11,101,11) } else { false }));
}
#[test]
fn test_delete_by_rdata() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.delete_by_rdata(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_by_rdata(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_answers().len(), 1);
assert!(result.get_answers().iter().any(|rr| if let &RData::A(ref ip) = rr.get_rdata() { *ip == Ipv4Addr::new(100,10,100,10) } else { false }));
}
#[test]
fn test_delete_rrset() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.delete_rrset(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rdata(RData::A(Ipv4Addr::new(101,11,101,11)));
let result = client.append(record.clone(), origin.clone(), true, &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_rrset(record.clone(), origin.clone(), &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), record.get_rr_type()).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}
#[test]
fn test_delete_all() {
let mut catalog = Catalog::new();
let (client, signer, origin) = create_sig0_ready_client(&mut catalog);
// append a record
let mut record = Record::with(domain::Name::with_labels(vec!["new".to_string(), "example".to_string(), "com".to_string()]),
RecordType::A,
Duration::minutes(5).num_seconds() as u32);
record.rdata(RData::A(Ipv4Addr::new(100,10,100,10)));
// first check the must_exist option
let result = client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN, &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// next create to a non-existent RRset
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let mut record = record.clone();
record.rr_type(RecordType::AAAA);
record.rdata(RData::AAAA(Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)));
let result = client.create(record.clone(), origin.clone(), &signer).expect("create failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
// verify record contents
let result = client.delete_all(record.get_name().clone(), origin.clone(), DNSClass::IN, &signer).expect("delete failed");
assert_eq!(result.get_response_code(), ResponseCode::NoError);
let result = client.query(record.get_name(), record.get_dns_class(), RecordType::A).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
let result = client.query(record.get_name(), record.get_dns_class(), RecordType::AAAA).expect("query failed");
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_answers().len(), 0);
}

View File

@ -0,0 +1,68 @@
use std::fmt;
use std::io;
use futures::{Async, Future, finished, Poll};
use futures::stream::{Fuse, Stream};
use futures::task::park;
use tokio_core::reactor::*;
use tokio_core::channel::*;
use trust_dns::client::StreamHandle;
use trust_dns::op::*;
use trust_dns::serialize::binary::*;
use trust_dns_server::authority::Catalog;
pub struct TestClientStream {
catalog: Catalog,
outbound_messages: Fuse<Receiver<Vec<u8>>>,
}
impl TestClientStream {
pub fn new(catalog: Catalog, loop_handle: Handle) -> (Box<Future<Item=Self, Error=io::Error>>, StreamHandle) {
let (message_sender, outbound_messages) = channel(&loop_handle).expect("somethings wrong with the event loop");
let stream: Box<Future<Item=TestClientStream, Error=io::Error>> = Box::new(finished(
TestClientStream { catalog: catalog, outbound_messages: outbound_messages.fuse() }
));
(stream, message_sender)
}
}
impl Stream for TestClientStream {
type Item = Vec<u8>;
type Error = io::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
match try!(self.outbound_messages.poll()) {
// already handled above, here to make sure the poll() pops the next message
Async::Ready(Some(bytes)) => {
let mut decoder = BinDecoder::new(&bytes);
let message = Message::read(&mut decoder).expect("could not decode message");
let response = self.catalog.handle_request(&message);
let mut buf = Vec::with_capacity(512);
{
let mut encoder = BinEncoder::new(&mut buf);
response.emit(&mut encoder).expect("could not encode");
}
Ok(Async::Ready(Some(buf)))
},
// now we get to drop through to the receives...
// TODO: should we also return None if there are no more messages to send?
_ => {
park().unpark();
Ok(Async::NotReady)
},
}
}
}
impl fmt::Debug for TestClientStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TestClientStream catalog")
}
}

View File

@ -0,0 +1,241 @@
extern crate chrono;
extern crate futures;
extern crate openssl;
extern crate tokio_core;
extern crate trust_dns;
extern crate trust_dns_server;
use std::net::*;
use tokio_core::reactor::Core;
use trust_dns::client::{BasicClientHandle, ClientFuture, ClientHandle, MemoizeClientHandle, SecureClientHandle};
use trust_dns::op::ResponseCode;
use trust_dns::rr::domain;
use trust_dns::rr::{DNSClass, RData, RecordType};
use trust_dns::rr::dnssec::TrustAnchor;
use trust_dns::tcp::TcpClientStream;
use trust_dns::udp::UdpClientStream;
use trust_dns_server::authority::Catalog;
use trust_dns_server::authority::authority::create_secure_example;
mod common;
use common::TestClientStream;
#[test]
fn test_secure_query_example_nonet() {
with_nonet(test_secure_query_example);
}
#[test]
#[ignore]
fn test_secure_query_example_udp() {
with_udp(test_secure_query_example);
}
#[test]
#[ignore]
fn test_secure_query_example_tcp() {
with_tcp(test_secure_query_example);
}
fn test_secure_query_example<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).expect("query failed");
println!("response records: {:?}", response);
assert!(response.get_edns().expect("edns not here").is_dnssec_ok());
assert!(!response.get_answers().is_empty());
let record = &response.get_answers()[0];
assert_eq!(record.get_name(), &name);
assert_eq!(record.get_rr_type(), RecordType::A);
assert_eq!(record.get_dns_class(), DNSClass::IN);
if let &RData::A(ref address) = record.get_rdata() {
assert_eq!(address, &Ipv4Addr::new(93,184,216,34))
} else {
assert!(false);
}
}
#[test]
fn test_nsec_query_example_nonet() {
with_nonet(test_nsec_query_example);
}
#[test]
#[ignore]
fn test_nsec_query_example_udp() {
with_udp(test_nsec_query_example);
}
#[test]
#[ignore]
fn test_nsec_query_example_tcp() {
with_tcp(test_nsec_query_example);
}
fn test_nsec_query_example<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::with_labels(vec!["none".to_string(), "example".to_string(), "com".to_string()]);
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::A)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NXDomain);
}
// TODO: NSEC response code wrong in Trust-DNS? Issue #53
// #[test]
// fn test_nsec_query_type_nonet() {
// with_nonet(test_nsec_query_type);
// }
#[test]
#[ignore]
fn test_nsec_query_type_udp() {
with_udp(test_nsec_query_type);
}
#[test]
#[ignore]
fn test_nsec_query_type_tcp() {
with_tcp(test_nsec_query_type);
}
fn test_nsec_query_type<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::with_labels(vec!["www".to_string(), "example".to_string(), "com".to_string()]);
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::NS)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NoError);
assert!(response.get_answers().is_empty());
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_udp() {
with_udp(dnssec_rollernet_td_test);
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp() {
with_udp(dnssec_rollernet_td_test);
}
#[test]
#[ignore]
fn test_dnssec_rollernet_td_tcp_mixed_case() {
with_tcp(dnssec_rollernet_td_mixed_case_test);
}
fn dnssec_rollernet_td_test<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::parse("rollernet.us.", None).unwrap();
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::DS)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NoError);
// rollernet doesn't have any DS records...
// would have failed validation
assert!(response.get_answers().is_empty());
}
fn dnssec_rollernet_td_mixed_case_test<H>(client: SecureClientHandle<H>, mut io_loop: Core)
where H: ClientHandle + 'static {
let name = domain::Name::parse("RollErnet.Us.", None).unwrap();
let response = io_loop.run(client.query(name.clone(), DNSClass::IN, RecordType::DS)).expect("query failed");
assert_eq!(response.get_response_code(), ResponseCode::NoError);
// rollernet doesn't have any DS records...
// would have failed validation
assert!(response.get_answers().is_empty());
}
fn with_nonet<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<BasicClientHandle>>, Core) {
let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let succeeded_clone = succeeded.clone();
std::thread::Builder::new().name("thread_killer".to_string()).spawn(move || {
let succeeded = succeeded_clone.clone();
for _ in 0..15 {
std::thread::sleep(std::time::Duration::from_secs(1));
if succeeded.load(std::sync::atomic::Ordering::Relaxed) { return }
}
panic!("timeout");
}).unwrap();
let authority = create_secure_example();
let public_key = {
let signers = authority.get_secure_keys();
signers.first().expect("expected a key in the authority").get_public_key()
};
let mut catalog = Catalog::new();
catalog.upsert(authority.get_origin().clone(), authority);
let mut trust_anchor = TrustAnchor::new();
trust_anchor.insert_trust_anchor(public_key);
let io_loop = Core::new().unwrap();
let (stream, sender) = TestClientStream::new(catalog, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
let client = MemoizeClientHandle::new(client);
let secure_client = SecureClientHandle::with_trust_anchor(client, trust_anchor);
test(secure_client, io_loop);
succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
}
fn with_udp<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<BasicClientHandle>>, Core) {
let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let succeeded_clone = succeeded.clone();
std::thread::Builder::new().name("thread_killer".to_string()).spawn(move || {
let succeeded = succeeded_clone.clone();
for _ in 0..15 {
std::thread::sleep(std::time::Duration::from_secs(1));
if succeeded.load(std::sync::atomic::Ordering::Relaxed) { return }
}
panic!("timeout");
}).unwrap();
let io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).to_socket_addrs().unwrap().next().unwrap();
let (stream, sender) = UdpClientStream::new(addr, io_loop.handle());
let client = ClientFuture::new(stream, sender, io_loop.handle(), None);
let client = MemoizeClientHandle::new(client);
let secure_client = SecureClientHandle::new(client);
test(secure_client, io_loop);
succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
}
fn with_tcp<F>(test: F) where F: Fn(SecureClientHandle<MemoizeClientHandle<BasicClientHandle>>, Core) {
let succeeded = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
let succeeded_clone = succeeded.clone();
std::thread::Builder::new().name("thread_killer".to_string()).spawn(move || {
let succeeded = succeeded_clone.clone();
for _ in 0..15 {
std::thread::sleep(std::time::Duration::from_secs(1));
if succeeded.load(std::sync::atomic::Ordering::Relaxed) { return }
}
panic!("timeout");
}).unwrap();
let io_loop = Core::new().unwrap();
let addr: SocketAddr = ("8.8.8.8",53).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 client = MemoizeClientHandle::new(client);
let secure_client = SecureClientHandle::new(client);
test(secure_client, io_loop);
succeeded.store(true, std::sync::atomic::Ordering::Relaxed);
}

View File

@ -1,10 +1,13 @@
extern crate trust_dns;
extern crate trust_dns_server;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use ::rr::*;
use ::authority::ZoneType;
use trust_dns::rr::*;
use trust_dns::serialize::txt::*;
use trust_dns_server::authority::*;
use super::*;
#[test]
@ -38,10 +41,11 @@ short 70 A 26.3.0.104
venera A 10.1.0.52
A 128.9.0.32");
let authority = Parser::new().parse(lexer, Some(Name::new().label("isi").label("edu")), ZoneType::Master, false);
if authority.is_err() { panic!("failed to parse: {:?}", authority.err()) }
let records = Parser::new().parse(lexer, Some(Name::new().label("isi").label("edu")));
if records.is_err() { panic!("failed to parse: {:?}", records.err()) }
let authority = authority.unwrap();
let (origin, records) = records.unwrap();
let authority = Authority::new(origin, records, ZoneType::Master, false);
// not validating everything, just one of each...

View File

@ -3,6 +3,6 @@
trust_dns_dir=$(dirname $0)/..
pushd ${trust_dns_dir}
docker run -a STDERR -a STDOUT --rm -v ${PWD}:/src fnichol/rust:1.11.0 cargo test "$@" | tee target/linux_output.txt
docker run -a STDERR -a STDOUT --rm -v ${PWD}:/src fnichol/rust:1.12.0 bash scripts/run_tests.sh "$@" | tee target/linux_output.txt
popd

52
scripts/run_kcov.sh Executable file
View File

@ -0,0 +1,52 @@
#!/bin/bash -e
trust_dns_dir=$(dirname $0)/..
cd ${trust_dns_dir:?}
case $(uname) in
Darwin) exit 0;;
*) KCOV=true;;
esac
# don't run on nightly or beta
rustc --version | grep beta && exit 0;
rustc --version | grep nightly && exit 0;
rm -rf kcov-master master.tar.gz*
# install kcov
# sudo apt-get install libcurl4-openssl-dev libelf-dev libdw-dev
sudo apt-get install cmake libcurl4-openssl-dev libelf-dev libdw-dev
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz
tar xzf master.tar.gz
mkdir kcov-master/build
cd kcov-master/build
cmake ..
make
sudo make install
cd ../..
# run kcov on all tests, rerunning all tests with coverage report
mkdir -p target
# needed to tell some config tests where the server root directory is
export TDNS_SERVER_SRC_ROOT=./server
export COVERALLS_PARALLEL=true
SRC_PATHS=client/src,server/src
EXCLUDE_PATHS=client/src/error,server/src/error
for i in target/debug/trust_dns*-* target/debug/*_tests-* ; do
if [ -f $i ] && [ -x $i ]; then
# submit the report... what's the executable since there are many?
echo "executing kcov on $i"
kcov --exclude-pattern=/.cargo \
--include-path=${SRC_PATHS} \
--exclude-path=${EXCLUDE_PATHS} \
target/kcov-$(basename $i) $i
fi
done
echo "merging and uploading to coveralls.io"
kcov --coveralls-id=${TRAVIS_JOB_ID} \
--merge target/kcov-*

12
scripts/run_tests.sh Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash -e
trust_dns_dir=$(dirname $0)/..
cd ${trust_dns_dir:?}
for i in client server; do
pushd $i
echo "executing cargo on $i"
cargo build --verbose
cargo test --verbose
popd
done

543
server/Cargo.lock generated Normal file
View File

@ -0,0 +1,543 @@
[root]
name = "trust-dns-server"
version = "0.8.1"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.86 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rusqlite 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns 0.8.1",
]
[[package]]
name = "aho-corasick"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bytes"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "data-encoding"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "dbghelp-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "docopt"
version = "0.6.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error-chain"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "futures"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gdi32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "kernel32-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lazy_static"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazycell"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libressl-pnacl-sys"
version = "2.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"pnacl-build-helper 1.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libsqlite3-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "linked-hash-map"
version = "0.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "log"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lru-cache"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"linked-hash-map 0.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mio"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "miow"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "net2"
version = "0.2.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libressl-pnacl-sys 2.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pkg-config"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pnacl-build-helper"
version = "1.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex-syntax"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rusqlite"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"libsqlite3-sys 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lru-cache 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-serialize"
version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "scoped-tls"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "slab"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "strsim"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "tempdir"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread-id"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "time"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tokio-core"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "trust-dns"
version = "0.8.1"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"data-encoding 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rusqlite 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "user32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "utf8-ranges"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-build"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

63
server/Cargo.toml Normal file
View File

@ -0,0 +1,63 @@
[package]
name = "trust-dns-server"
version = "0.8.1"
authors = ["Benjamin Fry <benjaminfry@me.com>"]
# A short blurb about the package. This is not rendered in any format when
# uploaded to crates.io (aka this is not markdown)
description = """
TRust-DNS is a safe and secure DNS server and client with DNSec support.
Eventually this could be a replacement for BIND9. DNSSec on the client side,
with NSEC validation for negative records, is complete. The client and
server both support dynamic DNS with authenticated requests.
"""
# These URLs point to more information about the repository
documentation = "https://docs.rs/trust-dns"
homepage = "http://www.trust-dns.org/index.html"
repository = "https://github.com/bluejekyll/trust-dns"
# This points to a file in the repository (relative to this Cargo.toml). The
# contents of this file are stored and indexed in the registry.
readme = "README.md"
# This is a small list of keywords used to categorize and search for this
# package.
keywords = ["DNS", "BIND", "dig", "named", "dnssec"]
# This is a string description of the license for this package. Currently
# crates.io will validate the license provided against a whitelist of known
# license identifiers from http://spdx.org/licenses/. Multiple licenses can
# be separated with a `/`
license = "MIT/Apache-2.0"
# custom build steps
build = "build.rs"
[features]
[lib]
name = "trust_dns_server"
path = "src/lib.rs"
[[bin]]
name = "named"
path = "src/named.rs"
[dependencies]
backtrace = "^0.2.1"
chrono = "^0.2.21"
docopt = "^0.6.78"
error-chain = "0.1.12"
futures = "^0.1"
lazy_static = "^0.2.1"
log = "^0.3.5"
mio = "^0.5.1"
openssl = "^0.8.3"
rand = "^0.3"
rustc-serialize = "^0.3.18"
rusqlite = "^0.7.3"
time = "^0.1"
tokio-core = "^0.1"
toml = "^0.1"
trust-dns = { version = "*", path = "../client" }

32
server/build.rs Normal file
View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
fn main() {
// write out a version file to link against for version information
let out_dir = env::var("OUT_DIR").unwrap();
let version = env::var("CARGO_PKG_VERSION").unwrap();
let dest_path = Path::new(&out_dir).join("version.rs");
let mut f = File::create(&dest_path).unwrap();
f.write_all(b"pub fn version() -> &'static str {").unwrap();
write!(f, " \"{}\" ", version).unwrap();
f.write_all(b" }").unwrap();
}

View File

@ -14,53 +14,17 @@
* limitations under the License.
*/
use std::collections::BTreeMap;
use std::cmp::Ordering;
use chrono::UTC;
use ::authority::{Journal, RRSet, UpdateResult, ZoneType};
use trust_dns::op::{Message, UpdateMessage, ResponseCode, Query};
use trust_dns::rr::{DNSClass, Name, RData, Record, RecordType, RrKey, RrSet};
use trust_dns::rr::rdata::{NSEC, SIG};
use trust_dns::rr::dnssec::Signer;
use ::authority::{Journal, UpdateResult, ZoneType};
use ::error::{PersistenceErrorKind, PersistenceResult};
use ::op::{Message, UpdateMessage, ResponseCode, Query};
use ::rr::{DNSClass, Name, RData, Record, RecordType};
use ::rr::rdata::{NSEC, SIG};
use ::rr::dnssec::Signer;
/// Accessor key for RRSets in the Authority.
#[derive(Eq, PartialEq, Debug, Hash, Clone)]
pub struct RrKey { name: Name, record_type: RecordType }
impl RrKey {
/// Creates a new key to access the Authority.
///
/// # Arguments
///
/// * `name` - domain name to lookup.
/// * `record_type` - the `RecordType` to lookup.
///
/// # Return value
///
/// A new key to access the Authorities.
pub fn new(name: &Name, record_type: RecordType) -> RrKey {
RrKey{ name: name.clone(), record_type: record_type }
}
}
impl PartialOrd for RrKey {
fn partial_cmp(&self, other: &RrKey) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for RrKey {
fn cmp(&self, other: &Self) -> Ordering {
let order = self.name.cmp(&other.name);
if order == Ordering::Equal {
self.record_type.cmp(&other.record_type)
} else {
order
}
}
}
/// Authority is responsible for storing the resource records for a particular zone.
///
@ -70,7 +34,7 @@ pub struct Authority {
origin: Name,
class: DNSClass,
journal: Option<Journal>,
records: BTreeMap<RrKey, RRSet>,
records: BTreeMap<RrKey, RrSet>,
zone_type: ZoneType,
allow_update: bool,
// Private key mapped to the Record of the DNSKey
@ -95,7 +59,7 @@ impl Authority {
/// # Return value
///
/// The new `Authority`.
pub fn new(origin: Name, records: BTreeMap<RrKey, RRSet>, zone_type: ZoneType, allow_update: bool) -> Authority {
pub fn new(origin: Name, records: BTreeMap<RrKey, RrSet>, zone_type: ZoneType, allow_update: bool) -> Authority {
Authority{ origin: origin, class: DNSClass::IN, journal: None, records: records, zone_type: zone_type,
allow_update: allow_update, secure_keys: Vec::new() }
}
@ -178,25 +142,28 @@ impl Authority {
self.journal.as_ref()
}
#[cfg(test)]
/// Enables the zone for dynamic DNS updates
pub fn set_allow_update(&mut self, allow_update: bool) {
self.allow_update = allow_update;
}
#[cfg(test)]
/// Retrieve the Signer, which contains the private keys, for this zone
pub fn get_secure_keys(&self) -> &[Signer] {
&self.secure_keys
}
/// Get the origin of this zone, i.e. example.com is the origin for www.example.com
pub fn get_origin(&self) -> &Name {
&self.origin
}
/// What type is this zone
pub fn get_zone_type(&self) -> ZoneType {
self.zone_type
}
pub fn get_records(&self) -> &BTreeMap<RrKey, RRSet> {
/// Get all the
pub fn get_records(&self) -> &BTreeMap<RrKey, RrSet> {
&self.records
}
@ -209,18 +176,18 @@ impl Authority {
self.lookup(&self.origin, RecordType::SOA, false).first().map(|v| *v)
}
/// Returns the SOA record
///
///
/// Returns the SOA record for the zone
pub fn get_soa_secure(&self, is_secure: bool) -> Vec<&Record> {
self.lookup(&self.origin, RecordType::SOA, is_secure)
}
/// Returns the minimum ttl (as used in the SOA record)
pub fn get_minimum_ttl(&self) -> u32 {
self.get_soa().map_or(0, |soa| if let &RData::SOA(ref rdata) = soa.get_rdata() { rdata.get_minimum() } else { 0 })
}
fn get_serial(&self) -> u32 {
/// get the current serial number for the zone.
pub fn get_serial(&self) -> u32 {
let soa = if let Some(ref soa_record) = self.get_soa() {
soa_record.clone()
} else {
@ -307,7 +274,7 @@ impl Authority {
/// NONE rrset empty RRset does not exist
/// zone rrset rr RRset exists (value dependent)
/// ```
fn verify_prerequisites(&self, pre_requisites: &[Record]) -> UpdateResult<()> {
pub fn verify_prerequisites(&self, pre_requisites: &[Record]) -> UpdateResult<()> {
// 3.2.5 - Pseudocode for Prerequisite Section Processing
//
// for rr in prerequisites
@ -443,7 +410,7 @@ impl Authority {
/// and restore the zone to its original state before answering the
/// requestor.
/// ```
fn authorize(&self, update_message: &Message) -> UpdateResult<()> {
pub fn authorize(&self, update_message: &Message) -> UpdateResult<()> {
// 3.3.3 - Pseudocode for Permission Checking
//
// if (security policy exists)
@ -527,7 +494,7 @@ impl Authority {
/// MAILB, or any other QUERY metatype besides ANY, or any unrecognized
/// type, else signal FORMERR to the requestor.
/// ```
fn pre_scan(&self, records: &[Record]) -> UpdateResult<()> {
pub fn pre_scan(&self, records: &[Record]) -> UpdateResult<()> {
// 3.4.1.3 - Pseudocode For Update Section Prescan
//
// [rr] for rr in updates
@ -603,7 +570,7 @@ impl Authority {
/// * `records` - set of record instructions for update following above rules
/// * `auto_sign` - if true, the zone will auto_sign (assuming there are signers present), this
/// should be disabled during recovery.
fn update_records(&mut self, records: &[Record], auto_sign: bool) -> UpdateResult<bool> {
pub fn update_records(&mut self, records: &[Record], auto_sign: bool) -> UpdateResult<bool> {
let mut updated = false;
let serial: u32 = self.get_serial();
@ -760,7 +727,7 @@ impl Authority {
assert_eq!(self.class, record.get_dns_class());
let rr_key = RrKey::new(record.get_name(), record.get_rr_type());
let records: &mut RRSet = self.records.entry(rr_key).or_insert(RRSet::new(record.get_name(), record.get_rr_type(), serial));
let records: &mut RrSet = self.records.entry(rr_key).or_insert(RrSet::new(record.get_name(), record.get_rr_type(), serial));
records.insert(record, serial)
}
@ -1073,448 +1040,75 @@ impl Authority {
}
}
#[cfg(test)]
pub mod authority_tests {
use std::collections::BTreeMap;
use std::net::{Ipv4Addr,Ipv6Addr};
use ::authority::ZoneType;
use ::rr::*;
use ::rr::rdata::{ NULL, SOA, TXT };
use ::op::*;
use super::*;
pub fn create_example() -> Authority {
let origin: Name = Name::parse("example.com.", None,).unwrap();
let mut records: Authority = Authority::new(origin.clone(), BTreeMap::new(), ZoneType::Master, false);
// example.com. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082403 7200 3600 1209600 3600
records.upsert(Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone(), 0);
// example.com. 60 IN TXT "v=spf1 -all"
//records.upsert(origin.clone(), Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT{ txt_data: vec!["v=spf1 -all".to_string()] }).clone());
// example.com. 60 IN TXT "$Id: example.com 4415 2015-08-24 20:12:23Z davids $"
records.upsert(Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["$Id: example.com 4415 2015-08-24 20:12:23Z davids $".to_string()]))).clone(), 0);
// example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// TODO support these later...
// example.com. 3600 IN RRSIG NSEC 8 2 3600 20150926015219 20150905040848 54108 example.com. d0AXd6QRITqLeiYbQUlJ5O0Og9tSjk7IlxQr9aJO+r+rc1g0dW9i9OCc XXQxdC1/zyubecjD6kSs3vwxzzEEupivaKHKtNPXdnDZ5UUiaIC1VU9l 9h/ik+AR4rCTY6dYPCI6lafD/TlqQLbpEnb34ywkRpl5G3pasPrwEY7b nrAndEY=
// example.com. 3600 IN NSEC www.example.com. A NS SOA TXT AAAA RRSIG NSEC DNSKEY
// example.com. 86400 IN RRSIG NS 8 2 86400 20150915033148 20150824191224 54108 example.com. O2TCB5/v/b1XGlTQEj0/oGKp7dTueQ7zRmCtADDEDWrzLdWrKcmDGF37 mgKejcAlSYVhWLxyLlet7KqJhLu+oQcDTNf/BT3vNX/Ivx3sKhUUMpfi 8Mn5zhRqM9gbzZVCS/toJIYqOBqvAkS7UpkmpLzl0Zt2h4j0Gp/8GwRb ZU67l6M=
// example.com. 86400 IN RRSIG AAAA 8 2 86400 20150914212400 20150824191224 54108 example.com. AHd2BDNjtg4jPRQwyT4FHtlVTZDZ6IIusYVGCzWfnt5SZOoizyXnJhqX 44MeVTqi1/2cskpKvRkK3bkYnVUcjZiFgSaa9xJHmXrslaTr5mOmXt9s 6k95N1daYKhDKKcr0M4TXLUgdnBr+/pMFiLsyOoDb8GJDT8Llmpk52Ie ysJX8BY=
// example.com. 86400 IN RRSIG A 8 2 86400 20150914083326 20150824191224 54108 example.com. La1p2R7GPMrXEm3kcznSJ70sOspmfSDsgOZ74GlzgaFfMRveA20IDUnZ /HI9M95/tBWbHdHBtm9aCK+4n7EluhNPTAT1+88V6xK7Lc7pcBfBXIHg DAdUoj26VIh7NRml/0QR0dFu4PriA/wLNe+d1Q961qf0JZP80TU4IMBC X/W6Ijk=
// example.com. 60 IN RRSIG TXT 8 2 60 20150914201612 20150824191224 54108 example.com. Be/bPvaVVK/o66QOHJZMFBDCQVhP44jptS9sZe8Vpfmzd72/v+1gwn1z u2+xisePSpAMtDZsFJgqsCjpbLFvmhNdh8ktlq/kuCME5hZs7qY7DZIB VwkSTsJPIq8qhX22clfIbqzaypuIX9ajWr+5i0nGQLNekMB07t4/GCoJ q5QpQoE=
// example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20150914090528 20150824071818 31406 example.com. rZJRBwHhYzCDwkDEXqECHNWezTNj2A683I/yHHqD1j9ytGHGskGEEyJC i5fk70YCm64GqDYKu70kgv7hCFqc4OM3aD88QDe3L4Uv7ZXqouNbjTEO 3BEBI13GetRkK5qLndl30Y/urOBASQFELQUJsvQBR2gJMdQsb6G0mHIW rubY2SxAGa9rQW7yehRQNK4ME37FqINBDuIV9o7kULPhn9Ux1Qx62prd 9nikzamGxFL+9dFDOfnYVw2C/OgGJNIXh5QyKMG4qXmXb6sB/V3P+FE+ +vkt3RToE2xPN5bf1vVIlEJof6LtojrowwnZpiphTXFJF/BJrgiotGt3 Gsd8Cw==
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAcZMEndf6/+kG6Dp7re/grJ9f5CP5bQplBGokyxbM4oPNeBfWMIC +xY+ICgTyJarVB4aPYNMV7znsHM4XwU8hfpZ3ZcmT+69KyGqs+tt2pc/ si30dnUpPo/AMnN7Kul2SgqT9g1bb5O0D/CH2txo6YXr/BbuNHLqAh/x mof1QYkl6GoP
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAeZFCLkW/sztmJmpmZo/udvAyqshiLO34zHzzkVPrhuUBA/xb3wk YeCvMO6iBxCD+/Dk7fWEAT1NR21bDKHySVHE5cre+fqnXI+9NCjkMoBE 193j8G5HscIpWpG1qgkelBhmucfUPv+R4AIhpfjc352eh1q/SniYUGR4 fytlDZVXCLhL
// example.com. 3600 IN DNSKEY 257 3 8 AwEAAbOFAxl+Lkt0UMglZizKEC1AxUu8zlj65KYatR5wBWMrh18TYzK/ ig6Y1t5YTWCO68bynorpNu9fqNFALX7bVl9/gybA0v0EhF+dgXmoUfRX 7ksMGgBvtfa2/Y9a3klXNLqkTszIQ4PEMVCjtryl19Be9/PkFeC9ITjg MRQsQhmB39eyMYnal+f3bUxKk4fq7cuEU0dbRpue4H/N6jPucXWOwiMA kTJhghqgy+o9FfIp+tR/emKao94/wpVXDcPf5B18j7xz2SvTTxiuqCzC MtsxnikZHcoh1j4g+Y1B8zIMIvrEM+pZGhh/Yuf4RwCBgaYCi9hpiMWV vS4WBzx0/lU=
// example.com. 3600 IN RRSIG SOA 8 2 3600 20150926132522 20150905040848 54108 example.com. q8psdDPaJVo9KPVgMNR2N1by3LMEci+3HyTmN/Xv3DgDFG5MqNlX9Dfj dUBIMbvYmkUUPQ9fIWYA+ldmDHiRBiHIcvvk/LYD8mODWL6RoF+GEsW0 zm43RNBnbE41wtNrch5WU/q1ko2svB98ooqePWWuFzmdyPpidtLCgSCz FCiCiVQ=
// www
let www_name: Name = Name::parse("www.example.com.", None).unwrap();
// www.example.com. 86400 IN TXT "v=spf1 -all"
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["v=spf1 -all".to_string()]))).clone(), 0);
// www.example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// www.example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20150925215757 20150905040848 54108 example.com. ZKIVt1IN3O1FWZPSfrQAH7nHt7RUFDjcbh7NxnEqd/uTGCnZ6SrAEgrY E9GMmBwvRjoucphGtjkYOpPJPe5MlnTHoYCjxL4qmG3LsD2KD0bfPufa ibtlQZRrPglxZ92hBKK3ZiPnPRe7I9yni2UQSQA7XDi7CQySYyo490It AxdXjAo=
// www.example.com. 3600 IN NSEC example.com. A TXT AAAA RRSIG NSEC
// www.example.com. 86400 IN RRSIG TXT 8 3 86400 20150914142952 20150824191224 54108 example.com. LvODnPb7NLDZfHPBOrr/qLnOKA670vVYKQSk5Qkz3MPNKDVAFJqsP2Y6 UYcypSJZfcSjfIk2mU9dUiansU2ZL80OZJUsUobqJt5De748ovITYDJ7 afbohQzPg+4E1GIWMkJZ/VQD3B2pmr7J5rPn+vejxSQSoI93AIQaTpCU L5O/Bac=
// www.example.com. 86400 IN RRSIG AAAA 8 3 86400 20150914082216 20150824191224 54108 example.com. kje4FKE+7d/j4OzWQelcKkePq6DxCRY/5btAiUcZNf+zVNlHK+o57h1r Y76ZviWChQB8Np2TjA1DrXGi/kHr2KKE60H5822mFZ2b9O+sgW4q6o3G kO2E1CQxbYe+nI1Z8lVfjdCNm81zfvYqDjo2/tGqagehxG1V9MBZO6br 4KKdoa4=
// www.example.com. 86400 IN RRSIG A 8 3 86400 20150915023456 20150824191224 54108 example.com. cWtw0nMvcXcYNnxejB3Le3KBfoPPQZLmbaJ8ybdmzBDefQOm1ZjZZMOP wHEIxzdjRhG9mLt1mpyo1H7OezKTGX+mDtskcECTl/+jB/YSZyvbwRxj e88Lrg4D+D2MiajQn3XSWf+6LQVe1J67gdbKTXezvux0tRxBNHHqWXRk pxCILes=
return records;
}
pub fn create_secure_example() -> Authority {
use chrono::Duration;
use openssl::crypto::rsa::RSA;
use ::rr::dnssec::{Algorithm, Signer};
let mut authority: Authority = create_example();
let rsa = RSA::generate(2048).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa, authority.get_origin().clone(), Duration::weeks(1));
authority.add_secure_key(signer);
authority.secure_zone();
authority
}
#[test]
fn test_search() {
let example = create_example();
let origin = example.get_origin().clone();
let mut query: Query = Query::new();
query.name(origin.clone());
let result = example.search(&query, false);
if !result.is_empty() {
assert_eq!(result.first().unwrap().get_rr_type(), RecordType::A);
assert_eq!(result.first().unwrap().get_dns_class(), DNSClass::IN);
assert_eq!(result.first().unwrap().get_rdata(), &RData::A(Ipv4Addr::new(93,184,216,34)));
} else {
panic!("expected a result"); // valid panic, in test
}
}
/// this is a litte more interesting b/c it requires a recursive lookup for the origin
#[test]
fn test_search_www() {
let example = create_example();
let www_name = Name::parse("www.example.com.", None).unwrap();
let mut query: Query = Query::new();
query.name(www_name.clone());
let result = example.search(&query, false);
if !result.is_empty() {
assert_eq!(result.first().unwrap().get_rr_type(), RecordType::A);
assert_eq!(result.first().unwrap().get_dns_class(), DNSClass::IN);
assert_eq!(result.first().unwrap().get_rdata(), &RData::A(Ipv4Addr::new(93,184,216,34)));
} else {
panic!("expected a result"); // valid panic, in test
}
}
#[test]
fn test_authority() {
let authority: Authority = create_example();
assert!(authority.get_soa().is_some());
assert_eq!(authority.get_soa().unwrap().get_dns_class(), DNSClass::IN);
assert!(!authority.lookup(authority.get_origin(), RecordType::NS, false).is_empty());
let mut lookup: Vec<_> = authority.get_ns(false);
lookup.sort();
assert_eq!(**lookup.first().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone());
assert_eq!(**lookup.last().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone());
assert!(!authority.lookup(authority.get_origin(), RecordType::TXT, false).is_empty());
let mut lookup: Vec<_> = authority.lookup(authority.get_origin(), RecordType::TXT, false);
lookup.sort();
assert_eq!(**lookup.first().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["$Id: example.com 4415 2015-08-24 20:12:23Z davids $".to_string()]))).clone());
assert_eq!(**authority.lookup(authority.get_origin(), RecordType::A, false).first().unwrap(), Record::new().name(authority.get_origin().clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone());
}
#[test]
fn test_authorize() {
let authority: Authority = create_example();
let mut message = Message::new();
message.id(10).message_type(MessageType::Query).op_code(OpCode::Update);
assert_eq!(authority.authorize(&message), Err(ResponseCode::Refused));
// TODO: this will nee to be more complex as additional policies are added
// authority.set_allow_update(true);
// assert!(authority.authorize(&message).is_ok());
}
#[test]
fn test_prerequisites() {
let not_zone = Name::new().label("not").label("a").label("domain").label("com");
let not_in_zone = Name::new().label("not").label("example").label("com");
let mut authority: Authority = create_example();
authority.set_allow_update(true);
// first check the initial negatives, ttl = 0, and the zone is the same
assert_eq!(authority.verify_prerequisites(&[Record::new().name(not_in_zone.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.verify_prerequisites(&[Record::new().name(not_zone.clone()).ttl(0).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::NotZone));
// * ANY ANY empty Name is in use
assert!(authority.verify_prerequisites(&[Record::new().name(authority.get_origin().clone()).ttl(0).dns_class(DNSClass::ANY).rr_type(RecordType::ANY).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert_eq!(authority.verify_prerequisites(&[Record::new().name(not_in_zone.clone()).ttl(0).dns_class(DNSClass::ANY).rr_type(RecordType::ANY).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::NXDomain));
// * ANY rrset empty RRset exists (value independent)
assert!(authority.verify_prerequisites(&[Record::new().name(authority.get_origin().clone()).ttl(0).dns_class(DNSClass::ANY).rr_type(RecordType::A).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert_eq!(authority.verify_prerequisites(&[Record::new().name(not_in_zone.clone()).ttl(0).dns_class(DNSClass::ANY).rr_type(RecordType::A).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::NXRRSet));
// * NONE ANY empty Name is not in use
assert!(authority.verify_prerequisites(&[Record::new().name(not_in_zone.clone()).ttl(0).dns_class(DNSClass::NONE).rr_type(RecordType::ANY).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert_eq!(authority.verify_prerequisites(&[Record::new().name(authority.get_origin().clone()).ttl(0).dns_class(DNSClass::NONE).rr_type(RecordType::ANY).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::YXDomain));
// * NONE rrset empty RRset does not exist
assert!(authority.verify_prerequisites(&[Record::new().name(not_in_zone.clone()).ttl(0).dns_class(DNSClass::NONE).rr_type(RecordType::A).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert_eq!(authority.verify_prerequisites(&[Record::new().name(authority.get_origin().clone()).ttl(0).dns_class(DNSClass::NONE).rr_type(RecordType::A).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::YXRRSet));
// * zone rrset rr RRset exists (value dependent)
assert!(authority.verify_prerequisites(&[Record::new().name(authority.get_origin().clone()).ttl(0).dns_class(DNSClass::IN).rr_type(RecordType::A).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone()]).is_ok());
// wrong class
assert_eq!(authority.verify_prerequisites(&[Record::new().name(authority.get_origin().clone()).ttl(0).dns_class(DNSClass::CH).rr_type(RecordType::A).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone()]), Err(ResponseCode::FormErr));
// wrong Name
assert_eq!(authority.verify_prerequisites(&[Record::new().name(not_in_zone.clone()).ttl(0).dns_class(DNSClass::IN).rr_type(RecordType::A).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()]), Err(ResponseCode::NXRRSet));
// wrong IP
assert_eq!(authority.verify_prerequisites(&[Record::new().name(authority.get_origin().clone()).ttl(0).dns_class(DNSClass::IN).rr_type(RecordType::A).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()]), Err(ResponseCode::NXRRSet));
}
#[test]
fn test_pre_scan() {
let up_name = Name::new().label("www").label("example").label("com");
let not_zone = Name::new().label("not").label("zone").label("com");
let authority: Authority = create_example();
assert_eq!(authority.pre_scan(&[Record::new().name(not_zone.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()]), Err(ResponseCode::NotZone));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::ANY).dns_class(DNSClass::IN).rdata(RData::NULL(NULL::new()) ).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::AXFR).dns_class(DNSClass::IN).rdata(RData::NULL(NULL::new()) ).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::IXFR).dns_class(DNSClass::IN).rdata(RData::NULL(NULL::new()) ).clone()]), Err(ResponseCode::FormErr));
assert!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()]).is_ok());
assert!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::ANY).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::A).dns_class(DNSClass::ANY).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::AXFR).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::IXFR).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
assert!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::ANY).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::A).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::NONE).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::ANY).dns_class(DNSClass::NONE).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::AXFR).dns_class(DNSClass::NONE).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::IXFR).dns_class(DNSClass::NONE).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
assert!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::A).dns_class(DNSClass::NONE).rdata(RData::NULL(NULL::new())).clone()]).is_ok());
assert!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(0).rr_type(RecordType::A).dns_class(DNSClass::NONE).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()]).is_ok());
assert_eq!(authority.pre_scan(&[Record::new().name(up_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::CH).rdata(RData::NULL(NULL::new())).clone()]), Err(ResponseCode::FormErr));
}
#[test]
fn test_update() {
let new_name = Name::new().label("new").label("example").label("com");
let www_name = Name::new().label("www").label("example").label("com");
let mut authority: Authority = create_example();
let serial = authority.get_serial();
authority.set_allow_update(true);
let mut original_vec: Vec<Record> = vec![
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["v=spf1 -all".to_string()]))).clone(),
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(),
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(),
];
original_vec.sort();
{
// assert that the correct set of records is there.
let mut www_rrset: Vec<&Record> = authority.lookup(&www_name, RecordType::ANY, false);
www_rrset.sort();
assert_eq!(www_rrset, original_vec.iter().collect::<Vec<&Record>>());
// assert new record doesn't exist
assert!(authority.lookup(&new_name, RecordType::ANY, false).is_empty());
}
//
// zone rrset rr Add to an RRset
let add_record = &[Record::new().name(new_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()];
assert!(authority.update_records(add_record, true).expect("update failed"));
assert_eq!(authority.lookup(&new_name, RecordType::ANY, false), add_record.iter().collect::<Vec<&Record>>());
assert_eq!(serial + 1, authority.get_serial());
let add_www_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(10,0,0,1))).clone()];
assert!(authority.update_records(add_www_record, true).expect("update failed"));
assert_eq!(serial + 2, authority.get_serial());
{
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY, false);
www_rrset.sort();
let mut plus_10 = original_vec.clone();
plus_10.push(add_www_record[0].clone());
plus_10.sort();
assert_eq!(www_rrset, plus_10.iter().collect::<Vec<&Record>>());
}
//
// NONE rrset rr Delete an RR from an RRset
let del_record = &[Record::new().name(new_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::NONE).rdata(RData::A(Ipv4Addr::new(93,184,216,24))).clone()];
assert!(authority.update_records(del_record, true).expect("update failed"));
assert_eq!(serial + 3, authority.get_serial());
{
println!("after delete of specific record: {:?}", authority.lookup(&new_name, RecordType::ANY, false));
assert!(authority.lookup(&new_name, RecordType::ANY, false).is_empty());
}
// remove one from www
let del_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::NONE).rdata(RData::A(Ipv4Addr::new(10,0,0,1))).clone()];
assert!(authority.update_records(del_record, true).expect("update failed"));
assert_eq!(serial + 4, authority.get_serial());
{
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY, false);
www_rrset.sort();
assert_eq!(www_rrset, original_vec.iter().collect::<Vec<&Record>>());
}
//
// ANY rrset empty Delete an RRset
let del_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()];
assert!(authority.update_records(del_record, true).expect("update failed"));
assert_eq!(serial + 5, authority.get_serial());
let mut removed_a_vec: Vec<_> = vec![
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["v=spf1 -all".to_string()]))).clone(),
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(),
];
removed_a_vec.sort();
{
let mut www_rrset = authority.lookup(&www_name, RecordType::ANY, false);
www_rrset.sort();
assert_eq!(www_rrset, removed_a_vec.iter().collect::<Vec<&Record>>());
}
//
// ANY ANY empty Delete all RRsets from a name
println!("deleting all records");
let del_record = &[Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::ANY).dns_class(DNSClass::ANY).rdata(RData::NULL(NULL::new())).clone()];
assert!(authority.update_records(del_record, true).expect("update failed"));
assert!(authority.lookup(&www_name, RecordType::ANY, false).is_empty());
assert_eq!(serial + 6, authority.get_serial());
}
#[test]
fn test_zone_signing() {
use ::rr::{RData};
let authority: Authority = create_secure_example();
let results = authority.lookup(&authority.get_origin(), RecordType::AXFR, true);
assert!(results.iter().any(|r| r.get_rr_type() == RecordType::DNSKEY), "must contain a DNSKEY");
for record in results.iter() {
if record.get_rr_type() == RecordType::RRSIG { continue }
if record.get_rr_type() == RecordType::DNSKEY { continue }
// validate all records have associated RRSIGs after signing
assert!(results.iter().any(|r| r.get_rr_type() == RecordType::RRSIG &&
r.get_name() == record.get_name() &&
if let &RData::SIG(ref rrsig) = r.get_rdata() {
rrsig.get_type_covered() == record.get_rr_type()
} else {
false
} ), "record type not covered: {:?}", record);
}
}
#[test]
fn test_get_nsec() {
let name = Name::new().label("zzz").label("example").label("com");
let authority: Authority = create_secure_example();
let results = authority.get_nsec_records(&name, true);
for record in results.iter() {
assert!(record.get_name() < &name);
}
}
#[test]
fn test_journal() {
use std::net::Ipv4Addr;
use rusqlite::Connection;
use ::authority::Journal;
// test that this message can be inserted
let conn = Connection::open_in_memory().expect("could not create in memory DB");
let mut journal = Journal::new(conn).unwrap();
journal.schema_up().unwrap();
let mut authority = create_example();
authority.journal(journal);
authority.persist_to_journal().unwrap();
let new_name = Name::new().label("new").label("example").label("com");
let delete_name = Name::new().label("www").label("example").label("com");
let new_record = Record::new().name(new_name.clone()).rdata(RData::A(Ipv4Addr::new(10,11,12,13))).clone();
let delete_record = Record::new().name(delete_name.clone()).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).dns_class(DNSClass::NONE).clone();
authority.update_records(&[new_record.clone(), delete_record], true).unwrap();
// assert that the correct set of records is there.
let new_rrset: Vec<&Record> = authority.lookup(&new_name, RecordType::A, false);
assert!(new_rrset.iter().all(|r| *r == &new_record));
let delete_rrset: Vec<&Record> = authority.lookup(&delete_name, RecordType::A, false);
assert!(delete_rrset.is_empty());
// that record should have been recorded... let's reload the journal and see if we get it.
let mut recovered_authority = Authority::new(authority.get_origin().clone(),
BTreeMap::new(),
ZoneType::Master,
false);
recovered_authority.recover_with_journal(authority.get_journal().expect("journal not Some")).expect("recovery");
// assert that the correct set of records is there.
let new_rrset: Vec<&Record> = recovered_authority.lookup(&new_name, RecordType::A, false);
assert!(new_rrset.iter().all(|r| *r == &new_record));
let delete_rrset: Vec<&Record> = authority.lookup(&delete_name, RecordType::A, false);
assert!(delete_rrset.is_empty());
}
#[test]
fn test_recovery() {
use rusqlite::Connection;
use ::authority::Journal;
// test that this message can be inserted
let conn = Connection::open_in_memory().expect("could not create in memory DB");
let mut journal = Journal::new(conn).unwrap();
journal.schema_up().unwrap();
let mut authority = create_example();
authority.journal(journal);
authority.persist_to_journal().unwrap();
let journal = authority.get_journal().unwrap();
let mut recovered_authority = Authority::new(authority.get_origin().clone(),
BTreeMap::new(),
ZoneType::Master,
false);
recovered_authority.recover_with_journal(journal).expect("recovery");
assert_eq!(recovered_authority.get_records().len(), authority.get_records().len());
assert_eq!(recovered_authority.get_soa(), authority.get_soa());
assert!(recovered_authority.get_records().iter().all(|(rr_key, rr_set)| {
let other_rr_set = authority.get_records().get(rr_key).expect(&format!("key doesn't exist: {:?}", rr_key));
rr_set.iter().zip(other_rr_set.iter()).all(|(record, other_record)| {
record.get_ttl() == other_record.get_ttl() &&
record.get_rdata() == other_record.get_rdata()
})
}));
assert!(authority.get_records().iter().all(|(rr_key, rr_set)| {
let other_rr_set = recovered_authority.get_records().get(rr_key).expect(&format!("key doesn't exist: {:?}", rr_key));
rr_set.iter().zip(other_rr_set.iter()).all(|(record, other_record)| {
record.get_ttl() == other_record.get_ttl() &&
record.get_rdata() == other_record.get_rdata()
})
}));
}
pub fn create_example() -> Authority {
use std::net::*;
use trust_dns::rr::rdata::*;
let origin: Name = Name::parse("example.com.", None,).unwrap();
let mut records: Authority = Authority::new(origin.clone(), BTreeMap::new(), ZoneType::Master, false);
// example.com. 3600 IN SOA sns.dns.icann.org. noc.dns.icann.org. 2015082403 7200 3600 1209600 3600
records.upsert(Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone(), 0);
// example.com. 60 IN TXT "v=spf1 -all"
//records.upsert(origin.clone(), Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT{ txt_data: vec!["v=spf1 -all".to_string()] }).clone());
// example.com. 60 IN TXT "$Id: example.com 4415 2015-08-24 20:12:23Z davids $"
records.upsert(Record::new().name(origin.clone()).ttl(60).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["$Id: example.com 4415 2015-08-24 20:12:23Z davids $".to_string()]))).clone(), 0);
// example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// TODO support these later...
// example.com. 3600 IN RRSIG NSEC 8 2 3600 20150926015219 20150905040848 54108 example.com. d0AXd6QRITqLeiYbQUlJ5O0Og9tSjk7IlxQr9aJO+r+rc1g0dW9i9OCc XXQxdC1/zyubecjD6kSs3vwxzzEEupivaKHKtNPXdnDZ5UUiaIC1VU9l 9h/ik+AR4rCTY6dYPCI6lafD/TlqQLbpEnb34ywkRpl5G3pasPrwEY7b nrAndEY=
// example.com. 3600 IN NSEC www.example.com. A NS SOA TXT AAAA RRSIG NSEC DNSKEY
// example.com. 86400 IN RRSIG NS 8 2 86400 20150915033148 20150824191224 54108 example.com. O2TCB5/v/b1XGlTQEj0/oGKp7dTueQ7zRmCtADDEDWrzLdWrKcmDGF37 mgKejcAlSYVhWLxyLlet7KqJhLu+oQcDTNf/BT3vNX/Ivx3sKhUUMpfi 8Mn5zhRqM9gbzZVCS/toJIYqOBqvAkS7UpkmpLzl0Zt2h4j0Gp/8GwRb ZU67l6M=
// example.com. 86400 IN RRSIG AAAA 8 2 86400 20150914212400 20150824191224 54108 example.com. AHd2BDNjtg4jPRQwyT4FHtlVTZDZ6IIusYVGCzWfnt5SZOoizyXnJhqX 44MeVTqi1/2cskpKvRkK3bkYnVUcjZiFgSaa9xJHmXrslaTr5mOmXt9s 6k95N1daYKhDKKcr0M4TXLUgdnBr+/pMFiLsyOoDb8GJDT8Llmpk52Ie ysJX8BY=
// example.com. 86400 IN RRSIG A 8 2 86400 20150914083326 20150824191224 54108 example.com. La1p2R7GPMrXEm3kcznSJ70sOspmfSDsgOZ74GlzgaFfMRveA20IDUnZ /HI9M95/tBWbHdHBtm9aCK+4n7EluhNPTAT1+88V6xK7Lc7pcBfBXIHg DAdUoj26VIh7NRml/0QR0dFu4PriA/wLNe+d1Q961qf0JZP80TU4IMBC X/W6Ijk=
// example.com. 60 IN RRSIG TXT 8 2 60 20150914201612 20150824191224 54108 example.com. Be/bPvaVVK/o66QOHJZMFBDCQVhP44jptS9sZe8Vpfmzd72/v+1gwn1z u2+xisePSpAMtDZsFJgqsCjpbLFvmhNdh8ktlq/kuCME5hZs7qY7DZIB VwkSTsJPIq8qhX22clfIbqzaypuIX9ajWr+5i0nGQLNekMB07t4/GCoJ q5QpQoE=
// example.com. 3600 IN RRSIG DNSKEY 8 2 3600 20150914090528 20150824071818 31406 example.com. rZJRBwHhYzCDwkDEXqECHNWezTNj2A683I/yHHqD1j9ytGHGskGEEyJC i5fk70YCm64GqDYKu70kgv7hCFqc4OM3aD88QDe3L4Uv7ZXqouNbjTEO 3BEBI13GetRkK5qLndl30Y/urOBASQFELQUJsvQBR2gJMdQsb6G0mHIW rubY2SxAGa9rQW7yehRQNK4ME37FqINBDuIV9o7kULPhn9Ux1Qx62prd 9nikzamGxFL+9dFDOfnYVw2C/OgGJNIXh5QyKMG4qXmXb6sB/V3P+FE+ +vkt3RToE2xPN5bf1vVIlEJof6LtojrowwnZpiphTXFJF/BJrgiotGt3 Gsd8Cw==
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAcZMEndf6/+kG6Dp7re/grJ9f5CP5bQplBGokyxbM4oPNeBfWMIC +xY+ICgTyJarVB4aPYNMV7znsHM4XwU8hfpZ3ZcmT+69KyGqs+tt2pc/ si30dnUpPo/AMnN7Kul2SgqT9g1bb5O0D/CH2txo6YXr/BbuNHLqAh/x mof1QYkl6GoP
// example.com. 3600 IN DNSKEY 256 3 8 AwEAAeZFCLkW/sztmJmpmZo/udvAyqshiLO34zHzzkVPrhuUBA/xb3wk YeCvMO6iBxCD+/Dk7fWEAT1NR21bDKHySVHE5cre+fqnXI+9NCjkMoBE 193j8G5HscIpWpG1qgkelBhmucfUPv+R4AIhpfjc352eh1q/SniYUGR4 fytlDZVXCLhL
// example.com. 3600 IN DNSKEY 257 3 8 AwEAAbOFAxl+Lkt0UMglZizKEC1AxUu8zlj65KYatR5wBWMrh18TYzK/ ig6Y1t5YTWCO68bynorpNu9fqNFALX7bVl9/gybA0v0EhF+dgXmoUfRX 7ksMGgBvtfa2/Y9a3klXNLqkTszIQ4PEMVCjtryl19Be9/PkFeC9ITjg MRQsQhmB39eyMYnal+f3bUxKk4fq7cuEU0dbRpue4H/N6jPucXWOwiMA kTJhghqgy+o9FfIp+tR/emKao94/wpVXDcPf5B18j7xz2SvTTxiuqCzC MtsxnikZHcoh1j4g+Y1B8zIMIvrEM+pZGhh/Yuf4RwCBgaYCi9hpiMWV vS4WBzx0/lU=
// example.com. 3600 IN RRSIG SOA 8 2 3600 20150926132522 20150905040848 54108 example.com. q8psdDPaJVo9KPVgMNR2N1by3LMEci+3HyTmN/Xv3DgDFG5MqNlX9Dfj dUBIMbvYmkUUPQ9fIWYA+ldmDHiRBiHIcvvk/LYD8mODWL6RoF+GEsW0 zm43RNBnbE41wtNrch5WU/q1ko2svB98ooqePWWuFzmdyPpidtLCgSCz FCiCiVQ=
// www
let www_name: Name = Name::parse("www.example.com.", None).unwrap();
// www.example.com. 86400 IN TXT "v=spf1 -all"
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::TXT).dns_class(DNSClass::IN).rdata(RData::TXT(TXT::new(vec!["v=spf1 -all".to_string()]))).clone(), 0);
// www.example.com. 86400 IN A 93.184.216.34
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(93,184,216,34))).clone(), 0);
// www.example.com. 86400 IN AAAA 2606:2800:220:1:248:1893:25c8:1946
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
// www.example.com. 3600 IN RRSIG NSEC 8 3 3600 20150925215757 20150905040848 54108 example.com. ZKIVt1IN3O1FWZPSfrQAH7nHt7RUFDjcbh7NxnEqd/uTGCnZ6SrAEgrY E9GMmBwvRjoucphGtjkYOpPJPe5MlnTHoYCjxL4qmG3LsD2KD0bfPufa ibtlQZRrPglxZ92hBKK3ZiPnPRe7I9yni2UQSQA7XDi7CQySYyo490It AxdXjAo=
// www.example.com. 3600 IN NSEC example.com. A TXT AAAA RRSIG NSEC
// www.example.com. 86400 IN RRSIG TXT 8 3 86400 20150914142952 20150824191224 54108 example.com. LvODnPb7NLDZfHPBOrr/qLnOKA670vVYKQSk5Qkz3MPNKDVAFJqsP2Y6 UYcypSJZfcSjfIk2mU9dUiansU2ZL80OZJUsUobqJt5De748ovITYDJ7 afbohQzPg+4E1GIWMkJZ/VQD3B2pmr7J5rPn+vejxSQSoI93AIQaTpCU L5O/Bac=
// www.example.com. 86400 IN RRSIG AAAA 8 3 86400 20150914082216 20150824191224 54108 example.com. kje4FKE+7d/j4OzWQelcKkePq6DxCRY/5btAiUcZNf+zVNlHK+o57h1r Y76ZviWChQB8Np2TjA1DrXGi/kHr2KKE60H5822mFZ2b9O+sgW4q6o3G kO2E1CQxbYe+nI1Z8lVfjdCNm81zfvYqDjo2/tGqagehxG1V9MBZO6br 4KKdoa4=
// www.example.com. 86400 IN RRSIG A 8 3 86400 20150915023456 20150824191224 54108 example.com. cWtw0nMvcXcYNnxejB3Le3KBfoPPQZLmbaJ8ybdmzBDefQOm1ZjZZMOP wHEIxzdjRhG9mLt1mpyo1H7OezKTGX+mDtskcECTl/+jB/YSZyvbwRxj e88Lrg4D+D2MiajQn3XSWf+6LQVe1J67gdbKTXezvux0tRxBNHHqWXRk pxCILes=
return records;
}
pub fn create_secure_example() -> Authority {
use chrono::Duration;
use openssl::crypto::rsa::RSA;
use trust_dns::rr::dnssec::*;
let mut authority: Authority = create_example();
let rsa = RSA::generate(2048).unwrap();
let signer = Signer::new(Algorithm::RSASHA256, rsa, authority.get_origin().clone(), Duration::weeks(1));
authority.add_secure_key(signer);
authority.secure_zone();
authority
}

View File

@ -19,26 +19,23 @@
use std::collections::HashMap;
use std::sync::RwLock;
use ::rr::{Name, RecordType};
use trust_dns::op::{Edns, Message, MessageType, OpCode, Query, UpdateMessage, RequestHandler, ResponseCode};
use trust_dns::rr::{Name, RecordType};
use ::authority::{Authority, ZoneType};
use ::op::{Edns, Message, MessageType, OpCode, Query, UpdateMessage, ResponseCode};
/// Set of authorities, zones, available to this server.
pub struct Catalog {
authorities: HashMap<Name, RwLock<Authority>>,
}
impl Catalog {
pub fn new() -> Self {
Catalog{ authorities: HashMap::new() }
}
impl RequestHandler for Catalog {
/// Determine's what needs to happen given the type of request, i.e. Query or Update.
///
/// # Arguments
///
/// * `request` - the requested action to perform.
pub fn handle_request(&self, request: &Message) -> Message {
fn handle_request(&self, request: &Message) -> Message {
info!("id: {} type: {:?} op_code: {:?}", request.get_id(), request.get_message_type(), request.get_op_code());
debug!("request: {:?}", request);
@ -92,13 +89,13 @@ impl Catalog {
}
c @ _ => {
error!("unimplemented op_code: {:?}", c);
Self::error_msg(request.get_id(), request.get_op_code(), ResponseCode::NotImp)
Message::error_msg(request.get_id(), request.get_op_code(), ResponseCode::NotImp)
},
}
},
MessageType::Response => {
warn!("got a response as a request from id: {}", request.get_id());
Self::error_msg(request.get_id(), request.get_op_code(), ResponseCode::NotImp)
Message::error_msg(request.get_id(), request.get_op_code(), ResponseCode::NotImp)
},
};
@ -112,15 +109,11 @@ impl Catalog {
response
}
}
pub fn error_msg(id: u16, op_code: OpCode, response_code: ResponseCode) -> Message {
let mut message: Message = Message::new();
message.message_type(MessageType::Response);
message.id(id);
message.response_code(response_code);
message.op_code(op_code);
return message;
impl Catalog {
pub fn new() -> Self {
Catalog{ authorities: HashMap::new() }
}
pub fn upsert(&mut self, name: Name, authority: Authority) {
@ -294,159 +287,3 @@ impl Catalog {
None
}
}
#[cfg(test)]
mod catalog_tests {
use std::net::*;
use std::collections::*;
use ::authority::{Authority, ZoneType};
use ::authority::authority_tests::create_example;
use ::op::*;
use ::rr::*;
use ::rr::rdata::SOA;
use super::*;
pub fn create_test() -> Authority {
let origin: Name = Name::parse("test.com.", None).unwrap();
let mut records: Authority = Authority::new(origin.clone(), BTreeMap::new(), ZoneType::Master, false);
records.upsert(Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(94,184,216,34))).clone(), 0);
records.upsert(Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
let www_name: Name = Name::parse("www.test.com.", None).unwrap();
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(94,184,216,34))).clone(), 0);
records.upsert(Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(), 0);
records
}
#[test]
fn test_catalog_lookup() {
let example = create_example();
let test = create_test();
let origin = example.get_origin().clone();
let test_origin = test.get_origin().clone();
let mut catalog: Catalog = Catalog::new();
catalog.upsert(origin.clone(), example);
catalog.upsert(test_origin.clone(), test);
let mut question: Message = Message::new();
let mut query: Query = Query::new();
query.name(origin.clone());
question.add_query(query);
let result: Message = catalog.lookup(&question);
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_message_type(), MessageType::Response);
let answers: &[Record] = result.get_answers();
assert!(!answers.is_empty());
assert_eq!(answers.first().unwrap().get_rr_type(), RecordType::A);
assert_eq!(answers.first().unwrap().get_rdata(), &RData::A(Ipv4Addr::new(93,184,216,34)));
let mut ns: Vec<Record> = result.get_name_servers().to_vec();
ns.sort();
assert_eq!(ns.len(), 2);
assert_eq!(ns.first().unwrap().get_rr_type(), RecordType::NS);
assert_eq!(ns.first().unwrap().get_rdata(), &RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) );
assert_eq!(ns.last().unwrap().get_rr_type(), RecordType::NS);
assert_eq!(ns.last().unwrap().get_rdata(), &RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) );
// other zone
let mut query: Query = Query::new();
query.name(test_origin.clone());
question.add_query(query);
let result: Message = catalog.lookup(&question);
assert_eq!(result.get_response_code(), ResponseCode::NoError);
assert_eq!(result.get_message_type(), MessageType::Response);
let answers: &[Record] = result.get_answers();
assert!(!answers.is_empty());
assert_eq!(answers.first().unwrap().get_rr_type(), RecordType::A);
assert_eq!(answers.first().unwrap().get_rdata(), &RData::A(Ipv4Addr::new(93,184,216,34)));
}
#[test]
fn test_catalog_nx_soa() {
let example = create_example();
let origin = example.get_origin().clone();
let mut catalog: Catalog = Catalog::new();
catalog.upsert(origin.clone(), example);
let mut question: Message = Message::new();
let mut query: Query = Query::new();
query.name(Name::parse("nx.example.com.", None).unwrap());
question.add_query(query);
let result: Message = catalog.lookup(&question);
assert_eq!(result.get_response_code(), ResponseCode::NXDomain);
assert_eq!(result.get_message_type(), MessageType::Response);
let ns: &[Record] = result.get_name_servers();
assert_eq!(ns.len(), 1);
assert_eq!(ns.first().unwrap().get_rr_type(), RecordType::SOA);
assert_eq!(ns.first().unwrap().get_rdata(), &RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 )));
}
#[test]
fn test_axfr() {
let test = create_test();
let origin = test.get_origin().clone();
let soa = Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone();
let mut catalog: Catalog = Catalog::new();
catalog.upsert(origin.clone(), test);
let mut query: Query = Query::new();
query.name(origin.clone());
query.query_type(RecordType::AXFR);
let mut question: Message = Message::new();
question.add_query(query);
let result: Message = catalog.lookup(&question);
let mut answers: Vec<Record> = result.get_answers().to_vec();
assert_eq!(answers.first().unwrap(), &soa);
assert_eq!(answers.last().unwrap(), &soa);
answers.sort();
let www_name: Name = Name::parse("www.test.com.", None).unwrap();
let mut expected_set = vec![
Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone(),
Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("a.iana-servers.net.", None).unwrap()) ).clone(),
Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::NS).dns_class(DNSClass::IN).rdata(RData::NS(Name::parse("b.iana-servers.net.", None).unwrap()) ).clone(),
Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(94,184,216,34))).clone(),
Record::new().name(origin.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(),
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::A).dns_class(DNSClass::IN).rdata(RData::A(Ipv4Addr::new(94,184,216,34))).clone(),
Record::new().name(www_name.clone()).ttl(86400).rr_type(RecordType::AAAA).dns_class(DNSClass::IN).rdata(RData::AAAA(Ipv6Addr::new(0x2606,0x2800,0x220,0x1,0x248,0x1893,0x25c8,0x1946))).clone(),
Record::new().name(origin.clone()).ttl(3600).rr_type(RecordType::SOA).dns_class(DNSClass::IN).rdata(RData::SOA(SOA::new(Name::parse("sns.dns.icann.org.", None).unwrap(), Name::parse("noc.dns.icann.org.", None).unwrap(), 2015082403, 7200, 3600, 1209600, 3600 ))).clone(),
];
expected_set.sort();
assert_eq!(expected_set, answers);
}
}

View File

@ -16,23 +16,17 @@
//! Module for `Catalog` of `Authority` zones which are responsible for storing `RRSet` records.
use ::op::ResponseCode;
use trust_dns::op::ResponseCode;
pub type UpdateResult<T> = Result<T, ResponseCode>;
#[derive(RustcDecodable, PartialEq, Eq, Debug, Clone, Copy)]
pub enum ZoneType { Master, Slave, Hint, Forward }
mod authority;
pub mod authority;
mod catalog;
mod persistence;
mod rr_set;
pub mod persistence;
pub use self::authority::Authority;
pub use self::authority::RrKey;
pub use self::catalog::Catalog;
pub use self::rr_set::RRSet;
pub use self::persistence::Journal;
#[cfg(test)]
pub use self::authority::authority_tests;

View File

@ -12,12 +12,12 @@ use rusqlite;
use rusqlite::Connection;
use rusqlite::SqliteError;
use ::error::PersistenceErrorKind;
use ::error::PersistenceResult;
use ::rr::Record;
use ::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
use trust_dns::rr::Record;
use trust_dns::serialize::binary::{BinDecoder, BinEncoder, BinSerializable};
const CURRENT_VERSION: i64 = 1;
use ::error::{PersistenceErrorKind, PersistenceResult};
pub const CURRENT_VERSION: i64 = 1;
/// The Journal is the audit log of all changes to a zone after initial creation.
pub struct Journal {
@ -42,6 +42,10 @@ impl Journal {
}
}
pub fn get_conn(&self) -> &Connection {
&self.conn
}
/// gets the current schema version of the journal
pub fn get_schema_version(&self) -> i64 {
self.version
@ -140,7 +144,7 @@ impl Journal {
/// # Arguments
///
/// * `conn` - db connection to use
fn select_schema_version(conn: &Connection) -> PersistenceResult<i64> {
pub fn select_schema_version(conn: &Connection) -> PersistenceResult<i64> {
// first see if our schema is there
let mut stmt = try!(conn.prepare("SELECT name
FROM sqlite_master
@ -258,87 +262,3 @@ impl<'j> Iterator for JournalIter<'j> {
}
}
}
#[test]
fn test_new_journal() {
let conn = Connection::open_in_memory().expect("could not create in memory DB");
assert_eq!(Journal::new(conn).expect("new Journal").get_schema_version(), -1);
}
#[test]
fn test_init_journal() {
let conn = Connection::open_in_memory().expect("could not create in memory DB");
let mut journal = Journal::new(conn).unwrap();
let version = journal.schema_up().unwrap();
assert_eq!(version, CURRENT_VERSION);
assert_eq!(Journal::select_schema_version(&journal.conn).unwrap(), CURRENT_VERSION);
}
#[cfg(test)]
fn create_test_journal() -> (Record, Journal) {
use std::net::Ipv4Addr;
use std::str::FromStr;
use ::rr::{Name, RData, Record, RecordType};
let www = Name::with_labels(vec!["www".to_string(),"example".to_string(), "com".to_string()]);
let mut record = Record::new();
record.name(www);
record.rr_type(RecordType::A);
record.rdata(RData::A(Ipv4Addr::from_str("127.0.0.1").unwrap()));
// test that this message can be inserted
let conn = Connection::open_in_memory().expect("could not create in memory DB");
let mut journal = Journal::new(conn).unwrap();
journal.schema_up().unwrap();
// insert the message
journal.insert_record(0, &record).unwrap();
// insert another...
record.rdata(RData::A(Ipv4Addr::from_str("127.0.1.1").unwrap()));
journal.insert_record(0, &record).unwrap();
(record, journal)
}
#[test]
fn test_insert_and_select_record() {
use std::net::Ipv4Addr;
use std::str::FromStr;
use rr::RData;
let (mut record, journal) = create_test_journal();
// select the record
let (row_id, journal_record) = journal.select_record(0).expect("persistence error").expect("none");
record.rdata(RData::A(Ipv4Addr::from_str("127.0.0.1").unwrap()));
assert_eq!(journal_record, record);
// test another
let (row_id, journal_record) = journal.select_record(row_id + 1).expect("persistence error").expect("none");
record.rdata(RData::A(Ipv4Addr::from_str("127.0.1.1").unwrap()));
assert_eq!(journal_record, record);
// check that we get nothing for id over row_id
let option_none = journal.select_record(row_id + 1).expect("persistence error");
assert!(option_none.is_none());
}
#[test]
fn test_iterator() {
use std::net::Ipv4Addr;
use std::str::FromStr;
use rr::RData;
let (mut record, journal) = create_test_journal();
let mut iter = journal.iter();
assert_eq!(record.rdata(RData::A(Ipv4Addr::from_str("127.0.0.1").unwrap())), &iter.next().unwrap());
assert_eq!(record.rdata(RData::A(Ipv4Addr::from_str("127.0.1.1").unwrap())), &iter.next().unwrap());
assert_eq!(None, iter.next());
}

View File

@ -27,9 +27,11 @@ use rustc_serialize::Decodable;
use toml::{Decoder, Value};
use ::error::{ConfigErrorKind, ConfigResult, ConfigError, ParseResult};
use ::rr::Name;
use trust_dns::error::ParseResult;
use trust_dns::rr::Name;
use ::authority::ZoneType;
use ::error::{ConfigErrorKind, ConfigResult, ConfigError};
static DEFAULT_PORT: u16 = 53;
static DEFAULT_PATH: &'static str = "/var/named"; // TODO what about windows (do I care? ;)

Some files were not shown because too many files have changed in this diff Show More