Merge branch 'master' into 0.7.2_patch

This commit is contained in:
Benjamin Fry 2016-08-10 22:12:08 -07:00
commit 389e6004d1
17 changed files with 455 additions and 294 deletions

View File

@ -1,4 +1,7 @@
language: rust
os:
- linux
- osx
rust:
- stable
- beta

View File

@ -2,6 +2,13 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## unreleased
### Fixed
- Randomized ports for client connections and message ids, #23
### Changed
- Cleaned up the Server implementation to isolate connection handlers
## 0.7.2 2016-08-10
### Fixed
- Issue #28: RRSIG validation of wildcards, label length > wildcard length

201
Cargo.lock generated
View File

@ -2,24 +2,25 @@
name = "trust-dns"
version = "0.7.1"
dependencies = [
"backtrace 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chrono 0.2.22 (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.78 (registry+https://github.com/rust-lang/crates.io-index)",
"docopt 0.6.81 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (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.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.14 (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)",
"toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "aho-corasick"
version = "0.5.1"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -27,15 +28,16 @@ dependencies = [
[[package]]
name = "backtrace"
version = "0.2.1"
version = "0.2.2"
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.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (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.13 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -43,8 +45,8 @@ name = "backtrace-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -69,10 +71,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "chrono"
version = "0.2.21"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -86,16 +88,16 @@ name = "dbghelp-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (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.78"
version = "0.6.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"regex 0.1.62 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 0.1.71 (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.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -105,39 +107,40 @@ name = "error-chain"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"backtrace 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gcc"
version = "0.3.26"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gdi32-sys"
version = "0.1.1"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (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.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (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.1.15"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.9"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -153,7 +156,7 @@ name = "libsqlite3-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -180,28 +183,23 @@ name = "memchr"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "mempool"
version = "0.3.0"
source = "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.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (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.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.25 (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.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -209,71 +207,98 @@ name = "miow"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (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.23"
version = "0.2.25"
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.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (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.13 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (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.0"
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.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num"
version = "0.1.31"
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-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (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.32 (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.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl"
version = "0.7.8"
version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys-extras 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.28 (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.13 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys-extras 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "openssl-sys"
version = "0.7.8"
version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gdi32-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"gdi32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (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.1.2 (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 = "openssl-sys-extras"
version = "0.7.8"
version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"gcc 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -294,24 +319,24 @@ name = "rand"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "regex"
version = "0.1.62"
version = "0.1.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"aho-corasick 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"mempool 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex-syntax 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"thread_local 0.2.6 (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.1"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -320,12 +345,17 @@ 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.9 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.13 (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.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc-serialize"
version = "0.3.19"
@ -349,19 +379,36 @@ 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.13 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "thread_local"
version = "0.2.6"
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.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.6 (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.13 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "toml"
version = "0.1.28"
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)",
@ -369,10 +416,10 @@ dependencies = [
[[package]]
name = "user32-sys"
version = "0.1.2"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -383,7 +430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi"
version = "0.2.6"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -396,7 +443,7 @@ name = "ws2_32-sys"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -73,6 +73,7 @@ log = "^0.3.5"
mio = "^0.5.1"
openssl = "^0.7.8"
openssl-sys = "^0.7.8"
rand = "^0.3"
rustc-serialize = "^0.3.18"
rusqlite = "^0.7.3"
time = "^0.1.35"

View File

@ -127,12 +127,21 @@ presume that the trust-dns repos have already been synced to the local system:
## Prerequisites
- openssl development libraries are necessary
- openssl development libraries
- sqlite3 development libraries
Mac OS X: using homebrew
$ brew install openssl
$ brew link --force openssl
$ brew install sqlite
Debian-based (includes Ubuntu & Raspbian): using apt-get
$ apt-get install openssl
$ apt-get install libssl-dev
$ apt-get install libsqlite3-dev
## Testing

View File

@ -12,13 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::cell::{Cell, RefCell};
use std::cell::RefCell;
use std::collections::HashSet;
use std::sync::Arc as Rc;
use chrono::UTC;
use data_encoding::base32hex;
use openssl::crypto::pkey::Role;
use rand;
use ::error::*;
use ::rr::{DNSClass, RecordType, Record, RData};
@ -34,7 +35,6 @@ use ::client::ClientConnection;
/// disallow TCP in some cases, so if TCP double check if UDP works.
pub struct Client<C: ClientConnection> {
client_connection: RefCell<C>,
next_id: Cell<u16>,
trust_anchor: TrustAnchor,
}
@ -46,7 +46,6 @@ impl<C: ClientConnection> Client<C> {
/// * `client_connection` - the client_connection to use for all communication
pub fn new(client_connection: C) -> Client<C> {
Client{ client_connection: RefCell::new(client_connection),
next_id: Cell::new(1037),
trust_anchor: TrustAnchor::default() }
}
@ -59,7 +58,6 @@ impl<C: ClientConnection> Client<C> {
/// root public_key.
pub fn with_trust_anchor(client_connection: C, trust_anchor: TrustAnchor) -> Client<C> {
Client{ client_connection: RefCell::new(client_connection),
next_id: Cell::new(1037),
trust_anchor: trust_anchor }
}
@ -494,7 +492,7 @@ impl<C: ClientConnection> Client<C> {
// build the message
let mut message: Message = Message::new();
let id = self.next_id();
let id: u16 = rand::random();
// TODO make recursion a parameter
message.id(id).message_type(MessageType::Query).op_code(OpCode::Query).recursion_desired(true);
@ -566,7 +564,7 @@ impl<C: ClientConnection> Client<C> {
// build the message
let mut message: Message = Message::new();
message.id(self.next_id()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.id(rand::random()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
let mut prerequisite = Record::with(record.get_name().clone(), record.get_rr_type(), 0);
@ -642,7 +640,7 @@ impl<C: ClientConnection> Client<C> {
// build the message
let mut message: Message = Message::new();
message.id(self.next_id()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.id(rand::random()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
if must_exist {
@ -729,7 +727,7 @@ impl<C: ClientConnection> Client<C> {
// build the message
let mut message: Message = Message::new();
message.id(self.next_id()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.id(rand::random()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
// make sure the record is what is expected
@ -816,7 +814,7 @@ impl<C: ClientConnection> Client<C> {
// build the message
let mut message: Message = Message::new();
message.id(self.next_id()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.id(rand::random()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
// the class must be none for delete
@ -893,7 +891,7 @@ impl<C: ClientConnection> Client<C> {
// build the message
let mut message: Message = Message::new();
message.id(self.next_id()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.id(rand::random()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
// the class must be none for an rrset delete
@ -962,7 +960,7 @@ impl<C: ClientConnection> Client<C> {
// build the message
let mut message: Message = Message::new();
message.id(self.next_id()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.id(rand::random()).message_type(MessageType::Query).op_code(OpCode::Update).recursion_desired(false);
message.add_zone(zone);
// the TTL shoudl be 0
@ -1018,13 +1016,6 @@ impl<C: ClientConnection> Client<C> {
Ok(response)
}
/// increments the next_id for use in messages
fn next_id(&self) -> u16 {
let id = self.next_id.get();
self.next_id.set(id + 1);
id
}
}
#[cfg(test)]

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
use std::error::Error as StdError;
use std::io::Error as IoError;
use ::op::ResponseCode;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::error::Error as StdError;
use std::io;
use toml::ParserError;

View File

@ -14,7 +14,6 @@
* limitations under the License.
*/
use std::error::Error as StdError;
use std::string::FromUtf8Error;
use openssl::ssl::error::SslError;

View File

@ -14,8 +14,6 @@
* limitations under the License.
*/
use std::error::Error as StdError;
error_chain! {
// The type defined for this error. These are the conventional
// and recommended names, but they can be arbitrarily chosen.

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::error::Error as StdError;
use std::num;
use std::string::FromUtf8Error;

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::error::Error as StdError;
use std::num;
use std::io;
use std::net::AddrParseError;

View File

@ -4,8 +4,6 @@
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
use std::error::Error as StdError;
use rusqlite;
use super::{decode_error, encode_error};

View File

@ -33,6 +33,7 @@ extern crate data_encoding;
extern crate mio;
extern crate openssl;
extern crate openssl_sys;
extern crate rand;
extern crate rusqlite;
extern crate rustc_serialize;
extern crate time;

View File

@ -19,7 +19,7 @@ use std::io;
use std::sync::Arc;
use std::cell::Cell;
use mio::{Token, EventLoop, Handler, EventSet, PollOpt, TryAccept};
use mio::{Token, Evented, EventLoop, Handler, EventSet, PollOpt};
use mio::tcp::{TcpListener, TcpStream};
use mio::udp::UdpSocket;
@ -31,13 +31,7 @@ use ::udp::{UdpHandler, UdpState};
// TODO, might be cool to store buffers for later usage...
pub struct Server {
udp_sockets: HashMap<Token, UdpSocket>,
// for each udp_socket, there is a set of udp_responses. The token is the same as the one
// registered in udp_sockets above, and the vector is the set of addresses for which we have
// responses.
udp_requests: HashMap<Token, VecDeque<UdpHandler>>,
tcp_sockets: HashMap<Token, TcpListener>,
tcp_handlers: HashMap<Token, TcpHandler>,
handlers: HashMap<Token, DnsHandlerType>,
next_token: Cell<usize>,
catalog: Arc<Catalog>, // should the catalog just be static?
}
@ -45,10 +39,7 @@ pub struct Server {
impl Server {
pub fn new(catalog: Catalog) -> Server {
Server {
udp_sockets: HashMap::new(),
udp_requests: HashMap::new(),
tcp_sockets: HashMap::new(),
tcp_handlers: HashMap::new(),
handlers: HashMap::new(),
next_token: Cell::new(0),
catalog: Arc::new(catalog),
}
@ -58,9 +49,7 @@ impl Server {
for _ in 0..100 {
self.next_token.set(self.next_token.get()+1);
let token: Token = Token(self.next_token.get());
if self.tcp_sockets.contains_key(&token) { continue }
else if self.tcp_handlers.contains_key(&token) { continue }
else if self.udp_sockets.contains_key(&token) { continue }
if self.handlers.contains_key(&token) { continue }
// ok, safe to use
return token;
@ -72,14 +61,14 @@ impl Server {
/// register a UDP socket. Should be bound before calling this.
pub fn register_socket(&mut self, socket: UdpSocket) {
let token = self.next_token();
self.udp_sockets.insert(token, socket);
self.handlers.insert(token, DnsHandlerType::UdpSocket((socket, VecDeque::new())));
}
/// register a TcpListener to the Server. This should already be bound to either an IPv6 or an
/// IPv4 address.
pub fn register_listener(&mut self, listener: TcpListener) {
let token = self.next_token();
self.tcp_sockets.insert(token, listener);
self.handlers.insert(token, DnsHandlerType::TcpListener(listener));
}
/// TODO how to do threads? should we do a bunch of listener threads and then query threads?
@ -90,8 +79,13 @@ impl Server {
let mut event_loop: EventLoop<Self> = try!(EventLoop::new());
// registering these on non-writable events, since these are the listeners.
for (ref token, ref socket) in &self.udp_sockets { try!(event_loop.register(*socket, **token, !EventSet::writable(), PollOpt::all())); }
for (ref token, ref socket) in &self.tcp_sockets { try!(event_loop.register(*socket, **token, !EventSet::writable(), PollOpt::all())); }
for (token, handler) in self.handlers.iter() {
match *handler {
DnsHandlerType::UdpSocket(ref handler) => try!(event_loop.register(handler.get_socket(), *token, !EventSet::writable(), PollOpt::all())),
DnsHandlerType::TcpListener(ref handler) => try!(event_loop.register(handler.get_socket(), *token, !EventSet::writable(), PollOpt::all())),
DnsHandlerType::TcpHandler(_) => panic!("tcp handlers should not have been registered yet"),
}
}
try!(event_loop.run(self));
@ -140,175 +134,279 @@ impl Server {
}
}
// each dns handler type is used for managing client requests.
enum DnsHandlerType {
// the deque represents responses that need to be sent back to the client
// as of now this these are local requests, but in the future these will be resolver based
// responses, which will have some time between resolve and response
UdpSocket((UdpSocket, VecDeque<UdpHandler>)),
// Inbound TCP connections
TcpListener(TcpListener),
// Handlers for the TCP connections
TcpHandler(TcpHandler),
}
/// Handler for DNS requests
trait DnsHandler {
/// Called when the Evented of the Handler is woken up on activity
///
/// # Arguments
/// * `events` - the set of events that that woke this socket up
/// * `catalog` - the local catalog for lookups
///
/// # Return
///
/// Returns a tuple of the next event_set for this handler, and/or a new handler to add to the
/// the event_loop. If the first of the tuple is None, self will be removed from the event_loop.
/// If the second is None, nothing will happen, otherwise the new handler will be added to the
/// event_loop.
fn handle(&mut self, events: EventSet, catalog: &Arc<Catalog>) -> (Option<EventSet>, Option<(DnsHandlerType, EventSet)>);
/// returns the Evented which self wraps.
fn get_socket(&self) -> &Evented;
}
impl DnsHandler for DnsHandlerType {
fn handle(&mut self, events: EventSet, catalog: &Arc<Catalog>) -> (Option<EventSet>, Option<(DnsHandlerType, EventSet)>) {
match *self {
DnsHandlerType::UdpSocket(ref mut udp_handler) => udp_handler.handle(events, catalog),
DnsHandlerType::TcpListener(ref mut tcp_listener) => tcp_listener.handle(events, catalog),
DnsHandlerType::TcpHandler(ref mut tcp_handler) => tcp_handler.handle(events, catalog),
}
}
fn get_socket(&self) -> &Evented {
match *self {
DnsHandlerType::UdpSocket(ref udp_handler) => udp_handler.get_socket() as &Evented,
DnsHandlerType::TcpListener(ref tcp_listener) => tcp_listener.get_socket() as &Evented,
DnsHandlerType::TcpHandler(ref tcp_handler) => tcp_handler.get_socket() as &Evented,
}
}
}
impl DnsHandler for TcpListener {
fn handle(&mut self, events: EventSet, _: &Arc<Catalog>) -> (Option<EventSet>, Option<(DnsHandlerType, EventSet)>) {
if events.is_error() { panic!("unexpected error state on: {:?}", self) }
else if events.is_hup() { panic!("listening socket hungup: {:?}", self) }
else if events.is_readable() || events.is_writable() {
// there's a new connection coming in
// give it a new token and insert the stream on the eventlistener
// then store in the map for reference when dealing with new streams
for _ in 0..100 { // loop a max of 100 times, don't want to starve the responses.
match self.accept() {
Ok(Some((stream, addr))) => {
info!("new tcp connection from: {}", addr);
return (Some(EventSet::all()), Some((DnsHandlerType::TcpHandler(TcpHandler::new_server_handler(stream)),
!EventSet::writable())))
},
Ok(None) => {
return (Some(EventSet::all()), None)
},
Err(e) => panic!("unexpected error accepting: {}", e),
}
}
}
// this should never happen
return (Some(EventSet::all()), None)
}
fn get_socket(&self) -> &Evented {
return self as &Evented
}
}
impl DnsHandler for (UdpSocket, VecDeque<UdpHandler>) {
fn handle(&mut self, events: EventSet, catalog: &Arc<Catalog>) -> (Option<EventSet>, Option<(DnsHandlerType, EventSet)>) {
let ref socket = self.0;
let ref mut requests = self.1;
if events.is_error() {
panic!("unexpected socket error: {:?}", socket)
} else if events.is_hup() {
panic!("unexpected socket hangup: {:?}", socket)
} else {
let mut next_event: EventSet = EventSet::all();
// process the responses before the requests...
if events.is_writable() {
let mut remove: Vec<usize> = Vec::new();
// send all the data for the incomplete requests
for (i, req) in requests.iter().enumerate() {
match req.handle_message (&socket, events) {
Ok(UdpState::Done) => {
// complete, remove
remove.push(i);
},
Ok(..) => {
// Noop, request not complete
},
Err(ref e) if io::ErrorKind::WouldBlock == e.kind() => {
// this is expected with the connection would block
// noop
},
Err(e) => {
// shutdown the connection, remove it.
warn!("error writing socket: {:?} error: {}", socket, e);
// TODO: do we need to shutdown the stream?
remove.push(i);
}
}
}
// remove the complete requests
for i in remove {
requests.remove(i);
// TODO might want to compress the list here, as it could become a leak after a large
// set of requests.
}
if requests.is_empty() {
next_event = !EventSet::writable();
}
}
// now process the incoming requests
if events.is_readable() {
// collect new requests
// TODO: could a ton of inbound requests starve the server
for _ in 0..100 {
if let Some(handler) = UdpHandler::new_server(&socket, catalog.clone()) {
// this is a new request for a UDP transaction
// let the handler read, etc.
requests.push_back(handler);
next_event = EventSet::all();
} else {
break
}
}
}
return (Some(next_event), None)
}
return (Some(EventSet::all()), None)
}
fn get_socket(&self) -> &Evented {
return &self.0 as &Evented
}
}
impl DnsHandler for TcpHandler {
fn handle(&mut self, events: EventSet, catalog: &Arc<Catalog>) -> (Option<EventSet>, Option<(DnsHandlerType, EventSet)>) {
if events.is_error() {
warn!("closing, error from: {:?}", self.get_stream());
// TODO: do we need to shutdown the stream?
return (None, None);
} else if events.is_hup() {
info!("client hungup: {:?}", self.get_stream());
// TODO: do we need to shutdown the stream?
return (None, None);
} else if events.is_readable() || events.is_writable() {
let mut process_resquest = false;
// the handler will deal with the rest of the connection, we need to check the return value
// for an error with wouldblock, this means that the handler couldn't complete the request.
match self.handle_message(events) {
Ok(TcpState::Done) => {
// reset, the client will close the connection according to the spec
self.reset();
debug!("TcpState::Done");
},
Ok(TcpState::WillWriteLength) => {
// this means that we have gotten through recieving a packet
process_resquest = true;
debug!("TcpState::WillWriteLength");
}
Ok(..) => {
// registering the event to only wake up on the correct event
// this reduces looping on states like writable that can remain set for a long time
debug!("reregistering for next call: {:?}", self.get_events());
},
Err(ref e) if io::ErrorKind::WouldBlock == e.kind() => {
// this is expected with the connection would block
// noop
},
Err(e) => {
// shutdown the connection, remove it.
warn!("connection: {:?} shutdown on error: {}", self.get_stream(), e);
// TODO: do we need to shutdown the stream?
return (None, None);
}
}
// need to process the response
if process_resquest {
let response = Server::process_request(self.get_buffer(), self.get_stream(), catalog.as_ref());
if Server::encode_message(response, self.get_buffer_mut()).is_err() {
warn!("could not encode message to: {:?}", self.get_stream());
return (None, None)
}
}
}
debug!("reregistering for next call: {:?}", self.get_events());
return (Some(self.get_events()), None)
}
fn get_socket(&self) -> &Evented {
return self.get_stream() as &Evented
}
}
impl Handler for Server {
type Timeout = Token; // Timeouts are registered with tokens.
type Message = ();
fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
let mut remove: Option<RemoveFrom> = None;
let mut remove_token: Option<Token> = None;
let mut add_handler: Option<(DnsHandlerType, EventSet)> = None;
if let Some(socket) = self.udp_sockets.get(&token) {
if events.is_error() {
panic!("unexpected socket error: {:?}", socket)
} else if events.is_hup() {
panic!("unexpected socket hangup: {:?}", socket)
// The token should always exist
if let Some(mut handler) = self.handlers.get_mut(&token) {
// the handler will perform the lookup or other actions.
// if none is returned for event_set_opt, the handler will be revmoed
let (event_set_opt, add) = handler.handle(events, &self.catalog);
// this represents a new handler to watch
add_handler = add;
// given the new event_set option, reregister the socket
if let Some(event_set) = event_set_opt {
let socket: &Evented = handler.get_socket();
if let Err(err) = event_loop.reregister(socket, token, event_set, PollOpt::all()) {
// removing the socket in case of an error
warn!("cound not reregister {:?}: {}", token, err);
remove_token = Some(token);
}
} else {
// process the responses before the requests...
if events.is_writable() {
// send out our queued up responses
if let Some(reqs) = self.udp_requests.get_mut(&token) {
let mut remove: Vec<usize> = Vec::new();
// send all the data for the incomplete requests
for (i, req) in reqs.iter().enumerate() {
match req.handle_message (&socket, events) {
Ok(UdpState::Done) => {
// complete, remove
remove.push(i);
},
Ok(..) => {
// Noop, request not complete
},
Err(ref e) if io::ErrorKind::WouldBlock == e.kind() => {
// this is expected with the connection would block
// noop
},
Err(e) => {
// shutdown the connection, remove it.
warn!("error writing socket: {:?} error: {}", socket, e);
// TODO: do we need to shutdown the stream?
remove.push(i);
}
}
}
// remove the complete requests
for i in remove {
reqs.remove(i);
// TODO might want to compress the list here, as it could become a leak after a large
// set of requests.
}
if reqs.is_empty() {
// theres nothing left you write, go back to just reading...
if let Err(e) = event_loop.reregister(socket, token, !EventSet::writable(), PollOpt::all()) {
error!("could not reregister socket: {:?} error: {}", socket, e);
}
}
}
}
// now process the incoming requests
if events.is_readable() {
// collect new requests
// TODO: could a ton of inbound requests starve the server
while let Some(handler) = UdpHandler::new_server(socket, self.catalog.clone()) {
// this is a new request for a UDP transaction
// let the handler read, etc.
self.udp_requests.entry(token).or_insert(VecDeque::new()).push_back(handler);
// reregeister the UDP socket for writes
if let Err(e) = event_loop.reregister(socket, token, EventSet::all(), PollOpt::all()) {
error!("could not reregister socket: {:?} error: {}", socket, e);
}
}
}
}
} else if let Some(ref socket) = self.tcp_sockets.get(&token) {
if events.is_error() { panic!("unexpected error state on: {:?}", socket) }
else if events.is_hup() { panic!("listening socket hungup: {:?}", socket) }
else if events.is_readable() || events.is_writable() {
// there's a new connection coming in
// give it a new token and insert the stream on the eventlistener
// then store in the map for reference when dealing with new streams
loop {
match socket.accept() {
Ok(Some((stream, addr))) => {
let token = self.next_token();
// initially we want readable sockets...
match event_loop.register(&stream, token, !EventSet::writable(), PollOpt::level()) {
Err(e) => error!("could not register stream: {:?} cause: {}", stream, e),
Ok(()) => {
info!("accepted tcp connection from: {:?} on {:?}", addr, stream.local_addr().ok());
self.tcp_handlers.insert(token, TcpHandler::new_server_handler(stream));
}
}
},
Ok(None) => return,
Err(e) => panic!("unexpected error accepting: {}", e),
}
}
}
} else if let Some(ref mut handler) = self.tcp_handlers.get_mut(&token) {
if events.is_error() {
warn!("closing, error from: {:?}", handler.get_stream());
// TODO: do we need to shutdown the stream?
remove = Some(RemoveFrom::TcpHandlers(token));
} else if events.is_hup() {
info!("client hungup: {:?}", handler.get_stream());
// TODO: do we need to shutdown the stream?
remove = Some(RemoveFrom::TcpHandlers(token));
} else if events.is_readable() || events.is_writable() {
let mut process_resquest = false;
// the handler will deal with the rest of the connection, we need to check the return value
// for an error with wouldblock, this means that the handler couldn't complete the request.
match handler.handle_message(events) {
Ok(TcpState::Done) => {
// reset, the client will close the connection according to the spec
handler.reset();
debug!("TcpState::Done");
},
Ok(TcpState::WillWriteLength) => {
// this means that we have gotten through recieving a packet
process_resquest = true;
debug!("TcpState::WillWriteLength");
}
Ok(..) => {
// registering the event to only wake up on the correct event
// this reduces looping on states like writable that can remain set for a long time
//if let Err(e) = event_loop.reregister(handler.get_stream(), token, handler.get_events(), PollOpt::level()) {
debug!("reregistering for next call: {:?}", handler.get_events());
if let Err(e) = event_loop.reregister(handler.get_stream(), token, handler.get_events(), PollOpt::all()) {
error!("could not reregister stream: {:?} cause: {}", handler.get_stream(), e);
remove = Some(RemoveFrom::TcpHandlers(token));
}
},
Err(ref e) if io::ErrorKind::WouldBlock == e.kind() => {
// this is expected with the connection would block
// noop
},
Err(e) => {
// shutdown the connection, remove it.
warn!("connection: {:?} shutdown on error: {}", handler.get_stream(), e);
// TODO: do we need to shutdown the stream?
remove = Some(RemoveFrom::TcpHandlers(token));
}
}
// need to process the response
if process_resquest {
let response = Self::process_request(handler.get_buffer(), handler.get_stream(), self.catalog.as_ref());
if Self::encode_message(response, handler.get_buffer_mut()).is_err() {
warn!("could not encode message to: {:?}", handler.get_stream());
remove = Some(RemoveFrom::TcpHandlers(token))
}
debug!("reregistering for next call: {:?}", handler.get_events());
if let Err(e) = event_loop.reregister(handler.get_stream(), token, handler.get_events(), PollOpt::all()) {
error!("could not reregister stream: {:?} cause: {}", handler.get_stream(), e);
remove = Some(RemoveFrom::TcpHandlers(token));
}
}
remove_token = Some(token);
}
}
// check if we need to remove something
match remove {
Some(RemoveFrom::TcpHandlers(t)) => { self.tcp_handlers.remove(&t); },
//Some(RemoveFrom::UdpRequests(t)) => { self.udp_requests.remove(&t); },
None => (),
// unregister the token
remove_token.and_then(|token| {
self.handlers.remove(&token)
}).and_then(|handler| {
event_loop.deregister(handler.get_socket()).unwrap_or_else(|e| debug!("error deregistering: {}", e));
Some(())
});
// need to register a new handler if there was one.
if let Some((handler, event_set)) = add_handler {
let register_res: io::Result<Token> = {
let socket: &Evented = handler.get_socket();
let next_token = self.next_token();
event_loop.register(socket, next_token, event_set, PollOpt::all()).map(|_| next_token)
};
match register_res {
Ok(token) => { self.handlers.insert(token, handler); },
Err(err) => warn!("error registering handler: {}", err),
}
}
}
@ -319,11 +417,6 @@ impl Handler for Server {
}
}
enum RemoveFrom {
TcpHandlers(Token),
//UdpRequests(Token),
}
#[cfg(test)]
mod server_tests {
use std::thread;

View File

@ -16,7 +16,6 @@
use std::net::SocketAddr;
use std::io;
use std::io::Write;
use std::mem;
use std::fmt;
@ -46,6 +45,8 @@ impl TcpClientConnection {
///
/// * `name_server` - address of the name server to use for queries
pub fn new(name_server: SocketAddr) -> ClientResult<Self> {
// TODO: randomize local port binding issue #23
// probably not necessary for TCP...
debug!("connecting to {:?}", name_server);
let stream = try!(TcpStream::connect(&name_server));

View File

@ -20,6 +20,8 @@ use std::fmt;
use mio::udp::UdpSocket;
use mio::{Token, EventLoop, Handler, EventSet, PollOpt}; // not * b/c don't want confusion with std::net
use rand::Rng;
use rand;
use ::error::*;
use client::ClientConnection;
@ -34,6 +36,23 @@ pub struct UdpClientConnection {
}
impl UdpClientConnection {
fn next_bound_local_address() -> ClientResult<UdpSocket> {
let mut rand = rand::thread_rng();
let mut error = Err(ClientErrorKind::Message("could not bind address in 10 tries").into());
for _ in 0..10 {
let zero_addr = ("0.0.0.0", rand.gen_range(1025_u16, u16::max_value())).to_socket_addrs().expect("could not parse 0.0.0.0 address").
next().expect("no addresses parsed from 0.0.0.0");
match UdpSocket::bound(&zero_addr) {
Ok(socket) => return Ok(socket),
Err(err) => error = Err(err.into()),
}
}
error
}
/// Creates a new client connection.
///
/// *Note* this has side affects of binding the socket to 0.0.0.0 and starting the listening
@ -43,11 +62,9 @@ impl UdpClientConnection {
///
/// * `name_server` - address of the name server to use for queries
pub fn new(name_server: SocketAddr) -> ClientResult<Self> {
// TODO: allow the bind address to be specified...
// client binds to all addresses... this shouldn't ever fail
let zero_addr = ("0.0.0.0", 0).to_socket_addrs().expect("could not parse 0.0.0.0 address").
next().expect("no addresses parsed from 0.0.0.0");
let socket = try!(UdpSocket::bound(&zero_addr));
let socket = try!(Self::next_bound_local_address());
let mut event_loop: EventLoop<Response> = try!(EventLoop::new());
// TODO make the timeout configurable, 5 seconds is the dig default
// TODO the error is private to mio, which makes this awkward...